Parcourir la source

ref(thumbnail): mutedWhileDisconnected -> redux

j8
Hristo Terezov il y a 5 ans
Parent
révision
1648e4b407

+ 3
- 45
modules/UI/videolayout/RemoteVideo.js Voir le fichier

@@ -100,17 +100,6 @@ export default class RemoteVideo extends SmallVideo {
100 100
          */
101 101
         this._canPlayEventReceived = false;
102 102
 
103
-        /**
104
-         * The flag is set to <tt>true</tt> if remote participant's video gets muted
105
-         * during his media connection disruption. This is to prevent black video
106
-         * being render on the thumbnail, because even though once the video has
107
-         * been played the image usually remains on the video element it seems that
108
-         * after longer period of the video element being hidden this image can be
109
-         * lost.
110
-         * @type {boolean}
111
-         */
112
-        this.mutedWhileDisconnected = false;
113
-
114 103
         // Bind event handlers so they are only bound once for every instance.
115 104
         // TODO The event handlers should be turned into actions so changes can be
116 105
         // handled through reducers and middleware.
@@ -306,36 +295,6 @@ export default class RemoteVideo extends SmallVideo {
306 295
         this._generatePopupContent();
307 296
     }
308 297
 
309
-    /**
310
-     * Video muted status changed handler.
311
-     */
312
-    onVideoMute() {
313
-        super.updateView();
314
-
315
-        // Update 'mutedWhileDisconnected' flag
316
-        this._figureOutMutedWhileDisconnected();
317
-    }
318
-
319
-    /**
320
-     * Figures out the value of {@link #mutedWhileDisconnected} flag by taking into
321
-     * account remote participant's network connectivity and video muted status.
322
-     *
323
-     * @private
324
-     */
325
-    _figureOutMutedWhileDisconnected() {
326
-        const state = APP.store.getState();
327
-        const participant = getParticipantById(state, this.id);
328
-        const connectionState = participant?.connectionStatus;
329
-        const isActive = connectionState === JitsiParticipantConnectionStatus.ACTIVE;
330
-        const isVideoMuted = isRemoteTrackMuted(state['features/base/tracks'], MEDIA_TYPE.VIDEO, this.id);
331
-
332
-        if (!isActive && isVideoMuted) {
333
-            this.mutedWhileDisconnected = true;
334
-        } else if (isActive && !isVideoMuted) {
335
-            this.mutedWhileDisconnected = false;
336
-        }
337
-    }
338
-
339 298
     /**
340 299
      * Removes the remote stream element corresponding to the given stream and
341 300
      * parent container.
@@ -378,12 +337,12 @@ export default class RemoteVideo extends SmallVideo {
378 337
      */
379 338
     isVideoPlayable() {
380 339
         const participant = getParticipantById(APP.store.getState(), this.id);
381
-        const connectionState = participant?.connectionStatus;
340
+        const { connectionStatus, mutedWhileDisconnected } = participant || {};
382 341
 
383 342
         return super.isVideoPlayable()
384 343
             && this._canPlayEventReceived
385
-            && (connectionState === JitsiParticipantConnectionStatus.ACTIVE
386
-                || (connectionState === JitsiParticipantConnectionStatus.INTERRUPTED && !this.mutedWhileDisconnected));
344
+            && (connectionStatus === JitsiParticipantConnectionStatus.ACTIVE
345
+                || (connectionStatus === JitsiParticipantConnectionStatus.INTERRUPTED && !mutedWhileDisconnected));
387 346
     }
388 347
 
389 348
     /**
@@ -391,7 +350,6 @@ export default class RemoteVideo extends SmallVideo {
391 350
      */
392 351
     updateView() {
393 352
         this.$container.toggleClass('audio-only', APP.conference.isAudioOnly());
394
-        this._figureOutMutedWhileDisconnected();
395 353
         super.updateView();
396 354
     }
397 355
 

+ 3
- 2
modules/UI/videolayout/SmallVideo.js Voir le fichier

@@ -433,7 +433,7 @@ export default class SmallVideo {
433 433
      */
434 434
     computeDisplayModeInput() {
435 435
         let isScreenSharing = false;
436
-        let connectionStatus;
436
+        let connectionStatus, mutedWhileDisconnected;
437 437
         const state = APP.store.getState();
438 438
         const participant = getParticipantById(state, this.id);
439 439
 
@@ -443,6 +443,7 @@ export default class SmallVideo {
443 443
 
444 444
             isScreenSharing = typeof track !== 'undefined' && track.videoType === 'desktop';
445 445
             connectionStatus = participant.connectionStatus;
446
+            mutedWhileDisconnected = participant.mutedWhileDisconnected;
446 447
         }
447 448
 
448 449
         return {
@@ -453,7 +454,7 @@ export default class SmallVideo {
453 454
             isVideoPlayable: this.isVideoPlayable(),
454 455
             hasVideo: Boolean(this.selectVideoElement().length),
455 456
             connectionStatus,
456
-            mutedWhileDisconnected: this.mutedWhileDisconnected,
457
+            mutedWhileDisconnected,
457 458
             canPlayEventReceived: this._canPlayEventReceived,
458 459
             videoStream: Boolean(this.videoStream),
459 460
             isScreenSharing,

+ 1
- 7
modules/UI/videolayout/VideoLayout.js Voir le fichier

@@ -337,7 +337,7 @@ const VideoLayout = {
337 337
             const remoteVideo = remoteVideos[id];
338 338
 
339 339
             if (remoteVideo) {
340
-                remoteVideo.onVideoMute();
340
+                remoteVideo.updateView();
341 341
             }
342 342
         }
343 343
 
@@ -391,12 +391,6 @@ const VideoLayout = {
391 391
         const remoteVideo = remoteVideos[id];
392 392
 
393 393
         if (remoteVideo) {
394
-            // Updating only connection status indicator is not enough, because
395
-            // when we the connection is restored while the avatar was displayed
396
-            // (due to 'muted while disconnected' condition) we may want to show
397
-            // the video stream again and in order to do that the display mode
398
-            // must be updated.
399
-            // remoteVideo.updateConnectionStatusIndicator(isActive);
400 394
             remoteVideo.updateView();
401 395
         }
402 396
     },

+ 11
- 7
react/features/base/participants/actions.js Voir le fichier

@@ -19,7 +19,8 @@ import {
19 19
 import {
20 20
     getLocalParticipant,
21 21
     getNormalizedDisplayName,
22
-    getParticipantDisplayName
22
+    getParticipantDisplayName,
23
+    figureOutMutedWhileDisconnectedStatus
23 24
 } from './functions';
24 25
 
25 26
 /**
@@ -216,12 +217,15 @@ export function muteRemoteParticipant(id) {
216 217
  * }}
217 218
  */
218 219
 export function participantConnectionStatusChanged(id, connectionStatus) {
219
-    return {
220
-        type: PARTICIPANT_UPDATED,
221
-        participant: {
222
-            connectionStatus,
223
-            id
224
-        }
220
+    return (dispatch, getState) => {
221
+        return {
222
+            type: PARTICIPANT_UPDATED,
223
+            participant: {
224
+                connectionStatus,
225
+                id,
226
+                mutedWhileDisconnected: figureOutMutedWhileDisconnectedStatus(getState(), id, connectionStatus)
227
+            }
228
+        };
225 229
     };
226 230
 }
227 231
 

+ 40
- 1
react/features/base/participants/functions.js Voir le fichier

@@ -5,7 +5,7 @@ import { getGravatarURL } from '@jitsi/js-utils/avatar';
5 5
 import { JitsiParticipantConnectionStatus } from '../lib-jitsi-meet';
6 6
 import { MEDIA_TYPE, shouldRenderVideoTrack } from '../media';
7 7
 import { toState } from '../redux';
8
-import { getTrackByMediaTypeAndParticipant } from '../tracks';
8
+import { getTrackByMediaTypeAndParticipant, isRemoteTrackMuted } from '../tracks';
9 9
 import { createDeferred } from '../util';
10 10
 
11 11
 import {
@@ -366,6 +366,45 @@ export function shouldRenderParticipantVideo(stateful: Object | Function, id: st
366 366
     return participantIsInLargeVideoWithScreen;
367 367
 }
368 368
 
369
+/**
370
+ * Figures out the value of mutedWhileDisconnected status by taking into
371
+ * account remote participant's network connectivity and video muted status.
372
+ * The flag is set to <tt>true</tt> if remote participant's video gets muted
373
+ * during his media connection disruption. This is to prevent black video
374
+ * being render on the thumbnail, because even though once the video has
375
+ * been played the image usually remains on the video element it seems that
376
+ * after longer period of the video element being hidden this image can be
377
+ * lost.
378
+ *
379
+ * @param {Object|Function} stateful - Object or function that can be resolved
380
+ * to the Redux state.
381
+ * @param {string} participantID - The ID of the participant.
382
+ * @param {string} [connectionStatus] - A connection status to be used.
383
+ * @returns {boolean} - The mutedWhileDisconnected value.
384
+ */
385
+export function figureOutMutedWhileDisconnectedStatus(
386
+        stateful: Function | Object, participantID: string, connectionStatus: ?string) {
387
+    const state = toState(stateful);
388
+    const participant = getParticipantById(state, participantID);
389
+
390
+    if (!participant || participant.local) {
391
+        return undefined;
392
+    }
393
+
394
+    const isActive = (connectionStatus || participant.connectionStatus) === JitsiParticipantConnectionStatus.ACTIVE;
395
+    const isVideoMuted = isRemoteTrackMuted(state['features/base/tracks'], MEDIA_TYPE.VIDEO, participantID);
396
+    let mutedWhileDisconnected = participant.mutedWhileDisconnected || false;
397
+
398
+    if (!isActive && isVideoMuted) {
399
+        mutedWhileDisconnected = true;
400
+    } else if (isActive && !isVideoMuted) {
401
+        mutedWhileDisconnected = false;
402
+    }
403
+
404
+    return mutedWhileDisconnected;
405
+}
406
+
407
+
369 408
 /**
370 409
  * Resolves the first loadable avatar URL for a participant.
371 410
  *

+ 57
- 1
react/features/base/participants/middleware.js Voir le fichier

@@ -12,6 +12,7 @@ import {
12 12
 import { JitsiConferenceEvents } from '../lib-jitsi-meet';
13 13
 import { MiddlewareRegistry, StateListenerRegistry } from '../redux';
14 14
 import { playSound, registerSound, unregisterSound } from '../sounds';
15
+import { getTrackByJitsiTrack, TRACK_ADDED, TRACK_REMOVED, TRACK_UPDATED } from '../tracks';
15 16
 
16 17
 import {
17 18
     DOMINANT_SPEAKER_CHANGED,
@@ -41,7 +42,8 @@ import {
41 42
     getLocalParticipant,
42 43
     getParticipantById,
43 44
     getParticipantCount,
44
-    getParticipantDisplayName
45
+    getParticipantDisplayName,
46
+    figureOutMutedWhileDisconnectedStatus
45 47
 } from './functions';
46 48
 import { PARTICIPANT_JOINED_FILE, PARTICIPANT_LEFT_FILE } from './sounds';
47 49
 
@@ -134,6 +136,11 @@ MiddlewareRegistry.register(store => next => action => {
134 136
 
135 137
     case PARTICIPANT_UPDATED:
136 138
         return _participantJoinedOrUpdated(store, next, action);
139
+
140
+    case TRACK_ADDED:
141
+    case TRACK_REMOVED:
142
+    case TRACK_UPDATED:
143
+        return _trackChanged(store, next, action);
137 144
     }
138 145
 
139 146
     return next(action);
@@ -452,6 +459,55 @@ function _registerSounds({ dispatch }) {
452 459
     dispatch(registerSound(PARTICIPANT_LEFT_SOUND_ID, PARTICIPANT_LEFT_FILE));
453 460
 }
454 461
 
462
+/**
463
+ * Notifies the feature base/participants that the action there has been a change in the tracks of the participants.
464
+ *
465
+ * @param {Store} store - The redux store in which the specified {@code action} is being dispatched.
466
+ * @param {Dispatch} next - The redux {@code dispatch} function to dispatch the specified {@code action} in the
467
+ * specified {@code store}.
468
+ * @param {Action} action - The redux action {@code PARTICIPANT_JOINED} or {@code PARTICIPANT_UPDATED} which is being
469
+ * dispatched in the specified {@code store}.
470
+ * @private
471
+ * @returns {Object} The value returned by {@code next(action)}.
472
+ */
473
+function _trackChanged({ dispatch, getState }, next, action) {
474
+    const { jitsiTrack } = action.track;
475
+    let track;
476
+
477
+    if (action.type === TRACK_REMOVED) {
478
+        track = getTrackByJitsiTrack(getState()['features/base/tracks'], jitsiTrack);
479
+    }
480
+
481
+    const result = next(action);
482
+
483
+    if (action.type !== TRACK_REMOVED) {
484
+        track = getTrackByJitsiTrack(getState()['features/base/tracks'], jitsiTrack);
485
+    }
486
+
487
+    if (typeof track === 'undefined' || track.local) {
488
+        return result;
489
+    }
490
+
491
+    const { participantId } = track;
492
+    const state = getState();
493
+    const participant = getParticipantById(state, participantId);
494
+
495
+    if (!participant) {
496
+        return result;
497
+    }
498
+
499
+    const mutedWhileDisconnected = figureOutMutedWhileDisconnectedStatus(state, participantId);
500
+
501
+    if (participant.mutedWhileDisconnected !== mutedWhileDisconnected) {
502
+        dispatch(participantUpdated({
503
+            id: participantId,
504
+            mutedWhileDisconnected
505
+        }));
506
+    }
507
+
508
+    return result;
509
+}
510
+
455 511
 /**
456 512
  * Unregisters sounds related with the participants feature.
457 513
  *

+ 1
- 0
react/features/base/participants/reducer.js Voir le fichier

@@ -221,6 +221,7 @@ function _participantJoined({ participant }) {
221 221
         isJigasi,
222 222
         loadableAvatarUrl,
223 223
         local: local || false,
224
+        mutedWhileDisconnected: local ? undefined : false,
224 225
         name,
225 226
         pinned: pinned || false,
226 227
         presence,

Chargement…
Annuler
Enregistrer