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.
|
||||
},
|
||||
|
||||
// Feature Flags.
|
||||
flags: {
|
||||
// Enables source names in the signaling.
|
||||
// sourceNameSignaling: false,
|
||||
},
|
||||
|
||||
// Disables moderator indicators.
|
||||
// disableModeratorIndicator: false,
|
||||
|
||||
|
|
|
@ -56,3 +56,14 @@ export const PREMEETING_BUTTONS = [ 'microphone', 'camera', 'select-background',
|
|||
* The toolbar buttons to show on 3rdParty prejoin screen.
|
||||
*/
|
||||
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 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 logger from './logger';
|
||||
|
||||
|
@ -49,6 +49,29 @@ export function getMeetingRegion(state: Object) {
|
|||
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.
|
||||
*
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
export * from './actions';
|
||||
export * from './actionTypes';
|
||||
export { default as CONFIG_WHITELIST } from './configWhitelist';
|
||||
export * from './constants';
|
||||
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
|
||||
* of JitsiLocalTrack or JitsiRemoteTrack.
|
||||
|
|
|
@ -3,8 +3,11 @@
|
|||
import debounce from 'lodash/debounce';
|
||||
|
||||
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 { getTrackSourceNameByMediaTypeAndParticipant } from '../base/tracks';
|
||||
import { reportError } from '../base/util';
|
||||
import { shouldDisplayTileView } from '../video-layout';
|
||||
|
||||
|
@ -193,43 +196,107 @@ function _updateReceiverVideoConstraints({ getState }) {
|
|||
const maxFrameHeight = Math.min(maxReceiverVideoQuality, preferredVideoQuality);
|
||||
const { remoteScreenShares } = state['features/video-layout'];
|
||||
const { visibleRemoteParticipants } = state['features/filmstrip'];
|
||||
const tracks = state['features/base/tracks'];
|
||||
const sourceNameSignaling = getSourceNameSignalingFeatureFlag(state);
|
||||
const localParticipantId = getLocalParticipant(state).id;
|
||||
|
||||
const receiverConstraints = {
|
||||
constraints: {},
|
||||
defaultConstraints: { 'maxHeight': VIDEO_QUALITY_LEVELS.NONE },
|
||||
lastN,
|
||||
onStageEndpoints: [],
|
||||
selectedEndpoints: []
|
||||
...sourceNameSignaling ? { onStageSources: [] } : { onStageEndpoints: [] },
|
||||
...sourceNameSignaling ? { selectedSources: [] } : { selectedEndpoints: [] }
|
||||
};
|
||||
|
||||
// Tile view.
|
||||
if (shouldDisplayTileView(state)) {
|
||||
if (!visibleRemoteParticipants?.size) {
|
||||
return;
|
||||
}
|
||||
if (sourceNameSignaling) {
|
||||
const visibleRemoteTrackSourceNames = [];
|
||||
let largeVideoSourceName;
|
||||
|
||||
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) {
|
||||
if (visibleRemoteParticipants?.size) {
|
||||
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) {
|
||||
receiverConstraints.constraints[largeVideoParticipantId] = { 'maxHeight': maxFrameHeight };
|
||||
receiverConstraints.onStageEndpoints = [ largeVideoParticipantId ];
|
||||
if (localParticipantId !== largeVideoParticipantId) {
|
||||
largeVideoSourceName = getTrackSourceNameByMediaTypeAndParticipant(
|
||||
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