Bladeren bron

feat(last-n): Implement startLastN and make last-n configurable through UI. (#9093)

master
Jaya Allamsetty 4 jaren geleden
bovenliggende
commit
1898e4a768
No account linked to committer's email address

+ 5
- 0
config.js Bestand weergeven

@@ -228,6 +228,11 @@ var config = {
228 228
     // Default value for the channel "last N" attribute. -1 for unlimited.
229 229
     channelLastN: -1,
230 230
 
231
+    // Provides a way for the lastN value to be controlled through the UI.
232
+    // When startLastN is present, conference starts with a last-n value of startLastN and channelLastN
233
+    // value will be used when the quality level is selected using "Manage Video Quality" slider.
234
+    // startLastN: 1,
235
+
231 236
     // Provides a way to use different "last N" values based on the number of participants in the conference.
232 237
     // The keys in an Object represent number of participants and the values are "last N" to be used when number of
233 238
     // participants gets to or above the number.

+ 1
- 0
react/features/base/config/configWhitelist.js Bestand weergeven

@@ -153,6 +153,7 @@ export default [
153 153
     'resolution',
154 154
     'startAudioMuted',
155 155
     'startAudioOnly',
156
+    'startLastN',
156 157
     'startScreenSharing',
157 158
     'startSilent',
158 159
     'startVideoMuted',

+ 11
- 0
react/features/base/lastn/actionTypes.js Bestand weergeven

@@ -0,0 +1,11 @@
1
+// @flow
2
+
3
+/**
4
+ * The type of (redux) action which sets the last-n for the conference.
5
+ *
6
+ * {
7
+ *     type: SET_LAST_N,
8
+ *     lastN: number
9
+ * }
10
+ */
11
+export const SET_LAST_N = 'SET_LAST_N';

+ 19
- 0
react/features/base/lastn/actions.js Bestand weergeven

@@ -0,0 +1,19 @@
1
+// @flow
2
+
3
+import { SET_LAST_N } from './actionTypes';
4
+
5
+/**
6
+ * Sets the last-n, i.e., the number of remote videos to be requested from the bridge for the conference.
7
+ *
8
+ * @param {number} lastN - The number of remote videos to be requested.
9
+ * @returns {{
10
+ *     type: SET_LAST_N,
11
+ *     lastN: number
12
+ * }}
13
+ */
14
+export function setLastN(lastN: number) {
15
+    return {
16
+        type: SET_LAST_N,
17
+        lastN
18
+    };
19
+}

+ 25
- 0
react/features/base/lastn/functions.js Bestand weergeven

@@ -1,3 +1,28 @@
1
+import { VIDEO_QUALITY_LEVELS } from '../../video-quality/constants';
2
+
3
+/**
4
+ * Determines the lastN value to be used for the conference based on the video quality selected.
5
+ *
6
+ * @param {string} qualityLevel - Quality level (height) selected.
7
+ * @param {number} channelLastN - LastN value set for the whole conference.
8
+ * @returns {number} LastN value applicable to the quality level specified.
9
+ */
10
+export function getLastNForQualityLevel(qualityLevel, channelLastN) {
11
+    let lastN = channelLastN;
12
+
13
+    const videoQualityLevels = Object.values(VIDEO_QUALITY_LEVELS);
14
+
15
+    for (const lvl in videoQualityLevels) {
16
+        if (videoQualityLevels.hasOwnProperty(lvl)
17
+            && qualityLevel === videoQualityLevels[lvl]
18
+            && lvl > 1) {
19
+            lastN = Math.floor(channelLastN / Math.pow(2, lvl - 1));
20
+        }
21
+    }
22
+
23
+    return lastN;
24
+}
25
+
1 26
 /**
2 27
  * Checks if the given Object is a correct last N limit mapping, coverts both keys and values to numbers and sorts
3 28
  * the keys in ascending order.

+ 3
- 0
react/features/base/lastn/index.js Bestand weergeven

@@ -0,0 +1,3 @@
1
+export * from './actions';
2
+export * from './actionTypes';
3
+export * from './functions';

+ 26
- 12
react/features/base/lastn/middleware.js Bestand weergeven

@@ -18,6 +18,7 @@ import {
18 18
 import { MiddlewareRegistry } from '../redux';
19 19
 import { isLocalVideoTrackDesktop } from '../tracks/functions';
20 20
 
21
+import { SET_LAST_N } from './actionTypes';
21 22
 import { limitLastN } from './functions';
22 23
 import logger from './logger';
23 24
 
@@ -40,6 +41,12 @@ MiddlewareRegistry.register(store => next => action => {
40 41
     case SET_TILE_VIEW:
41 42
         _updateLastN(store);
42 43
         break;
44
+    case SET_LAST_N: {
45
+        const { lastN } = action;
46
+
47
+        _updateLastN(store, lastN);
48
+        break;
49
+    }
43 50
     }
44 51
 
45 52
     return result;
@@ -49,17 +56,18 @@ MiddlewareRegistry.register(store => next => action => {
49 56
  * Updates the last N value in the conference based on the current state of the redux store.
50 57
  *
51 58
  * @param {Store} store - The redux store.
59
+ * @param {number} value - The last-n value to be set.
52 60
  * @private
53 61
  * @returns {void}
54 62
  */
55
-function _updateLastN({ getState }) {
63
+function _updateLastN({ getState }, value = null) {
56 64
     const state = getState();
57 65
     const { conference } = state['features/base/conference'];
58 66
     const { enabled: audioOnly } = state['features/base/audio-only'];
59 67
     const { appState } = state['features/background'] || {};
60 68
     const { enabled: filmStripEnabled } = state['features/filmstrip'];
61 69
     const config = state['features/base/config'];
62
-    const { lastNLimits } = state['features/base/lastn'];
70
+    const { lastNLimits, lastN } = state['features/base/lastn'];
63 71
     const participantCount = getParticipantCount(state);
64 72
 
65 73
     if (!conference) {
@@ -68,17 +76,23 @@ function _updateLastN({ getState }) {
68 76
         return;
69 77
     }
70 78
 
71
-    let lastN = typeof config.channelLastN === 'undefined' ? -1 : config.channelLastN;
79
+    // Select the lastN value based on the following preference order.
80
+    // 1. The value passed to the setLastN action that is dispatched.
81
+    // 2. The last-n value in redux.
82
+    // 3. The last-n value from 'startLastN' if it is specified in config.js
83
+    // 4. The last-n value from 'channelLastN' if specified in config.js.
84
+    // 5. -1 as the default value.
85
+    let lastNSelected = value || lastN || (config.startLastN ?? (config.channelLastN ?? -1));
72 86
 
73
-    // Apply last N limit based on the # of participants and channelLastN settings.
87
+    // Apply last N limit based on the # of participants and config settings.
74 88
     const limitedLastN = limitLastN(participantCount, lastNLimits);
75 89
 
76 90
     if (limitedLastN !== undefined) {
77
-        lastN = lastN === -1 ? limitedLastN : Math.min(limitedLastN, lastN);
91
+        lastNSelected = lastNSelected === -1 ? limitedLastN : Math.min(limitedLastN, lastNSelected);
78 92
     }
79 93
 
80 94
     if (typeof appState !== 'undefined' && appState !== 'active') {
81
-        lastN = isLocalVideoTrackDesktop(state) ? 1 : 0;
95
+        lastNSelected = isLocalVideoTrackDesktop(state) ? 1 : 0;
82 96
     } else if (audioOnly) {
83 97
         const { remoteScreenShares, tileViewEnabled } = state['features/video-layout'];
84 98
         const largeVideoParticipantId = state['features/large-video'].participantId;
@@ -89,22 +103,22 @@ function _updateLastN({ getState }) {
89 103
         // view since we make an exception only for screenshare when in audio-only mode. If the user unpins
90 104
         // the screenshare, lastN will be set to 0 here. It will be set to 1 if screenshare has been auto pinned.
91 105
         if (!tileViewEnabled && largeVideoParticipant && !largeVideoParticipant.local) {
92
-            lastN = (remoteScreenShares || []).includes(largeVideoParticipantId) ? 1 : 0;
106
+            lastNSelected = (remoteScreenShares || []).includes(largeVideoParticipantId) ? 1 : 0;
93 107
         } else {
94
-            lastN = 0;
108
+            lastNSelected = 0;
95 109
         }
96 110
     } else if (!filmStripEnabled) {
97
-        lastN = 1;
111
+        lastNSelected = 1;
98 112
     }
99 113
 
100
-    if (conference.getLastN() === lastN) {
114
+    if (conference.getLastN() === lastNSelected) {
101 115
         return;
102 116
     }
103 117
 
104
-    logger.info(`Setting last N to: ${lastN}`);
118
+    logger.info(`Setting last N to: ${lastNSelected}`);
105 119
 
106 120
     try {
107
-        conference.setLastN(lastN);
121
+        conference.setLastN(lastNSelected);
108 122
     } catch (err) {
109 123
         logger.error(`Failed to set lastN: ${err}`);
110 124
     }

+ 9
- 0
react/features/base/lastn/reducer.js Bestand weergeven

@@ -3,12 +3,21 @@ import {
3 3
 } from '../config';
4 4
 import { ReducerRegistry, set } from '../redux';
5 5
 
6
+import { SET_LAST_N } from './actionTypes';
6 7
 import { validateLastNLimits } from './functions';
7 8
 
8 9
 ReducerRegistry.register('features/base/lastn', (state = { }, action) => {
9 10
     switch (action.type) {
10 11
     case SET_CONFIG:
11 12
         return _setConfig(state, action);
13
+    case SET_LAST_N: {
14
+        const { lastN } = action;
15
+
16
+        return {
17
+            ...state,
18
+            lastN
19
+        };
20
+    }
12 21
     }
13 22
 
14 23
     return state;

+ 18
- 2
react/features/video-quality/components/VideoQualitySlider.web.js Bestand weergeven

@@ -6,9 +6,10 @@ import type { Dispatch } from 'redux';
6 6
 import { createToolbarEvent, sendAnalytics } from '../../analytics';
7 7
 import { setAudioOnly } from '../../base/audio-only';
8 8
 import { translate } from '../../base/i18n';
9
+import { setLastN, getLastNForQualityLevel } from '../../base/lastn';
9 10
 import { connect } from '../../base/redux';
10 11
 import { setPreferredVideoQuality } from '../actions';
11
-import { VIDEO_QUALITY_LEVELS } from '../constants';
12
+import { DEFAULT_LAST_N, VIDEO_QUALITY_LEVELS } from '../constants';
12 13
 import logger from '../logger';
13 14
 
14 15
 const {
@@ -44,6 +45,11 @@ type Props = {
44 45
      */
45 46
     _audioOnly: Boolean,
46 47
 
48
+    /**
49
+     * The channelLastN value configured for the conference.
50
+     */
51
+    _channelLastN: Number,
52
+
47 53
     /**
48 54
      * Whether or not the conference is in peer to peer mode.
49 55
      */
@@ -342,10 +348,18 @@ class VideoQualitySlider extends Component<Props> {
342 348
      */
343 349
     _setPreferredVideoQuality(qualityLevel) {
344 350
         this.props.dispatch(setPreferredVideoQuality(qualityLevel));
345
-
346 351
         if (this.props._audioOnly) {
347 352
             this.props.dispatch(setAudioOnly(false));
348 353
         }
354
+
355
+        // Determine the lastN value based on the quality setting.
356
+        let { _channelLastN = DEFAULT_LAST_N } = this.props;
357
+
358
+        _channelLastN = _channelLastN === -1 ? DEFAULT_LAST_N : _channelLastN;
359
+        const lastN = getLastNForQualityLevel(qualityLevel, _channelLastN);
360
+
361
+        // Set the lastN for the conference.
362
+        this.props.dispatch(setLastN(lastN));
349 363
     }
350 364
 }
351 365
 
@@ -361,9 +375,11 @@ function _mapStateToProps(state) {
361 375
     const { enabled: audioOnly } = state['features/base/audio-only'];
362 376
     const { p2p } = state['features/base/conference'];
363 377
     const { preferredVideoQuality } = state['features/video-quality'];
378
+    const { channelLastN } = state['features/base/config'];
364 379
 
365 380
     return {
366 381
         _audioOnly: audioOnly,
382
+        _channelLastN: channelLastN,
367 383
         _p2p: p2p,
368 384
         _sendrecvVideoQuality: preferredVideoQuality
369 385
     };

+ 6
- 0
react/features/video-quality/constants.js Bestand weergeven

@@ -1,3 +1,9 @@
1
+/**
2
+ * Default last-n value used to be used for "HD" video quality setting when no channelLastN value is specified.
3
+ * @type {number}
4
+ */
5
+export const DEFAULT_LAST_N = 20;
6
+
1 7
 /**
2 8
  * The supported remote video resolutions. The values are currently based on
3 9
  * available simulcast layers.

Laden…
Annuleren
Opslaan