|
@@ -5,7 +5,6 @@ import {
|
5
|
5
|
JitsiParticipantConnectionStatus
|
6
|
6
|
} from '../../../react/features/base/lib-jitsi-meet';
|
7
|
7
|
import {
|
8
|
|
- getParticipants,
|
9
|
8
|
getPinnedParticipant,
|
10
|
9
|
pinParticipant
|
11
|
10
|
} from '../../../react/features/base/participants';
|
|
@@ -42,6 +41,29 @@ function onLocalFlipXChanged(val) {
|
42
|
41
|
}
|
43
|
42
|
}
|
44
|
43
|
|
|
44
|
+/**
|
|
45
|
+ * Returns the redux representation of all known users.
|
|
46
|
+ *
|
|
47
|
+ * @private
|
|
48
|
+ * @returns {Array}
|
|
49
|
+ */
|
|
50
|
+function getAllParticipants() {
|
|
51
|
+ return APP.store.getState()['features/base/participants'];
|
|
52
|
+}
|
|
53
|
+
|
|
54
|
+/**
|
|
55
|
+ * Returns an array of all thumbnails in the filmstrip.
|
|
56
|
+ *
|
|
57
|
+ * @private
|
|
58
|
+ * @returns {Array}
|
|
59
|
+ */
|
|
60
|
+function getAllThumbnails() {
|
|
61
|
+ return [
|
|
62
|
+ localVideoThumbnail,
|
|
63
|
+ ...Object.values(remoteVideos)
|
|
64
|
+ ];
|
|
65
|
+}
|
|
66
|
+
|
45
|
67
|
/**
|
46
|
68
|
* Returns the user ID of the remote participant that is current the dominant
|
47
|
69
|
* speaker.
|
|
@@ -50,7 +72,7 @@ function onLocalFlipXChanged(val) {
|
50
|
72
|
* @returns {string|null}
|
51
|
73
|
*/
|
52
|
74
|
function getCurrentRemoteDominantSpeakerID() {
|
53
|
|
- const dominantSpeaker = getParticipants(APP.store.getState)
|
|
75
|
+ const dominantSpeaker = getAllParticipants()
|
54
|
76
|
.find(participant => participant.dominantSpeaker);
|
55
|
77
|
|
56
|
78
|
if (dominantSpeaker) {
|
|
@@ -93,8 +115,6 @@ const VideoLayout = {
|
93
|
115
|
// the local video thumb maybe one pixel
|
94
|
116
|
this.resizeThumbnails(true);
|
95
|
117
|
|
96
|
|
- this.handleVideoThumbClicked = this.handleVideoThumbClicked.bind(this);
|
97
|
|
-
|
98
|
118
|
this.registerListeners();
|
99
|
119
|
},
|
100
|
120
|
|
|
@@ -376,61 +396,36 @@ const VideoLayout = {
|
376
|
396
|
},
|
377
|
397
|
|
378
|
398
|
/**
|
379
|
|
- * Updates the desired pinned participant and notifies web UI of the change.
|
|
399
|
+ * Callback invoked to update display when the pin participant has changed.
|
380
|
400
|
*
|
381
|
|
- * @param {string|null} id - The participant id of the participant to be
|
382
|
|
- * pinned. Pass in null to unpin without pinning another participant.
|
|
401
|
+ * @paramn {string|null} pinnedParticipantID - The participant ID of the
|
|
402
|
+ * participant that is pinned or null if no one is pinned.
|
383
|
403
|
* @returns {void}
|
384
|
404
|
*/
|
385
|
|
- pinParticipant(id) {
|
386
|
|
- APP.store.dispatch(pinParticipant(id));
|
387
|
|
- APP.UI.emitEvent(UIEvents.PINNED_ENDPOINT, id, Boolean(id));
|
388
|
|
- },
|
389
|
|
-
|
390
|
|
- /**
|
391
|
|
- * Handles the click on a video thumbnail.
|
392
|
|
- *
|
393
|
|
- * @param id the identifier of the video thumbnail
|
394
|
|
- */
|
395
|
|
- handleVideoThumbClicked(id) {
|
396
|
|
- const smallVideo = VideoLayout.getSmallVideo(id);
|
397
|
|
- const pinnedId = this.getPinnedId();
|
398
|
|
-
|
399
|
|
- if (pinnedId) {
|
400
|
|
- const oldSmallVideo = VideoLayout.getSmallVideo(pinnedId);
|
401
|
|
-
|
402
|
|
- if (oldSmallVideo && !interfaceConfig.filmStripOnly) {
|
403
|
|
- oldSmallVideo.focus(false);
|
404
|
|
- }
|
|
405
|
+ onPinChange(pinnedParticipantID) {
|
|
406
|
+ if (interfaceConfig.filmStripOnly) {
|
|
407
|
+ return;
|
405
|
408
|
}
|
406
|
409
|
|
407
|
|
- // Unpin if currently pinned.
|
408
|
|
- if (pinnedId === id) {
|
409
|
|
- this.pinParticipant(null);
|
|
410
|
+ getAllThumbnails().forEach(thumbnail =>
|
|
411
|
+ thumbnail.focus(pinnedParticipantID === thumbnail.getId()));
|
410
|
412
|
|
411
|
|
- // Enable the currently set dominant speaker.
|
412
|
|
- if (getCurrentRemoteDominantSpeakerID()) {
|
413
|
|
- this.updateLargeVideo(getCurrentRemoteDominantSpeakerID());
|
|
413
|
+ if (pinnedParticipantID) {
|
|
414
|
+ this.updateLargeVideo(pinnedParticipantID);
|
|
415
|
+ } else {
|
|
416
|
+ const currentDominantSpeakerID
|
|
417
|
+ = getCurrentRemoteDominantSpeakerID();
|
|
418
|
+
|
|
419
|
+ if (currentDominantSpeakerID) {
|
|
420
|
+ this.updateLargeVideo(currentDominantSpeakerID);
|
414
|
421
|
} else {
|
415
|
|
- // if there is no currentDominantSpeaker, it can also be
|
|
422
|
+ // if there is no currentDominantSpeakerID, it can also be
|
416
|
423
|
// that local participant is the dominant speaker
|
417
|
424
|
// we should act as a participant has left and was on large
|
418
|
425
|
// and we should choose somebody (electLastVisibleVideo)
|
419
|
426
|
this.updateLargeVideo(this.electLastVisibleVideo());
|
420
|
427
|
}
|
421
|
|
-
|
422
|
|
- return;
|
423
|
|
- }
|
424
|
|
-
|
425
|
|
- // Update focused/pinned interface.
|
426
|
|
- if (id) {
|
427
|
|
- if (smallVideo && !interfaceConfig.filmStripOnly) {
|
428
|
|
- smallVideo.focus(true);
|
429
|
|
- this.pinParticipant(id);
|
430
|
|
- }
|
431
|
428
|
}
|
432
|
|
-
|
433
|
|
- this.updateLargeVideo(id);
|
434
|
429
|
},
|
435
|
430
|
|
436
|
431
|
/**
|
|
@@ -684,12 +679,9 @@ const VideoLayout = {
|
684
|
679
|
* @returns {void}
|
685
|
680
|
*/
|
686
|
681
|
onDominantSpeakerChanged(id) {
|
687
|
|
- Object.values(remoteVideos).forEach(remoteVideo =>
|
688
|
|
- remoteVideo.showDominantSpeakerIndicator(
|
689
|
|
- id === remoteVideo.getId()));
|
|
682
|
+ getAllThumbnails().forEach(thumbnail =>
|
|
683
|
+ thumbnail.showDominantSpeakerIndicator(id === thumbnail.getId()));
|
690
|
684
|
|
691
|
|
- localVideoThumbnail.showDominantSpeakerIndicator(
|
692
|
|
- APP.conference.isLocalId(id));
|
693
|
685
|
|
694
|
686
|
if (!remoteVideos[id]) {
|
695
|
687
|
return;
|
|
@@ -797,7 +789,7 @@ const VideoLayout = {
|
797
|
789
|
// Unlock large video
|
798
|
790
|
if (this.getPinnedId() === id) {
|
799
|
791
|
logger.info('Focused video owner has left the conference');
|
800
|
|
- this.pinParticipant(null);
|
|
792
|
+ APP.store.dispatch(pinParticipant(null));
|
801
|
793
|
}
|
802
|
794
|
|
803
|
795
|
const remoteVideo = remoteVideos[id];
|