瀏覽代碼

feat: Handles hidden-from-recorder from jwt. (#10973)

* feat: Handles hidden-from-recorder from jwt.

Hides the participant that has this flag in jwt from the recorder. A hidden meeting moderator.
Makes sure follows me works and no tracks are being added.

* squash: Skips showing notification when disabling
local audio and video.

* squash: Fixes comments.

* squash: Updates with ljm changes.
master
Дамян Минков 3 年之前
父節點
當前提交
59e51f107e
No account linked to committer's email address

+ 27
- 2
conference.js 查看文件

@@ -148,6 +148,7 @@ import { AudioMixerEffect } from './react/features/stream-effects/audio-mixer/Au
148 148
 import { createPresenterEffect } from './react/features/stream-effects/presenter';
149 149
 import { createRnnoiseProcessor } from './react/features/stream-effects/rnnoise';
150 150
 import { endpointMessageReceived } from './react/features/subtitles';
151
+import { muteLocal } from './react/features/video-menu/actions.any';
151 152
 import UIEvents from './service/UI/UIEvents';
152 153
 
153 154
 const logger = Logger.getLogger(__filename);
@@ -1144,7 +1145,8 @@ export default {
1144 1145
      * Used by Jibri to detect when it's alone and the meeting should be terminated.
1145 1146
      */
1146 1147
     get membersCount() {
1147
-        return room.getParticipants().filter(p => !p.isHidden()).length + 1;
1148
+        return room.getParticipants()
1149
+            .filter(p => !p.isHidden() || !(config.iAmRecorder && p.isHiddenFromRecorder())).length + 1;
1148 1150
     },
1149 1151
 
1150 1152
     /**
@@ -2063,6 +2065,10 @@ export default {
2063 2065
             APP.store.dispatch(updateRemoteParticipantFeatures(user));
2064 2066
         });
2065 2067
         room.on(JitsiConferenceEvents.USER_JOINED, (id, user) => {
2068
+            if (config.iAmRecorder && user.isHiddenFromRecorder()) {
2069
+                return;
2070
+            }
2071
+
2066 2072
             // The logic shared between RN and web.
2067 2073
             commonUserJoinedHandling(APP.store, room, user);
2068 2074
 
@@ -2112,6 +2118,14 @@ export default {
2112 2118
                 return;
2113 2119
             }
2114 2120
 
2121
+            if (config.iAmRecorder) {
2122
+                const participant = room.getParticipantById(track.getParticipantId());
2123
+
2124
+                if (participant.isHiddenFromRecorder()) {
2125
+                    return;
2126
+                }
2127
+            }
2128
+
2115 2129
             APP.store.dispatch(trackAdded(track));
2116 2130
         });
2117 2131
 
@@ -2599,13 +2613,24 @@ export default {
2599 2613
      * @returns {void}
2600 2614
      */
2601 2615
     _onConferenceJoined() {
2616
+        const { dispatch } = APP.store;
2617
+
2602 2618
         APP.UI.initConference();
2603 2619
 
2604 2620
         if (!config.disableShortcuts) {
2605 2621
             APP.keyboardshortcut.init();
2606 2622
         }
2607 2623
 
2608
-        APP.store.dispatch(conferenceJoined(room));
2624
+        dispatch(conferenceJoined(room));
2625
+
2626
+        const jwt = APP.store.getState()['features/base/jwt'];
2627
+
2628
+        if (jwt?.user?.hiddenFromRecorder) {
2629
+            dispatch(muteLocal(true, MEDIA_TYPE.AUDIO));
2630
+            dispatch(muteLocal(true, MEDIA_TYPE.VIDEO));
2631
+            dispatch(setAudioUnmutePermissions(true, true));
2632
+            dispatch(setVideoUnmutePermissions(true, true));
2633
+        }
2609 2634
     },
2610 2635
 
2611 2636
     /**

+ 1
- 0
config.js 查看文件

@@ -1167,6 +1167,7 @@ var config = {
1167 1167
      forceJVB121Ratio
1168 1168
      forceTurnRelay
1169 1169
      hiddenDomain
1170
+     hiddenFromRecorderFeatureEnabled
1170 1171
      ignoreStartMuted
1171 1172
      websocketKeepAlive
1172 1173
      websocketKeepAliveUrl

+ 5
- 5
package-lock.json 查看文件

@@ -67,7 +67,7 @@
67 67
         "jquery-i18next": "1.2.1",
68 68
         "js-md5": "0.6.1",
69 69
         "jwt-decode": "2.2.0",
70
-        "lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1360.0.0+9eb93e0e/lib-jitsi-meet.tgz",
70
+        "lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1361.0.0+9e98e989/lib-jitsi-meet.tgz",
71 71
         "libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
72 72
         "lodash": "4.17.21",
73 73
         "moment": "2.29.1",
@@ -12003,8 +12003,8 @@
12003 12003
     },
12004 12004
     "node_modules/lib-jitsi-meet": {
12005 12005
       "version": "0.0.0",
12006
-      "resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1360.0.0+9eb93e0e/lib-jitsi-meet.tgz",
12007
-      "integrity": "sha512-qeQOjeZcAVd7aACEwRu8tBD85ZIPS9V+U8Htm9QvB8FpHi+5hYxN3N0SDgLEJlQEKMxsDzpfpjkInX5UCWt/KQ==",
12006
+      "resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1361.0.0+9e98e989/lib-jitsi-meet.tgz",
12007
+      "integrity": "sha512-dIg6vWsiWIu77TRHsTSGhTvbLqRw9MAlzScMEw/0ooZTq/ztSCvRZQqQ3quP64+4F0FGm6n0P3y0YBp5t44f4g==",
12008 12008
       "license": "Apache-2.0",
12009 12009
       "dependencies": {
12010 12010
         "@jitsi/js-utils": "2.0.0",
@@ -29109,8 +29109,8 @@
29109 29109
       }
29110 29110
     },
29111 29111
     "lib-jitsi-meet": {
29112
-      "version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1360.0.0+9eb93e0e/lib-jitsi-meet.tgz",
29113
-      "integrity": "sha512-qeQOjeZcAVd7aACEwRu8tBD85ZIPS9V+U8Htm9QvB8FpHi+5hYxN3N0SDgLEJlQEKMxsDzpfpjkInX5UCWt/KQ==",
29112
+      "version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1361.0.0+9e98e989/lib-jitsi-meet.tgz",
29113
+      "integrity": "sha512-dIg6vWsiWIu77TRHsTSGhTvbLqRw9MAlzScMEw/0ooZTq/ztSCvRZQqQ3quP64+4F0FGm6n0P3y0YBp5t44f4g==",
29114 29114
       "requires": {
29115 29115
         "@jitsi/js-utils": "2.0.0",
29116 29116
         "@jitsi/logger": "2.0.0",

+ 1
- 1
package.json 查看文件

@@ -72,7 +72,7 @@
72 72
     "jquery-i18next": "1.2.1",
73 73
     "js-md5": "0.6.1",
74 74
     "jwt-decode": "2.2.0",
75
-    "lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1360.0.0+9eb93e0e/lib-jitsi-meet.tgz",
75
+    "lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1361.0.0+9e98e989/lib-jitsi-meet.tgz",
76 76
     "libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
77 77
     "lodash": "4.17.21",
78 78
     "moment": "2.29.1",

+ 7
- 2
react/features/base/jwt/middleware.js 查看文件

@@ -220,10 +220,11 @@ function _undoOverwriteLocalParticipant(
220 220
  *     avatarURL: ?string,
221 221
  *     email: ?string,
222 222
  *     id: ?string,
223
- *     name: ?string
223
+ *     name: ?string,
224
+ *     hidden-from-recorder: ?boolean
224 225
  * }}
225 226
  */
226
-function _user2participant({ avatar, avatarUrl, email, id, name }) {
227
+function _user2participant({ avatar, avatarUrl, email, id, name, 'hidden-from-recorder': hiddenFromRecorder }) {
227 228
     const participant = {};
228 229
 
229 230
     if (typeof avatarUrl === 'string') {
@@ -241,5 +242,9 @@ function _user2participant({ avatar, avatarUrl, email, id, name }) {
241 242
         participant.name = name.trim();
242 243
     }
243 244
 
245
+    if (hiddenFromRecorder === 'true' || hiddenFromRecorder === true) {
246
+        participant.hiddenFromRecorder = true;
247
+    }
248
+
244 249
     return Object.keys(participant).length ? participant : undefined;
245 250
 }

+ 8
- 4
react/features/base/media/actions.js 查看文件

@@ -65,12 +65,14 @@ export function setAudioMuted(muted: boolean, ensureTrack: boolean = false) {
65 65
  * Action to disable/enable the audio mute icon.
66 66
  *
67 67
  * @param {boolean} blocked - True if the audio mute icon needs to be disabled.
68
+ * @param {boolean|undefined} skipNotification - True if we want to skip showing the notification.
68 69
  * @returns {Function}
69 70
  */
70
-export function setAudioUnmutePermissions(blocked: boolean) {
71
+export function setAudioUnmutePermissions(blocked: boolean, skipNotification: boolean = false) {
71 72
     return {
72 73
         type: SET_AUDIO_UNMUTE_PERMISSIONS,
73
-        blocked
74
+        blocked,
75
+        skipNotification
74 76
     };
75 77
 }
76 78
 
@@ -155,12 +157,14 @@ export function setVideoMuted(
155 157
  * Action to disable/enable the video mute icon.
156 158
  *
157 159
  * @param {boolean} blocked - True if the video mute icon needs to be disabled.
160
+ * @param {boolean|undefined} skipNotification - True if we want to skip showing the notification.
158 161
  * @returns {Function}
159 162
  */
160
-export function setVideoUnmutePermissions(blocked: boolean) {
163
+export function setVideoUnmutePermissions(blocked: boolean, skipNotification: boolean = false) {
161 164
     return {
162 165
         type: SET_VIDEO_UNMUTE_PERMISSIONS,
163
-        blocked
166
+        blocked,
167
+        skipNotification
164 168
     };
165 169
 }
166 170
 

+ 4
- 4
react/features/base/media/middleware.js 查看文件

@@ -86,12 +86,12 @@ MiddlewareRegistry.register(store => next => action => {
86 86
     }
87 87
 
88 88
     case SET_AUDIO_UNMUTE_PERMISSIONS: {
89
-        const { blocked } = action;
89
+        const { blocked, skipNotification } = action;
90 90
         const state = store.getState();
91 91
         const tracks = state['features/base/tracks'];
92 92
         const isAudioMuted = isLocalTrackMuted(tracks, MEDIA_TYPE.AUDIO);
93 93
 
94
-        if (blocked && isAudioMuted) {
94
+        if (blocked && isAudioMuted && !skipNotification) {
95 95
             store.dispatch(showWarningNotification({
96 96
                 descriptionKey: 'notify.audioUnmuteBlockedDescription',
97 97
                 titleKey: 'notify.audioUnmuteBlockedTitle'
@@ -111,13 +111,13 @@ MiddlewareRegistry.register(store => next => action => {
111 111
     }
112 112
 
113 113
     case SET_VIDEO_UNMUTE_PERMISSIONS: {
114
-        const { blocked } = action;
114
+        const { blocked, skipNotification } = action;
115 115
         const state = store.getState();
116 116
         const tracks = state['features/base/tracks'];
117 117
         const isVideoMuted = isLocalTrackMuted(tracks, MEDIA_TYPE.VIDEO);
118 118
         const isMediaShared = isScreenMediaShared(state);
119 119
 
120
-        if (blocked && isVideoMuted && !isMediaShared) {
120
+        if (blocked && isVideoMuted && !isMediaShared && !skipNotification) {
121 121
             store.dispatch(showWarningNotification({
122 122
                 descriptionKey: 'notify.videoUnmuteBlockedDescription',
123 123
                 titleKey: 'notify.videoUnmuteBlockedTitle'

+ 24
- 8
react/features/follow-me/middleware.js 查看文件

@@ -102,16 +102,32 @@ function _onFollowMeCommand(attributes = {}, id, store) {
102 102
 
103 103
     const participantSendingCommand = getParticipantById(state, id);
104 104
 
105
-    // The Command(s) API will send us our own commands and we don't want
106
-    // to act upon them.
107
-    if (participantSendingCommand.local) {
108
-        return;
109
-    }
105
+    if (participantSendingCommand) {
106
+        // The Command(s) API will send us our own commands and we don't want
107
+        // to act upon them.
108
+        if (participantSendingCommand.local) {
109
+            return;
110
+        }
110 111
 
111
-    if (participantSendingCommand.role !== 'moderator') {
112
-        logger.warn('Received follow-me command not from moderator');
112
+        if (participantSendingCommand.role !== 'moderator') {
113
+            logger.warn('Received follow-me command not from moderator');
113 114
 
114
-        return;
115
+            return;
116
+        }
117
+    } else {
118
+        // This is the case of jibri receiving commands from a hidden participant.
119
+        const { iAmRecorder } = state['features/base/config'];
120
+        const { conference } = state['features/base/conference'];
121
+
122
+        // As this participant is not stored in redux store we do the checks on the JitsiParticipant from lib-jitsi-meet
123
+        const participant = conference.getParticipantById(id);
124
+
125
+        if (!iAmRecorder || !participant || participant.getRole() !== 'moderator'
126
+            || !participant.isHiddenFromRecorder()) {
127
+            logger.warn('Something went wrong with follow-me command');
128
+
129
+            return;
130
+        }
115 131
     }
116 132
 
117 133
     if (!isFollowMeActive(state)) {

Loading…
取消
儲存