|
@@ -5,6 +5,7 @@ import {
|
5
|
5
|
JitsiParticipantConnectionStatus
|
6
|
6
|
} from '../../../react/features/base/lib-jitsi-meet';
|
7
|
7
|
import {
|
|
8
|
+ getParticipants,
|
8
|
9
|
getPinnedParticipant,
|
9
|
10
|
pinParticipant
|
10
|
11
|
} from '../../../react/features/base/participants';
|
|
@@ -21,8 +22,6 @@ import LocalVideo from './LocalVideo';
|
21
|
22
|
const remoteVideos = {};
|
22
|
23
|
let localVideoThumbnail = null;
|
23
|
24
|
|
24
|
|
-let currentDominantSpeaker = null;
|
25
|
|
-
|
26
|
25
|
let eventEmitter = null;
|
27
|
26
|
|
28
|
27
|
let largeVideo;
|
|
@@ -43,6 +42,24 @@ function onLocalFlipXChanged(val) {
|
43
|
42
|
}
|
44
|
43
|
}
|
45
|
44
|
|
|
45
|
+/**
|
|
46
|
+ * Returns the user ID of the remote participant that is current the dominant
|
|
47
|
+ * speaker.
|
|
48
|
+ *
|
|
49
|
+ * @private
|
|
50
|
+ * @returns {string|null}
|
|
51
|
+ */
|
|
52
|
+function getCurrentRemoteDominantSpeakerID() {
|
|
53
|
+ const dominantSpeaker = getParticipants(APP.store.getState)
|
|
54
|
+ .find(participant => participant.dominantSpeaker);
|
|
55
|
+
|
|
56
|
+ if (dominantSpeaker) {
|
|
57
|
+ return dominantSpeaker.local ? null : dominantSpeaker.id;
|
|
58
|
+ }
|
|
59
|
+
|
|
60
|
+ return null;
|
|
61
|
+}
|
|
62
|
+
|
46
|
63
|
/**
|
47
|
64
|
* Returns the corresponding resource id to the given peer container
|
48
|
65
|
* DOM element.
|
|
@@ -228,8 +245,8 @@ const VideoLayout = {
|
228
|
245
|
|
229
|
246
|
if (pinnedId) {
|
230
|
247
|
newId = pinnedId;
|
231
|
|
- } else if (currentDominantSpeaker) {
|
232
|
|
- newId = currentDominantSpeaker;
|
|
248
|
+ } else if (getCurrentRemoteDominantSpeakerID()) {
|
|
249
|
+ newId = getCurrentRemoteDominantSpeakerID();
|
233
|
250
|
} else { // Otherwise select last visible video
|
234
|
251
|
newId = this.electLastVisibleVideo();
|
235
|
252
|
}
|
|
@@ -392,8 +409,8 @@ const VideoLayout = {
|
392
|
409
|
this.pinParticipant(null);
|
393
|
410
|
|
394
|
411
|
// Enable the currently set dominant speaker.
|
395
|
|
- if (currentDominantSpeaker) {
|
396
|
|
- this.updateLargeVideo(currentDominantSpeaker);
|
|
412
|
+ if (getCurrentRemoteDominantSpeakerID()) {
|
|
413
|
+ this.updateLargeVideo(getCurrentRemoteDominantSpeakerID());
|
397
|
414
|
} else {
|
398
|
415
|
// if there is no currentDominantSpeaker, it can also be
|
399
|
416
|
// that local participant is the dominant speaker
|
|
@@ -501,11 +518,11 @@ const VideoLayout = {
|
501
|
518
|
const pinnedId = this.getPinnedId();
|
502
|
519
|
|
503
|
520
|
if ((!pinnedId
|
504
|
|
- && !currentDominantSpeaker
|
|
521
|
+ && !getCurrentRemoteDominantSpeakerID()
|
505
|
522
|
&& this.isLargeContainerTypeVisible(VIDEO_CONTAINER_TYPE))
|
506
|
523
|
|| pinnedId === resourceJid
|
507
|
524
|
|| (!pinnedId && resourceJid
|
508
|
|
- && currentDominantSpeaker === resourceJid)
|
|
525
|
+ && getCurrentRemoteDominantSpeakerID() === resourceJid)
|
509
|
526
|
|
510
|
527
|
/* Playback started while we're on the stage - may need to update
|
511
|
528
|
video source with the new stream */
|
|
@@ -662,43 +679,22 @@ const VideoLayout = {
|
662
|
679
|
|
663
|
680
|
/**
|
664
|
681
|
* On dominant speaker changed event.
|
|
682
|
+ *
|
|
683
|
+ * @param {string} id - The participant ID of the new dominant speaker.
|
|
684
|
+ * @returns {void}
|
665
|
685
|
*/
|
666
|
686
|
onDominantSpeakerChanged(id) {
|
667
|
|
- if (id === currentDominantSpeaker) {
|
668
|
|
- return;
|
669
|
|
- }
|
670
|
|
-
|
671
|
|
- const oldSpeakerRemoteVideo = remoteVideos[currentDominantSpeaker];
|
|
687
|
+ Object.values(remoteVideos).forEach(remoteVideo =>
|
|
688
|
+ remoteVideo.showDominantSpeakerIndicator(
|
|
689
|
+ id === remoteVideo.getId()));
|
672
|
690
|
|
673
|
|
- // We ignore local user events, but just unmark remote user as dominant
|
674
|
|
- // while we are talking
|
|
691
|
+ localVideoThumbnail.showDominantSpeakerIndicator(
|
|
692
|
+ APP.conference.isLocalId(id));
|
675
|
693
|
|
676
|
|
- if (APP.conference.isLocalId(id)) {
|
677
|
|
- if (oldSpeakerRemoteVideo) {
|
678
|
|
- oldSpeakerRemoteVideo.showDominantSpeakerIndicator(false);
|
679
|
|
- currentDominantSpeaker = null;
|
680
|
|
- }
|
681
|
|
- localVideoThumbnail.showDominantSpeakerIndicator(true);
|
682
|
|
-
|
683
|
|
- return;
|
684
|
|
- }
|
685
|
|
-
|
686
|
|
- const remoteVideo = remoteVideos[id];
|
687
|
|
-
|
688
|
|
- if (!remoteVideo) {
|
|
694
|
+ if (!remoteVideos[id]) {
|
689
|
695
|
return;
|
690
|
696
|
}
|
691
|
697
|
|
692
|
|
- // Update the current dominant speaker.
|
693
|
|
- remoteVideo.showDominantSpeakerIndicator(true);
|
694
|
|
- localVideoThumbnail.showDominantSpeakerIndicator(false);
|
695
|
|
-
|
696
|
|
- // let's remove the indications from the remote video if any
|
697
|
|
- if (oldSpeakerRemoteVideo) {
|
698
|
|
- oldSpeakerRemoteVideo.showDominantSpeakerIndicator(false);
|
699
|
|
- }
|
700
|
|
- currentDominantSpeaker = id;
|
701
|
|
-
|
702
|
698
|
// Local video will not have container found, but that's ok
|
703
|
699
|
// since we don't want to switch to local video.
|
704
|
700
|
if (!interfaceConfig.filmStripOnly && !this.getPinnedId()
|
|
@@ -804,11 +800,6 @@ const VideoLayout = {
|
804
|
800
|
this.pinParticipant(null);
|
805
|
801
|
}
|
806
|
802
|
|
807
|
|
- if (currentDominantSpeaker === id) {
|
808
|
|
- logger.info('Dominant speaker has left the conference');
|
809
|
|
- currentDominantSpeaker = null;
|
810
|
|
- }
|
811
|
|
-
|
812
|
803
|
const remoteVideo = remoteVideos[id];
|
813
|
804
|
|
814
|
805
|
if (remoteVideo) {
|