Browse Source

fix(video):Always show avatar if video is inactive

master
Hristo Terezov 5 years ago
parent
commit
87b1155180

+ 2
- 12
modules/UI/videolayout/LargeVideoManager.js View File

218
             // change the avatar url on large
218
             // change the avatar url on large
219
             this.updateAvatar();
219
             this.updateAvatar();
220
 
220
 
221
-            // If the user's connection is disrupted then the avatar will be
222
-            // displayed in case we have no video image cached. That is if
223
-            // there was a user switch (image is lost on stream detach) or if
224
-            // the video was not rendered, before the connection has failed.
225
-            const wasUsersImageCached
226
-                = !isUserSwitch && container.wasVideoRendered;
227
             const isVideoMuted = !stream || stream.isMuted();
221
             const isVideoMuted = !stream || stream.isMuted();
228
             const participant = getParticipantById(APP.store.getState(), id);
222
             const participant = getParticipantById(APP.store.getState(), id);
229
             const connectionStatus = participant?.connectionStatus;
223
             const connectionStatus = participant?.connectionStatus;
230
-            const isVideoRenderable
231
-                = !isVideoMuted
232
-                    && (APP.conference.isLocalId(id)
233
-                        || connectionStatus
234
-                                === JitsiParticipantConnectionStatus.ACTIVE
235
-                        || wasUsersImageCached);
224
+            const isVideoRenderable = !isVideoMuted
225
+                && (APP.conference.isLocalId(id) || connectionStatus === JitsiParticipantConnectionStatus.ACTIVE);
236
 
226
 
237
             const showAvatar
227
             const showAvatar
238
                 = isVideoContainer
228
                 = isVideoContainer

+ 15
- 13
modules/UI/videolayout/RemoteVideo.js View File

331
     }
331
     }
332
 
332
 
333
     /**
333
     /**
334
-     * The remote video is considered "playable" once the can play event has been received. It will be allowed to
335
-     * display video also in {@link JitsiParticipantConnectionStatus.INTERRUPTED} if the video has received the canplay
336
-     * event and was not muted while not in ACTIVE state. This basically means that there is stalled video image cached
337
-     * that could be displayed. It's used to show "grey video image" in user's thumbnail when there are connectivity
338
-     * issues.
334
+     * The remote video is considered "playable" once the can play event has been received.
339
      *
335
      *
340
      * @inheritdoc
336
      * @inheritdoc
341
      * @override
337
      * @override
342
      */
338
      */
343
     isVideoPlayable() {
339
     isVideoPlayable() {
344
         const participant = getParticipantById(APP.store.getState(), this.id);
340
         const participant = getParticipantById(APP.store.getState(), this.id);
345
-        const { connectionStatus, mutedWhileDisconnected } = participant || {};
341
+        const { connectionStatus } = participant || {};
346
 
342
 
347
-        return super.isVideoPlayable()
348
-            && this._canPlayEventReceived
349
-            && (connectionStatus === JitsiParticipantConnectionStatus.ACTIVE
350
-                || (connectionStatus === JitsiParticipantConnectionStatus.INTERRUPTED && !mutedWhileDisconnected));
343
+        return (
344
+            super.isVideoPlayable()
345
+                && this._canPlayEventReceived
346
+                && connectionStatus === JitsiParticipantConnectionStatus.ACTIVE
347
+        );
351
     }
348
     }
352
 
349
 
353
     /**
350
     /**
373
      * @param {*} stream
370
      * @param {*} stream
374
      */
371
      */
375
     waitForPlayback(streamElement, stream) {
372
     waitForPlayback(streamElement, stream) {
373
+        $(streamElement).hide();
374
+
376
         const webRtcStream = stream.getOriginalStream();
375
         const webRtcStream = stream.getOriginalStream();
377
         const isVideo = stream.isVideoTrack();
376
         const isVideo = stream.isVideoTrack();
378
 
377
 
382
 
381
 
383
         const listener = () => {
382
         const listener = () => {
384
             this._canPlayEventReceived = true;
383
             this._canPlayEventReceived = true;
385
-            this.VideoLayout.remoteVideoActive(streamElement, this.id);
384
+
385
+            logger.info(`${this.id} video is now active`, streamElement);
386
+            if (streamElement) {
387
+                $(streamElement).show();
388
+            }
389
+
386
             streamElement.removeEventListener('canplay', listener);
390
             streamElement.removeEventListener('canplay', listener);
387
 
391
 
388
             // Refresh to show the video
392
             // Refresh to show the video
422
         // Put new stream element always in front
426
         // Put new stream element always in front
423
         streamElement = UIUtils.prependChild(this.container, streamElement);
427
         streamElement = UIUtils.prependChild(this.container, streamElement);
424
 
428
 
425
-        $(streamElement).hide();
426
-
427
         this.waitForPlayback(streamElement, stream);
429
         this.waitForPlayback(streamElement, stream);
428
         stream.attach(streamElement);
430
         stream.attach(streamElement);
429
 
431
 

+ 1
- 3
modules/UI/videolayout/SmallVideo.js View File

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

+ 2
- 19
modules/UI/videolayout/VideoContainer.js View File

233
 
233
 
234
         this.$remotePresenceMessage = $('#remotePresenceMessage');
234
         this.$remotePresenceMessage = $('#remotePresenceMessage');
235
 
235
 
236
-        /**
237
-         * Indicates whether or not the video stream attached to the video
238
-         * element has started(which means that there is any image rendered
239
-         * even if the video is stalled).
240
-         * @type {boolean}
241
-         */
242
-        this.wasVideoRendered = false;
243
-
244
         this.$wrapper = $('#largeVideoWrapper');
236
         this.$wrapper = $('#largeVideoWrapper');
245
 
237
 
246
         /**
238
         /**
249
          * video anyway.
241
          * video anyway.
250
          */
242
          */
251
         this.$wrapperParent = this.$wrapper.parent();
243
         this.$wrapperParent = this.$wrapper.parent();
252
-
253
         this.avatarHeight = $('#dominantSpeakerAvatarContainer').height();
244
         this.avatarHeight = $('#dominantSpeakerAvatarContainer').height();
254
-
255
-        const onPlayingCallback = function(event) {
245
+        this.$video[0].onplaying = function(event) {
256
             if (typeof resizeContainer === 'function') {
246
             if (typeof resizeContainer === 'function') {
257
                 resizeContainer(event);
247
                 resizeContainer(event);
258
             }
248
             }
259
-            this.wasVideoRendered = true;
260
-        }.bind(this);
261
-
262
-        this.$video[0].onplaying = onPlayingCallback;
249
+        };
263
 
250
 
264
         /**
251
         /**
265
          * A Set of functions to invoke when the video element resizes.
252
          * A Set of functions to invoke when the video element resizes.
491
             return;
478
             return;
492
         }
479
         }
493
 
480
 
494
-        // The stream has changed, so the image will be lost on detach
495
-        this.wasVideoRendered = false;
496
-
497
-
498
         // detach old stream
481
         // detach old stream
499
         if (this.stream) {
482
         if (this.stream) {
500
             this.stream.detach(this.$video[0]);
483
             this.stream.detach(this.$video[0]);

+ 1
- 10
modules/UI/videolayout/VideoLayout.js View File

1
-/* global APP, $  */
1
+/* global APP  */
2
 
2
 
3
 import Logger from 'jitsi-meet-logger';
3
 import Logger from 'jitsi-meet-logger';
4
 
4
 
314
         remoteVideo.updateView();
314
         remoteVideo.updateView();
315
     },
315
     },
316
 
316
 
317
-    // FIXME: what does this do???
318
-    remoteVideoActive(videoElement, resourceJid) {
319
-        logger.info(`${resourceJid} video is now active`, videoElement);
320
-        if (videoElement) {
321
-            $(videoElement).show();
322
-        }
323
-        this._updateLargeVideoIfDisplayed(resourceJid, true);
324
-    },
325
-
326
     /**
317
     /**
327
      * On video muted event.
318
      * On video muted event.
328
      */
319
      */

+ 7
- 11
react/features/base/participants/actions.js View File

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

+ 1
- 40
react/features/base/participants/functions.js View File

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

+ 1
- 56
react/features/base/participants/middleware.js View File

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

+ 0
- 1
react/features/base/participants/reducer.js View File

221
         isJigasi,
221
         isJigasi,
222
         loadableAvatarUrl,
222
         loadableAvatarUrl,
223
         local: local || false,
223
         local: local || false,
224
-        mutedWhileDisconnected: local ? undefined : false,
225
         name,
224
         name,
226
         pinned: pinned || false,
225
         pinned: pinned || false,
227
         presence,
226
         presence,

Loading…
Cancel
Save