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 { isTestModeEnabled } from '../../../react/features/base/testing';
|
||||||
import { FILMSTRIP_BREAKPOINT } from '../../../react/features/filmstrip';
|
import { FILMSTRIP_BREAKPOINT } from '../../../react/features/filmstrip';
|
||||||
import { ORIENTATION, LargeVideoBackground, updateLastLargeVideoMediaEvent } from '../../../react/features/large-video';
|
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';
|
import { LAYOUTS, getCurrentLayout } from '../../../react/features/video-layout';
|
||||||
/* eslint-enable no-unused-vars */
|
/* eslint-enable no-unused-vars */
|
||||||
import UIUtil from '../util/UIUtil';
|
import UIUtil from '../util/UIUtil';
|
||||||
|
@ -446,6 +447,8 @@ export class VideoContainer extends LargeContainer {
|
||||||
const { horizontalIndent, verticalIndent }
|
const { horizontalIndent, verticalIndent }
|
||||||
= this.getVideoPosition(width, height, containerWidth, containerHeight, verticalFilmstripWidth);
|
= this.getVideoPosition(width, height, containerWidth, containerHeight, verticalFilmstripWidth);
|
||||||
|
|
||||||
|
APP.store.dispatch(setLargeVideoDimensions(height, width));
|
||||||
|
|
||||||
this.$wrapper.animate({
|
this.$wrapper.animate({
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { getCurrentLayout, LAYOUTS } from '../../../video-layout';
|
||||||
import {
|
import {
|
||||||
FILMSTRIP_TYPE
|
FILMSTRIP_TYPE
|
||||||
} from '../../constants';
|
} from '../../constants';
|
||||||
|
import { getScreenshareFilmstripParticipantId } from '../../functions';
|
||||||
|
|
||||||
import Filmstrip from './Filmstrip';
|
import Filmstrip from './Filmstrip';
|
||||||
|
|
||||||
|
@ -105,15 +106,9 @@ function _mapStateToProps(state) {
|
||||||
filmstripHeight,
|
filmstripHeight,
|
||||||
filmstripWidth,
|
filmstripWidth,
|
||||||
thumbnailSize
|
thumbnailSize
|
||||||
},
|
}
|
||||||
screenshareFilmstripParticipantId
|
|
||||||
} = state['features/filmstrip'];
|
} = state['features/filmstrip'];
|
||||||
const screenshares = state['features/video-layout'].remoteScreenShares;
|
const id = getScreenshareFilmstripParticipantId(state);
|
||||||
let id = screenshares.find(sId => sId === screenshareFilmstripParticipantId);
|
|
||||||
|
|
||||||
if (!id && screenshares.length) {
|
|
||||||
id = screenshares[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_columns: 1,
|
_columns: 1,
|
||||||
|
|
|
@ -71,6 +71,15 @@ export function shouldRemoteVideosBeVisible(state: Object) {
|
||||||
|| disable1On1Mode);
|
|| disable1On1Mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not implemented on mobile.
|
||||||
|
*
|
||||||
|
* @returns {Array<string>}
|
||||||
|
*/
|
||||||
|
export function getActiveParticipantsIds() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of participants displayed in tile view.
|
* Returns the number of participants displayed in tile view.
|
||||||
*
|
*
|
||||||
|
@ -169,6 +178,16 @@ export function isStageFilmstripEnabled() {
|
||||||
return false;
|
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.
|
* 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';
|
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.
|
* Whether or not the top panel is enabled.
|
||||||
*
|
*
|
||||||
|
|
|
@ -9,6 +9,17 @@
|
||||||
export const SELECT_LARGE_VIDEO_PARTICIPANT
|
export const SELECT_LARGE_VIDEO_PARTICIPANT
|
||||||
= '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.
|
* Action to update the redux store with the current resolution of large video.
|
||||||
*
|
*
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { isStageFilmstripAvailable } from '../filmstrip/functions';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
SELECT_LARGE_VIDEO_PARTICIPANT,
|
SELECT_LARGE_VIDEO_PARTICIPANT,
|
||||||
|
SET_LARGE_VIDEO_DIMENSIONS,
|
||||||
UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION
|
UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION
|
||||||
} from './actionTypes';
|
} 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.
|
* Returns the most recent existing remote video track.
|
||||||
*
|
*
|
||||||
|
|
|
@ -3,6 +3,7 @@ import ReducerRegistry from '../base/redux/ReducerRegistry';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
SELECT_LARGE_VIDEO_PARTICIPANT,
|
SELECT_LARGE_VIDEO_PARTICIPANT,
|
||||||
|
SET_LARGE_VIDEO_DIMENSIONS,
|
||||||
UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION,
|
UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION,
|
||||||
UPDATE_LAST_LARGE_VIDEO_MEDIA_EVENT,
|
UPDATE_LAST_LARGE_VIDEO_MEDIA_EVENT,
|
||||||
SET_SEE_WHAT_IS_BEING_SHARED
|
SET_SEE_WHAT_IS_BEING_SHARED
|
||||||
|
@ -38,6 +39,13 @@ ReducerRegistry.register('features/large-video', (state: ILargeVideoState = {},
|
||||||
participantId: action.participantId
|
participantId: action.participantId
|
||||||
};
|
};
|
||||||
|
|
||||||
|
case SET_LARGE_VIDEO_DIMENSIONS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
height: action.height,
|
||||||
|
width: action.width
|
||||||
|
};
|
||||||
|
|
||||||
case UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION:
|
case UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|
|
@ -10,6 +10,8 @@ import {
|
||||||
import { isStageFilmstripAvailable } from '../filmstrip/functions';
|
import { isStageFilmstripAvailable } from '../filmstrip/functions';
|
||||||
import { isVideoPlaying } from '../shared-video/functions';
|
import { isVideoPlaying } from '../shared-video/functions';
|
||||||
import { VIDEO_QUALITY_LEVELS } from '../video-quality/constants';
|
import { VIDEO_QUALITY_LEVELS } from '../video-quality/constants';
|
||||||
|
import { getReceiverVideoQualityLevel } from '../video-quality/functions';
|
||||||
|
import { getMinHeightForQualityLvlMap } from '../video-quality/selector';
|
||||||
|
|
||||||
import { LAYOUTS } from './constants';
|
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.
|
* @param {number|undefined} height - Height of the video container.
|
||||||
* @returns {number}
|
* @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.
|
* @param {Object} state - Redux state.
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
export function getVideoQualityForResizableFilmstripThumbnails(state) {
|
export function getVideoQualityForResizableFilmstripThumbnails(height, state) {
|
||||||
const height = state['features/filmstrip'].verticalViewDimensions?.gridView?.thumbnailSize?.height;
|
if (!height) {
|
||||||
|
return VIDEO_QUALITY_LEVELS.LOW;
|
||||||
|
}
|
||||||
|
|
||||||
return getVideoQualityForHeight(height);
|
return getReceiverVideoQualityLevel(height, getMinHeightForQualityLvlMap(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the video quality for the large video.
|
* Returns the video quality level for the screen sharing filmstrip thumbnail height.
|
||||||
*
|
|
||||||
* @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.
|
|
||||||
*
|
*
|
||||||
|
* @param {number} height - The height of the thumbnail.
|
||||||
* @param {Object} state - Redux state.
|
* @param {Object} state - Redux state.
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
export function getVideoQualityForStageThumbnails(state) {
|
export function getVideoQualityForScreenSharingFilmstrip(height, state) {
|
||||||
const height = state['features/filmstrip'].stageFilmstripDimensions?.thumbnailSize?.height;
|
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 { MEDIA_TYPE, setVideoMuted, VIDEO_MUTISM_AUTHORITY } from '../base/media';
|
||||||
import { MiddlewareRegistry } from '../base/redux';
|
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 { SET_CAR_MODE } from './actionTypes';
|
||||||
import './middleware.any';
|
import './middleware.any';
|
||||||
|
@ -18,6 +20,13 @@ MiddlewareRegistry.register(store => next => action => {
|
||||||
case SET_CAR_MODE:
|
case SET_CAR_MODE:
|
||||||
dispatch(setVideoMuted(action.enabled, MEDIA_TYPE.VIDEO, VIDEO_MUTISM_AUTHORITY.CAR_MODE));
|
dispatch(setVideoMuted(action.enabled, MEDIA_TYPE.VIDEO, VIDEO_MUTISM_AUTHORITY.CAR_MODE));
|
||||||
break;
|
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;
|
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
|
* The type of (redux) action which sets the preferred maximum video height that
|
||||||
* should be sent to and received from remote participants.
|
* should be sent to and received from remote participants.
|
||||||
|
@ -7,17 +69,4 @@
|
||||||
* preferredVideoQuality: number
|
* preferredVideoQuality: number
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
export const SET_PREFERRED_VIDEO_QUALITY = 'SET_PREFERRED_VIDEO_QUALITY';
|
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';
|
|
|
@ -2,10 +2,102 @@
|
||||||
|
|
||||||
import type { Dispatch } from 'redux';
|
import type { Dispatch } from 'redux';
|
||||||
|
|
||||||
import { SET_MAX_RECEIVER_VIDEO_QUALITY, SET_PREFERRED_VIDEO_QUALITY } from './actionTypes';
|
import {
|
||||||
import { VIDEO_QUALITY_LEVELS } from './constants';
|
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';
|
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
|
* Sets the max frame height the user prefers to send and receive from the
|
||||||
* remote participants.
|
* 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
|
* Sets the maximum video size the local participant should send and receive from
|
||||||
* remote participants.
|
* remote participants.
|
||||||
|
@ -58,6 +132,6 @@ export function setVideoQuality(frameHeight: number) {
|
||||||
return;
|
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
|
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
|
* Maps quality level names used in the config.videoQuality.minHeightForQualityLvl to the quality level constants used
|
||||||
* by the application.
|
* by the application.
|
||||||
|
@ -28,5 +38,6 @@ export const VIDEO_QUALITY_LEVELS = {
|
||||||
export const CFG_LVL_TO_APP_QUALITY_LVL = {
|
export const CFG_LVL_TO_APP_QUALITY_LVL = {
|
||||||
'low': VIDEO_QUALITY_LEVELS.LOW,
|
'low': VIDEO_QUALITY_LEVELS.LOW,
|
||||||
'standard': VIDEO_QUALITY_LEVELS.STANDARD,
|
'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';
|
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.
|
* 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
|
* @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.
|
* {@code undefined} if the map contains invalid values.
|
||||||
*/
|
*/
|
||||||
export function validateMinHeightForQualityLvl(minHeightForQualityLvl: Object): ?Map<number, number> {
|
export function validateMinHeightForQualityLvl(minHeightForQualityLvl) {
|
||||||
if (typeof minHeightForQualityLvl !== 'object'
|
if (typeof minHeightForQualityLvl !== 'object'
|
||||||
|| Object.keys(minHeightForQualityLvl).map(lvl => Number(lvl))
|
|| Object.keys(minHeightForQualityLvl).map(lvl => Number(lvl))
|
||||||
.find(lvl => lvl === null || isNaN(lvl) || lvl < 0)) {
|
.find(lvl => lvl === null || isNaN(lvl) || lvl < 0)) {
|
||||||
|
@ -65,6 +42,13 @@ export function validateMinHeightForQualityLvl(minHeightForQualityLvl: Object):
|
||||||
.sort((a, b) => a - b);
|
.sort((a, b) => a - b);
|
||||||
const map = new Map();
|
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) {
|
for (const level of levelsSorted) {
|
||||||
const configQuality = minHeightForQualityLvl[level];
|
const configQuality = minHeightForQualityLvl[level];
|
||||||
const appQuality = CFG_LVL_TO_APP_QUALITY_LVL[configQuality];
|
const appQuality = CFG_LVL_TO_APP_QUALITY_LVL[configQuality];
|
||||||
|
@ -73,6 +57,7 @@ export function validateMinHeightForQualityLvl(minHeightForQualityLvl: Object):
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
map.delete(appQuality);
|
||||||
map.set(level, appQuality);
|
map.set(level, appQuality);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,14 @@ import PersistenceRegistry from '../base/redux/PersistenceRegistry';
|
||||||
import ReducerRegistry from '../base/redux/ReducerRegistry';
|
import ReducerRegistry from '../base/redux/ReducerRegistry';
|
||||||
import { set } from '../base/redux/functions';
|
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';
|
import { VIDEO_QUALITY_LEVELS } from './constants';
|
||||||
/* eslint-disable-next-line lines-around-comment */
|
/* eslint-disable-next-line lines-around-comment */
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
@ -12,16 +19,29 @@ import { validateMinHeightForQualityLvl } from './functions';
|
||||||
import logger from './logger';
|
import logger from './logger';
|
||||||
|
|
||||||
const DEFAULT_STATE = {
|
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(),
|
minHeightForQualityLvl: new Map(),
|
||||||
preferredVideoQuality: VIDEO_QUALITY_LEVELS.ULTRA
|
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 {
|
export interface IVideoQualityState {
|
||||||
maxReceiverVideoQuality: number;
|
maxReceiverVideoQualityForLargeVideo: number,
|
||||||
|
maxReceiverVideoQualityForScreenSharingFilmstrip: number,
|
||||||
|
maxReceiverVideoQualityForStageFilmstrip: number,
|
||||||
|
maxReceiverVideoQualityForTileView: number,
|
||||||
|
maxReceiverVideoQualityForVerticalFilmstrip: number,
|
||||||
minHeightForQualityLvl: Map<number, number>;
|
minHeightForQualityLvl: Map<number, number>;
|
||||||
preferredVideoQuality: number;
|
preferredVideoQuality: number;
|
||||||
}
|
}
|
||||||
|
@ -56,10 +76,28 @@ ReducerRegistry.register('features/video-quality',
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case SET_CONFIG:
|
case SET_CONFIG:
|
||||||
return _setConfig(state, action);
|
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(
|
return set(
|
||||||
state,
|
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);
|
action.maxReceiverVideoQuality);
|
||||||
case SET_PREFERRED_VIDEO_QUALITY: {
|
case SET_PREFERRED_VIDEO_QUALITY: {
|
||||||
const { preferredVideoQuality } = action;
|
const { preferredVideoQuality } = action;
|
||||||
|
|
|
@ -1,30 +1,40 @@
|
||||||
// @flow
|
/* global APP */
|
||||||
|
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
|
|
||||||
import { _handleParticipantError } from '../base/conference';
|
import { _handleParticipantError } from '../base/conference';
|
||||||
import { getSourceNameSignalingFeatureFlag } from '../base/config';
|
import { getSourceNameSignalingFeatureFlag } from '../base/config';
|
||||||
import { MEDIA_TYPE } from '../base/media';
|
import { MEDIA_TYPE } from '../base/media';
|
||||||
import { getLocalParticipant, getParticipantCount } from '../base/participants';
|
import { getLocalParticipant } from '../base/participants';
|
||||||
import { StateListenerRegistry } from '../base/redux';
|
import { StateListenerRegistry } from '../base/redux';
|
||||||
import { getRemoteScreenSharesSourceNames, getTrackSourceNameByMediaTypeAndParticipant } from '../base/tracks';
|
import { getRemoteScreenSharesSourceNames, getTrackSourceNameByMediaTypeAndParticipant } from '../base/tracks';
|
||||||
import { reportError } from '../base/util';
|
import { reportError } from '../base/util';
|
||||||
import { getActiveParticipantsIds } from '../filmstrip/functions.web';
|
import {
|
||||||
|
getActiveParticipantsIds,
|
||||||
|
getScreenshareFilmstripParticipantId,
|
||||||
|
isTopPanelEnabled
|
||||||
|
} from '../filmstrip/functions';
|
||||||
import {
|
import {
|
||||||
getVideoQualityForLargeVideo,
|
getVideoQualityForLargeVideo,
|
||||||
getVideoQualityForResizableFilmstripThumbnails,
|
getVideoQualityForResizableFilmstripThumbnails,
|
||||||
getVideoQualityForStageThumbnails,
|
getVideoQualityForStageThumbnails,
|
||||||
|
LAYOUTS,
|
||||||
shouldDisplayTileView
|
shouldDisplayTileView
|
||||||
} from '../video-layout';
|
} from '../video-layout';
|
||||||
|
import { getCurrentLayout, getVideoQualityForScreenSharingFilmstrip } from '../video-layout/functions.any';
|
||||||
|
|
||||||
import { setMaxReceiverVideoQuality } from './actions';
|
import {
|
||||||
import { VIDEO_QUALITY_LEVELS } from './constants';
|
setMaxReceiverVideoQualityForLargeVideo,
|
||||||
|
setMaxReceiverVideoQualityForScreenSharingFilmstrip,
|
||||||
|
setMaxReceiverVideoQualityForStageFilmstrip,
|
||||||
|
setMaxReceiverVideoQualityForTileView,
|
||||||
|
setMaxReceiverVideoQualityForVerticalFilmstrip
|
||||||
|
} from './actions';
|
||||||
|
import { MAX_VIDEO_QUALITY, VIDEO_QUALITY_LEVELS, VIDEO_QUALITY_UNLIMITED } from './constants';
|
||||||
import { getReceiverVideoQualityLevel } from './functions';
|
import { getReceiverVideoQualityLevel } from './functions';
|
||||||
import logger from './logger';
|
import logger from './logger';
|
||||||
import { getMinHeightForQualityLvlMap } from './selector';
|
import { getMinHeightForQualityLvlMap } from './selector';
|
||||||
|
|
||||||
declare var APP: Object;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles changes in the visible participants in the filmstrip. The listener is debounced
|
* 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
|
* 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
|
* StateListenerRegistry provides a reliable way of detecting changes to
|
||||||
* lastn state and dispatching additional actions.
|
* lastn state and dispatching additional actions.
|
||||||
|
@ -84,26 +83,6 @@ StateListenerRegistry.register(
|
||||||
_updateReceiverVideoConstraints(store);
|
_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.
|
* Updates the receiver constraints when the stage participants change.
|
||||||
*/
|
*/
|
||||||
|
@ -118,30 +97,37 @@ StateListenerRegistry.register(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* StateListenerRegistry provides a reliable way of detecting changes to
|
* 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(
|
StateListenerRegistry.register(
|
||||||
/* selector */ state => {
|
/* selector */ state => {
|
||||||
const {
|
const {
|
||||||
maxReceiverVideoQuality,
|
maxReceiverVideoQualityForLargeVideo,
|
||||||
|
maxReceiverVideoQualityForScreenSharingFilmstrip,
|
||||||
|
maxReceiverVideoQualityForStageFilmstrip,
|
||||||
|
maxReceiverVideoQualityForTileView,
|
||||||
|
maxReceiverVideoQualityForVerticalFilmstrip,
|
||||||
preferredVideoQuality
|
preferredVideoQuality
|
||||||
} = state['features/video-quality'];
|
} = state['features/video-quality'];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
maxReceiverVideoQuality,
|
maxReceiverVideoQualityForLargeVideo,
|
||||||
|
maxReceiverVideoQualityForScreenSharingFilmstrip,
|
||||||
|
maxReceiverVideoQualityForStageFilmstrip,
|
||||||
|
maxReceiverVideoQualityForTileView,
|
||||||
|
maxReceiverVideoQualityForVerticalFilmstrip,
|
||||||
preferredVideoQuality
|
preferredVideoQuality
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
/* listener */ (currentState, store, previousState = {}) => {
|
/* listener */ (currentState, store, previousState = {}) => {
|
||||||
const { maxReceiverVideoQuality, preferredVideoQuality } = currentState;
|
const { preferredVideoQuality } = currentState;
|
||||||
const changedPreferredVideoQuality = preferredVideoQuality !== previousState.preferredVideoQuality;
|
const changedPreferredVideoQuality = preferredVideoQuality !== previousState.preferredVideoQuality;
|
||||||
const changedReceiverVideoQuality = maxReceiverVideoQuality !== previousState.maxReceiverVideoQuality;
|
|
||||||
|
|
||||||
if (changedPreferredVideoQuality) {
|
if (changedPreferredVideoQuality) {
|
||||||
_setSenderVideoConstraint(preferredVideoQuality, store);
|
_setSenderVideoConstraint(preferredVideoQuality, store);
|
||||||
typeof APP !== 'undefined' && APP.API.notifyVideoQualityChanged(preferredVideoQuality);
|
typeof APP !== 'undefined' && APP.API.notifyVideoQualityChanged(preferredVideoQuality);
|
||||||
}
|
}
|
||||||
changedReceiverVideoQuality && _updateReceiverVideoConstraints(store);
|
_updateReceiverVideoConstraints(store);
|
||||||
}, {
|
}, {
|
||||||
deepEquals: true
|
deepEquals: true
|
||||||
});
|
});
|
||||||
|
@ -153,48 +139,158 @@ StateListenerRegistry.register(
|
||||||
/* selector */ state => {
|
/* selector */ state => {
|
||||||
const { reducedUI } = state['features/base/responsive-ui'];
|
const { reducedUI } = state['features/base/responsive-ui'];
|
||||||
const _shouldDisplayTileView = shouldDisplayTileView(state);
|
const _shouldDisplayTileView = shouldDisplayTileView(state);
|
||||||
const thumbnailSize = state['features/filmstrip']?.tileViewDimensions?.thumbnailSize;
|
const tileViewThumbnailSize = state['features/filmstrip']?.tileViewDimensions?.thumbnailSize;
|
||||||
const participantCount = getParticipantCount(state);
|
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 {
|
return {
|
||||||
|
activeParticipantsCount: activeParticipantsIds?.length,
|
||||||
displayTileView: _shouldDisplayTileView,
|
displayTileView: _shouldDisplayTileView,
|
||||||
participantCount,
|
largeVideoHeight,
|
||||||
|
participantCount: visibleRemoteParticipants?.size || 0,
|
||||||
reducedUI,
|
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 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'];
|
const { maxFullResolutionParticipants = 2 } = state['features/base/config'];
|
||||||
|
let maxVideoQualityChanged = false;
|
||||||
|
|
||||||
let newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.ULTRA;
|
|
||||||
|
|
||||||
if (reducedUI) {
|
if (displayTileView) {
|
||||||
newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.LOW;
|
let newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.STANDARD;
|
||||||
} else if (displayTileView && !Number.isNaN(thumbnailHeight)) {
|
|
||||||
newMaxRecvVideoQuality = getReceiverVideoQualityLevel(thumbnailHeight, getMinHeightForQualityLvlMap(state));
|
|
||||||
|
|
||||||
// Override HD level calculated for the thumbnail height when # of participants threshold is exceeded
|
if (reducedUI) {
|
||||||
if (maxReceiverVideoQuality !== newMaxRecvVideoQuality && maxFullResolutionParticipants !== -1) {
|
newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.LOW;
|
||||||
const override
|
} else if (typeof tileViewThumbnailHeight === 'number' && !Number.isNaN(tileViewThumbnailHeight)) {
|
||||||
= participantCount > maxFullResolutionParticipants
|
newMaxRecvVideoQuality
|
||||||
&& newMaxRecvVideoQuality > VIDEO_QUALITY_LEVELS.STANDARD;
|
= getReceiverVideoQualityLevel(tileViewThumbnailHeight, getMinHeightForQualityLvlMap(state));
|
||||||
|
|
||||||
logger.info(`Video quality level for thumbnail height: ${thumbnailHeight}, `
|
// Override HD level calculated for the thumbnail height when # of participants threshold is exceeded
|
||||||
+ `is: ${newMaxRecvVideoQuality}, `
|
if (maxFullResolutionParticipants !== -1) {
|
||||||
+ `override: ${String(override)}, `
|
const override
|
||||||
+ `max full res N: ${maxFullResolutionParticipants}`);
|
= participantCount > maxFullResolutionParticipants
|
||||||
|
&& newMaxRecvVideoQuality > VIDEO_QUALITY_LEVELS.STANDARD;
|
||||||
|
|
||||||
if (override) {
|
logger.info(`Video quality level for thumbnail height: ${tileViewThumbnailHeight}, `
|
||||||
newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.STANDARD;
|
+ `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) {
|
if (!maxVideoQualityChanged && Boolean(displayTileView) !== Boolean(previousState.displayTileView)) {
|
||||||
dispatch(setMaxReceiverVideoQuality(newMaxRecvVideoQuality));
|
_updateReceiverVideoConstraints(store);
|
||||||
}
|
}
|
||||||
|
|
||||||
}, {
|
}, {
|
||||||
deepEquals: true
|
deepEquals: true
|
||||||
});
|
});
|
||||||
|
@ -235,31 +331,47 @@ function _updateReceiverVideoConstraints({ getState }) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { lastN } = state['features/base/lastn'];
|
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 { 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 { remoteScreenShares } = state['features/video-layout'];
|
||||||
const { visibleRemoteParticipants } = state['features/filmstrip'];
|
const { visibleRemoteParticipants } = state['features/filmstrip'];
|
||||||
const tracks = state['features/base/tracks'];
|
const tracks = state['features/base/tracks'];
|
||||||
const sourceNameSignaling = getSourceNameSignalingFeatureFlag(state);
|
const sourceNameSignaling = getSourceNameSignalingFeatureFlag(state);
|
||||||
const localParticipantId = getLocalParticipant(state).id;
|
const localParticipantId = getLocalParticipant(state).id;
|
||||||
const activeParticipantsIds = getActiveParticipantsIds(state);
|
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) {
|
if (sourceNameSignaling) {
|
||||||
const remoteScreenSharesSourceNames = getRemoteScreenSharesSourceNames(state, remoteScreenShares);
|
receiverConstraints.onStageSources = [];
|
||||||
|
receiverConstraints.selectedSources = [];
|
||||||
|
|
||||||
receiverConstraints = {
|
remoteScreenSharesSourceNames = getRemoteScreenSharesSourceNames(state, remoteScreenShares);
|
||||||
constraints: {},
|
|
||||||
defaultConstraints: { 'maxHeight': VIDEO_QUALITY_LEVELS.NONE },
|
|
||||||
lastN,
|
|
||||||
onStageSources: [],
|
|
||||||
selectedSources: []
|
|
||||||
};
|
|
||||||
const visibleRemoteTrackSourceNames = [];
|
|
||||||
let largeVideoSourceName;
|
|
||||||
const activeParticipantsSources = [];
|
|
||||||
|
|
||||||
if (visibleRemoteParticipants?.size) {
|
if (visibleRemoteParticipants?.size) {
|
||||||
visibleRemoteParticipants.forEach(participantId => {
|
visibleRemoteParticipants.forEach(participantId => {
|
||||||
|
@ -273,13 +385,27 @@ function _updateReceiverVideoConstraints({ getState }) {
|
||||||
|
|
||||||
if (sourceName) {
|
if (sourceName) {
|
||||||
visibleRemoteTrackSourceNames.push(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 (localParticipantId !== largeVideoParticipantId) {
|
||||||
if (remoteScreenSharesSourceNames.includes(largeVideoParticipantId)) {
|
if (remoteScreenSharesSourceNames.includes(largeVideoParticipantId)) {
|
||||||
largeVideoSourceName = 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 {
|
} else {
|
||||||
receiverConstraints = {
|
receiverConstraints.onStageEndpoints = [];
|
||||||
constraints: {},
|
receiverConstraints.selectedEndpoints = [];
|
||||||
defaultConstraints: { 'maxHeight': VIDEO_QUALITY_LEVELS.NONE },
|
|
||||||
lastN,
|
|
||||||
onStageEndpoints: [],
|
|
||||||
selectedEndpoints: []
|
|
||||||
};
|
|
||||||
|
|
||||||
// Tile view.
|
remoteScreenSharesSourceNames = remoteScreenShares;
|
||||||
if (shouldDisplayTileView(state)) {
|
visibleRemoteTrackSourceNames = [ ...visibleRemoteParticipants ];
|
||||||
if (!visibleRemoteParticipants?.size) {
|
largeVideoSourceName = largeVideoParticipantId;
|
||||||
return;
|
activeParticipantsSources = activeParticipantsIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
visibleRemoteParticipants.forEach(participantId => {
|
// Tile view.
|
||||||
receiverConstraints.constraints[participantId] = { 'maxHeight': maxFrameHeight };
|
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.
|
if (screenshareFilmstripParticipantId) {
|
||||||
remoteScreenShares?.length && (receiverConstraints.selectedEndpoints = remoteScreenShares);
|
onStageSources.push(screenshareFilmstripParticipantId);
|
||||||
|
receiverConstraints.constraints[screenshareFilmstripParticipantId]
|
||||||
// Stage view.
|
= {
|
||||||
} else {
|
'maxHeight':
|
||||||
if (!visibleRemoteParticipants?.size && !largeVideoParticipantId) {
|
preferredVideoQuality >= MAX_VIDEO_QUALITY
|
||||||
return;
|
? VIDEO_QUALITY_UNLIMITED : maxFrameHeightForScreenSharingFilmstrip
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (visibleRemoteParticipants?.size > 0) {
|
receiverConstraints[sourceNameSignaling ? 'onStageSources' : 'onStageEndpoints'] = onStageSources;
|
||||||
const qualityLevel = getVideoQualityForResizableFilmstripThumbnails(state);
|
} else if (largeVideoSourceName) {
|
||||||
const stageParticipantsLevel = getVideoQualityForStageThumbnails(state);
|
let quality = VIDEO_QUALITY_UNLIMITED;
|
||||||
|
|
||||||
visibleRemoteParticipants.forEach(participantId => {
|
if (preferredVideoQuality < MAX_VIDEO_QUALITY
|
||||||
const isStageParticipant = activeParticipantsIds.find(id => id === participantId);
|
|| !remoteScreenShares.find(id => id === largeVideoParticipantId)) {
|
||||||
const quality = Math.min(maxFrameHeight, isStageParticipant
|
quality = maxFrameHeightForLargeVideo;
|
||||||
? 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 ];
|
|
||||||
}
|
}
|
||||||
|
receiverConstraints.constraints[largeVideoSourceName] = { 'maxHeight': quality };
|
||||||
|
receiverConstraints[sourceNameSignaling ? 'onStageSources' : 'onStageEndpoints']
|
||||||
|
= [ largeVideoSourceName ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue