From ee7d180cbbe9ed9ed5fca0b3a2d3f427e3a64877 Mon Sep 17 00:00:00 2001 From: Leonard Kim Date: Tue, 24 Jul 2018 09:23:38 -0700 Subject: [PATCH] feat(video-quality): be able to set an internal max The internal max will be used for tile view. Whatever the user has set for preferred video quality, the internal maximum will be respected. This allows for the case where the user prefers high definition video, but in tile view it only makes sense to send low definition; ux wise the user is allowed to continue messing with the video quality slider. --- react/features/base/conference/actionTypes.js | 17 +++++- react/features/base/conference/actions.js | 21 +++++++- react/features/base/conference/middleware.js | 52 +++++++++++++++++-- react/features/base/conference/reducer.js | 7 +++ 4 files changed, 89 insertions(+), 8 deletions(-) diff --git a/react/features/base/conference/actionTypes.js b/react/features/base/conference/actionTypes.js index fbc03d59b..39aa715bc 100644 --- a/react/features/base/conference/actionTypes.js +++ b/react/features/base/conference/actionTypes.js @@ -152,6 +152,19 @@ export const SET_FOLLOW_ME = Symbol('SET_FOLLOW_ME'); */ export const SET_LASTN = Symbol('SET_LASTN'); +/** + * 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 + = Symbol('SET_MAX_RECEIVER_VIDEO_QUALITY'); + /** * The type of (redux) action which sets the password to join or lock a specific * {@code JitsiConference}. @@ -177,8 +190,8 @@ export const SET_PASSWORD = Symbol('SET_PASSWORD'); export const SET_PASSWORD_FAILED = Symbol('SET_PASSWORD_FAILED'); /** - * The type of (redux) action which sets the maximum video size should be - * received from remote participants. + * The type of (redux) action which sets the preferred maximum video height that + * should be received from remote participants. * * { * type: SET_PREFERRED_RECEIVER_VIDEO_QUALITY, diff --git a/react/features/base/conference/actions.js b/react/features/base/conference/actions.js index ddbc75c6c..5f976f99a 100644 --- a/react/features/base/conference/actions.js +++ b/react/features/base/conference/actions.js @@ -37,6 +37,7 @@ import { SET_DESKTOP_SHARING_ENABLED, SET_FOLLOW_ME, SET_LASTN, + SET_MAX_RECEIVER_VIDEO_QUALITY, SET_PASSWORD, SET_PASSWORD_FAILED, SET_PREFERRED_RECEIVER_VIDEO_QUALITY, @@ -569,6 +570,23 @@ export function setLastN(lastN: ?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 password to join or lock a specific JitsiConference. * @@ -641,7 +659,8 @@ export function setPassword( } /** - * Sets the max frame height to receive from remote participant videos. + * Sets the max frame height the user prefers to receive from remote participant + * videos. * * @param {number} preferredReceiverVideoQuality - The max video resolution to * receive. diff --git a/react/features/base/conference/middleware.js b/react/features/base/conference/middleware.js index 742458e62..974aa6c7e 100644 --- a/react/features/base/conference/middleware.js +++ b/react/features/base/conference/middleware.js @@ -34,6 +34,7 @@ import { DATA_CHANNEL_OPENED, SET_AUDIO_ONLY, SET_LASTN, + SET_MAX_RECEIVER_VIDEO_QUALITY, SET_PREFERRED_RECEIVER_VIDEO_QUALITY, SET_ROOM } from './actionTypes'; @@ -80,6 +81,9 @@ MiddlewareRegistry.register(store => next => action => { case SET_LASTN: return _setLastN(store, next, action); + case SET_MAX_RECEIVER_VIDEO_QUALITY: + return _setMaximumReceiverVideoQuality(store, next, action); + case SET_PREFERRED_RECEIVER_VIDEO_QUALITY: return _setPreferredReceiverVideoQuality(store, next, action); @@ -434,7 +438,38 @@ function _setLastN({ getState }, next, action) { } /** - * Sets the maximum receive video quality and will turn off audio only mode if + * Sets an internal maximum for the video frame height to receive from remote + * videos. This maximum acts as a cap so user preferences cannot exceed a + * specified frame height. + * + * @private + * @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 SET_MAXIMUM_RECEIVER_VIDEO_QUALITY} which is being dispatched in the + * specified {@code store}. + * @private + * @returns {Object} The value returned by {@code next(action)}. + */ +function _setMaximumReceiverVideoQuality({ getState }, next, action) { + const { conference, preferredReceiverVideoQuality } + = getState()['features/base/conference']; + + if (conference) { + if (typeof preferredReceiverVideoQuality === 'undefined' + || preferredReceiverVideoQuality > action.maxReceiverVideoQuality) { + conference.setReceiverVideoConstraint( + action.maxReceiverVideoQuality); + } + } + + return next(action); +} + +/** + * Sets the preferred receive video quality and will turn off audio only mode if * enabled. * * @param {Store} store - The redux store in which the specified {@code action} @@ -451,12 +486,19 @@ function _setPreferredReceiverVideoQuality( { dispatch, getState }, next, action) { - const { audioOnly, conference } - = getState()['features/base/conference']; + const { + audioOnly, + conference, + maxReceiverVideoQuality + } = getState()['features/base/conference']; if (conference) { - conference.setReceiverVideoConstraint( - action.preferredReceiverVideoQuality); + const { preferredReceiverVideoQuality } = action; + const targetQuality = typeof maxReceiverVideoQuality === 'undefined' + ? preferredReceiverVideoQuality + : Math.min(maxReceiverVideoQuality, preferredReceiverVideoQuality); + + conference.setReceiverVideoConstraint(targetQuality); audioOnly && dispatch(toggleAudioOnly()); } diff --git a/react/features/base/conference/reducer.js b/react/features/base/conference/reducer.js index 3578d8df2..8441fe4df 100644 --- a/react/features/base/conference/reducer.js +++ b/react/features/base/conference/reducer.js @@ -17,6 +17,7 @@ import { SET_AUDIO_ONLY, SET_DESKTOP_SHARING_ENABLED, SET_FOLLOW_ME, + SET_MAX_RECEIVER_VIDEO_QUALITY, SET_PASSWORD, SET_PREFERRED_RECEIVER_VIDEO_QUALITY, SET_ROOM, @@ -69,6 +70,12 @@ ReducerRegistry.register('features/base/conference', (state = {}, action) => { 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);