feat: Update video receiver constraints to use source names (#10527)
* feat: Use source name based receiver constraints * add sourceNameSignaling feature flag to config * move source name specific variables into if block * ensure sourceName is defined in constraints * use source name for selectedSources * use selector to find video track by participant id * add selector to encapsulate logic to get track source name * refactor getTrackSourceNameByMediaTypeAndParticipant selector * rename variable * move flags config into Feature Flags section * do not set constraints for local large video * rename prioritizedSources to onStageSources * fix flow error * refactor visibleRemoteTrackSourceNames to a constant * use selector to get feature flags * rename selector function * fix flow error * add selector for sourceNameSignaling feature flag
This commit is contained in:
parent
5dee37dd82
commit
5461bb52c8
|
@ -74,6 +74,12 @@ var config = {
|
||||||
// callStatsThreshold: 5 // enable callstats for 5% of the users.
|
// callStatsThreshold: 5 // enable callstats for 5% of the users.
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Feature Flags.
|
||||||
|
flags: {
|
||||||
|
// Enables source names in the signaling.
|
||||||
|
// sourceNameSignaling: false,
|
||||||
|
},
|
||||||
|
|
||||||
// Disables moderator indicators.
|
// Disables moderator indicators.
|
||||||
// disableModeratorIndicator: false,
|
// disableModeratorIndicator: false,
|
||||||
|
|
||||||
|
|
|
@ -56,3 +56,14 @@ export const PREMEETING_BUTTONS = [ 'microphone', 'camera', 'select-background',
|
||||||
* The toolbar buttons to show on 3rdParty prejoin screen.
|
* The toolbar buttons to show on 3rdParty prejoin screen.
|
||||||
*/
|
*/
|
||||||
export const THIRD_PARTY_PREJOIN_BUTTONS = [ 'microphone', 'camera', 'select-background' ];
|
export const THIRD_PARTY_PREJOIN_BUTTONS = [ 'microphone', 'camera', 'select-background' ];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set of feature flags.
|
||||||
|
*
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const FEATURE_FLAGS = {
|
||||||
|
SOURCE_NAME_SIGNALING: 'sourceNameSignaling'
|
||||||
|
};
|
||||||
|
|
|
@ -7,7 +7,7 @@ import _ from 'lodash';
|
||||||
import { parseURLParams } from '../util';
|
import { parseURLParams } from '../util';
|
||||||
|
|
||||||
import CONFIG_WHITELIST from './configWhitelist';
|
import CONFIG_WHITELIST from './configWhitelist';
|
||||||
import { _CONFIG_STORE_PREFIX } from './constants';
|
import { _CONFIG_STORE_PREFIX, FEATURE_FLAGS } from './constants';
|
||||||
import INTERFACE_CONFIG_WHITELIST from './interfaceConfigWhitelist';
|
import INTERFACE_CONFIG_WHITELIST from './interfaceConfigWhitelist';
|
||||||
import logger from './logger';
|
import logger from './logger';
|
||||||
|
|
||||||
|
@ -49,6 +49,29 @@ export function getMeetingRegion(state: Object) {
|
||||||
return state['features/base/config']?.deploymentInfo?.region || '';
|
return state['features/base/config']?.deploymentInfo?.region || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selector used to get the sourceNameSignaling feature flag.
|
||||||
|
*
|
||||||
|
* @param {Object} state - The global state.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function getSourceNameSignalingFeatureFlag(state: Object) {
|
||||||
|
return getFeatureFlag(state, FEATURE_FLAGS.SOURCE_NAME_SIGNALING);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selector used to get a feature flag.
|
||||||
|
*
|
||||||
|
* @param {Object} state - The global state.
|
||||||
|
* @param {string} featureFlag - The name of the feature flag.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function getFeatureFlag(state: Object, featureFlag: string) {
|
||||||
|
const featureFlags = state['features/base/config']?.flags || {};
|
||||||
|
|
||||||
|
return Boolean(featureFlags[featureFlag]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selector used to get the disableRemoveRaisedHandOnFocus.
|
* Selector used to get the disableRemoveRaisedHandOnFocus.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
export * from './actions';
|
export * from './actions';
|
||||||
export * from './actionTypes';
|
export * from './actionTypes';
|
||||||
export { default as CONFIG_WHITELIST } from './configWhitelist';
|
export { default as CONFIG_WHITELIST } from './configWhitelist';
|
||||||
|
export * from './constants';
|
||||||
export * from './functions';
|
export * from './functions';
|
||||||
|
|
|
@ -399,6 +399,26 @@ export function getTrackByMediaTypeAndParticipant(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns track source name of specified media type for specified participant id.
|
||||||
|
*
|
||||||
|
* @param {Track[]} tracks - List of all tracks.
|
||||||
|
* @param {MEDIA_TYPE} mediaType - Media type.
|
||||||
|
* @param {string} participantId - Participant ID.
|
||||||
|
* @returns {(string|undefined)}
|
||||||
|
*/
|
||||||
|
export function getTrackSourceNameByMediaTypeAndParticipant(
|
||||||
|
tracks,
|
||||||
|
mediaType,
|
||||||
|
participantId) {
|
||||||
|
const track = getTrackByMediaTypeAndParticipant(
|
||||||
|
tracks,
|
||||||
|
mediaType,
|
||||||
|
participantId);
|
||||||
|
|
||||||
|
return track?.jitsiTrack?.getSourceName();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the track if any which corresponds to a specific instance
|
* Returns the track if any which corresponds to a specific instance
|
||||||
* of JitsiLocalTrack or JitsiRemoteTrack.
|
* of JitsiLocalTrack or JitsiRemoteTrack.
|
||||||
|
|
|
@ -3,8 +3,11 @@
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
|
|
||||||
import { _handleParticipantError } from '../base/conference';
|
import { _handleParticipantError } from '../base/conference';
|
||||||
import { getParticipantCount } from '../base/participants';
|
import { getSourceNameSignalingFeatureFlag } from '../base/config';
|
||||||
|
import { MEDIA_TYPE } from '../base/media';
|
||||||
|
import { getLocalParticipant, getParticipantCount } from '../base/participants';
|
||||||
import { StateListenerRegistry } from '../base/redux';
|
import { StateListenerRegistry } from '../base/redux';
|
||||||
|
import { getTrackSourceNameByMediaTypeAndParticipant } from '../base/tracks';
|
||||||
import { reportError } from '../base/util';
|
import { reportError } from '../base/util';
|
||||||
import { shouldDisplayTileView } from '../video-layout';
|
import { shouldDisplayTileView } from '../video-layout';
|
||||||
|
|
||||||
|
@ -193,43 +196,107 @@ function _updateReceiverVideoConstraints({ getState }) {
|
||||||
const maxFrameHeight = Math.min(maxReceiverVideoQuality, preferredVideoQuality);
|
const maxFrameHeight = Math.min(maxReceiverVideoQuality, preferredVideoQuality);
|
||||||
const { remoteScreenShares } = state['features/video-layout'];
|
const { remoteScreenShares } = state['features/video-layout'];
|
||||||
const { visibleRemoteParticipants } = state['features/filmstrip'];
|
const { visibleRemoteParticipants } = state['features/filmstrip'];
|
||||||
|
const tracks = state['features/base/tracks'];
|
||||||
|
const sourceNameSignaling = getSourceNameSignalingFeatureFlag(state);
|
||||||
|
const localParticipantId = getLocalParticipant(state).id;
|
||||||
|
|
||||||
const receiverConstraints = {
|
const receiverConstraints = {
|
||||||
constraints: {},
|
constraints: {},
|
||||||
defaultConstraints: { 'maxHeight': VIDEO_QUALITY_LEVELS.NONE },
|
defaultConstraints: { 'maxHeight': VIDEO_QUALITY_LEVELS.NONE },
|
||||||
lastN,
|
lastN,
|
||||||
onStageEndpoints: [],
|
...sourceNameSignaling ? { onStageSources: [] } : { onStageEndpoints: [] },
|
||||||
selectedEndpoints: []
|
...sourceNameSignaling ? { selectedSources: [] } : { selectedEndpoints: [] }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Tile view.
|
if (sourceNameSignaling) {
|
||||||
if (shouldDisplayTileView(state)) {
|
const visibleRemoteTrackSourceNames = [];
|
||||||
if (!visibleRemoteParticipants?.size) {
|
let largeVideoSourceName;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
visibleRemoteParticipants.forEach(participantId => {
|
if (visibleRemoteParticipants?.size) {
|
||||||
receiverConstraints.constraints[participantId] = { 'maxHeight': maxFrameHeight };
|
|
||||||
});
|
|
||||||
|
|
||||||
// Prioritize screenshare in tile view.
|
|
||||||
remoteScreenShares?.length && (receiverConstraints.selectedEndpoints = remoteScreenShares);
|
|
||||||
|
|
||||||
// Stage view.
|
|
||||||
} else {
|
|
||||||
if (!visibleRemoteParticipants?.size && !largeVideoParticipantId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (visibleRemoteParticipants?.size > 0) {
|
|
||||||
visibleRemoteParticipants.forEach(participantId => {
|
visibleRemoteParticipants.forEach(participantId => {
|
||||||
receiverConstraints.constraints[participantId] = { 'maxHeight': VIDEO_QUALITY_LEVELS.LOW };
|
const sourceName = getTrackSourceNameByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, participantId);
|
||||||
|
|
||||||
|
if (sourceName) {
|
||||||
|
visibleRemoteTrackSourceNames.push(sourceName);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (largeVideoParticipantId) {
|
if (localParticipantId !== largeVideoParticipantId) {
|
||||||
receiverConstraints.constraints[largeVideoParticipantId] = { 'maxHeight': maxFrameHeight };
|
largeVideoSourceName = getTrackSourceNameByMediaTypeAndParticipant(
|
||||||
receiverConstraints.onStageEndpoints = [ largeVideoParticipantId ];
|
tracks, MEDIA_TYPE.VIDEO,
|
||||||
|
largeVideoParticipantId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tile view.
|
||||||
|
if (shouldDisplayTileView(state)) {
|
||||||
|
if (!visibleRemoteTrackSourceNames?.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
visibleRemoteTrackSourceNames.forEach(sourceName => {
|
||||||
|
receiverConstraints.constraints[sourceName] = { 'maxHeight': maxFrameHeight };
|
||||||
|
});
|
||||||
|
|
||||||
|
// Prioritize screenshare in tile view.
|
||||||
|
if (remoteScreenShares?.length) {
|
||||||
|
const remoteScreenShareSourceNames = remoteScreenShares.map(remoteScreenShare =>
|
||||||
|
getTrackSourceNameByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, remoteScreenShare)
|
||||||
|
);
|
||||||
|
|
||||||
|
receiverConstraints.selectedSources = remoteScreenShareSourceNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stage view.
|
||||||
|
} else {
|
||||||
|
if (!visibleRemoteTrackSourceNames?.length && !largeVideoSourceName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (visibleRemoteTrackSourceNames?.length) {
|
||||||
|
visibleRemoteTrackSourceNames.forEach(sourceName => {
|
||||||
|
receiverConstraints.constraints[sourceName] = { 'maxHeight': VIDEO_QUALITY_LEVELS.LOW };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (largeVideoSourceName) {
|
||||||
|
receiverConstraints.constraints[largeVideoSourceName] = { 'maxHeight': maxFrameHeight };
|
||||||
|
receiverConstraints.onStageSources = [ largeVideoSourceName ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Tile view.
|
||||||
|
// eslint-disable-next-line no-lonely-if
|
||||||
|
if (shouldDisplayTileView(state)) {
|
||||||
|
if (!visibleRemoteParticipants?.size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
visibleRemoteParticipants.forEach(participantId => {
|
||||||
|
receiverConstraints.constraints[participantId] = { 'maxHeight': maxFrameHeight };
|
||||||
|
});
|
||||||
|
|
||||||
|
// Prioritize screenshare in tile view.
|
||||||
|
remoteScreenShares?.length && (receiverConstraints.selectedEndpoints = remoteScreenShares);
|
||||||
|
|
||||||
|
// Stage view.
|
||||||
|
} else {
|
||||||
|
if (!visibleRemoteParticipants?.size && !largeVideoParticipantId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (visibleRemoteParticipants?.size > 0) {
|
||||||
|
visibleRemoteParticipants.forEach(participantId => {
|
||||||
|
receiverConstraints.constraints[participantId] = { 'maxHeight': VIDEO_QUALITY_LEVELS.LOW };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (largeVideoParticipantId) {
|
||||||
|
receiverConstraints.constraints[largeVideoParticipantId] = { 'maxHeight': maxFrameHeight };
|
||||||
|
receiverConstraints.onStageEndpoints = [ largeVideoParticipantId ];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue