Files
jitsi-meet/react/features/base/media/reducer.js
Jaya Allamsetty b19e4d76b5 fix(media) dispatch the unmute blocked action irrepective of the muted state.
This fixes an issue where the user muted by focus is able to unmute themselves even when the sender limit has been reached.
2021-12-07 17:13:29 -06:00

246 lines
6.1 KiB
JavaScript

import { combineReducers } from 'redux';
import { CONFERENCE_FAILED, CONFERENCE_LEFT } from '../conference/actionTypes';
import { ReducerRegistry } from '../redux';
import { TRACK_REMOVED } from '../tracks/actionTypes';
import {
SET_AUDIO_AVAILABLE,
SET_AUDIO_MUTED,
SET_AUDIO_UNMUTE_PERMISSIONS,
SET_CAMERA_FACING_MODE,
SET_VIDEO_AVAILABLE,
SET_VIDEO_MUTED,
SET_VIDEO_UNMUTE_PERMISSIONS,
STORE_VIDEO_TRANSFORM,
TOGGLE_CAMERA_FACING_MODE
} from './actionTypes';
import { CAMERA_FACING_MODE } from './constants';
/**
* Media state object for local audio.
*
* @typedef {Object} AudioMediaState
* @property {boolean} muted=false - Audio muted state.
*/
// FIXME Technically, _AUDIO_INITIAL_MEDIA_STATE is a constant internal to the
// feature base/media and used in multiple files so it should be in
// constants.js. Practically though, AudioMediaState would then be used in
// multiple files as well so I don't know where and how to move it.
/**
* Initial state for local audio.
*
* @type {AudioMediaState}
*/
export const _AUDIO_INITIAL_MEDIA_STATE = {
available: true,
unmuteBlocked: false,
muted: false
};
/**
* Reducer for audio media state.
*
* @param {AudioMediaState} state - Media state of local audio.
* @param {Object} action - Action object.
* @param {string} action.type - Type of action.
* @private
* @returns {AudioMediaState}
*/
function _audio(state = _AUDIO_INITIAL_MEDIA_STATE, action) {
switch (action.type) {
case SET_AUDIO_AVAILABLE:
return {
...state,
available: action.available
};
case SET_AUDIO_MUTED:
return {
...state,
muted: action.muted
};
case SET_AUDIO_UNMUTE_PERMISSIONS:
return {
...state,
unmuteBlocked: action.blocked
};
default:
return state;
}
}
/**
* Media state object for local video.
*
* @typedef {Object} VideoMediaState
* @property {CAMERA_FACING_MODE} facingMode='user' - Camera facing mode.
* @property {boolean} muted=false - Video muted state.
*/
// FIXME Technically, _VIDEO_INITIAL_MEDIA_STATE is a constant internal to the
// feature base/media and used in multiple files so it should be in
// constants.js. Practically though, VideoMediaState would then be used in
// multiple files as well so I don't know where and how to move it.
/**
* Initial state for video.
*
* @type {VideoMediaState}
*/
export const _VIDEO_INITIAL_MEDIA_STATE = {
available: true,
unmuteBlocked: false,
facingMode: CAMERA_FACING_MODE.USER,
muted: 0,
/**
* The video {@link Transform}s applied to {@code MediaStream}s by
* {@code id} i.e. "pinch to zoom".
*/
transforms: {}
};
/**
* Reducer for camera media state.
*
* @param {VideoMediaState} state - Media state of local video.
* @param {Object} action - Action object.
* @param {string} action.type - Type of action.
* @private
* @returns {VideoMediaState}
*/
function _video(state = _VIDEO_INITIAL_MEDIA_STATE, action) {
switch (action.type) {
case CONFERENCE_FAILED:
case CONFERENCE_LEFT:
return _clearAllVideoTransforms(state);
case SET_CAMERA_FACING_MODE:
return {
...state,
facingMode: action.cameraFacingMode
};
case SET_VIDEO_AVAILABLE:
return {
...state,
available: action.available
};
case SET_VIDEO_MUTED:
return {
...state,
muted: action.muted
};
case SET_VIDEO_UNMUTE_PERMISSIONS:
return {
...state,
unmuteBlocked: action.blocked
};
case STORE_VIDEO_TRANSFORM:
return _storeVideoTransform(state, action);
case TOGGLE_CAMERA_FACING_MODE: {
let cameraFacingMode = state.facingMode;
cameraFacingMode
= cameraFacingMode === CAMERA_FACING_MODE.USER
? CAMERA_FACING_MODE.ENVIRONMENT
: CAMERA_FACING_MODE.USER;
return {
...state,
facingMode: cameraFacingMode
};
}
case TRACK_REMOVED:
return _trackRemoved(state, action);
default:
return state;
}
}
/**
* Listen for various actions related to media devices.
*
* @param {Object} state - State of media devices.
* @param {Object} action - Action object.
* @param {string} action.type - Type of action.
* @param {Object} action.media - Information about media devices to be
* modified.
* @returns {Object}
*/
ReducerRegistry.register('features/base/media', combineReducers({
audio: _audio,
video: _video
}));
/**
* Removes all stored video {@link Transform}s.
*
* @param {Object} state - The {@code video} state of the feature base/media.
* @private
* @returns {Object}
*/
function _clearAllVideoTransforms(state) {
return {
...state,
transforms: _VIDEO_INITIAL_MEDIA_STATE.transforms
};
}
/**
* Stores the last applied transform to a stream.
*
* @param {Object} state - The {@code video} state of the feature base/media.
* @param {Object} action - The redux action {@link STORE_VIDEO_TRANSFORM}.
* @private
* @returns {Object}
*/
function _storeVideoTransform(state, { streamId, transform }) {
return {
...state,
transforms: {
...state.transforms,
[streamId]: transform
}
};
}
/**
* Removes the stored video {@link Transform} associated with a
* {@code MediaStream} when its respective track is removed.
*
* @param {Object} state - The {@code video} state of the feature base/media.
* @param {Object} action - The redux action {@link TRACK_REMOVED}.
* @private
* @returns {Object}
*/
function _trackRemoved(state, { track: { jitsiTrack } }) {
if (jitsiTrack) {
const streamId = jitsiTrack.getStreamId();
if (streamId && streamId in state.transforms) {
const nextTransforms = {
...state.transforms
};
delete nextTransforms[streamId];
return {
...state,
transforms: nextTransforms
};
}
}
return state;
}