From 25839b18d2ecb7fc485059185764c048680b2957 Mon Sep 17 00:00:00 2001 From: Hristo Terezov Date: Tue, 1 Sep 2020 16:45:59 -0500 Subject: [PATCH] feat(video-quality): persist. --- .../OverflowMenuVideoQualityItem.web.js | 6 ++- .../components/VideoQualitySlider.web.js | 9 +++-- react/features/video-quality/functions.js | 20 ++++++++++ react/features/video-quality/middleware.js | 13 +++++++ react/features/video-quality/reducer.js | 39 ++++++++++++++----- 5 files changed, 73 insertions(+), 14 deletions(-) diff --git a/react/features/video-quality/components/OverflowMenuVideoQualityItem.web.js b/react/features/video-quality/components/OverflowMenuVideoQualityItem.web.js index da68a39a8..c704ae693 100644 --- a/react/features/video-quality/components/OverflowMenuVideoQualityItem.web.js +++ b/react/features/video-quality/components/OverflowMenuVideoQualityItem.web.js @@ -12,6 +12,7 @@ import { } from '../../base/icons'; import { connect } from '../../base/redux'; import { VIDEO_QUALITY_LEVELS } from '../constants'; +import { findNearestQualityLevel } from '../functions'; /** * A map of of selectable receive resolutions to corresponding icons. @@ -69,9 +70,10 @@ class OverflowMenuVideoQualityItem extends Component { */ render() { const { _audioOnly, _videoQuality } = this.props; - const icon = _audioOnly || !_videoQuality + const videoQualityLevel = findNearestQualityLevel(_videoQuality); + const icon = _audioOnly || !videoQualityLevel ? IconVideoQualityAudioOnly - : VIDEO_QUALITY_TO_ICON[_videoQuality]; + : VIDEO_QUALITY_TO_ICON[videoQualityLevel]; return (
  • { return _sliderOptions.indexOf(audioOnlyOption); } - const matchingOption = _sliderOptions.find( - ({ videoQuality }) => videoQuality === _sendrecvVideoQuality); + for (let i = 0; i < _sliderOptions.length; i++) { + if (_sliderOptions[i].videoQuality >= _sendrecvVideoQuality) { + return i; + } + } - return _sliderOptions.indexOf(matchingOption); + return -1; } _onSliderChange: () => void; diff --git a/react/features/video-quality/functions.js b/react/features/video-quality/functions.js index 30567e611..90db1e8f5 100644 --- a/react/features/video-quality/functions.js +++ b/react/features/video-quality/functions.js @@ -2,6 +2,26 @@ import { CFG_LVL_TO_APP_QUALITY_LVL, VIDEO_QUALITY_LEVELS } from './constants'; +const { LOW, STANDARD, HIGH } = VIDEO_QUALITY_LEVELS; +const videoQualityLevels = [ LOW, STANDARD, HIGH ]; + +/** + * 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. diff --git a/react/features/video-quality/middleware.js b/react/features/video-quality/middleware.js index 053efb164..501141e90 100644 --- a/react/features/video-quality/middleware.js +++ b/react/features/video-quality/middleware.js @@ -4,6 +4,7 @@ import { CONFERENCE_JOINED, DATA_CHANNEL_OPENED } from '../base/conference'; +import { SET_CONFIG } from '../base/config'; import { getParticipantCount } from '../base/participants'; import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux'; import { shouldDisplayTileView } from '../video-layout'; @@ -39,6 +40,18 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => { } break; } + case SET_CONFIG: { + const state = getState(); + const { videoQuality = {} } = state['features/base/config']; + + if (videoQuality.persist) { + dispatch( + setPreferredVideoQuality( + state['features/video-quality-persistent-storage'].persistedPrefferedVideoQuality)); + } + + break; + } } return result; diff --git a/react/features/video-quality/reducer.js b/react/features/video-quality/reducer.js index c26fa66a5..1c11fe0ff 100644 --- a/react/features/video-quality/reducer.js +++ b/react/features/video-quality/reducer.js @@ -1,13 +1,11 @@ import { SET_CONFIG } from '../base/config'; -import { ReducerRegistry, set } from '../base/redux'; +import { PersistenceRegistry, 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 = { maxReceiverVideoQuality: VIDEO_QUALITY_LEVELS.HIGH, minHeightForQualityLvl: new Map(), @@ -17,7 +15,27 @@ const DEFAULT_STATE = { DEFAULT_STATE.minHeightForQualityLvl.set(360, VIDEO_QUALITY_LEVELS.STANDARD); DEFAULT_STATE.minHeightForQualityLvl.set(720, VIDEO_QUALITY_LEVELS.HIGH); -ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => { + +// When the persisted state is initialized the current state (for example the deafault state) is erased. +// In order to workaround this issue we need additional state for the persisted properties. +PersistenceRegistry.register('features/video-quality-persistent-storage'); + +ReducerRegistry.register('features/video-quality-persistent-storage', (state = {}, action) => { + switch (action.type) { + case SET_PREFERRED_VIDEO_QUALITY: { + const { preferredVideoQuality } = action; + + return { + ...state, + persistedPrefferedVideoQuality: preferredVideoQuality + }; + } + } + + return state; +}); + +ReducerRegistry.register('features/video-quality', (state = DEFAULT_STATE, action) => { switch (action.type) { case SET_CONFIG: return _setConfig(state, action); @@ -26,11 +44,14 @@ ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => { state, 'maxReceiverVideoQuality', action.maxReceiverVideoQuality); - case SET_PREFERRED_VIDEO_QUALITY: - return set( - state, - 'preferredVideoQuality', - action.preferredVideoQuality); + case SET_PREFERRED_VIDEO_QUALITY: { + const { preferredVideoQuality } = action; + + return { + ...state, + preferredVideoQuality + }; + } } return state;