fix: Fixes selecting screen share when shared video stopped.

This commit is contained in:
damencho 2021-06-04 16:11:18 -05:00 committed by Дамян Минков
parent 37e7919fd1
commit 5f657a7d6c
3 changed files with 95 additions and 67 deletions

View File

@ -1,7 +1,12 @@
// @flow
import type { Dispatch } from 'redux';
import { getFeatureFlag, TILE_VIEW_ENABLED } from '../base/flags';
import { getPinnedParticipant, getParticipantCount } from '../base/participants';
import {
getPinnedParticipant,
getParticipantCount,
pinParticipant
} from '../base/participants';
import {
ASPECT_RATIO_BREAKPOINT,
DEFAULT_MAX_COLUMNS,
@ -15,6 +20,21 @@ import { LAYOUTS } from './constants';
declare var interfaceConfig: Object;
/**
* A selector for retrieving the current automatic pinning setting.
*
* @private
* @returns {string|undefined} The string "remote-only" is returned if only
* remote screen sharing should be automatically pinned, any other truthy value
* means automatically pin all screen shares. Falsy means do not automatically
* pin any screen shares.
*/
export function getAutoPinSetting() {
return typeof interfaceConfig === 'object'
? interfaceConfig.AUTO_PIN_LATEST_SCREEN_SHARE
: 'remote-only';
}
/**
* Returns the {@code LAYOUTS} constant associated with the layout
* the application should currently be in.
@ -72,8 +92,6 @@ export function getMaxColumnCount(state: Object) {
* which rows will be added but no more columns.
*
* @param {Object} state - The redux store state.
* @param {number} maxColumns - The maximum number of columns that can be
* displayed.
* @returns {Object} An object is return with the desired number of columns,
* rows, and visible rows (the rest should overflow) for the tile view layout.
*/
@ -148,3 +166,43 @@ export function shouldDisplayTileView(state: Object = {}) {
return !shouldDisplayNormalMode;
}
/**
* Private helper to automatically pin the latest screen share stream or unpin
* if there are no more screen share streams.
*
* @param {Array<string>} screenShares - Array containing the list of all the screen sharing endpoints
* before the update was triggered (including the ones that have been removed from redux because of the update).
* @param {Store} store - The redux store.
* @returns {void}
*/
export function updateAutoPinnedParticipant(
screenShares: Array<string>, { dispatch, getState }: { dispatch: Dispatch<any>, getState: Function }) {
const state = getState();
const remoteScreenShares = state['features/video-layout'].remoteScreenShares;
const pinned = getPinnedParticipant(getState);
// if the pinned participant is shared video or some other fake participant we want to skip auto-pinning
if (pinned?.isFakeParticipant) {
return;
}
// Unpin the screen share when the screen sharing participant leaves. Switch to tile view if no other
// participant was pinned before screen share was auto-pinned, pin the previously pinned participant otherwise.
if (!remoteScreenShares?.length) {
let participantId = null;
if (pinned && !screenShares.find(share => share === pinned.id)) {
participantId = pinned.id;
}
dispatch(pinParticipant(participantId));
return;
}
const latestScreenShareParticipantId = remoteScreenShares[remoteScreenShares.length - 1];
if (latestScreenShareParticipantId) {
dispatch(pinParticipant(latestScreenShareParticipantId));
}
}

View File

@ -1,12 +1,20 @@
// @flow
import { getCurrentConference } from '../base/conference';
import { PIN_PARTICIPANT, pinParticipant, getPinnedParticipant } from '../base/participants';
import {
PARTICIPANT_LEFT,
PIN_PARTICIPANT,
pinParticipant,
getParticipantById,
getPinnedParticipant
} from '../base/participants';
import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
import { SET_DOCUMENT_EDITING_STATUS } from '../etherpad';
import { isFollowMeActive } from '../follow-me';
import { SET_TILE_VIEW } from './actionTypes';
import { setTileView } from './actions';
import { getAutoPinSetting, updateAutoPinnedParticipant } from './functions';
import './subscriber';
@ -19,6 +27,20 @@ let previousTileViewEnabled;
* @returns {Function}
*/
MiddlewareRegistry.register(store => next => action => {
// we want to extract the leaving participant and check its type before actually the participant being removed.
let shouldUpdateAutoPin = false;
switch (action.type) {
case PARTICIPANT_LEFT: {
if (!getAutoPinSetting() || isFollowMeActive(store)) {
break;
}
shouldUpdateAutoPin = getParticipantById(store.getState(), action.participant.id)?.isFakeParticipant;
break;
}
}
const result = next(action);
switch (action.type) {
@ -50,6 +72,11 @@ MiddlewareRegistry.register(store => next => action => {
}
}
if (shouldUpdateAutoPin) {
const screenShares = store.getState()['features/video-layout'].remoteScreenShares || [];
updateAutoPinnedParticipant(screenShares, store);
}
return result;
});
@ -69,7 +96,7 @@ StateListenerRegistry.register(
});
/**
* Respores tile view state, if it wasn't updated since then.
* Restores tile view state, if it wasn't updated since then.
*
* @param {Object} store - The Redux Store.
* @returns {void}

View File

@ -2,15 +2,12 @@
import debounce from 'lodash/debounce';
import { pinParticipant, getPinnedParticipant } from '../base/participants';
import { StateListenerRegistry, equals } from '../base/redux';
import { isFollowMeActive } from '../follow-me';
import { selectParticipant } from '../large-video/actions';
import { selectParticipant } from '../large-video/actions.any';
import { setRemoteParticipantsWithScreenShare } from './actions';
declare var APP: Object;
declare var interfaceConfig: Object;
import { getAutoPinSetting, updateAutoPinnedParticipant } from './functions';
/**
* StateListenerRegistry provides a reliable way of detecting changes to
@ -33,14 +30,14 @@ StateListenerRegistry.register(
StateListenerRegistry.register(
/* selector */ state => state['features/base/tracks'],
/* listener */ debounce((tracks, store) => {
if (!_getAutoPinSetting() || isFollowMeActive(store)) {
if (!getAutoPinSetting() || isFollowMeActive(store)) {
return;
}
const oldScreenSharesOrder = store.getState()['features/video-layout'].remoteScreenShares || [];
const knownSharingParticipantIds = tracks.reduce((acc, track) => {
if (track.mediaType === 'video' && track.videoType === 'desktop') {
const skipTrack = _getAutoPinSetting() === 'remote-only' && track.local;
const skipTrack = getAutoPinSetting() === 'remote-only' && track.local;
if (!skipTrack) {
acc.push(track.participantId);
@ -68,60 +65,6 @@ StateListenerRegistry.register(
store.dispatch(
setRemoteParticipantsWithScreenShare(newScreenSharesOrder));
_updateAutoPinnedParticipant(oldScreenSharesOrder, store);
updateAutoPinnedParticipant(oldScreenSharesOrder, store);
}
}, 100));
/**
* A selector for retrieving the current automatic pinning setting.
*
* @private
* @returns {string|undefined} The string "remote-only" is returned if only
* remote screensharing should be automatically pinned, any other truthy value
* means automatically pin all screenshares. Falsy means do not automatically
* pin any screenshares.
*/
function _getAutoPinSetting() {
return typeof interfaceConfig === 'object'
? interfaceConfig.AUTO_PIN_LATEST_SCREEN_SHARE
: 'remote-only';
}
/**
* Private helper to automatically pin the latest screen share stream or unpin
* if there are no more screen share streams.
*
* @param {Array<string>} screenShares - Array containing the list of all the screensharing endpoints
* before the update was triggered (including the ones that have been removed from redux because of the update).
* @param {Store} store - The redux store.
* @returns {void}
*/
function _updateAutoPinnedParticipant(screenShares, { dispatch, getState }) {
const state = getState();
const remoteScreenShares = state['features/video-layout'].remoteScreenShares;
const pinned = getPinnedParticipant(getState);
// if the pinned participant is shared video or some other fake participant we want to skip auto-pinning
if (pinned?.isFakeParticipant) {
return;
}
// Unpin the screenshare when the screensharing participant leaves. Switch to tile view if no other
// participant was pinned before screenshare was auto-pinned, pin the previously pinned participant otherwise.
if (!remoteScreenShares?.length) {
let participantId = null;
if (pinned && !screenShares.find(share => share === pinned.id)) {
participantId = pinned.id;
}
dispatch(pinParticipant(participantId));
return;
}
const latestScreenshareParticipantId = remoteScreenShares[remoteScreenShares.length - 1];
if (latestScreenshareParticipantId) {
dispatch(pinParticipant(latestScreenshareParticipantId));
}
}