feat(video-quality):control sender resolution based on user pref

This commit is contained in:
Jaya Allamsetty 2020-04-27 22:51:40 -04:00 committed by Jaya Allamsetty
parent 3ab6b97b8b
commit b5676c3729
9 changed files with 68 additions and 50 deletions

4
package-lock.json generated
View File

@ -10884,8 +10884,8 @@
} }
}, },
"lib-jitsi-meet": { "lib-jitsi-meet": {
"version": "github:jitsi/lib-jitsi-meet#f97c37d0140a0f12644ae29f4dd93757b8b8610f", "version": "github:jitsi/lib-jitsi-meet#47b292e332e6c6e13de74f17540a0e6a6a80e165",
"from": "github:jitsi/lib-jitsi-meet#f97c37d0140a0f12644ae29f4dd93757b8b8610f", "from": "github:jitsi/lib-jitsi-meet#47b292e332e6c6e13de74f17540a0e6a6a80e165",
"requires": { "requires": {
"@jitsi/sdp-interop": "1.0.2", "@jitsi/sdp-interop": "1.0.2",
"@jitsi/sdp-simulcast": "0.3.0", "@jitsi/sdp-simulcast": "0.3.0",

View File

@ -56,7 +56,7 @@
"js-utils": "github:jitsi/js-utils#df68966e3c65b5c57fcd2670da1326a2c77518d1", "js-utils": "github:jitsi/js-utils#df68966e3c65b5c57fcd2670da1326a2c77518d1",
"jsrsasign": "8.0.12", "jsrsasign": "8.0.12",
"jwt-decode": "2.2.0", "jwt-decode": "2.2.0",
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#f97c37d0140a0f12644ae29f4dd93757b8b8610f", "lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#47b292e332e6c6e13de74f17540a0e6a6a80e165",
"libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d", "libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
"lodash": "4.17.13", "lodash": "4.17.13",
"moment": "2.19.4", "moment": "2.19.4",

View File

@ -212,15 +212,14 @@ export const SET_PENDING_SUBJECT_CHANGE = 'SET_PENDING_SUBJECT_CHANGE';
/** /**
* 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 received from remote participants. * should be sent to and received from remote participants.
* *
* { * {
* type: SET_PREFERRED_RECEIVER_VIDEO_QUALITY, * type: SET_PREFERRED_VIDEO_QUALITY,
* preferredReceiverVideoQuality: number * preferredVideoQuality: number
* } * }
*/ */
export const SET_PREFERRED_RECEIVER_VIDEO_QUALITY export const SET_PREFERRED_VIDEO_QUALITY = 'SET_PREFERRED_VIDEO_QUALITY';
= 'SET_PREFERRED_RECEIVER_VIDEO_QUALITY';
/** /**
* The type of (redux) action which sets the name of the room of the * The type of (redux) action which sets the name of the room of the

View File

@ -48,7 +48,7 @@ import {
SET_MAX_RECEIVER_VIDEO_QUALITY, SET_MAX_RECEIVER_VIDEO_QUALITY,
SET_PASSWORD, SET_PASSWORD,
SET_PASSWORD_FAILED, SET_PASSWORD_FAILED,
SET_PREFERRED_RECEIVER_VIDEO_QUALITY, SET_PREFERRED_VIDEO_QUALITY,
SET_ROOM, SET_ROOM,
SET_PENDING_SUBJECT_CHANGE, SET_PENDING_SUBJECT_CHANGE,
SET_START_MUTED_POLICY SET_START_MUTED_POLICY
@ -699,21 +699,20 @@ export function setPassword(
} }
/** /**
* Sets the max frame height the user prefers to receive from remote participant * Sets the max frame height the user prefers to send and receive from the
* videos. * remote participants.
* *
* @param {number} preferredReceiverVideoQuality - The max video resolution to * @param {number} preferredVideoQuality - The max video resolution to send and
* receive. * receive.
* @returns {{ * @returns {{
* type: SET_PREFERRED_RECEIVER_VIDEO_QUALITY, * type: SET_PREFERRED_VIDEO_QUALITY,
* preferredReceiverVideoQuality: number * preferredVideoQuality: number
* }} * }}
*/ */
export function setPreferredReceiverVideoQuality( export function setPreferredVideoQuality(preferredVideoQuality: number) {
preferredReceiverVideoQuality: number) {
return { return {
type: SET_PREFERRED_RECEIVER_VIDEO_QUALITY, type: SET_PREFERRED_VIDEO_QUALITY,
preferredReceiverVideoQuality preferredVideoQuality
}; };
} }

View File

@ -114,14 +114,17 @@ StateListenerRegistry.register(
const { const {
conference, conference,
maxReceiverVideoQuality, maxReceiverVideoQuality,
preferredReceiverVideoQuality preferredVideoQuality
} = currentState; } = currentState;
const changedPreferredVideoQuality const changedPreferredVideoQuality
= preferredReceiverVideoQuality !== previousState.preferredReceiverVideoQuality; = preferredVideoQuality !== previousState.preferredVideoQuality;
const changedMaxVideoQuality = maxReceiverVideoQuality !== previousState.maxReceiverVideoQuality; const changedMaxVideoQuality = maxReceiverVideoQuality !== previousState.maxReceiverVideoQuality;
if (changedPreferredVideoQuality || changedMaxVideoQuality) { if (changedPreferredVideoQuality || changedMaxVideoQuality) {
_setReceiverVideoConstraint(conference, preferredReceiverVideoQuality, maxReceiverVideoQuality); _setReceiverVideoConstraint(conference, preferredVideoQuality, maxReceiverVideoQuality);
}
if (changedPreferredVideoQuality) {
_setSenderVideoConstraint(conference, preferredVideoQuality);
} }
}); });
@ -433,6 +436,24 @@ function _setReceiverVideoConstraint(conference, preferred, max) {
} }
} }
/**
* 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 * Notifies the feature base/conference that the action
* {@code SET_ROOM} is being dispatched within a specific * {@code SET_ROOM} is being dispatched within a specific
@ -502,12 +523,12 @@ function _syncReceiveVideoQuality({ getState }, next, action) {
const { const {
conference, conference,
maxReceiverVideoQuality, maxReceiverVideoQuality,
preferredReceiverVideoQuality preferredVideoQuality
} = getState()['features/base/conference']; } = getState()['features/base/conference'];
_setReceiverVideoConstraint( _setReceiverVideoConstraint(
conference, conference,
preferredReceiverVideoQuality, preferredVideoQuality,
maxReceiverVideoQuality); maxReceiverVideoQuality);
return next(action); return next(action);

View File

@ -21,7 +21,7 @@ import {
SET_MAX_RECEIVER_VIDEO_QUALITY, SET_MAX_RECEIVER_VIDEO_QUALITY,
SET_PASSWORD, SET_PASSWORD,
SET_PENDING_SUBJECT_CHANGE, SET_PENDING_SUBJECT_CHANGE,
SET_PREFERRED_RECEIVER_VIDEO_QUALITY, SET_PREFERRED_VIDEO_QUALITY,
SET_ROOM, SET_ROOM,
SET_SIP_GATEWAY_ENABLED, SET_SIP_GATEWAY_ENABLED,
SET_START_MUTED_POLICY SET_START_MUTED_POLICY
@ -38,7 +38,7 @@ const DEFAULT_STATE = {
maxReceiverVideoQuality: VIDEO_QUALITY_LEVELS.HIGH, maxReceiverVideoQuality: VIDEO_QUALITY_LEVELS.HIGH,
password: undefined, password: undefined,
passwordRequired: undefined, passwordRequired: undefined,
preferredReceiverVideoQuality: VIDEO_QUALITY_LEVELS.HIGH preferredVideoQuality: VIDEO_QUALITY_LEVELS.HIGH
}; };
/** /**
@ -101,11 +101,11 @@ ReducerRegistry.register(
case SET_PENDING_SUBJECT_CHANGE: case SET_PENDING_SUBJECT_CHANGE:
return set(state, 'pendingSubjectChange', action.subject); return set(state, 'pendingSubjectChange', action.subject);
case SET_PREFERRED_RECEIVER_VIDEO_QUALITY: case SET_PREFERRED_VIDEO_QUALITY:
return set( return set(
state, state,
'preferredReceiverVideoQuality', 'preferredVideoQuality',
action.preferredReceiverVideoQuality); action.preferredVideoQuality);
case SET_ROOM: case SET_ROOM:
return _setRoom(state, action); return _setRoom(state, action);

View File

@ -7,7 +7,7 @@ import {
VIDEO_QUALITY_LEVELS, VIDEO_QUALITY_LEVELS,
conferenceLeft, conferenceLeft,
getCurrentConference, getCurrentConference,
setPreferredReceiverVideoQuality setPreferredVideoQuality
} from '../base/conference'; } from '../base/conference';
import { hideDialog, isDialogOpen } from '../base/dialog'; import { hideDialog, isDialogOpen } from '../base/dialog';
import { setActiveModalId } from '../base/modal'; import { setActiveModalId } from '../base/modal';
@ -32,7 +32,7 @@ MiddlewareRegistry.register(store => next => action => {
dispatch(setFilmstripEnabled(!reducedUI)); dispatch(setFilmstripEnabled(!reducedUI));
dispatch( dispatch(
setPreferredReceiverVideoQuality( setPreferredVideoQuality(
reducedUI reducedUI
? VIDEO_QUALITY_LEVELS.LOW ? VIDEO_QUALITY_LEVELS.LOW
: VIDEO_QUALITY_LEVELS.HIGH)); : VIDEO_QUALITY_LEVELS.HIGH));

View File

@ -38,9 +38,9 @@ type Props = {
/** /**
* The currently configured maximum quality resolution to be received from * The currently configured maximum quality resolution to be received from
* remote participants. * and sent to remote participants.
*/ */
_receiverVideoQuality: number, _videoQuality: number,
/** /**
* Callback to invoke when {@link OverflowMenuVideoQualityItem} is clicked. * Callback to invoke when {@link OverflowMenuVideoQualityItem} is clicked.
@ -68,10 +68,10 @@ class OverflowMenuVideoQualityItem extends Component<Props> {
* @returns {ReactElement} * @returns {ReactElement}
*/ */
render() { render() {
const { _audioOnly, _receiverVideoQuality } = this.props; const { _audioOnly, _videoQuality } = this.props;
const icon = _audioOnly || !_receiverVideoQuality const icon = _audioOnly || !_videoQuality
? IconVideoQualityAudioOnly ? IconVideoQualityAudioOnly
: VIDEO_QUALITY_TO_ICON[_receiverVideoQuality]; : VIDEO_QUALITY_TO_ICON[_videoQuality];
return ( return (
<li <li
@ -98,14 +98,13 @@ class OverflowMenuVideoQualityItem extends Component<Props> {
* @private * @private
* @returns {{ * @returns {{
* _audioOnly: boolean, * _audioOnly: boolean,
* _receiverVideoQuality: number * _videoQuality: number
* }} * }}
*/ */
function _mapStateToProps(state) { function _mapStateToProps(state) {
return { return {
_audioOnly: state['features/base/audio-only'].enabled, _audioOnly: state['features/base/audio-only'].enabled,
_receiverVideoQuality: _videoQuality: state['features/base/conference'].preferredVideoQuality
state['features/base/conference'].preferredReceiverVideoQuality
}; };
} }

View File

@ -6,7 +6,7 @@ import type { Dispatch } from 'redux';
import { createToolbarEvent, sendAnalytics } from '../../analytics'; import { createToolbarEvent, sendAnalytics } from '../../analytics';
import { setAudioOnly } from '../../base/audio-only'; import { setAudioOnly } from '../../base/audio-only';
import { VIDEO_QUALITY_LEVELS, setPreferredReceiverVideoQuality } from '../../base/conference'; import { VIDEO_QUALITY_LEVELS, setPreferredVideoQuality } from '../../base/conference';
import { translate } from '../../base/i18n'; import { translate } from '../../base/i18n';
import JitsiMeetJS from '../../base/lib-jitsi-meet'; import JitsiMeetJS from '../../base/lib-jitsi-meet';
import { connect } from '../../base/redux'; import { connect } from '../../base/redux';
@ -51,10 +51,10 @@ type Props = {
_p2p: Boolean, _p2p: Boolean,
/** /**
* The currently configured maximum quality resolution to be received * The currently configured maximum quality resolution to be sent and
* from remote participants. * received from the remote participants.
*/ */
_receiverVideoQuality: Number, _sendrecvVideoQuality: Number,
/** /**
* Whether or not displaying video is supported in the current * Whether or not displaying video is supported in the current
@ -326,7 +326,7 @@ class VideoQualitySlider extends Component<Props> {
* @returns {void} * @returns {void}
*/ */
_mapCurrentQualityToSliderValue() { _mapCurrentQualityToSliderValue() {
const { _audioOnly, _receiverVideoQuality } = this.props; const { _audioOnly, _sendrecvVideoQuality } = this.props;
const { _sliderOptions } = this; const { _sliderOptions } = this;
if (_audioOnly) { if (_audioOnly) {
@ -337,7 +337,7 @@ class VideoQualitySlider extends Component<Props> {
} }
const matchingOption = _sliderOptions.find( const matchingOption = _sliderOptions.find(
({ videoQuality }) => videoQuality === _receiverVideoQuality); ({ videoQuality }) => videoQuality === _sendrecvVideoQuality);
return _sliderOptions.indexOf(matchingOption); return _sliderOptions.indexOf(matchingOption);
} }
@ -352,7 +352,7 @@ class VideoQualitySlider extends Component<Props> {
* @returns {void} * @returns {void}
*/ */
_onSliderChange(event) { _onSliderChange(event) {
const { _audioOnly, _receiverVideoQuality } = this.props; const { _audioOnly, _sendrecvVideoQuality } = this.props;
const { const {
audioOnly, audioOnly,
onSelect, onSelect,
@ -362,7 +362,7 @@ class VideoQualitySlider extends Component<Props> {
// Take no action if the newly chosen option does not change audio only // Take no action if the newly chosen option does not change audio only
// or video quality state. // or video quality state.
if ((_audioOnly && audioOnly) if ((_audioOnly && audioOnly)
|| (!_audioOnly && videoQuality === _receiverVideoQuality)) { || (!_audioOnly && videoQuality === _sendrecvVideoQuality)) {
return; return;
} }
@ -379,7 +379,7 @@ class VideoQualitySlider extends Component<Props> {
* @returns {void} * @returns {void}
*/ */
_setPreferredVideoQuality(qualityLevel) { _setPreferredVideoQuality(qualityLevel) {
this.props.dispatch(setPreferredReceiverVideoQuality(qualityLevel)); this.props.dispatch(setPreferredVideoQuality(qualityLevel));
if (this.props._audioOnly) { if (this.props._audioOnly) {
this.props.dispatch(setAudioOnly(false)); this.props.dispatch(setAudioOnly(false));
@ -396,17 +396,17 @@ class VideoQualitySlider extends Component<Props> {
* @returns {{ * @returns {{
* _audioOnly: boolean, * _audioOnly: boolean,
* _p2p: boolean, * _p2p: boolean,
* _receiverVideoQuality: boolean * _sendrecvVideoQuality: number
* }} * }}
*/ */
function _mapStateToProps(state) { function _mapStateToProps(state) {
const { enabled: audioOnly } = state['features/base/audio-only']; const { enabled: audioOnly } = state['features/base/audio-only'];
const { p2p, preferredReceiverVideoQuality } = state['features/base/conference']; const { p2p, preferredVideoQuality } = state['features/base/conference'];
return { return {
_audioOnly: audioOnly, _audioOnly: audioOnly,
_p2p: p2p, _p2p: p2p,
_receiverVideoQuality: preferredReceiverVideoQuality, _sendrecvVideoQuality: preferredVideoQuality,
_videoSupported: JitsiMeetJS.mediaDevices.supportsVideo() _videoSupported: JitsiMeetJS.mediaDevices.supportsVideo()
}; };
} }