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
pull/10637/head
William Liang 3 years ago committed by GitHub
parent 5dee37dd82
commit 5461bb52c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      config.js
  2. 11
      react/features/base/config/constants.js
  3. 25
      react/features/base/config/functions.any.js
  4. 1
      react/features/base/config/index.js
  5. 20
      react/features/base/tracks/functions.js
  6. 111
      react/features/video-quality/subscriber.js

@ -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;
if (visibleRemoteParticipants?.size) {
visibleRemoteParticipants.forEach(participantId => {
const sourceName = getTrackSourceNameByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, participantId);
if (sourceName) {
visibleRemoteTrackSourceNames.push(sourceName);
}
});
}
visibleRemoteParticipants.forEach(participantId => {
receiverConstraints.constraints[participantId] = { 'maxHeight': maxFrameHeight };
});
if (localParticipantId !== largeVideoParticipantId) {
largeVideoSourceName = getTrackSourceNameByMediaTypeAndParticipant(
tracks, MEDIA_TYPE.VIDEO,
largeVideoParticipantId
);
}
// Prioritize screenshare in tile view.
remoteScreenShares?.length && (receiverConstraints.selectedEndpoints = remoteScreenShares);
// Tile view.
if (shouldDisplayTileView(state)) {
if (!visibleRemoteTrackSourceNames?.length) {
return;
}
// Stage view.
} else {
if (!visibleRemoteParticipants?.size && !largeVideoParticipantId) {
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 ];
}
}
if (visibleRemoteParticipants?.size > 0) {
} else {
// Tile view.
// eslint-disable-next-line no-lonely-if
if (shouldDisplayTileView(state)) {
if (!visibleRemoteParticipants?.size) {
return;
}
visibleRemoteParticipants.forEach(participantId => {
receiverConstraints.constraints[participantId] = { 'maxHeight': VIDEO_QUALITY_LEVELS.LOW };
receiverConstraints.constraints[participantId] = { 'maxHeight': maxFrameHeight };
});
}
if (largeVideoParticipantId) {
receiverConstraints.constraints[largeVideoParticipantId] = { 'maxHeight': maxFrameHeight };
receiverConstraints.onStageEndpoints = [ largeVideoParticipantId ];
// 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…
Cancel
Save