jiti-meet/react/features/base/sounds/reducer.ts

142 lines
3.8 KiB
TypeScript

// @ts-ignore
import type { AudioElement } from '../media';
import ReducerRegistry from '../redux/ReducerRegistry';
import { assign } from '../redux/functions';
import {
REGISTER_SOUND,
UNREGISTER_SOUND,
_ADD_AUDIO_ELEMENT,
_REMOVE_AUDIO_ELEMENT
} from './actionTypes';
/**
* The structure use by this reducer to describe a sound.
*/
export type Sound = {
/**
* The HTMLAudioElement which implements the audio playback functionality.
* Becomes available once the sound resource gets loaded and the sound can
* not be played until that happens.
*/
audioElement?: AudioElement;
/**
* This field is container for all optional parameters related to the sound.
*/
options?: Object;
/**
* This field describes the source of the audio resource to be played. It
* can be either a path to the file or an object depending on the platform
* (native vs web).
*/
src?: Object | string;
};
/**
* Initial/default state of the feature {@code base/sounds}. It is a {@code Map}
* of globally stored sounds.
*
* @type {Map<string, Sound>}
*/
const DEFAULT_STATE = new Map();
export type ISoundsState = Map<string, Sound>;
/**
* The base/sounds feature's reducer.
*/
ReducerRegistry.register<ISoundsState>(
'features/base/sounds',
(state = DEFAULT_STATE, action): ISoundsState => {
switch (action.type) {
case _ADD_AUDIO_ELEMENT:
case _REMOVE_AUDIO_ELEMENT:
return _addOrRemoveAudioElement(state, action);
case REGISTER_SOUND:
return _registerSound(state, action);
case UNREGISTER_SOUND:
return _unregisterSound(state, action);
default:
return state;
}
});
/**
* Adds or removes {@link AudioElement} associated with a {@link Sound}.
*
* @param {Map<string, Sound>} state - The current Redux state of this feature.
* @param {_ADD_AUDIO_ELEMENT | _REMOVE_AUDIO_ELEMENT} action - The action to be
* handled.
* @private
* @returns {Map<string, Sound>}
*/
function _addOrRemoveAudioElement(state: ISoundsState, action: any) {
const isAddAction = action.type === _ADD_AUDIO_ELEMENT;
const nextState = new Map(state);
const { soundId } = action;
const sound = nextState.get(soundId);
if (sound) {
if (isAddAction) {
nextState.set(soundId,
assign(sound, {
audioElement: action.audioElement
}));
} else {
nextState.set(soundId,
assign(sound, {
audioElement: undefined
}));
}
}
return nextState;
}
/**
* Registers a new {@link Sound} for given id and source. It will make
* the {@link SoundCollection} component render HTMLAudioElement for given
* source making it available for playback through the redux actions.
*
* @param {Map<string, Sound>} state - The current Redux state of the sounds
* features.
* @param {REGISTER_SOUND} action - The register sound action.
* @private
* @returns {Map<string, Sound>}
*/
function _registerSound(state: ISoundsState, action: any) {
const nextState = new Map(state);
nextState.set(action.soundId, {
src: action.src,
options: action.options
});
return nextState;
}
/**
* Unregisters a {@link Sound} which will make the {@link SoundCollection}
* component stop rendering the corresponding HTMLAudioElement. This will
* result further in the audio resource disposal.
*
* @param {Map<string, Sound>} state - The current Redux state of this feature.
* @param {UNREGISTER_SOUND} action - The unregister sound action.
* @private
* @returns {Map<string, Sound>}
*/
function _unregisterSound(state: ISoundsState, action: any) {
const nextState = new Map(state);
nextState.delete(action.soundId);
return nextState;
}