2022-09-14 11:32:58 +00:00
|
|
|
import { IState } from '../app/types';
|
2021-06-23 11:23:44 +00:00
|
|
|
import { MEDIA_TYPE, type MediaType } from '../base/media/constants';
|
2021-07-09 12:36:19 +00:00
|
|
|
import { isLocalParticipantModerator } from '../base/participants/functions';
|
2022-09-14 11:32:58 +00:00
|
|
|
import { Participant } from '../base/participants/types';
|
2022-05-19 08:41:29 +00:00
|
|
|
import { isInBreakoutRoom } from '../breakout-rooms/functions';
|
2021-06-23 11:23:44 +00:00
|
|
|
|
|
|
|
import { MEDIA_TYPE_TO_WHITELIST_STORE_KEY, MEDIA_TYPE_TO_PENDING_STORE_KEY } from './constants';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns this feature's root state.
|
|
|
|
*
|
2022-09-14 11:32:58 +00:00
|
|
|
* @param {IState} state - Global state.
|
2021-06-23 11:23:44 +00:00
|
|
|
* @returns {Object} Feature state.
|
|
|
|
*/
|
2022-09-14 11:32:58 +00:00
|
|
|
const getState = (state: IState) => state['features/av-moderation'];
|
2021-06-23 11:23:44 +00:00
|
|
|
|
2021-07-09 12:36:19 +00:00
|
|
|
/**
|
|
|
|
* We use to construct once the empty array so we can keep the same instance between calls
|
|
|
|
* of getParticipantsAskingToAudioUnmute.
|
|
|
|
*
|
2022-09-14 11:32:58 +00:00
|
|
|
* @type {any[]}
|
2021-07-09 12:36:19 +00:00
|
|
|
*/
|
2022-09-14 11:32:58 +00:00
|
|
|
const EMPTY_ARRAY: any[] = [];
|
2021-07-09 12:36:19 +00:00
|
|
|
|
2021-06-23 11:23:44 +00:00
|
|
|
/**
|
|
|
|
* Returns whether moderation is enabled per media type.
|
|
|
|
*
|
|
|
|
* @param {MEDIA_TYPE} mediaType - The media type to check.
|
2022-09-14 11:32:58 +00:00
|
|
|
* @param {IState} state - Global state.
|
|
|
|
* @returns {boolean}
|
2021-06-23 11:23:44 +00:00
|
|
|
*/
|
2022-09-14 11:32:58 +00:00
|
|
|
export const isEnabledFromState = (mediaType: MediaType, state: IState) =>
|
2021-06-23 11:23:44 +00:00
|
|
|
(mediaType === MEDIA_TYPE.AUDIO
|
2021-06-30 07:34:17 +00:00
|
|
|
? getState(state)?.audioModerationEnabled
|
|
|
|
: getState(state)?.videoModerationEnabled) === true;
|
2021-06-23 11:23:44 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns whether moderation is enabled per media type.
|
|
|
|
*
|
|
|
|
* @param {MEDIA_TYPE} mediaType - The media type to check.
|
2022-09-14 11:32:58 +00:00
|
|
|
* @returns {boolean}
|
2021-06-23 11:23:44 +00:00
|
|
|
*/
|
2022-09-14 11:32:58 +00:00
|
|
|
export const isEnabled = (mediaType: MediaType) => (state: IState) => isEnabledFromState(mediaType, state);
|
2021-06-23 11:23:44 +00:00
|
|
|
|
2021-07-09 12:36:19 +00:00
|
|
|
/**
|
|
|
|
* Returns whether moderation is supported by the backend.
|
|
|
|
*
|
2022-09-14 11:32:58 +00:00
|
|
|
* @returns {boolean}
|
2021-07-09 12:36:19 +00:00
|
|
|
*/
|
2022-09-14 11:32:58 +00:00
|
|
|
export const isSupported = () => (state: IState) => {
|
2021-07-09 12:36:19 +00:00
|
|
|
const { conference } = state['features/base/conference'];
|
|
|
|
|
2022-05-19 08:41:29 +00:00
|
|
|
return Boolean(!isInBreakoutRoom(state) && conference?.isAVModerationSupported());
|
2021-07-09 12:36:19 +00:00
|
|
|
};
|
|
|
|
|
2021-06-23 11:23:44 +00:00
|
|
|
/**
|
|
|
|
* Returns whether local participant is approved to unmute a media type.
|
|
|
|
*
|
|
|
|
* @param {MEDIA_TYPE} mediaType - The media type to check.
|
2022-09-14 11:32:58 +00:00
|
|
|
* @param {IState} state - Global state.
|
2021-06-23 11:23:44 +00:00
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
2022-09-14 11:32:58 +00:00
|
|
|
export const isLocalParticipantApprovedFromState = (mediaType: MediaType, state: IState) => {
|
2021-06-23 11:23:44 +00:00
|
|
|
const approved = (mediaType === MEDIA_TYPE.AUDIO
|
|
|
|
? getState(state).audioUnmuteApproved
|
|
|
|
: getState(state).videoUnmuteApproved) === true;
|
|
|
|
|
|
|
|
return approved || isLocalParticipantModerator(state);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns whether local participant is approved to unmute a media type.
|
|
|
|
*
|
|
|
|
* @param {MEDIA_TYPE} mediaType - The media type to check.
|
2022-09-14 11:32:58 +00:00
|
|
|
* @returns {boolean}
|
2021-06-23 11:23:44 +00:00
|
|
|
*/
|
|
|
|
export const isLocalParticipantApproved = (mediaType: MediaType) =>
|
2022-09-14 11:32:58 +00:00
|
|
|
(state: IState) =>
|
2021-06-23 11:23:44 +00:00
|
|
|
isLocalParticipantApprovedFromState(mediaType, state);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a selector creator which determines if the participant is approved or not for a media type.
|
|
|
|
*
|
|
|
|
* @param {string} id - The participant id.
|
|
|
|
* @param {MEDIA_TYPE} mediaType - The media type to check.
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
2022-09-14 11:32:58 +00:00
|
|
|
export const isParticipantApproved = (id: string, mediaType: MediaType) => (state: IState) => {
|
2021-06-23 11:23:44 +00:00
|
|
|
const storeKey = MEDIA_TYPE_TO_WHITELIST_STORE_KEY[mediaType];
|
|
|
|
|
2022-09-14 11:32:58 +00:00
|
|
|
const avModerationState = getState(state);
|
|
|
|
const stateForMediaType = avModerationState[storeKey as keyof typeof avModerationState];
|
|
|
|
|
|
|
|
return Boolean(stateForMediaType && stateForMediaType[id as keyof typeof stateForMediaType]);
|
2021-06-23 11:23:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a selector creator which determines if the participant is pending or not for a media type.
|
|
|
|
*
|
2021-07-09 12:36:19 +00:00
|
|
|
* @param {Participant} participant - The participant.
|
2021-06-23 11:23:44 +00:00
|
|
|
* @param {MEDIA_TYPE} mediaType - The media type to check.
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
2022-09-14 11:32:58 +00:00
|
|
|
export const isParticipantPending = (participant: Participant, mediaType: MediaType) => (state: IState) => {
|
2021-06-23 11:23:44 +00:00
|
|
|
const storeKey = MEDIA_TYPE_TO_PENDING_STORE_KEY[mediaType];
|
|
|
|
const arr = getState(state)[storeKey];
|
|
|
|
|
2021-07-09 12:36:19 +00:00
|
|
|
return Boolean(arr.find(pending => pending.id === participant.id));
|
2021-06-23 11:23:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Selector which returns a list with all the participants asking to audio unmute.
|
2022-07-14 07:10:08 +00:00
|
|
|
* This is visible only for the moderator.
|
2021-06-23 11:23:44 +00:00
|
|
|
*
|
|
|
|
* @param {Object} state - The global state.
|
|
|
|
* @returns {Array<Object>}
|
|
|
|
*/
|
2022-09-14 11:32:58 +00:00
|
|
|
export const getParticipantsAskingToAudioUnmute = (state: IState) => {
|
2021-06-23 11:23:44 +00:00
|
|
|
if (isLocalParticipantModerator(state)) {
|
2021-07-09 12:36:19 +00:00
|
|
|
return getState(state).pendingAudio;
|
2021-06-23 11:23:44 +00:00
|
|
|
}
|
|
|
|
|
2021-07-09 12:36:19 +00:00
|
|
|
return EMPTY_ARRAY;
|
2021-06-23 11:23:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns true if a special notification can be displayed when a participant
|
|
|
|
* tries to unmute.
|
|
|
|
*
|
|
|
|
* @param {MediaType} mediaType - 'audio' or 'video' media type.
|
|
|
|
* @param {Object} state - The global state.
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
2022-09-14 11:32:58 +00:00
|
|
|
export const shouldShowModeratedNotification = (mediaType: MediaType, state: IState) =>
|
2021-06-23 11:23:44 +00:00
|
|
|
isEnabledFromState(mediaType, state)
|
|
|
|
&& !isLocalParticipantApprovedFromState(mediaType, state);
|