Bladeren bron

ref(large-video): switch LargeVideo logic to react

j8
Hristo Terezov 5 jaren geleden
bovenliggende
commit
21dcc41d31

+ 1
- 4
conference.js Bestand weergeven

1253
                         this.localVideo = newStream;
1253
                         this.localVideo = newStream;
1254
                         this._setSharingScreen(newStream);
1254
                         this._setSharingScreen(newStream);
1255
                         if (newStream) {
1255
                         if (newStream) {
1256
-                            APP.UI.addLocalStream(newStream);
1256
+                            APP.UI.addLocalVideoStream(newStream);
1257
                         }
1257
                         }
1258
                         this.setVideoMuteStatus(this.isLocalVideoMuted());
1258
                         this.setVideoMuteStatus(this.isLocalVideoMuted());
1259
                     })
1259
                     })
1304
                 replaceLocalTrack(this.localAudio, newStream, room))
1304
                 replaceLocalTrack(this.localAudio, newStream, room))
1305
                     .then(() => {
1305
                     .then(() => {
1306
                         this.localAudio = newStream;
1306
                         this.localAudio = newStream;
1307
-                        if (newStream) {
1308
-                            APP.UI.addLocalStream(newStream);
1309
-                        }
1310
                         this.setAudioMuteStatus(this.isLocalAudioMuted());
1307
                         this.setAudioMuteStatus(this.isLocalAudioMuted());
1311
                     })
1308
                     })
1312
                     .then(resolve)
1309
                     .then(resolve)

+ 3
- 14
modules/UI/UI.js Bestand weergeven

229
 };
229
 };
230
 
230
 
231
 /**
231
 /**
232
- * Show local stream on UI.
232
+ * Show local video stream on UI.
233
  * @param {JitsiTrack} track stream to show
233
  * @param {JitsiTrack} track stream to show
234
  */
234
  */
235
-UI.addLocalStream = track => {
236
-    switch (track.getType()) {
237
-    case 'audio':
238
-        // Local audio is not rendered so no further action is needed at this
239
-        // point.
240
-        break;
241
-    case 'video':
242
-        VideoLayout.changeLocalVideo(track);
243
-        break;
244
-    default:
245
-        logger.error(`Unknown stream type: ${track.getType()}`);
246
-        break;
247
-    }
235
+UI.addLocalVideoStream = track => {
236
+    VideoLayout.changeLocalVideo(track);
248
 };
237
 };
249
 
238
 
250
 /**
239
 /**

+ 5
- 207
modules/UI/videolayout/VideoLayout.js Bestand weergeven

53
     }
53
     }
54
 }
54
 }
55
 
55
 
56
-/**
57
- * Returns the redux representation of all known users.
58
- *
59
- * @private
60
- * @returns {Array}
61
- */
62
-function getAllParticipants() {
63
-    return APP.store.getState()['features/base/participants'];
64
-}
65
-
66
 /**
56
 /**
67
  * Returns an array of all thumbnails in the filmstrip.
57
  * Returns an array of all thumbnails in the filmstrip.
68
  *
58
  *
86
     return getLocalParticipantFromStore(APP.store.getState());
76
     return getLocalParticipantFromStore(APP.store.getState());
87
 }
77
 }
88
 
78
 
89
-/**
90
- * Returns the user ID of the remote participant that is current the dominant
91
- * speaker.
92
- *
93
- * @private
94
- * @returns {string|null}
95
- */
96
-function getCurrentRemoteDominantSpeakerID() {
97
-    const dominantSpeaker = getAllParticipants()
98
-        .find(participant => participant.dominantSpeaker);
99
-
100
-    if (dominantSpeaker) {
101
-        return dominantSpeaker.local ? null : dominantSpeaker.id;
102
-    }
103
-
104
-    return null;
105
-}
106
-
107
-/**
108
- * Returns the corresponding resource id to the given peer container
109
- * DOM element.
110
- *
111
- * @return the corresponding resource id to the given peer container
112
- * DOM element
113
- */
114
-function getPeerContainerResourceId(containerElement) {
115
-    if (localVideoThumbnail.container === containerElement) {
116
-        return localVideoThumbnail.id;
117
-    }
118
-
119
-    const i = containerElement.id.indexOf('participant_');
120
-
121
-    if (i >= 0) {
122
-        return containerElement.id.substring(i + 12);
123
-    }
124
-}
125
-
126
 const VideoLayout = {
79
 const VideoLayout = {
127
     init(emitter) {
80
     init(emitter) {
128
         eventEmitter = emitter;
81
         eventEmitter = emitter;
208
      * and setting them assume the id is already set.
161
      * and setting them assume the id is already set.
209
      */
162
      */
210
     mucJoined() {
163
     mucJoined() {
211
-        if (largeVideo && !largeVideo.id) {
212
-            this.updateLargeVideo(getLocalParticipant().id, true);
213
-        }
214
-
215
         // FIXME: replace this call with a generic update call once SmallVideo
164
         // FIXME: replace this call with a generic update call once SmallVideo
216
         // only contains a ReactElement. Then remove this call once the
165
         // only contains a ReactElement. Then remove this call once the
217
         // Filmstrip is fully in React.
166
         // Filmstrip is fully in React.
247
         localVideoThumbnail.setVisible(visible);
196
         localVideoThumbnail.setVisible(visible);
248
     },
197
     },
249
 
198
 
250
-    /**
251
-     * Checks if removed video is currently displayed and tries to display
252
-     * another one instead.
253
-     * Uses focusedID if any or dominantSpeakerID if any,
254
-     * otherwise elects new video, in this order.
255
-     */
256
-    _updateAfterThumbRemoved(id) {
257
-        // Always trigger an update if large video is empty.
258
-        if (!largeVideo
259
-            || (this.getLargeVideoID() && !this.isCurrentlyOnLarge(id))) {
260
-            return;
261
-        }
262
-
263
-        const pinnedId = this.getPinnedId();
264
-        let newId;
265
-
266
-        if (pinnedId) {
267
-            newId = pinnedId;
268
-        } else if (getCurrentRemoteDominantSpeakerID()) {
269
-            newId = getCurrentRemoteDominantSpeakerID();
270
-        } else { // Otherwise select last visible video
271
-            newId = this.electLastVisibleVideo();
272
-        }
273
-
274
-        this.updateLargeVideo(newId);
275
-    },
276
-
277
-    electLastVisibleVideo() {
278
-        // pick the last visible video in the row
279
-        // if nobody else is left, this picks the local video
280
-        const remoteThumbs = Filmstrip.getThumbs(true).remoteThumbs;
281
-        let thumbs = remoteThumbs.filter('[id!="mixedstream"]');
282
-
283
-        const lastVisible = thumbs.filter(':visible:last');
284
-
285
-        if (lastVisible.length) {
286
-            const id = getPeerContainerResourceId(lastVisible[0]);
287
-
288
-            if (remoteVideos[id]) {
289
-                logger.info(`electLastVisibleVideo: ${id}`);
290
-
291
-                return id;
292
-            }
293
-
294
-            // The RemoteVideo was removed (but the DOM elements may still
295
-            // exist).
296
-        }
297
-
298
-        logger.info('Last visible video no longer exists');
299
-        thumbs = Filmstrip.getThumbs().remoteThumbs;
300
-        if (thumbs.length) {
301
-            const id = getPeerContainerResourceId(thumbs[0]);
302
-
303
-            if (remoteVideos[id]) {
304
-                logger.info(`electLastVisibleVideo: ${id}`);
305
-
306
-                return id;
307
-            }
308
-
309
-            // The RemoteVideo was removed (but the DOM elements may
310
-            // still exist).
311
-        }
312
-
313
-        // Go with local video
314
-        logger.info('Fallback to local video...');
315
-
316
-        const { id } = getLocalParticipant();
317
-
318
-        logger.info(`electLastVisibleVideo: ${id}`);
319
-
320
-        return id;
321
-    },
322
-
323
     onRemoteStreamAdded(stream) {
199
     onRemoteStreamAdded(stream) {
324
         const id = stream.getParticipantId();
200
         const id = stream.getParticipantId();
325
         const remoteVideo = remoteVideos[id];
201
         const remoteVideo = remoteVideos[id];
423
 
299
 
424
         getAllThumbnails().forEach(thumbnail =>
300
         getAllThumbnails().forEach(thumbnail =>
425
             thumbnail.focus(pinnedParticipantID === thumbnail.getId()));
301
             thumbnail.focus(pinnedParticipantID === thumbnail.getId()));
426
-
427
-        if (pinnedParticipantID) {
428
-            this.updateLargeVideo(pinnedParticipantID);
429
-        } else {
430
-            const currentDominantSpeakerID
431
-                = getCurrentRemoteDominantSpeakerID();
432
-
433
-            if (currentDominantSpeakerID) {
434
-                this.updateLargeVideo(currentDominantSpeakerID);
435
-            } else {
436
-                // if there is no currentDominantSpeakerID, it can also be
437
-                // that local participant is the dominant speaker
438
-                // we should act as a participant has left and was on large
439
-                // and we should choose somebody (electLastVisibleVideo)
440
-                this.updateLargeVideo(this.electLastVisibleVideo());
441
-            }
442
-        }
443
     },
302
     },
444
 
303
 
445
     /**
304
     /**
473
 
332
 
474
         this.updateMutedForNoTracks(id, 'audio');
333
         this.updateMutedForNoTracks(id, 'audio');
475
         this.updateMutedForNoTracks(id, 'video');
334
         this.updateMutedForNoTracks(id, 'video');
476
-
477
-        const remoteVideosCount = Object.keys(remoteVideos).length;
478
-
479
-        if (remoteVideosCount === 1) {
480
-            window.setTimeout(() => {
481
-                const updatedRemoteVideosCount
482
-                    = Object.keys(remoteVideos).length;
483
-
484
-                if (updatedRemoteVideosCount === 1 && remoteVideos[id]) {
485
-                    this._maybePlaceParticipantOnLargeVideo(id);
486
-                }
487
-            }, 3000);
488
-        }
489
     },
335
     },
490
 
336
 
491
     /**
337
     /**
512
 
358
 
513
     // FIXME: what does this do???
359
     // FIXME: what does this do???
514
     remoteVideoActive(videoElement, resourceJid) {
360
     remoteVideoActive(videoElement, resourceJid) {
515
-
516
         logger.info(`${resourceJid} video is now active`, videoElement);
361
         logger.info(`${resourceJid} video is now active`, videoElement);
517
-
518
         VideoLayout.resizeThumbnails(
362
         VideoLayout.resizeThumbnails(
519
             false, () => {
363
             false, () => {
520
                 if (videoElement) {
364
                 if (videoElement) {
521
                     $(videoElement).show();
365
                     $(videoElement).show();
522
                 }
366
                 }
523
             });
367
             });
524
-
525
-        this._maybePlaceParticipantOnLargeVideo(resourceJid);
526
-    },
527
-
528
-    /**
529
-     * Update the large video to the last added video only if there's no current
530
-     * dominant, focused speaker or update it to the current dominant speaker.
531
-     *
532
-     * @params {string} resourceJid - The id of the user to maybe display on
533
-     * large video.
534
-     * @returns {void}
535
-     */
536
-    _maybePlaceParticipantOnLargeVideo(resourceJid) {
537
-        const pinnedId = this.getPinnedId();
538
-
539
-        if ((!pinnedId
540
-            && !getCurrentRemoteDominantSpeakerID()
541
-            && this.isLargeContainerTypeVisible(VIDEO_CONTAINER_TYPE))
542
-            || pinnedId === resourceJid
543
-            || (!pinnedId && resourceJid
544
-                && getCurrentRemoteDominantSpeakerID() === resourceJid)
545
-
546
-            /* Playback started while we're on the stage - may need to update
547
-               video source with the new stream */
548
-            || this.isCurrentlyOnLarge(resourceJid)) {
549
-
550
-            this.updateLargeVideo(resourceJid, true);
551
-        }
368
+        this._updateLargeVideoIfDisplayed(resourceJid, true);
552
     },
369
     },
553
 
370
 
554
     /**
371
     /**
646
             }
463
             }
647
         }
464
         }
648
 
465
 
649
-        if (this.isCurrentlyOnLarge(id)) {
650
-            // large video will show avatar instead of muted stream
651
-            this.updateLargeVideo(id, true);
652
-        }
466
+        // large video will show avatar instead of muted stream
467
+        this._updateLargeVideoIfDisplayed(id, true);
653
     },
468
     },
654
 
469
 
655
     /**
470
     /**
677
     onDominantSpeakerChanged(id) {
492
     onDominantSpeakerChanged(id) {
678
         getAllThumbnails().forEach(thumbnail =>
493
         getAllThumbnails().forEach(thumbnail =>
679
             thumbnail.showDominantSpeakerIndicator(id === thumbnail.getId()));
494
             thumbnail.showDominantSpeakerIndicator(id === thumbnail.getId()));
680
-
681
-
682
-        if (!remoteVideos[id]) {
683
-            return;
684
-        }
685
-
686
-        // Local video will not have container found, but that's ok
687
-        // since we don't want to switch to local video.
688
-        if (!interfaceConfig.filmStripOnly && !this.getPinnedId()
689
-            && !this.getCurrentlyOnLargeContainer().stayOnStage()) {
690
-            this.updateLargeVideo(id);
691
-        }
692
     },
495
     },
693
 
496
 
694
     /**
497
     /**
758
 
561
 
759
         if (remoteVideo) {
562
         if (remoteVideo) {
760
             remoteVideo.updateView();
563
             remoteVideo.updateView();
761
-            if (remoteVideo.isCurrentlyOnLargeVideo()) {
762
-                this.updateLargeVideo(id);
763
-            }
564
+            this._updateLargeVideoIfDisplayed(id);
764
         }
565
         }
765
     },
566
     },
766
 
567
 
809
         }
610
         }
810
 
611
 
811
         VideoLayout.resizeThumbnails();
612
         VideoLayout.resizeThumbnails();
812
-        VideoLayout._updateAfterThumbRemoved(id);
813
     },
613
     },
814
 
614
 
815
     onVideoTypeChanged(id, newVideoType) {
615
     onVideoTypeChanged(id, newVideoType) {
835
         }
635
         }
836
         smallVideo.setVideoType(newVideoType);
636
         smallVideo.setVideoType(newVideoType);
837
 
637
 
838
-        if (this.isCurrentlyOnLarge(id)) {
839
-            this.updateLargeVideo(id, true);
840
-        }
638
+        this._updateLargeVideoIfDisplayed(id, true);
841
     },
639
     },
842
 
640
 
843
     /**
641
     /**

+ 1
- 3
react/features/base/tracks/middleware.js Bestand weergeven

124
                 } else {
124
                 } else {
125
                     APP.UI.setVideoMuted(participantID, muted);
125
                     APP.UI.setVideoMuted(participantID, muted);
126
                 }
126
                 }
127
-                APP.UI.onPeerVideoTypeChanged(
128
-                    participantID,
129
-                    jitsiTrack.videoType);
127
+                APP.UI.onPeerVideoTypeChanged(participantID, jitsiTrack.videoType);
130
             } else if (jitsiTrack.isLocal()) {
128
             } else if (jitsiTrack.isLocal()) {
131
                 APP.conference.setAudioMuteStatus(muted);
129
                 APP.conference.setAudioMuteStatus(muted);
132
             } else {
130
             } else {

+ 1
- 0
react/features/large-video/index.js Bestand weergeven

3
 
3
 
4
 import './middleware';
4
 import './middleware';
5
 import './reducer';
5
 import './reducer';
6
+import './subscriber';

+ 1
- 8
react/features/large-video/middleware.js Bestand weergeven

38
 
38
 
39
         break;
39
         break;
40
     }
40
     }
41
-
41
+    case CONFERENCE_JOINED:
42
     case PARTICIPANT_JOINED:
42
     case PARTICIPANT_JOINED:
43
     case PARTICIPANT_LEFT:
43
     case PARTICIPANT_LEFT:
44
     case PIN_PARTICIPANT:
44
     case PIN_PARTICIPANT:
47
         store.dispatch(selectParticipantInLargeVideo());
47
         store.dispatch(selectParticipantInLargeVideo());
48
         break;
48
         break;
49
 
49
 
50
-    case CONFERENCE_JOINED:
51
-        // Ensure a participant is selected on conference join. This addresses
52
-        // the case where video tracks were received before CONFERENCE_JOINED
53
-        // fired; without the conference selection may not happen.
54
-        store.dispatch(selectParticipant());
55
-        break;
56
-
57
     case TRACK_UPDATED:
50
     case TRACK_UPDATED:
58
         // In order to minimize re-calculations, we need to select participant
51
         // In order to minimize re-calculations, we need to select participant
59
         // only if the videoType of the current participant rendered in
52
         // only if the videoType of the current participant rendered in

+ 14
- 0
react/features/large-video/subscriber.js Bestand weergeven

1
+// @flow
2
+
3
+import { StateListenerRegistry } from '../base/redux';
4
+import VideoLayout from '../../../modules/UI/videolayout/VideoLayout';
5
+
6
+/**
7
+ * Updates the on stage participant video.
8
+ */
9
+StateListenerRegistry.register(
10
+    /* selector */ state => state['features/large-video'].participantId,
11
+    /* listener */ participantId => {
12
+        VideoLayout.updateLargeVideo(participantId, true);
13
+    }
14
+);

Laden…
Annuleren
Opslaan