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

147 lines
3.9 KiB
JavaScript

// @flow
import type { AudioElement } from '../media';
import { assign, ReducerRegistry } from '../redux';
import {
_ADD_AUDIO_ELEMENT,
_REMOVE_AUDIO_ELEMENT,
REGISTER_SOUND,
UNREGISTER_SOUND
} from './actionTypes';
const logger = require('jitsi-meet-logger').getLogger(__filename);
/**
* 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 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,
/**
* This field is container for all optional parameters related to the sound.
*/
options: Object
}
/**
* 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();
/**
* The base/sounds feature's reducer.
*/
ReducerRegistry.register(
'features/base/sounds',
(state = DEFAULT_STATE, action) => {
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, action) {
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
}));
}
} else {
const actionName
= isAddAction ? '_ADD_AUDIO_ELEMENT' : '_REMOVE_AUDIO_ELEMENT';
logger.error(`${actionName}: no sound for id: ${soundId}`);
}
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, action) {
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, action) {
const nextState = new Map(state);
nextState.delete(action.soundId);
return nextState;
}