ref(receiver-constraints): Refactor and fixes.
This commit is contained in:
parent
cfb1fef162
commit
adcd9a501b
|
@ -9,6 +9,7 @@ import { browser } from '../../../react/features/base/lib-jitsi-meet';
|
|||
import { isTestModeEnabled } from '../../../react/features/base/testing';
|
||||
import { FILMSTRIP_BREAKPOINT } from '../../../react/features/filmstrip';
|
||||
import { ORIENTATION, LargeVideoBackground, updateLastLargeVideoMediaEvent } from '../../../react/features/large-video';
|
||||
import { setLargeVideoDimensions } from '../../../react/features/large-video/actions.any';
|
||||
import { LAYOUTS, getCurrentLayout } from '../../../react/features/video-layout';
|
||||
/* eslint-enable no-unused-vars */
|
||||
import UIUtil from '../util/UIUtil';
|
||||
|
@ -446,6 +447,8 @@ export class VideoContainer extends LargeContainer {
|
|||
const { horizontalIndent, verticalIndent }
|
||||
= this.getVideoPosition(width, height, containerWidth, containerHeight, verticalFilmstripWidth);
|
||||
|
||||
APP.store.dispatch(setLargeVideoDimensions(height, width));
|
||||
|
||||
this.$wrapper.animate({
|
||||
width,
|
||||
height,
|
||||
|
|
|
@ -7,6 +7,7 @@ import { getCurrentLayout, LAYOUTS } from '../../../video-layout';
|
|||
import {
|
||||
FILMSTRIP_TYPE
|
||||
} from '../../constants';
|
||||
import { getScreenshareFilmstripParticipantId } from '../../functions';
|
||||
|
||||
import Filmstrip from './Filmstrip';
|
||||
|
||||
|
@ -105,15 +106,9 @@ function _mapStateToProps(state) {
|
|||
filmstripHeight,
|
||||
filmstripWidth,
|
||||
thumbnailSize
|
||||
},
|
||||
screenshareFilmstripParticipantId
|
||||
}
|
||||
} = state['features/filmstrip'];
|
||||
const screenshares = state['features/video-layout'].remoteScreenShares;
|
||||
let id = screenshares.find(sId => sId === screenshareFilmstripParticipantId);
|
||||
|
||||
if (!id && screenshares.length) {
|
||||
id = screenshares[0];
|
||||
}
|
||||
const id = getScreenshareFilmstripParticipantId(state);
|
||||
|
||||
return {
|
||||
_columns: 1,
|
||||
|
|
|
@ -71,6 +71,15 @@ export function shouldRemoteVideosBeVisible(state: Object) {
|
|||
|| disable1On1Mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not implemented on mobile.
|
||||
*
|
||||
* @returns {Array<string>}
|
||||
*/
|
||||
export function getActiveParticipantsIds() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of participants displayed in tile view.
|
||||
*
|
||||
|
@ -169,6 +178,16 @@ export function isStageFilmstripEnabled() {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the top panel is enabled.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isTopPanelEnabled() {
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the width and height of the filmstrip based on the screen size and aspect ratio.
|
||||
*
|
||||
|
@ -232,4 +251,13 @@ export function shouldDisplayLocalThumbnailSeparately() {
|
|||
return Platform.OS !== 'android';
|
||||
}
|
||||
|
||||
/**
|
||||
* Not implemented on mobile.
|
||||
*
|
||||
* @returns {undefined}
|
||||
*/
|
||||
export function getScreenshareFilmstripParticipantId() {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -778,6 +778,24 @@ export function getThumbnailTypeFromLayout(currentLayout, filmstripType) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the participant displayed on the screen share filmstrip.
|
||||
*
|
||||
* @param {Object} state - Redux state.
|
||||
* @returns {string} - The participant id.
|
||||
*/
|
||||
export function getScreenshareFilmstripParticipantId(state) {
|
||||
const { screenshareFilmstripParticipantId } = state['features/filmstrip'];
|
||||
const screenshares = state['features/video-layout'].remoteScreenShares;
|
||||
let id = screenshares.find(sId => sId === screenshareFilmstripParticipantId);
|
||||
|
||||
if (!id && screenshares.length) {
|
||||
id = screenshares[0];
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the top panel is enabled.
|
||||
*
|
||||
|
|
|
@ -9,6 +9,17 @@
|
|||
export const SELECT_LARGE_VIDEO_PARTICIPANT
|
||||
= 'SELECT_LARGE_VIDEO_PARTICIPANT';
|
||||
|
||||
/**
|
||||
* Action to set the dimensions of the large video.
|
||||
*
|
||||
* {
|
||||
* type: SET_LARGE_VIDEO_DIMENSIONS,
|
||||
* height: number,
|
||||
* width: number
|
||||
* }
|
||||
*/
|
||||
export const SET_LARGE_VIDEO_DIMENSIONS = 'SET_LARGE_VIDEO_DIMENSIONS';
|
||||
|
||||
/**
|
||||
* Action to update the redux store with the current resolution of large video.
|
||||
*
|
||||
|
|
|
@ -13,6 +13,7 @@ import { isStageFilmstripAvailable } from '../filmstrip/functions';
|
|||
|
||||
import {
|
||||
SELECT_LARGE_VIDEO_PARTICIPANT,
|
||||
SET_LARGE_VIDEO_DIMENSIONS,
|
||||
UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION
|
||||
} from './actionTypes';
|
||||
|
||||
|
@ -79,6 +80,25 @@ export function updateKnownLargeVideoResolution(resolution: number) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the dimenstions of the large video in redux.
|
||||
*
|
||||
* @param {number} height - The height of the large video.
|
||||
* @param {number} width - The width of the large video.
|
||||
* @returns {{
|
||||
* type: SET_LARGE_VIDEO_DIMENSIONS,
|
||||
* height: number,
|
||||
* width: number
|
||||
* }}
|
||||
*/
|
||||
export function setLargeVideoDimensions(height, width) {
|
||||
return {
|
||||
type: SET_LARGE_VIDEO_DIMENSIONS,
|
||||
height,
|
||||
width
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent existing remote video track.
|
||||
*
|
||||
|
|
|
@ -3,6 +3,7 @@ import ReducerRegistry from '../base/redux/ReducerRegistry';
|
|||
|
||||
import {
|
||||
SELECT_LARGE_VIDEO_PARTICIPANT,
|
||||
SET_LARGE_VIDEO_DIMENSIONS,
|
||||
UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION,
|
||||
UPDATE_LAST_LARGE_VIDEO_MEDIA_EVENT,
|
||||
SET_SEE_WHAT_IS_BEING_SHARED
|
||||
|
@ -38,6 +39,13 @@ ReducerRegistry.register('features/large-video', (state: ILargeVideoState = {},
|
|||
participantId: action.participantId
|
||||
};
|
||||
|
||||
case SET_LARGE_VIDEO_DIMENSIONS:
|
||||
return {
|
||||
...state,
|
||||
height: action.height,
|
||||
width: action.width
|
||||
};
|
||||
|
||||
case UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION:
|
||||
return {
|
||||
...state,
|
||||
|
|
|
@ -10,6 +10,8 @@ import {
|
|||
import { isStageFilmstripAvailable } from '../filmstrip/functions';
|
||||
import { isVideoPlaying } from '../shared-video/functions';
|
||||
import { VIDEO_QUALITY_LEVELS } from '../video-quality/constants';
|
||||
import { getReceiverVideoQualityLevel } from '../video-quality/functions';
|
||||
import { getMinHeightForQualityLvlMap } from '../video-quality/selector';
|
||||
|
||||
import { LAYOUTS } from './constants';
|
||||
|
||||
|
@ -154,7 +156,7 @@ export function isLayoutTileView(state: Object) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the video quality for the given height.
|
||||
* Returns the video quality for the given height.
|
||||
*
|
||||
* @param {number|undefined} height - Height of the video container.
|
||||
* @returns {number}
|
||||
|
@ -177,36 +179,56 @@ function getVideoQualityForHeight(height: number) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the video quality level for the resizable filmstrip thumbnail height.
|
||||
* Returns the video quality level for the resizable filmstrip thumbnail height.
|
||||
*
|
||||
* @param {number} height - The height of the thumbnail.
|
||||
* @param {Object} state - Redux state.
|
||||
* @returns {number}
|
||||
*/
|
||||
export function getVideoQualityForResizableFilmstripThumbnails(state) {
|
||||
const height = state['features/filmstrip'].verticalViewDimensions?.gridView?.thumbnailSize?.height;
|
||||
export function getVideoQualityForResizableFilmstripThumbnails(height, state) {
|
||||
if (!height) {
|
||||
return VIDEO_QUALITY_LEVELS.LOW;
|
||||
}
|
||||
|
||||
return getVideoQualityForHeight(height);
|
||||
return getReceiverVideoQualityLevel(height, getMinHeightForQualityLvlMap(state));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the video quality for the large video.
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
export function getVideoQualityForLargeVideo() {
|
||||
const wrapper = document.querySelector('#largeVideoWrapper');
|
||||
|
||||
return getVideoQualityForHeight(wrapper.clientHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the video quality level for the thumbnails in the stage filmstrip.
|
||||
* Returns the video quality level for the screen sharing filmstrip thumbnail height.
|
||||
*
|
||||
* @param {number} height - The height of the thumbnail.
|
||||
* @param {Object} state - Redux state.
|
||||
* @returns {number}
|
||||
*/
|
||||
export function getVideoQualityForStageThumbnails(state) {
|
||||
const height = state['features/filmstrip'].stageFilmstripDimensions?.thumbnailSize?.height;
|
||||
export function getVideoQualityForScreenSharingFilmstrip(height, state) {
|
||||
if (!height) {
|
||||
return VIDEO_QUALITY_LEVELS.LOW;
|
||||
}
|
||||
|
||||
return getVideoQualityForHeight(height);
|
||||
return getReceiverVideoQualityLevel(height, getMinHeightForQualityLvlMap(state));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the video quality for the large video.
|
||||
*
|
||||
* @param {number} largeVideoHeight - The height of the large video.
|
||||
* @returns {number} - The video quality for the large video.
|
||||
*/
|
||||
export function getVideoQualityForLargeVideo(largeVideoHeight) {
|
||||
return getVideoQualityForHeight(largeVideoHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the video quality level for the thumbnails in the stage filmstrip.
|
||||
*
|
||||
* @param {number} height - The height of the thumbnails.
|
||||
* @param {Object} state - Redux state.
|
||||
* @returns {number}
|
||||
*/
|
||||
export function getVideoQualityForStageThumbnails(height, state) {
|
||||
if (!height) {
|
||||
return VIDEO_QUALITY_LEVELS.LOW;
|
||||
}
|
||||
|
||||
return getReceiverVideoQualityLevel(height, getMinHeightForQualityLvlMap(state));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { MEDIA_TYPE, setVideoMuted, VIDEO_MUTISM_AUTHORITY } from '../base/media';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
import { CLIENT_RESIZED } from '../base/responsive-ui';
|
||||
import { setLargeVideoDimensions } from '../large-video/actions.any';
|
||||
|
||||
import { SET_CAR_MODE } from './actionTypes';
|
||||
import './middleware.any';
|
||||
|
@ -18,6 +20,13 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
case SET_CAR_MODE:
|
||||
dispatch(setVideoMuted(action.enabled, MEDIA_TYPE.VIDEO, VIDEO_MUTISM_AUTHORITY.CAR_MODE));
|
||||
break;
|
||||
case CLIENT_RESIZED: {
|
||||
const { clientHeight, clientWidth } = store.getState()['features/base/responsive-ui'];
|
||||
|
||||
// On mobile the large video should always fill the screen.
|
||||
dispatch(setLargeVideoDimensions(clientHeight, clientWidth));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -1,3 +1,65 @@
|
|||
/**
|
||||
* The type of (redux) action which sets the maximum video height that should be
|
||||
* received from remote participants for the large video, even if the user prefers a larger video
|
||||
* height.
|
||||
*
|
||||
* {
|
||||
* type: SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_LARGE_VIDEO,
|
||||
* maxReceiverVideoQuality: number
|
||||
* }
|
||||
*/
|
||||
export const SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_LARGE_VIDEO = 'SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_LARGE_VIDEO';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The type of (redux) action which sets the maximum video height that should be
|
||||
* received from remote participants for the screen sharing filmstrip, even if the user prefers a larger video
|
||||
* height.
|
||||
*
|
||||
* {
|
||||
* type: SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_SCREEN_SHARING_FILMSTRIP,
|
||||
* maxReceiverVideoQuality: number
|
||||
* }
|
||||
*/
|
||||
export const SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_SCREEN_SHARING_FILMSTRIP = 'SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_SCREEN_SHARING_FILMSTRIP';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which sets the maximum video height that should be
|
||||
* received from remote participants for stage filmstrip, even if the user prefers a larger video
|
||||
* height.
|
||||
*
|
||||
* {
|
||||
* type: SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_STAGE_FILMSTRIP,
|
||||
* maxReceiverVideoQuality: number
|
||||
* }
|
||||
*/
|
||||
export const SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_STAGE_FILMSTRIP = 'SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_STAGE_FILMSTRIP';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which sets the maximum video height that should be
|
||||
* received from remote participants for tile view, even if the user prefers a larger video
|
||||
* height.
|
||||
*
|
||||
* {
|
||||
* type: SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_TILE_VIEW,
|
||||
* maxReceiverVideoQuality: number
|
||||
* }
|
||||
*/
|
||||
export const SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_TILE_VIEW = 'SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_TILE_VIEW';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which sets the maximum video height that should be
|
||||
* received from remote participants for vertical filmstrip, even if the user prefers a larger video
|
||||
* height.
|
||||
*
|
||||
* {
|
||||
* type: SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_VERTICAL_FILMSTRIP,
|
||||
* maxReceiverVideoQuality: number
|
||||
* }
|
||||
*/
|
||||
export const SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_VERTICAL_FILMSTRIP = 'SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_VERTICAL_FILMSTRIP';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which sets the preferred maximum video height that
|
||||
* should be sent to and received from remote participants.
|
||||
|
@ -7,17 +69,4 @@
|
|||
* preferredVideoQuality: number
|
||||
* }
|
||||
*/
|
||||
export const SET_PREFERRED_VIDEO_QUALITY = 'SET_PREFERRED_VIDEO_QUALITY';
|
||||
|
||||
|
||||
/**
|
||||
* The type of (redux) action which sets the maximum video height that should be
|
||||
* received from remote participants, even if the user prefers a larger video
|
||||
* height.
|
||||
*
|
||||
* {
|
||||
* type: SET_MAX_RECEIVER_VIDEO_QUALITY,
|
||||
* maxReceiverVideoQuality: number
|
||||
* }
|
||||
*/
|
||||
export const SET_MAX_RECEIVER_VIDEO_QUALITY = 'SET_MAX_RECEIVER_VIDEO_QUALITY';
|
||||
export const SET_PREFERRED_VIDEO_QUALITY = 'SET_PREFERRED_VIDEO_QUALITY';
|
|
@ -2,10 +2,102 @@
|
|||
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { SET_MAX_RECEIVER_VIDEO_QUALITY, SET_PREFERRED_VIDEO_QUALITY } from './actionTypes';
|
||||
import { VIDEO_QUALITY_LEVELS } from './constants';
|
||||
import {
|
||||
SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_LARGE_VIDEO,
|
||||
SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_SCREEN_SHARING_FILMSTRIP,
|
||||
SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_STAGE_FILMSTRIP,
|
||||
SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_TILE_VIEW,
|
||||
SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_VERTICAL_FILMSTRIP,
|
||||
SET_PREFERRED_VIDEO_QUALITY
|
||||
} from './actionTypes';
|
||||
import { MAX_VIDEO_QUALITY, VIDEO_QUALITY_LEVELS } from './constants';
|
||||
import logger from './logger';
|
||||
|
||||
/**
|
||||
* Sets the max frame height that should be received for the large video.
|
||||
*
|
||||
* @param {number} maxReceiverVideoQuality - The max video frame height to
|
||||
* receive.
|
||||
* @returns {{
|
||||
* type: SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_LARGE_VIDEO,
|
||||
* maxReceiverVideoQuality: number
|
||||
* }}
|
||||
*/
|
||||
export function setMaxReceiverVideoQualityForLargeVideo(maxReceiverVideoQuality: number) {
|
||||
return {
|
||||
type: SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_LARGE_VIDEO,
|
||||
maxReceiverVideoQuality
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the max frame height that should be received for the screen sharing filmstrip particpant.
|
||||
*
|
||||
* @param {number} maxReceiverVideoQuality - The max video frame height to
|
||||
* receive.
|
||||
* @returns {{
|
||||
* type: SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_SCREEN_SHARING_FILMSTRIP,
|
||||
* maxReceiverVideoQuality: number
|
||||
* }}
|
||||
*/
|
||||
export function setMaxReceiverVideoQualityForScreenSharingFilmstrip(maxReceiverVideoQuality: number) {
|
||||
return {
|
||||
type: SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_SCREEN_SHARING_FILMSTRIP,
|
||||
maxReceiverVideoQuality
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the max frame height that should be received from remote videos for the stage filmstrip.
|
||||
*
|
||||
* @param {number} maxReceiverVideoQuality - The max video frame height to
|
||||
* receive.
|
||||
* @returns {{
|
||||
* type: SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_STAGE_FILMSTRIP,
|
||||
* maxReceiverVideoQuality: number
|
||||
* }}
|
||||
*/
|
||||
export function setMaxReceiverVideoQualityForStageFilmstrip(maxReceiverVideoQuality: number) {
|
||||
return {
|
||||
type: SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_STAGE_FILMSTRIP,
|
||||
maxReceiverVideoQuality
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the max frame height that should be received from remote videos in tile view.
|
||||
*
|
||||
* @param {number} maxReceiverVideoQuality - The max video frame height to
|
||||
* receive.
|
||||
* @returns {{
|
||||
* type: SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_TILE_VIEW,
|
||||
* maxReceiverVideoQuality: number
|
||||
* }}
|
||||
*/
|
||||
export function setMaxReceiverVideoQualityForTileView(maxReceiverVideoQuality: number) {
|
||||
return {
|
||||
type: SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_TILE_VIEW,
|
||||
maxReceiverVideoQuality
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the max frame height that should be received from remote videos for the vertical filmstrip.
|
||||
*
|
||||
* @param {number} maxReceiverVideoQuality - The max video frame height to
|
||||
* receive.
|
||||
* @returns {{
|
||||
* type: SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_VERTICAL_FILMSTRIP,
|
||||
* maxReceiverVideoQuality: number
|
||||
* }}
|
||||
*/
|
||||
export function setMaxReceiverVideoQualityForVerticalFilmstrip(maxReceiverVideoQuality: number) {
|
||||
return {
|
||||
type: SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_VERTICAL_FILMSTRIP,
|
||||
maxReceiverVideoQuality
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the max frame height the user prefers to send and receive from the
|
||||
* remote participants.
|
||||
|
@ -24,24 +116,6 @@ export function setPreferredVideoQuality(preferredVideoQuality: number) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the max frame height that should be received from remote videos.
|
||||
*
|
||||
* @param {number} maxReceiverVideoQuality - The max video frame height to
|
||||
* receive.
|
||||
* @returns {{
|
||||
* type: SET_MAX_RECEIVER_VIDEO_QUALITY,
|
||||
* maxReceiverVideoQuality: number
|
||||
* }}
|
||||
*/
|
||||
export function setMaxReceiverVideoQuality(maxReceiverVideoQuality: number) {
|
||||
return {
|
||||
type: SET_MAX_RECEIVER_VIDEO_QUALITY,
|
||||
maxReceiverVideoQuality
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the maximum video size the local participant should send and receive from
|
||||
* remote participants.
|
||||
|
@ -58,6 +132,6 @@ export function setVideoQuality(frameHeight: number) {
|
|||
return;
|
||||
}
|
||||
|
||||
dispatch(setPreferredVideoQuality(Math.min(frameHeight, VIDEO_QUALITY_LEVELS.HIGH)));
|
||||
dispatch(setPreferredVideoQuality(Math.min(frameHeight, MAX_VIDEO_QUALITY)));
|
||||
};
|
||||
}
|
||||
|
|
|
@ -19,6 +19,16 @@ export const VIDEO_QUALITY_LEVELS = {
|
|||
NONE: 0
|
||||
};
|
||||
|
||||
/**
|
||||
* Indicates unlimited video quality.
|
||||
*/
|
||||
export const VIDEO_QUALITY_UNLIMITED = -1;
|
||||
|
||||
/**
|
||||
* The maximum video quality from the VIDEO_QUALITY_LEVELS map.
|
||||
*/
|
||||
export const MAX_VIDEO_QUALITY = Math.max(...Object.values(VIDEO_QUALITY_LEVELS));
|
||||
|
||||
/**
|
||||
* Maps quality level names used in the config.videoQuality.minHeightForQualityLvl to the quality level constants used
|
||||
* by the application.
|
||||
|
@ -28,5 +38,6 @@ export const VIDEO_QUALITY_LEVELS = {
|
|||
export const CFG_LVL_TO_APP_QUALITY_LVL = {
|
||||
'low': VIDEO_QUALITY_LEVELS.LOW,
|
||||
'standard': VIDEO_QUALITY_LEVELS.STANDARD,
|
||||
'high': VIDEO_QUALITY_LEVELS.HIGH
|
||||
'high': VIDEO_QUALITY_LEVELS.HIGH,
|
||||
'ultra': VIDEO_QUALITY_LEVELS.ULTRA
|
||||
};
|
||||
|
|
|
@ -1,28 +1,5 @@
|
|||
// @flow
|
||||
|
||||
import { CFG_LVL_TO_APP_QUALITY_LVL, VIDEO_QUALITY_LEVELS } from './constants';
|
||||
|
||||
const { LOW, STANDARD, HIGH, ULTRA } = VIDEO_QUALITY_LEVELS;
|
||||
const videoQualityLevels = [ LOW, STANDARD, HIGH, ULTRA ];
|
||||
|
||||
/**
|
||||
* Finds the nearest video quality level to the passed video quality.
|
||||
*
|
||||
* @param {number} videoQuality - The video quality.
|
||||
* @returns {number|undefined} - The found quality level.
|
||||
*/
|
||||
export function findNearestQualityLevel(videoQuality: number) {
|
||||
for (let i = 0; i < videoQualityLevels.length; i++) {
|
||||
const level = videoQualityLevels[i];
|
||||
|
||||
if (level >= videoQuality) {
|
||||
return level;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects {@code VIDEO_QUALITY_LEVELS} for the given {@link availableHeight} and threshold to quality mapping.
|
||||
*
|
||||
|
@ -52,7 +29,7 @@ export function getReceiverVideoQualityLevel(availableHeight: number, heightToLe
|
|||
* @returns {Map<number, number>|undefined} - A mapping of minimal thumbnail height required for given quality level or
|
||||
* {@code undefined} if the map contains invalid values.
|
||||
*/
|
||||
export function validateMinHeightForQualityLvl(minHeightForQualityLvl: Object): ?Map<number, number> {
|
||||
export function validateMinHeightForQualityLvl(minHeightForQualityLvl) {
|
||||
if (typeof minHeightForQualityLvl !== 'object'
|
||||
|| Object.keys(minHeightForQualityLvl).map(lvl => Number(lvl))
|
||||
.find(lvl => lvl === null || isNaN(lvl) || lvl < 0)) {
|
||||
|
@ -65,6 +42,13 @@ export function validateMinHeightForQualityLvl(minHeightForQualityLvl: Object):
|
|||
.sort((a, b) => a - b);
|
||||
const map = new Map();
|
||||
|
||||
Object.values(VIDEO_QUALITY_LEVELS).sort()
|
||||
.forEach(value => {
|
||||
if (value > VIDEO_QUALITY_LEVELS.NONE) {
|
||||
map.set(value, value);
|
||||
}
|
||||
});
|
||||
|
||||
for (const level of levelsSorted) {
|
||||
const configQuality = minHeightForQualityLvl[level];
|
||||
const appQuality = CFG_LVL_TO_APP_QUALITY_LVL[configQuality];
|
||||
|
@ -73,6 +57,7 @@ export function validateMinHeightForQualityLvl(minHeightForQualityLvl: Object):
|
|||
return undefined;
|
||||
}
|
||||
|
||||
map.delete(appQuality);
|
||||
map.set(level, appQuality);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,14 @@ import PersistenceRegistry from '../base/redux/PersistenceRegistry';
|
|||
import ReducerRegistry from '../base/redux/ReducerRegistry';
|
||||
import { set } from '../base/redux/functions';
|
||||
|
||||
import { SET_MAX_RECEIVER_VIDEO_QUALITY, SET_PREFERRED_VIDEO_QUALITY } from './actionTypes';
|
||||
import {
|
||||
SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_LARGE_VIDEO,
|
||||
SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_SCREEN_SHARING_FILMSTRIP,
|
||||
SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_STAGE_FILMSTRIP,
|
||||
SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_TILE_VIEW,
|
||||
SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_VERTICAL_FILMSTRIP,
|
||||
SET_PREFERRED_VIDEO_QUALITY
|
||||
} from './actionTypes';
|
||||
import { VIDEO_QUALITY_LEVELS } from './constants';
|
||||
/* eslint-disable-next-line lines-around-comment */
|
||||
// @ts-ignore
|
||||
|
@ -12,16 +19,29 @@ import { validateMinHeightForQualityLvl } from './functions';
|
|||
import logger from './logger';
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
maxReceiverVideoQuality: VIDEO_QUALITY_LEVELS.ULTRA,
|
||||
maxReceiverVideoQualityForLargeVideo: VIDEO_QUALITY_LEVELS.ULTRA,
|
||||
maxReceiverVideoQualityForScreenSharingFilmstrip: VIDEO_QUALITY_LEVELS.HIGH,
|
||||
maxReceiverVideoQualityForStageFilmstrip: VIDEO_QUALITY_LEVELS.HIGH,
|
||||
maxReceiverVideoQualityForTileView: VIDEO_QUALITY_LEVELS.STANDARD,
|
||||
maxReceiverVideoQualityForVerticalFilmstrip: VIDEO_QUALITY_LEVELS.LOW,
|
||||
minHeightForQualityLvl: new Map(),
|
||||
preferredVideoQuality: VIDEO_QUALITY_LEVELS.ULTRA
|
||||
};
|
||||
|
||||
DEFAULT_STATE.minHeightForQualityLvl.set(360, VIDEO_QUALITY_LEVELS.STANDARD);
|
||||
DEFAULT_STATE.minHeightForQualityLvl.set(720, VIDEO_QUALITY_LEVELS.HIGH);
|
||||
|
||||
Object.values(VIDEO_QUALITY_LEVELS).sort()
|
||||
.forEach(value => {
|
||||
if (value > VIDEO_QUALITY_LEVELS.NONE) {
|
||||
DEFAULT_STATE.minHeightForQualityLvl.set(value, value);
|
||||
}
|
||||
});
|
||||
|
||||
export interface IVideoQualityState {
|
||||
maxReceiverVideoQuality: number;
|
||||
maxReceiverVideoQualityForLargeVideo: number,
|
||||
maxReceiverVideoQualityForScreenSharingFilmstrip: number,
|
||||
maxReceiverVideoQualityForStageFilmstrip: number,
|
||||
maxReceiverVideoQualityForTileView: number,
|
||||
maxReceiverVideoQualityForVerticalFilmstrip: number,
|
||||
minHeightForQualityLvl: Map<number, number>;
|
||||
preferredVideoQuality: number;
|
||||
}
|
||||
|
@ -56,10 +76,28 @@ ReducerRegistry.register('features/video-quality',
|
|||
switch (action.type) {
|
||||
case SET_CONFIG:
|
||||
return _setConfig(state, action);
|
||||
case SET_MAX_RECEIVER_VIDEO_QUALITY:
|
||||
case SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_LARGE_VIDEO:
|
||||
return set(state,
|
||||
'maxReceiverVideoQualityForLargeVideo',
|
||||
action.maxReceiverVideoQuality);
|
||||
case SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_SCREEN_SHARING_FILMSTRIP:
|
||||
return set(state,
|
||||
'maxReceiverVideoQualityForScreenSharingFilmstrip',
|
||||
action.maxReceiverVideoQuality);
|
||||
case SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_STAGE_FILMSTRIP:
|
||||
return set(
|
||||
state,
|
||||
'maxReceiverVideoQuality',
|
||||
'maxReceiverVideoQualityForStageFilmstrip',
|
||||
action.maxReceiverVideoQuality);
|
||||
case SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_TILE_VIEW:
|
||||
return set(
|
||||
state,
|
||||
'maxReceiverVideoQualityForTileView',
|
||||
action.maxReceiverVideoQuality);
|
||||
case SET_MAX_RECEIVER_VIDEO_QUALITY_FOR_VERTICAL_FILMSTRIP:
|
||||
return set(
|
||||
state,
|
||||
'maxReceiverVideoQualityForVerticalFilmstrip',
|
||||
action.maxReceiverVideoQuality);
|
||||
case SET_PREFERRED_VIDEO_QUALITY: {
|
||||
const { preferredVideoQuality } = action;
|
||||
|
|
|
@ -1,30 +1,40 @@
|
|||
// @flow
|
||||
/* global APP */
|
||||
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
import { _handleParticipantError } from '../base/conference';
|
||||
import { getSourceNameSignalingFeatureFlag } from '../base/config';
|
||||
import { MEDIA_TYPE } from '../base/media';
|
||||
import { getLocalParticipant, getParticipantCount } from '../base/participants';
|
||||
import { getLocalParticipant } from '../base/participants';
|
||||
import { StateListenerRegistry } from '../base/redux';
|
||||
import { getRemoteScreenSharesSourceNames, getTrackSourceNameByMediaTypeAndParticipant } from '../base/tracks';
|
||||
import { reportError } from '../base/util';
|
||||
import { getActiveParticipantsIds } from '../filmstrip/functions.web';
|
||||
import {
|
||||
getActiveParticipantsIds,
|
||||
getScreenshareFilmstripParticipantId,
|
||||
isTopPanelEnabled
|
||||
} from '../filmstrip/functions';
|
||||
import {
|
||||
getVideoQualityForLargeVideo,
|
||||
getVideoQualityForResizableFilmstripThumbnails,
|
||||
getVideoQualityForStageThumbnails,
|
||||
LAYOUTS,
|
||||
shouldDisplayTileView
|
||||
} from '../video-layout';
|
||||
import { getCurrentLayout, getVideoQualityForScreenSharingFilmstrip } from '../video-layout/functions.any';
|
||||
|
||||
import { setMaxReceiverVideoQuality } from './actions';
|
||||
import { VIDEO_QUALITY_LEVELS } from './constants';
|
||||
import {
|
||||
setMaxReceiverVideoQualityForLargeVideo,
|
||||
setMaxReceiverVideoQualityForScreenSharingFilmstrip,
|
||||
setMaxReceiverVideoQualityForStageFilmstrip,
|
||||
setMaxReceiverVideoQualityForTileView,
|
||||
setMaxReceiverVideoQualityForVerticalFilmstrip
|
||||
} from './actions';
|
||||
import { MAX_VIDEO_QUALITY, VIDEO_QUALITY_LEVELS, VIDEO_QUALITY_UNLIMITED } from './constants';
|
||||
import { getReceiverVideoQualityLevel } from './functions';
|
||||
import logger from './logger';
|
||||
import { getMinHeightForQualityLvlMap } from './selector';
|
||||
|
||||
declare var APP: Object;
|
||||
|
||||
/**
|
||||
* Handles changes in the visible participants in the filmstrip. The listener is debounced
|
||||
* so that the client doesn't end up sending too many bridge messages when the user is
|
||||
|
@ -63,17 +73,6 @@ StateListenerRegistry.register(
|
|||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Updates the receiver constraints when the layout changes. When we are in stage view we need to handle the
|
||||
* on-stage participant differently.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
/* selector */ state => state['features/video-layout'].tileViewEnabled,
|
||||
/* listener */ (tileViewEnabled, store) => {
|
||||
_updateReceiverVideoConstraints(store);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* StateListenerRegistry provides a reliable way of detecting changes to
|
||||
* lastn state and dispatching additional actions.
|
||||
|
@ -84,26 +83,6 @@ StateListenerRegistry.register(
|
|||
_updateReceiverVideoConstraints(store);
|
||||
});
|
||||
|
||||
/**
|
||||
* Updates the receiver constraints when the tiles in the resizable filmstrip change dimensions.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
state => getVideoQualityForResizableFilmstripThumbnails(state),
|
||||
(_, store) => {
|
||||
_updateReceiverVideoConstraints(store);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Updates the receiver constraints when the tiles in the resizable top panel change dimensions.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
state => getVideoQualityForStageThumbnails(state),
|
||||
(_, store) => {
|
||||
_updateReceiverVideoConstraints(store);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Updates the receiver constraints when the stage participants change.
|
||||
*/
|
||||
|
@ -118,30 +97,37 @@ StateListenerRegistry.register(
|
|||
|
||||
/**
|
||||
* StateListenerRegistry provides a reliable way of detecting changes to
|
||||
* maxReceiverVideoQuality and preferredVideoQuality state and dispatching additional actions.
|
||||
* maxReceiverVideoQuality* and preferredVideoQuality state and dispatching additional actions.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
/* selector */ state => {
|
||||
const {
|
||||
maxReceiverVideoQuality,
|
||||
maxReceiverVideoQualityForLargeVideo,
|
||||
maxReceiverVideoQualityForScreenSharingFilmstrip,
|
||||
maxReceiverVideoQualityForStageFilmstrip,
|
||||
maxReceiverVideoQualityForTileView,
|
||||
maxReceiverVideoQualityForVerticalFilmstrip,
|
||||
preferredVideoQuality
|
||||
} = state['features/video-quality'];
|
||||
|
||||
return {
|
||||
maxReceiverVideoQuality,
|
||||
maxReceiverVideoQualityForLargeVideo,
|
||||
maxReceiverVideoQualityForScreenSharingFilmstrip,
|
||||
maxReceiverVideoQualityForStageFilmstrip,
|
||||
maxReceiverVideoQualityForTileView,
|
||||
maxReceiverVideoQualityForVerticalFilmstrip,
|
||||
preferredVideoQuality
|
||||
};
|
||||
},
|
||||
/* listener */ (currentState, store, previousState = {}) => {
|
||||
const { maxReceiverVideoQuality, preferredVideoQuality } = currentState;
|
||||
const { preferredVideoQuality } = currentState;
|
||||
const changedPreferredVideoQuality = preferredVideoQuality !== previousState.preferredVideoQuality;
|
||||
const changedReceiverVideoQuality = maxReceiverVideoQuality !== previousState.maxReceiverVideoQuality;
|
||||
|
||||
if (changedPreferredVideoQuality) {
|
||||
_setSenderVideoConstraint(preferredVideoQuality, store);
|
||||
typeof APP !== 'undefined' && APP.API.notifyVideoQualityChanged(preferredVideoQuality);
|
||||
}
|
||||
changedReceiverVideoQuality && _updateReceiverVideoConstraints(store);
|
||||
_updateReceiverVideoConstraints(store);
|
||||
}, {
|
||||
deepEquals: true
|
||||
});
|
||||
|
@ -153,48 +139,158 @@ StateListenerRegistry.register(
|
|||
/* selector */ state => {
|
||||
const { reducedUI } = state['features/base/responsive-ui'];
|
||||
const _shouldDisplayTileView = shouldDisplayTileView(state);
|
||||
const thumbnailSize = state['features/filmstrip']?.tileViewDimensions?.thumbnailSize;
|
||||
const participantCount = getParticipantCount(state);
|
||||
const tileViewThumbnailSize = state['features/filmstrip']?.tileViewDimensions?.thumbnailSize;
|
||||
const { visibleRemoteParticipants } = state['features/filmstrip'];
|
||||
const { height: largeVideoHeight } = state['features/large-video'];
|
||||
const activeParticipantsIds = getActiveParticipantsIds(state);
|
||||
const {
|
||||
screenshareFilmstripDimensions: {
|
||||
thumbnailSize
|
||||
}
|
||||
} = state['features/filmstrip'];
|
||||
const screenshareFilmstripParticipantId = getScreenshareFilmstripParticipantId(state);
|
||||
|
||||
return {
|
||||
activeParticipantsCount: activeParticipantsIds?.length,
|
||||
displayTileView: _shouldDisplayTileView,
|
||||
participantCount,
|
||||
largeVideoHeight,
|
||||
participantCount: visibleRemoteParticipants?.size || 0,
|
||||
reducedUI,
|
||||
thumbnailHeight: thumbnailSize?.height
|
||||
screenSharingFilmstripHeight:
|
||||
screenshareFilmstripParticipantId && getCurrentLayout(state) === LAYOUTS.STAGE_FILMSTRIP_VIEW
|
||||
? thumbnailSize?.height : undefined,
|
||||
stageFilmstripThumbnailHeight: state['features/filmstrip'].stageFilmstripDimensions?.thumbnailSize?.height,
|
||||
tileViewThumbnailHeight: tileViewThumbnailSize?.height,
|
||||
verticalFilmstripThumbnailHeight:
|
||||
state['features/filmstrip'].verticalViewDimensions?.gridView?.thumbnailSize?.height
|
||||
};
|
||||
},
|
||||
/* listener */ ({ displayTileView, participantCount, reducedUI, thumbnailHeight }, { dispatch, getState }) => {
|
||||
/* listener */ ({
|
||||
activeParticipantsCount,
|
||||
displayTileView,
|
||||
largeVideoHeight,
|
||||
participantCount,
|
||||
reducedUI,
|
||||
screenSharingFilmstripHeight,
|
||||
stageFilmstripThumbnailHeight,
|
||||
tileViewThumbnailHeight,
|
||||
verticalFilmstripThumbnailHeight
|
||||
}, store, previousState = {}) => {
|
||||
const { dispatch, getState } = store;
|
||||
const state = getState();
|
||||
const { maxReceiverVideoQuality } = state['features/video-quality'];
|
||||
const {
|
||||
maxReceiverVideoQualityForLargeVideo,
|
||||
maxReceiverVideoQualityForScreenSharingFilmstrip,
|
||||
maxReceiverVideoQualityForStageFilmstrip,
|
||||
maxReceiverVideoQualityForTileView,
|
||||
maxReceiverVideoQualityForVerticalFilmstrip
|
||||
} = state['features/video-quality'];
|
||||
const { maxFullResolutionParticipants = 2 } = state['features/base/config'];
|
||||
let maxVideoQualityChanged = false;
|
||||
|
||||
let newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.ULTRA;
|
||||
|
||||
if (reducedUI) {
|
||||
newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.LOW;
|
||||
} else if (displayTileView && !Number.isNaN(thumbnailHeight)) {
|
||||
newMaxRecvVideoQuality = getReceiverVideoQualityLevel(thumbnailHeight, getMinHeightForQualityLvlMap(state));
|
||||
if (displayTileView) {
|
||||
let newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.STANDARD;
|
||||
|
||||
// Override HD level calculated for the thumbnail height when # of participants threshold is exceeded
|
||||
if (maxReceiverVideoQuality !== newMaxRecvVideoQuality && maxFullResolutionParticipants !== -1) {
|
||||
const override
|
||||
= participantCount > maxFullResolutionParticipants
|
||||
&& newMaxRecvVideoQuality > VIDEO_QUALITY_LEVELS.STANDARD;
|
||||
if (reducedUI) {
|
||||
newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.LOW;
|
||||
} else if (typeof tileViewThumbnailHeight === 'number' && !Number.isNaN(tileViewThumbnailHeight)) {
|
||||
newMaxRecvVideoQuality
|
||||
= getReceiverVideoQualityLevel(tileViewThumbnailHeight, getMinHeightForQualityLvlMap(state));
|
||||
|
||||
logger.info(`Video quality level for thumbnail height: ${thumbnailHeight}, `
|
||||
+ `is: ${newMaxRecvVideoQuality}, `
|
||||
+ `override: ${String(override)}, `
|
||||
+ `max full res N: ${maxFullResolutionParticipants}`);
|
||||
// Override HD level calculated for the thumbnail height when # of participants threshold is exceeded
|
||||
if (maxFullResolutionParticipants !== -1) {
|
||||
const override
|
||||
= participantCount > maxFullResolutionParticipants
|
||||
&& newMaxRecvVideoQuality > VIDEO_QUALITY_LEVELS.STANDARD;
|
||||
|
||||
if (override) {
|
||||
newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.STANDARD;
|
||||
logger.info(`Video quality level for thumbnail height: ${tileViewThumbnailHeight}, `
|
||||
+ `is: ${newMaxRecvVideoQuality}, `
|
||||
+ `override: ${String(override)}, `
|
||||
+ `max full res N: ${maxFullResolutionParticipants}`);
|
||||
|
||||
if (override) {
|
||||
newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.STANDARD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (maxReceiverVideoQualityForTileView !== newMaxRecvVideoQuality) {
|
||||
maxVideoQualityChanged = true;
|
||||
dispatch(setMaxReceiverVideoQualityForTileView(newMaxRecvVideoQuality));
|
||||
}
|
||||
} else {
|
||||
let newMaxRecvVideoQualityForStageFilmstrip;
|
||||
let newMaxRecvVideoQualityForVerticalFilmstrip;
|
||||
let newMaxRecvVideoQualityForLargeVideo;
|
||||
let newMaxRecvVideoQualityForScreenSharingFilmstrip;
|
||||
|
||||
if (reducedUI) {
|
||||
newMaxRecvVideoQualityForVerticalFilmstrip
|
||||
= newMaxRecvVideoQualityForStageFilmstrip
|
||||
= newMaxRecvVideoQualityForLargeVideo
|
||||
= newMaxRecvVideoQualityForScreenSharingFilmstrip
|
||||
= VIDEO_QUALITY_LEVELS.LOW;
|
||||
} else {
|
||||
newMaxRecvVideoQualityForStageFilmstrip
|
||||
= getVideoQualityForStageThumbnails(stageFilmstripThumbnailHeight, state);
|
||||
newMaxRecvVideoQualityForVerticalFilmstrip
|
||||
= getVideoQualityForResizableFilmstripThumbnails(verticalFilmstripThumbnailHeight, state);
|
||||
newMaxRecvVideoQualityForLargeVideo = getVideoQualityForLargeVideo(largeVideoHeight);
|
||||
newMaxRecvVideoQualityForScreenSharingFilmstrip
|
||||
= getVideoQualityForScreenSharingFilmstrip(screenSharingFilmstripHeight, state);
|
||||
|
||||
// Override HD level calculated for the thumbnail height when # of participants threshold is exceeded
|
||||
if (maxFullResolutionParticipants !== -1) {
|
||||
if (activeParticipantsCount > 0
|
||||
&& newMaxRecvVideoQualityForStageFilmstrip > VIDEO_QUALITY_LEVELS.STANDARD) {
|
||||
const isScreenSharingFilmstripParticipantFullResolution
|
||||
= newMaxRecvVideoQualityForScreenSharingFilmstrip > VIDEO_QUALITY_LEVELS.STANDARD;
|
||||
|
||||
if (activeParticipantsCount > maxFullResolutionParticipants
|
||||
- (isScreenSharingFilmstripParticipantFullResolution ? 1 : 0)) {
|
||||
newMaxRecvVideoQualityForStageFilmstrip = VIDEO_QUALITY_LEVELS.STANDARD;
|
||||
newMaxRecvVideoQualityForVerticalFilmstrip
|
||||
= Math.min(VIDEO_QUALITY_LEVELS.STANDARD, newMaxRecvVideoQualityForVerticalFilmstrip);
|
||||
} else if (newMaxRecvVideoQualityForVerticalFilmstrip > VIDEO_QUALITY_LEVELS.STANDARD
|
||||
&& participantCount > maxFullResolutionParticipants - activeParticipantsCount) {
|
||||
newMaxRecvVideoQualityForVerticalFilmstrip = VIDEO_QUALITY_LEVELS.STANDARD;
|
||||
}
|
||||
} else if (newMaxRecvVideoQualityForVerticalFilmstrip > VIDEO_QUALITY_LEVELS.STANDARD
|
||||
&& participantCount > maxFullResolutionParticipants
|
||||
- (newMaxRecvVideoQualityForLargeVideo > VIDEO_QUALITY_LEVELS.STANDARD ? 1 : 0)) {
|
||||
newMaxRecvVideoQualityForVerticalFilmstrip = VIDEO_QUALITY_LEVELS.STANDARD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (maxReceiverVideoQualityForStageFilmstrip !== newMaxRecvVideoQualityForStageFilmstrip) {
|
||||
maxVideoQualityChanged = true;
|
||||
dispatch(setMaxReceiverVideoQualityForStageFilmstrip(newMaxRecvVideoQualityForStageFilmstrip));
|
||||
}
|
||||
|
||||
if (maxReceiverVideoQualityForVerticalFilmstrip !== newMaxRecvVideoQualityForVerticalFilmstrip) {
|
||||
maxVideoQualityChanged = true;
|
||||
dispatch(setMaxReceiverVideoQualityForVerticalFilmstrip(newMaxRecvVideoQualityForVerticalFilmstrip));
|
||||
}
|
||||
|
||||
if (maxReceiverVideoQualityForLargeVideo !== newMaxRecvVideoQualityForLargeVideo) {
|
||||
maxVideoQualityChanged = true;
|
||||
dispatch(setMaxReceiverVideoQualityForLargeVideo(newMaxRecvVideoQualityForLargeVideo));
|
||||
}
|
||||
|
||||
if (maxReceiverVideoQualityForScreenSharingFilmstrip !== newMaxRecvVideoQualityForScreenSharingFilmstrip) {
|
||||
maxVideoQualityChanged = true;
|
||||
dispatch(
|
||||
setMaxReceiverVideoQualityForScreenSharingFilmstrip(
|
||||
newMaxRecvVideoQualityForScreenSharingFilmstrip));
|
||||
}
|
||||
}
|
||||
|
||||
if (maxReceiverVideoQuality !== newMaxRecvVideoQuality) {
|
||||
dispatch(setMaxReceiverVideoQuality(newMaxRecvVideoQuality));
|
||||
if (!maxVideoQualityChanged && Boolean(displayTileView) !== Boolean(previousState.displayTileView)) {
|
||||
_updateReceiverVideoConstraints(store);
|
||||
}
|
||||
|
||||
}, {
|
||||
deepEquals: true
|
||||
});
|
||||
|
@ -235,31 +331,47 @@ function _updateReceiverVideoConstraints({ getState }) {
|
|||
return;
|
||||
}
|
||||
const { lastN } = state['features/base/lastn'];
|
||||
const { maxReceiverVideoQuality, preferredVideoQuality } = state['features/video-quality'];
|
||||
const {
|
||||
maxReceiverVideoQualityForTileView,
|
||||
maxReceiverVideoQualityForStageFilmstrip,
|
||||
maxReceiverVideoQualityForVerticalFilmstrip,
|
||||
maxReceiverVideoQualityForLargeVideo,
|
||||
maxReceiverVideoQualityForScreenSharingFilmstrip,
|
||||
preferredVideoQuality
|
||||
} = state['features/video-quality'];
|
||||
const { participantId: largeVideoParticipantId } = state['features/large-video'];
|
||||
const maxFrameHeight = Math.min(maxReceiverVideoQuality, preferredVideoQuality);
|
||||
const maxFrameHeightForTileView = Math.min(maxReceiverVideoQualityForTileView, preferredVideoQuality);
|
||||
const maxFrameHeightForStageFilmstrip = Math.min(maxReceiverVideoQualityForStageFilmstrip, preferredVideoQuality);
|
||||
const maxFrameHeightForVerticalFilmstrip
|
||||
= Math.min(maxReceiverVideoQualityForVerticalFilmstrip, preferredVideoQuality);
|
||||
const maxFrameHeightForLargeVideo
|
||||
= Math.min(maxReceiverVideoQualityForLargeVideo, preferredVideoQuality);
|
||||
const maxFrameHeightForScreenSharingFilmstrip
|
||||
= Math.min(maxReceiverVideoQualityForScreenSharingFilmstrip, 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 activeParticipantsIds = getActiveParticipantsIds(state);
|
||||
const screenshareFilmstripParticipantId = isTopPanelEnabled(state) && getScreenshareFilmstripParticipantId(state);
|
||||
|
||||
let receiverConstraints;
|
||||
const receiverConstraints = {
|
||||
constraints: {},
|
||||
defaultConstraints: { 'maxHeight': VIDEO_QUALITY_LEVELS.NONE },
|
||||
lastN
|
||||
};
|
||||
|
||||
let remoteScreenSharesSourceNames;
|
||||
let visibleRemoteTrackSourceNames = [];
|
||||
let largeVideoSourceName;
|
||||
let activeParticipantsSources = [];
|
||||
|
||||
if (sourceNameSignaling) {
|
||||
const remoteScreenSharesSourceNames = getRemoteScreenSharesSourceNames(state, remoteScreenShares);
|
||||
receiverConstraints.onStageSources = [];
|
||||
receiverConstraints.selectedSources = [];
|
||||
|
||||
receiverConstraints = {
|
||||
constraints: {},
|
||||
defaultConstraints: { 'maxHeight': VIDEO_QUALITY_LEVELS.NONE },
|
||||
lastN,
|
||||
onStageSources: [],
|
||||
selectedSources: []
|
||||
};
|
||||
const visibleRemoteTrackSourceNames = [];
|
||||
let largeVideoSourceName;
|
||||
const activeParticipantsSources = [];
|
||||
remoteScreenSharesSourceNames = getRemoteScreenSharesSourceNames(state, remoteScreenShares);
|
||||
|
||||
if (visibleRemoteParticipants?.size) {
|
||||
visibleRemoteParticipants.forEach(participantId => {
|
||||
|
@ -273,13 +385,27 @@ function _updateReceiverVideoConstraints({ getState }) {
|
|||
|
||||
if (sourceName) {
|
||||
visibleRemoteTrackSourceNames.push(sourceName);
|
||||
if (activeParticipantsIds.find(id => id === participantId)) {
|
||||
activeParticipantsSources.push(sourceName);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (activeParticipantsIds?.length > 0) {
|
||||
activeParticipantsIds.forEach(participantId => {
|
||||
let sourceName;
|
||||
|
||||
if (remoteScreenSharesSourceNames.includes(participantId)) {
|
||||
sourceName = participantId;
|
||||
} else {
|
||||
sourceName = getTrackSourceNameByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, participantId);
|
||||
}
|
||||
|
||||
if (sourceName) {
|
||||
activeParticipantsSources.push(sourceName);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
if (localParticipantId !== largeVideoParticipantId) {
|
||||
if (remoteScreenSharesSourceNames.includes(largeVideoParticipantId)) {
|
||||
largeVideoSourceName = largeVideoParticipantId;
|
||||
|
@ -289,110 +415,77 @@ function _updateReceiverVideoConstraints({ getState }) {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Tile view.
|
||||
if (shouldDisplayTileView(state)) {
|
||||
if (!visibleRemoteTrackSourceNames?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
visibleRemoteTrackSourceNames.forEach(sourceName => {
|
||||
receiverConstraints.constraints[sourceName] = { 'maxHeight': maxFrameHeight };
|
||||
});
|
||||
|
||||
// Prioritize screenshare in tile view.
|
||||
if (remoteScreenSharesSourceNames?.length) {
|
||||
receiverConstraints.selectedSources = remoteScreenSharesSourceNames;
|
||||
}
|
||||
|
||||
// Stage view.
|
||||
} else {
|
||||
if (!visibleRemoteTrackSourceNames?.length && !largeVideoSourceName) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (visibleRemoteTrackSourceNames?.length) {
|
||||
const qualityLevel = getVideoQualityForResizableFilmstripThumbnails(state);
|
||||
const stageParticipantsLevel = getVideoQualityForStageThumbnails(state);
|
||||
|
||||
visibleRemoteTrackSourceNames.forEach(sourceName => {
|
||||
const isStageParticipant = activeParticipantsSources.find(name => name === sourceName);
|
||||
const quality = Math.min(maxFrameHeight, isStageParticipant
|
||||
? stageParticipantsLevel : qualityLevel);
|
||||
|
||||
receiverConstraints.constraints[sourceName] = { 'maxHeight': quality };
|
||||
});
|
||||
}
|
||||
|
||||
if (largeVideoSourceName) {
|
||||
let quality = maxFrameHeight;
|
||||
|
||||
if (navigator.product !== 'ReactNative'
|
||||
&& !remoteScreenShares.find(id => id === largeVideoParticipantId)) {
|
||||
quality = getVideoQualityForLargeVideo();
|
||||
}
|
||||
receiverConstraints.constraints[largeVideoSourceName] = { 'maxHeight': quality };
|
||||
receiverConstraints.onStageSources = [ largeVideoSourceName ];
|
||||
}
|
||||
}
|
||||
|
||||
if (remoteScreenSharesSourceNames?.length) {
|
||||
remoteScreenSharesSourceNames.forEach(sourceName => {
|
||||
receiverConstraints.constraints[sourceName] = { 'maxHeight': VIDEO_QUALITY_LEVELS.ULTRA };
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
receiverConstraints = {
|
||||
constraints: {},
|
||||
defaultConstraints: { 'maxHeight': VIDEO_QUALITY_LEVELS.NONE },
|
||||
lastN,
|
||||
onStageEndpoints: [],
|
||||
selectedEndpoints: []
|
||||
};
|
||||
receiverConstraints.onStageEndpoints = [];
|
||||
receiverConstraints.selectedEndpoints = [];
|
||||
|
||||
// Tile view.
|
||||
if (shouldDisplayTileView(state)) {
|
||||
if (!visibleRemoteParticipants?.size) {
|
||||
return;
|
||||
}
|
||||
remoteScreenSharesSourceNames = remoteScreenShares;
|
||||
visibleRemoteTrackSourceNames = [ ...visibleRemoteParticipants ];
|
||||
largeVideoSourceName = largeVideoParticipantId;
|
||||
activeParticipantsSources = activeParticipantsIds;
|
||||
}
|
||||
|
||||
visibleRemoteParticipants.forEach(participantId => {
|
||||
receiverConstraints.constraints[participantId] = { 'maxHeight': maxFrameHeight };
|
||||
// Tile view.
|
||||
if (shouldDisplayTileView(state)) {
|
||||
if (!visibleRemoteTrackSourceNames?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
visibleRemoteTrackSourceNames.forEach(sourceName => {
|
||||
receiverConstraints.constraints[sourceName] = { 'maxHeight': maxFrameHeightForTileView };
|
||||
});
|
||||
|
||||
// Prioritize screenshare in tile view.
|
||||
if (remoteScreenSharesSourceNames?.length) {
|
||||
receiverConstraints[sourceNameSignaling ? 'selectedSources' : 'selectedEndpoints']
|
||||
= remoteScreenSharesSourceNames;
|
||||
}
|
||||
|
||||
// Stage view.
|
||||
} else {
|
||||
if (!visibleRemoteTrackSourceNames?.length && !largeVideoSourceName && !activeParticipantsSources?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (visibleRemoteTrackSourceNames?.length) {
|
||||
visibleRemoteTrackSourceNames.forEach(sourceName => {
|
||||
receiverConstraints.constraints[sourceName] = { 'maxHeight': maxFrameHeightForVerticalFilmstrip };
|
||||
});
|
||||
}
|
||||
|
||||
if (getCurrentLayout(state) === LAYOUTS.STAGE_FILMSTRIP_VIEW && activeParticipantsSources.length > 0) {
|
||||
const onStageSources = [ ...activeParticipantsSources ];
|
||||
|
||||
activeParticipantsSources.forEach(sourceName => {
|
||||
const isScreenSharing = remoteScreenShares.includes(sourceName);
|
||||
const quality
|
||||
= isScreenSharing && preferredVideoQuality >= MAX_VIDEO_QUALITY
|
||||
? VIDEO_QUALITY_UNLIMITED : maxFrameHeightForStageFilmstrip;
|
||||
|
||||
receiverConstraints.constraints[sourceName] = { 'maxHeight': quality };
|
||||
});
|
||||
|
||||
// Prioritize screenshare in tile view.
|
||||
remoteScreenShares?.length && (receiverConstraints.selectedEndpoints = remoteScreenShares);
|
||||
|
||||
// Stage view.
|
||||
} else {
|
||||
if (!visibleRemoteParticipants?.size && !largeVideoParticipantId) {
|
||||
return;
|
||||
if (screenshareFilmstripParticipantId) {
|
||||
onStageSources.push(screenshareFilmstripParticipantId);
|
||||
receiverConstraints.constraints[screenshareFilmstripParticipantId]
|
||||
= {
|
||||
'maxHeight':
|
||||
preferredVideoQuality >= MAX_VIDEO_QUALITY
|
||||
? VIDEO_QUALITY_UNLIMITED : maxFrameHeightForScreenSharingFilmstrip
|
||||
};
|
||||
}
|
||||
|
||||
if (visibleRemoteParticipants?.size > 0) {
|
||||
const qualityLevel = getVideoQualityForResizableFilmstripThumbnails(state);
|
||||
const stageParticipantsLevel = getVideoQualityForStageThumbnails(state);
|
||||
receiverConstraints[sourceNameSignaling ? 'onStageSources' : 'onStageEndpoints'] = onStageSources;
|
||||
} else if (largeVideoSourceName) {
|
||||
let quality = VIDEO_QUALITY_UNLIMITED;
|
||||
|
||||
visibleRemoteParticipants.forEach(participantId => {
|
||||
const isStageParticipant = activeParticipantsIds.find(id => id === participantId);
|
||||
const quality = Math.min(maxFrameHeight, isStageParticipant
|
||||
? stageParticipantsLevel : qualityLevel);
|
||||
|
||||
receiverConstraints.constraints[participantId] = { 'maxHeight': quality };
|
||||
});
|
||||
}
|
||||
|
||||
if (largeVideoParticipantId) {
|
||||
let quality = maxFrameHeight;
|
||||
|
||||
if (navigator.product !== 'ReactNative'
|
||||
&& !remoteScreenShares.find(id => id === largeVideoParticipantId)) {
|
||||
quality = getVideoQualityForLargeVideo();
|
||||
}
|
||||
receiverConstraints.constraints[largeVideoParticipantId] = { 'maxHeight': quality };
|
||||
receiverConstraints.onStageEndpoints = [ largeVideoParticipantId ];
|
||||
if (preferredVideoQuality < MAX_VIDEO_QUALITY
|
||||
|| !remoteScreenShares.find(id => id === largeVideoParticipantId)) {
|
||||
quality = maxFrameHeightForLargeVideo;
|
||||
}
|
||||
receiverConstraints.constraints[largeVideoSourceName] = { 'maxHeight': quality };
|
||||
receiverConstraints[sourceNameSignaling ? 'onStageSources' : 'onStageEndpoints']
|
||||
= [ largeVideoSourceName ];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue