123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- // @flow
-
- 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';
-
- import { setPreferredVideoQuality, setMaxReceiverVideoQuality } from './actions';
- import { VIDEO_QUALITY_LEVELS } from './constants';
- import { getReceiverVideoQualityLevel } from './functions';
- import logger from './logger';
- import { getMinHeightForQualityLvlMap } from './selector';
-
- /**
- * Implements the middleware of the feature video-quality.
- *
- * @param {Store} store - The redux store.
- * @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) {
- case CONFERENCE_JOINED: {
- if (navigator.product === 'ReactNative') {
- const { resolution } = getState()['features/base/config'];
-
- if (typeof resolution !== 'undefined') {
- dispatch(setPreferredVideoQuality(Number.parseInt(resolution, 10)));
- logger.info(`Configured preferred receiver video frame height to: ${resolution}`);
- }
- }
- 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;
- });
-
- /**
- * Implements a state listener in order to calculate max receiver video quality.
- */
- StateListenerRegistry.register(
- /* selector */ state => {
- const { reducedUI } = state['features/base/responsive-ui'];
- const _shouldDisplayTileView = shouldDisplayTileView(state);
- const thumbnailSize = state['features/filmstrip']?.tileViewDimensions?.thumbnailSize;
- const participantCount = getParticipantCount(state);
-
- return {
- displayTileView: _shouldDisplayTileView,
- participantCount,
- reducedUI,
- thumbnailHeight: thumbnailSize?.height
- };
- },
- /* listener */ ({ displayTileView, participantCount, reducedUI, thumbnailHeight }, { dispatch, getState }) => {
- const state = getState();
- const { maxReceiverVideoQuality } = state['features/video-quality'];
- const { maxFullResolutionParticipants = 2 } = state['features/base/config'];
-
- let newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.HIGH;
-
- if (reducedUI) {
- newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.LOW;
- } 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 (maxReceiverVideoQuality !== newMaxRecvVideoQuality && maxFullResolutionParticipants !== -1) {
- const override
- = participantCount > maxFullResolutionParticipants
- && newMaxRecvVideoQuality > VIDEO_QUALITY_LEVELS.STANDARD;
-
- logger.info(`Video quality level for thumbnail height: ${thumbnailHeight}, `
- + `is: ${newMaxRecvVideoQuality}, `
- + `override: ${String(override)}, `
- + `max full res N: ${maxFullResolutionParticipants}`);
-
- if (override) {
- newMaxRecvVideoQuality = VIDEO_QUALITY_LEVELS.STANDARD;
- }
- }
- }
-
- if (maxReceiverVideoQuality !== newMaxRecvVideoQuality) {
- dispatch(setMaxReceiverVideoQuality(newMaxRecvVideoQuality));
- }
- }, {
- 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);
- }
- });
|