ref(video-quality): Move all related code.

This commit is contained in:
Hristo Terezov 2020-09-01 14:19:04 -05:00
parent 651d713206
commit b02d96231c
15 changed files with 213 additions and 204 deletions

View File

@ -163,19 +163,6 @@ export const SET_DESKTOP_SHARING_ENABLED
*/
export const SET_FOLLOW_ME = 'SET_FOLLOW_ME';
/**
* 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';
/**
* The type of (redux) action which sets the password to join or lock a specific
* {@code JitsiConference}.
@ -210,17 +197,6 @@ export const SET_PASSWORD_FAILED = 'SET_PASSWORD_FAILED';
*/
export const SET_PENDING_SUBJECT_CHANGE = 'SET_PENDING_SUBJECT_CHANGE';
/**
* The type of (redux) action which sets the preferred maximum video height that
* should be sent to and received from remote participants.
*
* {
* type: SET_PREFERRED_VIDEO_QUALITY,
* preferredVideoQuality: number
* }
*/
export const SET_PREFERRED_VIDEO_QUALITY = 'SET_PREFERRED_VIDEO_QUALITY';
/**
* The type of (redux) action which sets the name of the room of the
* conference to be joined.

View File

@ -45,10 +45,8 @@ import {
SEND_TONES,
SET_DESKTOP_SHARING_ENABLED,
SET_FOLLOW_ME,
SET_MAX_RECEIVER_VIDEO_QUALITY,
SET_PASSWORD,
SET_PASSWORD_FAILED,
SET_PREFERRED_VIDEO_QUALITY,
SET_ROOM,
SET_PENDING_SUBJECT_CHANGE,
SET_START_MUTED_POLICY
@ -615,23 +613,6 @@ export function setFollowMe(enabled: boolean) {
};
}
/**
* 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 password to join or lock a specific JitsiConference.
*
@ -698,24 +679,6 @@ export function setPassword(
};
}
/**
* Sets the max frame height the user prefers to send and receive from the
* remote participants.
*
* @param {number} preferredVideoQuality - The max video resolution to send and
* receive.
* @returns {{
* type: SET_PREFERRED_VIDEO_QUALITY,
* preferredVideoQuality: number
* }}
*/
export function setPreferredVideoQuality(preferredVideoQuality: number) {
return {
type: SET_PREFERRED_VIDEO_QUALITY,
preferredVideoQuality
};
}
/**
* Sets (the name of) the room of the conference to be joined.
*

View File

@ -34,15 +34,3 @@ export const EMAIL_COMMAND = 'email';
* from the outside is not cool but it should suffice for now.
*/
export const JITSI_CONFERENCE_URL_KEY = Symbol('url');
/**
* The supported remote video resolutions. The values are currently based on
* available simulcast layers.
*
* @type {object}
*/
export const VIDEO_QUALITY_LEVELS = {
HIGH: 720,
STANDARD: 360,
LOW: 180
};

View File

@ -20,7 +20,7 @@ import {
PARTICIPANT_UPDATED,
PIN_PARTICIPANT
} from '../participants';
import { MiddlewareRegistry, StateListenerRegistry } from '../redux';
import { MiddlewareRegistry } from '../redux';
import { TRACK_ADDED, TRACK_REMOVED } from '../tracks';
import {
@ -28,7 +28,6 @@ import {
CONFERENCE_JOINED,
CONFERENCE_SUBJECT_CHANGED,
CONFERENCE_WILL_LEAVE,
DATA_CHANNEL_OPENED,
SEND_TONES,
SET_PENDING_SUBJECT_CHANGE,
SET_ROOM
@ -81,9 +80,6 @@ MiddlewareRegistry.register(store => next => action => {
_conferenceWillLeave();
break;
case DATA_CHANNEL_OPENED:
return _syncReceiveVideoQuality(store, next, action);
case PARTICIPANT_UPDATED:
return _updateLocalParticipantInConference(store, next, action);
@ -104,31 +100,6 @@ MiddlewareRegistry.register(store => next => action => {
return next(action);
});
/**
* Registers a change handler for state['features/base/conference'] to update
* the preferred video quality levels based on user preferred and internal
* settings.
*/
StateListenerRegistry.register(
/* selector */ state => state['features/base/conference'],
/* listener */ (currentState, store, previousState = {}) => {
const {
conference,
maxReceiverVideoQuality,
preferredVideoQuality
} = currentState;
const changedConference = conference !== previousState.conference;
const changedPreferredVideoQuality
= preferredVideoQuality !== previousState.preferredVideoQuality;
const changedMaxVideoQuality = maxReceiverVideoQuality !== previousState.maxReceiverVideoQuality;
if (changedConference || changedPreferredVideoQuality || changedMaxVideoQuality) {
_setReceiverVideoConstraint(conference, preferredVideoQuality, maxReceiverVideoQuality);
}
if (changedConference || changedPreferredVideoQuality) {
_setSenderVideoConstraint(conference, preferredVideoQuality);
}
});
/**
* Makes sure to leave a failed conference in order to release any allocated
@ -448,44 +419,6 @@ function _sendTones({ getState }, next, action) {
return next(action);
}
/**
* Helper function for updating the preferred receiver video constraint, based
* on the user preference and the internal maximum.
*
* @param {JitsiConference} conference - The JitsiConference instance for the
* current call.
* @param {number} preferred - The user preferred max frame height.
* @param {number} max - The maximum frame height the application should
* receive.
* @returns {void}
*/
function _setReceiverVideoConstraint(conference, preferred, max) {
if (conference) {
const value = Math.min(preferred, max);
conference.setReceiverVideoConstraint(value);
logger.info(`setReceiverVideoConstraint: ${value}`);
}
}
/**
* Helper function for updating the preferred sender video constraint, based
* on the user preference.
*
* @param {JitsiConference} conference - The JitsiConference instance for the
* current call.
* @param {number} preferred - The user preferred max frame height.
* @returns {void}
*/
function _setSenderVideoConstraint(conference, preferred) {
if (conference) {
conference.setSenderVideoConstraint(preferred)
.catch(err => {
logger.error(`Changing sender resolution to ${preferred} failed - ${err} `);
});
}
}
/**
* Notifies the feature base/conference that the action
* {@code SET_ROOM} is being dispatched within a specific
@ -539,33 +472,6 @@ function _syncConferenceLocalTracksWithState({ getState }, action) {
return promise || Promise.resolve();
}
/**
* Sets the maximum receive video quality.
*
* @param {Store} store - The redux store in which the specified {@code action}
* is being dispatched.
* @param {Dispatch} next - The redux {@code dispatch} function to dispatch the
* specified {@code action} to the specified {@code store}.
* @param {Action} action - The redux action {@code DATA_CHANNEL_STATUS_CHANGED}
* which is being dispatched in the specified {@code store}.
* @private
* @returns {Object} The value returned by {@code next(action)}.
*/
function _syncReceiveVideoQuality({ getState }, next, action) {
const {
conference,
maxReceiverVideoQuality,
preferredVideoQuality
} = getState()['features/base/conference'];
_setReceiverVideoConstraint(
conference,
preferredVideoQuality,
maxReceiverVideoQuality);
return next(action);
}
/**
* Notifies the feature base/conference that the action {@code TRACK_ADDED}
* or {@code TRACK_REMOVED} is being dispatched within a specific redux store.

View File

@ -18,15 +18,12 @@ import {
P2P_STATUS_CHANGED,
SET_DESKTOP_SHARING_ENABLED,
SET_FOLLOW_ME,
SET_MAX_RECEIVER_VIDEO_QUALITY,
SET_PASSWORD,
SET_PENDING_SUBJECT_CHANGE,
SET_PREFERRED_VIDEO_QUALITY,
SET_ROOM,
SET_SIP_GATEWAY_ENABLED,
SET_START_MUTED_POLICY
} from './actionTypes';
import { VIDEO_QUALITY_LEVELS } from './constants';
import { isRoomValid } from './functions';
const DEFAULT_STATE = {
@ -35,11 +32,9 @@ const DEFAULT_STATE = {
joining: undefined,
leaving: undefined,
locked: undefined,
maxReceiverVideoQuality: VIDEO_QUALITY_LEVELS.HIGH,
membersOnly: undefined,
password: undefined,
passwordRequired: undefined,
preferredVideoQuality: VIDEO_QUALITY_LEVELS.HIGH
passwordRequired: undefined
};
/**
@ -90,24 +85,12 @@ ReducerRegistry.register(
case SET_LOCATION_URL:
return set(state, 'room', undefined);
case SET_MAX_RECEIVER_VIDEO_QUALITY:
return set(
state,
'maxReceiverVideoQuality',
action.maxReceiverVideoQuality);
case SET_PASSWORD:
return _setPassword(state, action);
case SET_PENDING_SUBJECT_CHANGE:
return set(state, 'pendingSubjectChange', action.subject);
case SET_PREFERRED_VIDEO_QUALITY:
return set(
state,
'preferredVideoQuality',
action.preferredVideoQuality);
case SET_ROOM:
return _setRoom(state, action);

View File

@ -0,0 +1,23 @@
/**
* The type of (redux) action which sets the preferred maximum video height that
* should be sent to and received from remote participants.
*
* {
* type: SET_PREFERRED_VIDEO_QUALITY,
* 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';

View File

@ -2,10 +2,45 @@
import type { Dispatch } from 'redux';
import { VIDEO_QUALITY_LEVELS } from '../base/conference';
import { SET_MAX_RECEIVER_VIDEO_QUALITY, SET_PREFERRED_VIDEO_QUALITY } from './actionTypes';
import { VIDEO_QUALITY_LEVELS } from './constants';
import logger from './logger';
/**
* Sets the max frame height the user prefers to send and receive from the
* remote participants.
*
* @param {number} preferredVideoQuality - The max video resolution to send and
* receive.
* @returns {{
* type: SET_PREFERRED_VIDEO_QUALITY,
* preferredVideoQuality: number
* }}
*/
export function setPreferredVideoQuality(preferredVideoQuality: number) {
return {
type: SET_PREFERRED_VIDEO_QUALITY,
preferredVideoQuality
};
}
/**
* 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

View File

@ -2,7 +2,6 @@
import React, { Component } from 'react';
import { VIDEO_QUALITY_LEVELS } from '../../base/conference/constants';
import { translate } from '../../base/i18n';
import {
Icon,
@ -12,6 +11,7 @@ import {
IconVideoQualitySD
} from '../../base/icons';
import { connect } from '../../base/redux';
import { VIDEO_QUALITY_LEVELS } from '../constants';
/**
* A map of of selectable receive resolutions to corresponding icons.
@ -104,7 +104,7 @@ class OverflowMenuVideoQualityItem extends Component<Props> {
function _mapStateToProps(state) {
return {
_audioOnly: state['features/base/audio-only'].enabled,
_videoQuality: state['features/base/conference'].preferredVideoQuality
_videoQuality: state['features/video-quality'].preferredVideoQuality
};
}

View File

@ -6,10 +6,11 @@ import type { Dispatch } from 'redux';
import { createToolbarEvent, sendAnalytics } from '../../analytics';
import { setAudioOnly } from '../../base/audio-only';
import { VIDEO_QUALITY_LEVELS, setPreferredVideoQuality } from '../../base/conference';
import { translate } from '../../base/i18n';
import JitsiMeetJS from '../../base/lib-jitsi-meet';
import { connect } from '../../base/redux';
import { setPreferredVideoQuality } from '../actions';
import { VIDEO_QUALITY_LEVELS } from '../constants';
import logger from '../logger';
const {
@ -380,7 +381,8 @@ class VideoQualitySlider extends Component<Props> {
*/
function _mapStateToProps(state) {
const { enabled: audioOnly } = state['features/base/audio-only'];
const { p2p, preferredVideoQuality } = state['features/base/conference'];
const { p2p } = state['features/base/conference'];
const { preferredVideoQuality } = state['features/video-quality'];
return {
_audioOnly: audioOnly,

View File

@ -1,4 +1,14 @@
import { VIDEO_QUALITY_LEVELS } from '../base/conference';
/**
* The supported remote video resolutions. The values are currently based on
* available simulcast layers.
*
* @type {object}
*/
export const VIDEO_QUALITY_LEVELS = {
HIGH: 720,
STANDARD: 360,
LOW: 180
};
/**
* Maps quality level names used in the config.videoQuality.minHeightForQualityLvl to the quality level constants used

View File

@ -1,8 +1,6 @@
// @flow
import { VIDEO_QUALITY_LEVELS } from '../base/conference';
import { CFG_LVL_TO_APP_QUALITY_LVL } from './constants';
import { CFG_LVL_TO_APP_QUALITY_LVL, VIDEO_QUALITY_LEVELS } from './constants';
/**

View File

@ -1,4 +1,5 @@
export * from './components';
export * from './actions';
export * from './actionTypes';
import './reducer';

View File

@ -2,14 +2,14 @@
import {
CONFERENCE_JOINED,
VIDEO_QUALITY_LEVELS,
setMaxReceiverVideoQuality,
setPreferredVideoQuality
DATA_CHANNEL_OPENED
} from '../base/conference';
import { getParticipantCount } from '../base/participants';
import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
import { shouldDisplayTileView } from '../video-layout';
import { setPreferredVideoQuality, setMaxReceiverVideoQuality } from './actions';
import { VIDEO_QUALITY_LEVELS } from './constants';
import { getReceiverVideoQualityLevel } from './functions';
import logger from './logger';
import { getMinHeightForQualityLvlMap } from './selector';
@ -21,6 +21,10 @@ import { getMinHeightForQualityLvlMap } from './selector';
* @returns {Function}
*/
MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
if (action.type === DATA_CHANNEL_OPENED) {
return _syncReceiveVideoQuality(getState, next, action);
}
const result = next(action);
switch (action.type) {
@ -59,7 +63,7 @@ StateListenerRegistry.register(
},
/* listener */ ({ displayTileView, participantCount, reducedUI, thumbnailHeight }, { dispatch, getState }) => {
const state = getState();
const { maxReceiverVideoQuality } = state['features/base/conference'];
const { maxReceiverVideoQuality } = state['features/video-quality'];
const { maxFullResolutionParticipants = 2 } = state['features/base/config'];
let newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.HIGH;
@ -92,3 +96,108 @@ StateListenerRegistry.register(
}, {
deepEquals: true
});
/**
* Helper function for updating the preferred receiver video constraint, based
* on the user preference and the internal maximum.
*
* @param {JitsiConference} conference - The JitsiConference instance for the
* current call.
* @param {number} preferred - The user preferred max frame height.
* @param {number} max - The maximum frame height the application should
* receive.
* @returns {void}
*/
function _setReceiverVideoConstraint(conference, preferred, max) {
if (conference) {
const value = Math.min(preferred, max);
conference.setReceiverVideoConstraint(value);
logger.info(`setReceiverVideoConstraint: ${value}`);
}
}
/**
* Helper function for updating the preferred sender video constraint, based
* on the user preference.
*
* @param {JitsiConference} conference - The JitsiConference instance for the
* current call.
* @param {number} preferred - The user preferred max frame height.
* @returns {void}
*/
function _setSenderVideoConstraint(conference, preferred) {
if (conference) {
conference.setSenderVideoConstraint(preferred)
.catch(err => {
logger.error(`Changing sender resolution to ${preferred} failed - ${err} `);
});
}
}
/**
* Sets the maximum receive video quality.
*
* @param {Function} getState - The redux function which returns the current redux state.
* @param {Dispatch} next - The redux {@code dispatch} function to dispatch the
* specified {@code action} to the specified {@code store}.
* @param {Action} action - The redux action {@code DATA_CHANNEL_STATUS_CHANGED}
* which is being dispatched in the specified {@code store}.
* @private
* @returns {Object} The value returned by {@code next(action)}.
*/
function _syncReceiveVideoQuality(getState, next, action) {
const state = getState();
const {
conference
} = state['features/base/conference'];
const {
maxReceiverVideoQuality,
preferredVideoQuality
} = state['features/video-quality'];
_setReceiverVideoConstraint(
conference,
preferredVideoQuality,
maxReceiverVideoQuality);
return next(action);
}
/**
* Registers a change handler for state['features/base/conference'] to update
* the preferred video quality levels based on user preferred and internal
* settings.
*/
StateListenerRegistry.register(
/* selector */ state => {
const { conference } = state['features/base/conference'];
const {
maxReceiverVideoQuality,
preferredVideoQuality
} = state['features/video-quality'];
return {
conference,
maxReceiverVideoQuality,
preferredVideoQuality
};
},
/* listener */ (currentState, store, previousState = {}) => {
const {
conference,
maxReceiverVideoQuality,
preferredVideoQuality
} = currentState;
const changedConference = conference !== previousState.conference;
const changedPreferredVideoQuality = preferredVideoQuality !== previousState.preferredVideoQuality;
const changedMaxVideoQuality = maxReceiverVideoQuality !== previousState.maxReceiverVideoQuality;
if (changedConference || changedPreferredVideoQuality || changedMaxVideoQuality) {
_setReceiverVideoConstraint(conference, preferredVideoQuality, maxReceiverVideoQuality);
}
if (changedConference || changedPreferredVideoQuality) {
_setSenderVideoConstraint(conference, preferredVideoQuality);
}
});

View File

@ -1,21 +1,36 @@
import { VIDEO_QUALITY_LEVELS } from '../base/conference';
import { SET_CONFIG } from '../base/config';
import { ReducerRegistry, set } from '../base/redux';
import { SET_MAX_RECEIVER_VIDEO_QUALITY, SET_PREFERRED_VIDEO_QUALITY } from './actionTypes';
import { VIDEO_QUALITY_LEVELS } from './constants';
import { validateMinHeightForQualityLvl } from './functions';
import logger from './logger';
const STORE_NAME = 'features/video-quality';
const DEFAULT_STATE = {
minHeightForQualityLvl: new Map()
maxReceiverVideoQuality: VIDEO_QUALITY_LEVELS.HIGH,
minHeightForQualityLvl: new Map(),
preferredVideoQuality: VIDEO_QUALITY_LEVELS.HIGH
};
DEFAULT_STATE.minHeightForQualityLvl.set(360, VIDEO_QUALITY_LEVELS.STANDARD);
DEFAULT_STATE.minHeightForQualityLvl.set(720, VIDEO_QUALITY_LEVELS.HIGH);
ReducerRegistry.register('features/base/videoquality', (state = DEFAULT_STATE, action) => {
ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
switch (action.type) {
case SET_CONFIG:
return _setConfig(state, action);
case SET_MAX_RECEIVER_VIDEO_QUALITY:
return set(
state,
'maxReceiverVideoQuality',
action.maxReceiverVideoQuality);
case SET_PREFERRED_VIDEO_QUALITY:
return set(
state,
'preferredVideoQuality',
action.preferredVideoQuality);
}
return state;

View File

@ -7,5 +7,5 @@
* @returns {Map<number,number>}
*/
export function getMinHeightForQualityLvlMap(state: Object): Map<number, number> {
return state['features/base/videoquality'].minHeightForQualityLvl;
return state['features/video-quality'].minHeightForQualityLvl;
}