fix: Fixes selecting screen share when shared video stopped.
This commit is contained in:
parent
37e7919fd1
commit
5f657a7d6c
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue