From 56b77df43001d516aa9ef022446de7c135f74542 Mon Sep 17 00:00:00 2001 From: damencho Date: Tue, 18 Feb 2025 22:56:42 -0600 Subject: [PATCH] fix(av-moderation): When we are allowed to unmute make the notification sticky. If the notification disappears, we don't have any other indication about this. We were not showing any notification if only video is allowed. Adds option to unmute audio or video, depend on what was allowed. --- lang/main.json | 5 ++- react/features/av-moderation/middleware.ts | 47 ++++++++++++++++------ react/features/video-menu/actions.any.ts | 4 +- 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/lang/main.json b/lang/main.json index 08f30b9686dc..cadc3259eb48 100644 --- a/lang/main.json +++ b/lang/main.json @@ -757,7 +757,7 @@ "focusFail": "{{component}} not available - retry in {{ms}} sec", "gifsMenu": "GIPHY", "groupTitle": "Notifications", - "hostAskedUnmute": "The moderator would like you to speak", + "hostAskedUnmute": "The moderator would like you to unmute.", "invalidTenant": "Invalid tenant", "invalidTenantHyphenDescription": "The tenant you are using is invalid (starts or ends with '-').", "invalidTenantLengthDescription": "The tenant you are using is too long.", @@ -826,7 +826,8 @@ "suggestRecordingAction": "Start", "suggestRecordingDescription": "Would you like to start a recording?", "suggestRecordingTitle": "Record this meeting", - "unmute": "Unmute", + "unmute": "Unmute Audio", + "unmuteVideo": "Unmute Video", "videoMutedRemotelyDescription": "You can always turn it on again.", "videoMutedRemotelyTitle": "Your video has been turned off by {{participantDisplayName}}", "videoUnmuteBlockedDescription": "Camera unmute and desktop sharing operation have been temporarily blocked because of system limits.", diff --git a/react/features/av-moderation/middleware.ts b/react/features/av-moderation/middleware.ts index b326bac4f251..8d2b47548cc2 100644 --- a/react/features/av-moderation/middleware.ts +++ b/react/features/av-moderation/middleware.ts @@ -4,6 +4,7 @@ import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app/actionTypes'; import { getConferenceState } from '../base/conference/functions'; import { JitsiConferenceEvents } from '../base/lib-jitsi-meet'; import { MEDIA_TYPE, MediaType } from '../base/media/constants'; +import { isAudioMuted, isVideoMuted } from '../base/media/functions'; import { PARTICIPANT_UPDATED } from '../base/participants/actionTypes'; import { raiseHand } from '../base/participants/actions'; import { @@ -208,24 +209,46 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => { */ StateListenerRegistry.register( state => state['features/base/conference'].conference, - (conference, { dispatch }, previousConference) => { + (conference, { dispatch, getState }, previousConference) => { if (conference && !previousConference) { // local participant is allowed to unmute conference.on(JitsiConferenceEvents.AV_MODERATION_APPROVED, ({ mediaType }: { mediaType: MediaType; }) => { dispatch(localParticipantApproved(mediaType)); - // Audio & video moderation are both enabled at the same time. - // Avoid displaying 2 different notifications. - if (mediaType === MEDIA_TYPE.AUDIO) { - dispatch(showNotification({ - titleKey: 'notify.hostAskedUnmute', - sticky: true, - customActionNameKey: [ 'notify.unmute' ], - customActionHandler: [ () => dispatch(muteLocal(false, MEDIA_TYPE.AUDIO)) ], - uid: ASKED_TO_UNMUTE_NOTIFICATION_ID - }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM)); - dispatch(playSound(ASKED_TO_UNMUTE_SOUND_ID)); + const customActionNameKey = []; + const customActionHandler = []; + + if ((mediaType === MEDIA_TYPE.AUDIO || getState()['features/av-moderation'].audioUnmuteApproved) + && isAudioMuted(getState())) { + customActionNameKey.push('notify.unmute'); + customActionHandler.push(() => { + dispatch(muteLocal(false, MEDIA_TYPE.AUDIO)); + dispatch(hideNotification(ASKED_TO_UNMUTE_NOTIFICATION_ID)); + }); } + + if ((mediaType === MEDIA_TYPE.VIDEO || getState()['features/av-moderation'].videoUnmuteApproved) + && isVideoMuted(getState())) { + customActionNameKey.push('notify.unmuteVideo'); + customActionHandler.push(() => { + dispatch(muteLocal(false, MEDIA_TYPE.VIDEO)); + dispatch(hideNotification(ASKED_TO_UNMUTE_NOTIFICATION_ID)); + + // lower hand as there will be no audio and change in dominant speaker to clear it + dispatch(raiseHand(false)); + + }); + } + + dispatch(showNotification({ + titleKey: 'notify.hostAskedUnmute', + sticky: true, + customActionNameKey, + customActionHandler, + uid: ASKED_TO_UNMUTE_NOTIFICATION_ID + }, NOTIFICATION_TIMEOUT_TYPE.STICKY)); + + dispatch(playSound(ASKED_TO_UNMUTE_SOUND_ID)); }); conference.on(JitsiConferenceEvents.AV_MODERATION_REJECTED, ({ mediaType }: { mediaType: MediaType; }) => { diff --git a/react/features/video-menu/actions.any.ts b/react/features/video-menu/actions.any.ts index 27a9a9027c48..36da60b6cc0d 100644 --- a/react/features/video-menu/actions.any.ts +++ b/react/features/video-menu/actions.any.ts @@ -11,7 +11,7 @@ import { shouldShowModeratedNotification } from '../av-moderation/functions'; import { setAudioMuted, setVideoMuted } from '../base/media/actions'; import { MEDIA_TYPE, MediaType, VIDEO_MUTISM_AUTHORITY } from '../base/media/constants'; import { muteRemoteParticipant } from '../base/participants/actions'; -import { getLocalParticipant, getRemoteParticipants } from '../base/participants/functions'; +import { getRemoteParticipants } from '../base/participants/functions'; import { toggleScreensharing } from '../base/tracks/actions'; import { isModerationNotificationDisplayed } from '../notifications/functions'; @@ -36,7 +36,7 @@ export function muteLocal(enable: boolean, mediaType: MediaType, stopScreenShari } // check for A/V Moderation when trying to unmute - if (!enable && shouldShowModeratedNotification(MEDIA_TYPE.AUDIO, getState())) { + if (isAudio && !enable && shouldShowModeratedNotification(MEDIA_TYPE.AUDIO, getState())) { if (!isModerationNotificationDisplayed(MEDIA_TYPE.AUDIO, getState())) { dispatch(showModeratedNotification(MEDIA_TYPE.AUDIO)); }