123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- // @flow
- import { batch } from 'react-redux';
-
- import { getConferenceState } from '../base/conference';
- import { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
- import { MEDIA_TYPE } from '../base/media';
- import {
- getParticipantDisplayName,
- isLocalParticipantModerator,
- PARTICIPANT_UPDATED,
- raiseHand
- } from '../base/participants';
- import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
- import {
- hideNotification,
- NOTIFICATION_TIMEOUT,
- showNotification
- } from '../notifications';
-
- import {
- DISABLE_MODERATION,
- ENABLE_MODERATION,
- LOCAL_PARTICIPANT_MODERATION_NOTIFICATION,
- REQUEST_DISABLE_MODERATION,
- REQUEST_ENABLE_MODERATION
- } from './actionTypes';
- import {
- disableModeration,
- dismissPendingParticipant,
- dismissPendingAudioParticipant,
- enableModeration,
- localParticipantApproved,
- participantApproved,
- participantPendingAudio
- } from './actions';
- import {
- isEnabledFromState,
- isParticipantApproved,
- isParticipantPending
- } from './functions';
-
- const VIDEO_MODERATION_NOTIFICATION_ID = 'video-moderation';
- const AUDIO_MODERATION_NOTIFICATION_ID = 'audio-moderation';
- const CS_MODERATION_NOTIFICATION_ID = 'video-moderation';
-
- MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
- const { actor, mediaType, type } = action;
-
- switch (type) {
- case DISABLE_MODERATION:
- case ENABLE_MODERATION: {
- // Audio & video moderation are both enabled at the same time.
- // Avoid displaying 2 different notifications.
- if (mediaType === MEDIA_TYPE.VIDEO) {
- const titleKey = type === ENABLE_MODERATION
- ? 'notify.moderationStartedTitle'
- : 'notify.moderationStoppedTitle';
-
- dispatch(showNotification({
- descriptionKey: actor ? 'notify.moderationToggleDescription' : undefined,
- descriptionArguments: actor ? {
- participantDisplayName: getParticipantDisplayName(getState, actor.getId())
- } : undefined,
- titleKey
- }, NOTIFICATION_TIMEOUT));
- }
-
- break;
- }
- case LOCAL_PARTICIPANT_MODERATION_NOTIFICATION: {
- let descriptionKey;
- let titleKey;
- let uid;
-
- switch (action.mediaType) {
- case MEDIA_TYPE.AUDIO: {
- titleKey = 'notify.moderationInEffectTitle';
- descriptionKey = 'notify.moderationInEffectDescription';
- uid = AUDIO_MODERATION_NOTIFICATION_ID;
- break;
- }
- case MEDIA_TYPE.VIDEO: {
- titleKey = 'notify.moderationInEffectVideoTitle';
- descriptionKey = 'notify.moderationInEffectVideoDescription';
- uid = VIDEO_MODERATION_NOTIFICATION_ID;
- break;
- }
- case MEDIA_TYPE.PRESENTER: {
- titleKey = 'notify.moderationInEffectCSTitle';
- descriptionKey = 'notify.moderationInEffectCSDescription';
- uid = CS_MODERATION_NOTIFICATION_ID;
- break;
- }
- }
-
- dispatch(showNotification({
- customActionNameKey: 'notify.raiseHandAction',
- customActionHandler: () => batch(() => {
- dispatch(raiseHand(true));
- dispatch(hideNotification(uid));
- }),
- descriptionKey,
- sticky: true,
- titleKey,
- uid
- }));
-
- break;
- }
- case REQUEST_DISABLE_MODERATION: {
- const { conference } = getConferenceState(getState());
-
- conference.disableAVModeration(MEDIA_TYPE.AUDIO);
- conference.disableAVModeration(MEDIA_TYPE.VIDEO);
- break;
- }
- case REQUEST_ENABLE_MODERATION: {
- const { conference } = getConferenceState(getState());
-
- conference.enableAVModeration(MEDIA_TYPE.AUDIO);
- conference.enableAVModeration(MEDIA_TYPE.VIDEO);
- break;
- }
- case PARTICIPANT_UPDATED: {
- const state = getState();
- const audioModerationEnabled = isEnabledFromState(MEDIA_TYPE.AUDIO, state);
-
- // this is handled only by moderators
- if (audioModerationEnabled && isLocalParticipantModerator(state)) {
- const participant = action.participant;
-
- if (participant.raisedHand) {
- // if participant raises hand show notification
- !isParticipantApproved(participant.id, MEDIA_TYPE.AUDIO)(state)
- && dispatch(participantPendingAudio(participant));
- } else {
- // if participant lowers hand hide notification
- isParticipantPending(participant, MEDIA_TYPE.AUDIO)(state)
- && dispatch(dismissPendingAudioParticipant(participant));
- }
- }
-
- break;
- }
- }
-
- return next(action);
- });
-
- /**
- * Registers a change handler for state['features/base/conference'].conference to
- * set the event listeners needed for the A/V moderation feature to operate.
- */
- StateListenerRegistry.register(
- state => state['features/base/conference'].conference,
- (conference, { dispatch }, previousConference) => {
- if (conference && !previousConference) {
- // local participant is allowed to unmute
- conference.on(JitsiConferenceEvents.AV_MODERATION_APPROVED, ({ mediaType }) => {
- dispatch(localParticipantApproved(mediaType));
-
- // Audio & video moderation are both enabled at the same time.
- // Avoid displaying 2 different notifications.
- if (mediaType === MEDIA_TYPE.VIDEO) {
- dispatch(showNotification({
- titleKey: 'notify.unmute',
- descriptionKey: 'notify.hostAskedUnmute',
- sticky: true
- }));
- }
- });
-
- conference.on(JitsiConferenceEvents.AV_MODERATION_CHANGED, ({ enabled, mediaType, actor }) => {
- enabled ? dispatch(enableModeration(mediaType, actor)) : dispatch(disableModeration(mediaType, actor));
- });
-
- // this is received by moderators
- conference.on(
- JitsiConferenceEvents.AV_MODERATION_PARTICIPANT_APPROVED,
- ({ participant, mediaType }) => {
- const { _id: id } = participant;
-
- batch(() => {
- // store in the whitelist
- dispatch(participantApproved(id, mediaType));
-
- // remove from pending list
- dispatch(dismissPendingParticipant(id, mediaType));
- });
- });
- }
- });
|