瀏覽代碼

feat(silent): track if participant joined without audio (#2534)

* feat(silent): track if participant joined without audio

* Fix failing tests, use jitsi.org namespace

---------

Co-authored-by: Дамян Минков <damencho@jitsi.org>
release-8443
Nathan Beck 1 年之前
父節點
當前提交
fc115be599
沒有連結到貢獻者的電子郵件帳戶。

+ 28
- 0
JitsiConference.js 查看文件

1052
     }
1052
     }
1053
 };
1053
 };
1054
 
1054
 
1055
+/**
1056
+ * Set join without audio
1057
+ * @param silent whether user joined without audio
1058
+ */
1059
+JitsiConference.prototype.setIsSilent = function(silent) {
1060
+    if (this.room) {
1061
+        this.room.addOrReplaceInPresence('silent', {
1062
+            attributes: { xmlns: 'http://jitsi.org/protocol/silent' },
1063
+            value: silent
1064
+        }) && this.room.sendPresence();
1065
+    }
1066
+};
1067
+
1055
 /**
1068
 /**
1056
  * Set new subject for this conference. (available only for moderator)
1069
  * Set new subject for this conference. (available only for moderator)
1057
  * @param {string} subject new subject
1070
  * @param {string} subject new subject
1997
         displayName);
2010
         displayName);
1998
 };
2011
 };
1999
 
2012
 
2013
+JitsiConference.prototype.onSilentStatusChanged = function(jid, isSilent) {
2014
+    const id = Strophe.getResourceFromJid(jid);
2015
+    const participant = this.getParticipantById(id);
2016
+
2017
+    if (!participant) {
2018
+        return;
2019
+    }
2020
+
2021
+    participant.setIsSilent(isSilent);
2022
+    this.eventEmitter.emit(
2023
+        JitsiConferenceEvents.SILENT_STATUS_CHANGED,
2024
+        id,
2025
+        isSilent);
2026
+};
2027
+
2000
 /**
2028
 /**
2001
  * Notifies this JitsiConference that a JitsiRemoteTrack was added to the conference.
2029
  * Notifies this JitsiConference that a JitsiRemoteTrack was added to the conference.
2002
  *
2030
  *

+ 3
- 0
JitsiConferenceEventManager.js 查看文件

345
     chatRoom.addListener(XMPPEvents.DISPLAY_NAME_CHANGED,
345
     chatRoom.addListener(XMPPEvents.DISPLAY_NAME_CHANGED,
346
         conference.onDisplayNameChanged.bind(conference));
346
         conference.onDisplayNameChanged.bind(conference));
347
 
347
 
348
+    chatRoom.addListener(XMPPEvents.SILENT_STATUS_CHANGED,
349
+        conference.onSilentStatusChanged.bind(conference));
350
+
348
     chatRoom.addListener(XMPPEvents.LOCAL_ROLE_CHANGED, role => {
351
     chatRoom.addListener(XMPPEvents.LOCAL_ROLE_CHANGED, role => {
349
         conference.onLocalRoleChanged(role);
352
         conference.onLocalRoleChanged(role);
350
     });
353
     });

+ 3
- 0
JitsiConferenceEvents.spec.ts 查看文件

85
         BREAKOUT_ROOMS_MOVE_TO_ROOM,
85
         BREAKOUT_ROOMS_MOVE_TO_ROOM,
86
         BREAKOUT_ROOMS_UPDATED,
86
         BREAKOUT_ROOMS_UPDATED,
87
         METADATA_UPDATED,
87
         METADATA_UPDATED,
88
+        SILENT_STATUS_CHANGED,
88
         JitsiConferenceEvents,
89
         JitsiConferenceEvents,
89
         ...others
90
         ...others
90
     } = exported;
91
     } = exported;
167
         expect( BREAKOUT_ROOMS_MOVE_TO_ROOM ).toBe( 'conference.breakout-rooms.move-to-room' );
168
         expect( BREAKOUT_ROOMS_MOVE_TO_ROOM ).toBe( 'conference.breakout-rooms.move-to-room' );
168
         expect( BREAKOUT_ROOMS_UPDATED ).toBe( 'conference.breakout-rooms.updated' );
169
         expect( BREAKOUT_ROOMS_UPDATED ).toBe( 'conference.breakout-rooms.updated' );
169
         expect( METADATA_UPDATED ).toBe( 'conference.metadata.updated' );
170
         expect( METADATA_UPDATED ).toBe( 'conference.metadata.updated' );
171
+        expect( SILENT_STATUS_CHANGED ).toBe( 'conference.silentStatusChanged' );
170
         expect( ENCODE_TIME_STATS_RECEIVED ).toBe( 'conference.encode_time_stats_received' );
172
         expect( ENCODE_TIME_STATS_RECEIVED ).toBe( 'conference.encode_time_stats_received' );
171
 
173
 
172
         expect( JitsiConferenceEvents ).toBeDefined();
174
         expect( JitsiConferenceEvents ).toBeDefined();
245
         expect( JitsiConferenceEvents.BREAKOUT_ROOMS_MOVE_TO_ROOM ).toBe( 'conference.breakout-rooms.move-to-room' );
247
         expect( JitsiConferenceEvents.BREAKOUT_ROOMS_MOVE_TO_ROOM ).toBe( 'conference.breakout-rooms.move-to-room' );
246
         expect( JitsiConferenceEvents.BREAKOUT_ROOMS_UPDATED ).toBe( 'conference.breakout-rooms.updated' );
248
         expect( JitsiConferenceEvents.BREAKOUT_ROOMS_UPDATED ).toBe( 'conference.breakout-rooms.updated' );
247
         expect( JitsiConferenceEvents.METADATA_UPDATED ).toBe( 'conference.metadata.updated' );
249
         expect( JitsiConferenceEvents.METADATA_UPDATED ).toBe( 'conference.metadata.updated' );
250
+        expect( JitsiConferenceEvents.SILENT_STATUS_CHANGED ).toBe( 'conference.silentStatusChanged' );
248
         expect( JitsiConferenceEvents.E2EE_VERIFICATION_READY ).toBe( 'conference.e2ee.verification.ready' );
251
         expect( JitsiConferenceEvents.E2EE_VERIFICATION_READY ).toBe( 'conference.e2ee.verification.ready' );
249
         expect( JitsiConferenceEvents.E2EE_VERIFICATION_COMPLETED ).toBe( 'conference.e2ee.verification.completed' );
252
         expect( JitsiConferenceEvents.E2EE_VERIFICATION_COMPLETED ).toBe( 'conference.e2ee.verification.completed' );
250
         expect( JitsiConferenceEvents.E2EE_VERIFICATION_AVAILABLE ).toBe( 'conference.e2ee.verification.available' );
253
         expect( JitsiConferenceEvents.E2EE_VERIFICATION_AVAILABLE ).toBe( 'conference.e2ee.verification.available' );

+ 6
- 0
JitsiConferenceEvents.ts 查看文件

363
      */
363
      */
364
     SERVER_REGION_CHANGED = 'conference.server_region_changed',
364
     SERVER_REGION_CHANGED = 'conference.server_region_changed',
365
 
365
 
366
+    /**
367
+     * Indicates a user has joined without audio
368
+     */
369
+    SILENT_STATUS_CHANGED = 'conference.silentStatusChanged',
370
+
366
     /**
371
     /**
367
      * Indicates that start muted settings changed.
372
      * Indicates that start muted settings changed.
368
      */
373
      */
550
 export const PROPERTIES_CHANGED = JitsiConferenceEvents.PROPERTIES_CHANGED;
555
 export const PROPERTIES_CHANGED = JitsiConferenceEvents.PROPERTIES_CHANGED;
551
 export const RECORDER_STATE_CHANGED = JitsiConferenceEvents.RECORDER_STATE_CHANGED;
556
 export const RECORDER_STATE_CHANGED = JitsiConferenceEvents.RECORDER_STATE_CHANGED;
552
 export const SERVER_REGION_CHANGED = JitsiConferenceEvents.SERVER_REGION_CHANGED;
557
 export const SERVER_REGION_CHANGED = JitsiConferenceEvents.SERVER_REGION_CHANGED;
558
+export const SILENT_STATUS_CHANGED = JitsiConferenceEvents.SILENT_STATUS_CHANGED;
553
 export const START_MUTED_POLICY_CHANGED = JitsiConferenceEvents.START_MUTED_POLICY_CHANGED;
559
 export const START_MUTED_POLICY_CHANGED = JitsiConferenceEvents.START_MUTED_POLICY_CHANGED;
554
 export const STARTED_MUTED = JitsiConferenceEvents.STARTED_MUTED;
560
 export const STARTED_MUTED = JitsiConferenceEvents.STARTED_MUTED;
555
 export const SUBJECT_CHANGED = JitsiConferenceEvents.SUBJECT_CHANGED;
561
 export const SUBJECT_CHANGED = JitsiConferenceEvents.SUBJECT_CHANGED;

+ 18
- 1
JitsiParticipant.js 查看文件

26
      * @param {object} identity - the xmpp identity
26
      * @param {object} identity - the xmpp identity
27
      * @param {boolean?} isReplacing - whether this is a participant replacing another into the meeting.
27
      * @param {boolean?} isReplacing - whether this is a participant replacing another into the meeting.
28
      * @param {boolean?} isReplaced - whether this is a participant to be kicked and replaced into the meeting.
28
      * @param {boolean?} isReplaced - whether this is a participant to be kicked and replaced into the meeting.
29
+     * @param {boolean?} isSilent - whether participant has joined without audio
29
      */
30
      */
30
-    constructor(jid, conference, displayName, hidden, statsID, status, identity, isReplacing, isReplaced) {
31
+    constructor(jid, conference, displayName, hidden, statsID, status, identity, isReplacing, isReplaced, isSilent) {
31
         this._jid = jid;
32
         this._jid = jid;
32
         this._id = Strophe.getResourceFromJid(jid);
33
         this._id = Strophe.getResourceFromJid(jid);
33
         this._conference = conference;
34
         this._conference = conference;
42
         this._identity = identity;
43
         this._identity = identity;
43
         this._isReplacing = isReplacing;
44
         this._isReplacing = isReplacing;
44
         this._isReplaced = isReplaced;
45
         this._isReplaced = isReplaced;
46
+        this._isSilent = isSilent;
45
         this._features = new Set();
47
         this._features = new Set();
46
 
48
 
47
         /**
49
         /**
276
         return this._isReplacing;
278
         return this._isReplacing;
277
     }
279
     }
278
 
280
 
281
+    /**
282
+     * @returns {Boolean} Whether this participant has joined without audio.
283
+     */
284
+    isSilent() {
285
+        return this._isSilent;
286
+    }
287
+
279
     /**
288
     /**
280
      * @returns {Boolean} Whether this participant has muted their video.
289
      * @returns {Boolean} Whether this participant has muted their video.
281
      */
290
      */
323
         this._isReplacing = newIsReplacing;
332
         this._isReplacing = newIsReplacing;
324
     }
333
     }
325
 
334
 
335
+    /**
336
+     * Sets whether participant has joined without audio.
337
+     * @param {boolean} newIsSilent - whether is silent.
338
+     */
339
+    setIsSilent(newIsSilent) {
340
+        this._isSilent = newIsSilent;
341
+    }
342
+
326
     /**
343
     /**
327
      * Sets the value of a property of this participant, and fires an event if
344
      * Sets the value of a property of this participant, and fires an event if
328
      * the value has changed.
345
      * the value has changed.

+ 16
- 1
modules/xmpp/ChatRoom.js 查看文件

583
             case 'nick':
583
             case 'nick':
584
                 member.nick = node.value;
584
                 member.nick = node.value;
585
                 break;
585
                 break;
586
+            case 'silent':
587
+                member.isSilent = node.value;
588
+                break;
586
             case 'userId':
589
             case 'userId':
587
                 member.id = node.value;
590
                 member.id = node.value;
588
                 break;
591
                 break;
685
                     member.botType,
688
                     member.botType,
686
                     member.jid,
689
                     member.jid,
687
                     member.features,
690
                     member.features,
688
-                    member.isReplaceParticipant);
691
+                    member.isReplaceParticipant,
692
+                    member.isSilent);
689
 
693
 
690
                 // we are reporting the status with the join
694
                 // we are reporting the status with the join
691
                 // so we do not want a second event about status update
695
                 // so we do not want a second event about status update
740
                 memberOfThis.displayName = member.displayName;
744
                 memberOfThis.displayName = member.displayName;
741
             }
745
             }
742
 
746
 
747
+            // join without audio
748
+            if (member.isSilent) {
749
+                memberOfThis.isSilent = member.isSilent;
750
+            }
751
+
743
             // update stored status message to be able to detect changes
752
             // update stored status message to be able to detect changes
744
             if (memberOfThis.status !== member.status) {
753
             if (memberOfThis.status !== member.status) {
745
                 hasStatusUpdate = true;
754
                 hasStatusUpdate = true;
776
                         displayName);
785
                         displayName);
777
                 }
786
                 }
778
                 break;
787
                 break;
788
+            case 'silent':
789
+                this.eventEmitter.emit(
790
+                    XMPPEvents.SILENT_STATUS_CHANGED,
791
+                    from,
792
+                    member.isSilent);
793
+                break;
779
             case 'bridgeNotAvailable':
794
             case 'bridgeNotAvailable':
780
                 if (member.isFocus && !this.noBridgeAvailable) {
795
                 if (member.isFocus && !this.noBridgeAvailable) {
781
                     this.noBridgeAvailable = true;
796
                     this.noBridgeAvailable = true;

+ 10
- 5
modules/xmpp/ChatRoom.spec.js 查看文件

185
                 undefined,
185
                 undefined,
186
                 'fulljid',
186
                 'fulljid',
187
                 undefined, // features
187
                 undefined, // features
188
-                0 // isReplaceParticipant
188
+                0, // isReplaceParticipant
189
+                undefined // isSilent
189
             ]);
190
             ]);
190
         });
191
         });
191
 
192
 
220
                 undefined,
221
                 undefined,
221
                 'jid=attr',
222
                 'jid=attr',
222
                 undefined, // features
223
                 undefined, // features
223
-                0); // isReplaceParticipant
224
+                0, // isReplaceParticipant
225
+                undefined); // isSilent
224
         });
226
         });
225
 
227
 
226
         it('parses muc user replacing other user correctly', () => {
228
         it('parses muc user replacing other user correctly', () => {
254
               undefined,
256
               undefined,
255
               'jid=attr',
257
               'jid=attr',
256
               undefined, // features
258
               undefined, // features
257
-              1); // isReplaceParticipant
259
+              1, // isReplaceParticipant
260
+              undefined); // isSilent
258
         });
261
         });
259
 
262
 
260
         it('parses identity correctly', () => {
263
         it('parses identity correctly', () => {
305
                 undefined,
308
                 undefined,
306
                 'fulljid',
309
                 'fulljid',
307
                 undefined, // features
310
                 undefined, // features
308
-                0 // isReplaceParticipant
311
+                0, // isReplaceParticipant
312
+                undefined // isSilent
309
             ]);
313
             ]);
310
         });
314
         });
311
 
315
 
342
                 expectedBotType,
346
                 expectedBotType,
343
                 'fulljid',
347
                 'fulljid',
344
                 undefined, // features
348
                 undefined, // features
345
-                0 // isReplaceParticipant
349
+                0, // isReplaceParticipant
350
+                undefined // isSilent
346
             ]);
351
             ]);
347
         });
352
         });
348
 
353
 

+ 5
- 0
service/xmpp/XMPPEvents.ts 查看文件

266
      */
266
      */
267
     SESSION_ACCEPT_TIMEOUT = 'xmpp.session_accept_timeout',
267
     SESSION_ACCEPT_TIMEOUT = 'xmpp.session_accept_timeout',
268
 
268
 
269
+    /**
270
+     * Event fired when participant joins a meeting without audio.
271
+     */
272
+    SILENT_STATUS_CHANGED = 'xmpp.silent_status_changed',
273
+
269
     /**
274
     /**
270
      * Event fired after successful sending of jingle source-add.
275
      * Event fired after successful sending of jingle source-add.
271
      */
276
      */

Loading…
取消
儲存