From 57f7abc6ddb7a66f2a1fd99d309288e215536722 Mon Sep 17 00:00:00 2001 From: Leonard Kim Date: Thu, 17 May 2018 17:41:28 -0700 Subject: [PATCH] ref(video-layout): get dominant speaker state from redux Instead of keeping dominant speaker locally, get it from redux and be updated when the dominant speaker changes. This is in an attempt to mimic the video layout being reactified and connected to redux. --- modules/UI/UI.js | 8 -- modules/UI/videolayout/SmallVideo.js | 4 + modules/UI/videolayout/VideoLayout.js | 81 +++++++++---------- .../features/base/participants/middleware.js | 2 - react/features/video-layout/middleware.web.js | 15 +++- 5 files changed, 54 insertions(+), 56 deletions(-) diff --git a/modules/UI/UI.js b/modules/UI/UI.js index 4425b7379..8dd4a88da 100644 --- a/modules/UI/UI.js +++ b/modules/UI/UI.js @@ -822,14 +822,6 @@ UI.notifyInitiallyMuted = function() { null); }; -/** - * Mark user as dominant speaker. - * @param {string} id user id - */ -UI.markDominantSpeaker = function(id) { - VideoLayout.onDominantSpeakerChanged(id); -}; - UI.handleLastNEndpoints = function(leavingIds, enteringIds) { VideoLayout.onLastNEndpointsChanged(leavingIds, enteringIds); }; diff --git a/modules/UI/videolayout/SmallVideo.js b/modules/UI/videolayout/SmallVideo.js index ba854afda..cff14a439 100644 --- a/modules/UI/videolayout/SmallVideo.js +++ b/modules/UI/videolayout/SmallVideo.js @@ -679,6 +679,10 @@ SmallVideo.prototype.showDominantSpeakerIndicator = function(show) { return; } + if (this._showDominantSpeaker === show) { + return; + } + this._showDominantSpeaker = show; this.updateIndicators(); diff --git a/modules/UI/videolayout/VideoLayout.js b/modules/UI/videolayout/VideoLayout.js index ec20ed600..11f4e7521 100644 --- a/modules/UI/videolayout/VideoLayout.js +++ b/modules/UI/videolayout/VideoLayout.js @@ -5,6 +5,7 @@ import { JitsiParticipantConnectionStatus } from '../../../react/features/base/lib-jitsi-meet'; import { + getParticipants, getPinnedParticipant, pinParticipant } from '../../../react/features/base/participants'; @@ -21,8 +22,6 @@ import LocalVideo from './LocalVideo'; const remoteVideos = {}; let localVideoThumbnail = null; -let currentDominantSpeaker = null; - let eventEmitter = null; let largeVideo; @@ -43,6 +42,24 @@ function onLocalFlipXChanged(val) { } } +/** + * Returns the user ID of the remote participant that is current the dominant + * speaker. + * + * @private + * @returns {string|null} + */ +function getCurrentRemoteDominantSpeakerID() { + const dominantSpeaker = getParticipants(APP.store.getState) + .find(participant => participant.dominantSpeaker); + + if (dominantSpeaker) { + return dominantSpeaker.local ? null : dominantSpeaker.id; + } + + return null; +} + /** * Returns the corresponding resource id to the given peer container * DOM element. @@ -228,8 +245,8 @@ const VideoLayout = { if (pinnedId) { newId = pinnedId; - } else if (currentDominantSpeaker) { - newId = currentDominantSpeaker; + } else if (getCurrentRemoteDominantSpeakerID()) { + newId = getCurrentRemoteDominantSpeakerID(); } else { // Otherwise select last visible video newId = this.electLastVisibleVideo(); } @@ -392,8 +409,8 @@ const VideoLayout = { this.pinParticipant(null); // Enable the currently set dominant speaker. - if (currentDominantSpeaker) { - this.updateLargeVideo(currentDominantSpeaker); + if (getCurrentRemoteDominantSpeakerID()) { + this.updateLargeVideo(getCurrentRemoteDominantSpeakerID()); } else { // if there is no currentDominantSpeaker, it can also be // that local participant is the dominant speaker @@ -501,11 +518,11 @@ const VideoLayout = { const pinnedId = this.getPinnedId(); if ((!pinnedId - && !currentDominantSpeaker + && !getCurrentRemoteDominantSpeakerID() && this.isLargeContainerTypeVisible(VIDEO_CONTAINER_TYPE)) || pinnedId === resourceJid || (!pinnedId && resourceJid - && currentDominantSpeaker === resourceJid) + && getCurrentRemoteDominantSpeakerID() === resourceJid) /* Playback started while we're on the stage - may need to update video source with the new stream */ @@ -662,43 +679,22 @@ const VideoLayout = { /** * On dominant speaker changed event. + * + * @param {string} id - The participant ID of the new dominant speaker. + * @returns {void} */ onDominantSpeakerChanged(id) { - if (id === currentDominantSpeaker) { + Object.values(remoteVideos).forEach(remoteVideo => + remoteVideo.showDominantSpeakerIndicator( + id === remoteVideo.getId())); + + localVideoThumbnail.showDominantSpeakerIndicator( + APP.conference.isLocalId(id)); + + if (!remoteVideos[id]) { return; } - const oldSpeakerRemoteVideo = remoteVideos[currentDominantSpeaker]; - - // We ignore local user events, but just unmark remote user as dominant - // while we are talking - - if (APP.conference.isLocalId(id)) { - if (oldSpeakerRemoteVideo) { - oldSpeakerRemoteVideo.showDominantSpeakerIndicator(false); - currentDominantSpeaker = null; - } - localVideoThumbnail.showDominantSpeakerIndicator(true); - - return; - } - - const remoteVideo = remoteVideos[id]; - - if (!remoteVideo) { - return; - } - - // Update the current dominant speaker. - remoteVideo.showDominantSpeakerIndicator(true); - localVideoThumbnail.showDominantSpeakerIndicator(false); - - // let's remove the indications from the remote video if any - if (oldSpeakerRemoteVideo) { - oldSpeakerRemoteVideo.showDominantSpeakerIndicator(false); - } - currentDominantSpeaker = id; - // Local video will not have container found, but that's ok // since we don't want to switch to local video. if (!interfaceConfig.filmStripOnly && !this.getPinnedId() @@ -804,11 +800,6 @@ const VideoLayout = { this.pinParticipant(null); } - if (currentDominantSpeaker === id) { - logger.info('Dominant speaker has left the conference'); - currentDominantSpeaker = null; - } - const remoteVideo = remoteVideos[id]; if (remoteVideo) { diff --git a/react/features/base/participants/middleware.js b/react/features/base/participants/middleware.js index e49d9e0c4..a2549f132 100644 --- a/react/features/base/participants/middleware.js +++ b/react/features/base/participants/middleware.js @@ -77,8 +77,6 @@ MiddlewareRegistry.register(store => next => action => { raisedHand: false })); - typeof APP === 'object' && APP.UI.markDominantSpeaker(id); - break; } diff --git a/react/features/video-layout/middleware.web.js b/react/features/video-layout/middleware.web.js index c0930695d..753ecc0d3 100644 --- a/react/features/video-layout/middleware.web.js +++ b/react/features/video-layout/middleware.web.js @@ -1,3 +1,6 @@ +import VideoLayout from '../../../modules/UI/videolayout/VideoLayout.js'; + +import { DOMINANT_SPEAKER_CHANGED } from '../base/participants'; import { MiddlewareRegistry } from '../base/redux'; /** @@ -9,4 +12,14 @@ import { MiddlewareRegistry } from '../base/redux'; * @returns {Function} */ // eslint-disable-next-line no-unused-vars -MiddlewareRegistry.register(store => next => action => next(action)); +MiddlewareRegistry.register(store => next => action => { + const result = next(action); + + switch (action.type) { + case DOMINANT_SPEAKER_CHANGED: + VideoLayout.onDominantSpeakerChanged(action.participant.id); + break; + } + + return result; +});