浏览代码

feat: request video only for visible thumbnails.

master
Hristo Terezov 4 年前
父节点
当前提交
2d319d18c3

+ 12
- 0
react/features/filmstrip/actionTypes.js 查看文件

70
  * }
70
  * }
71
  */
71
  */
72
 export const SET_VOLUME = 'SET_VOLUME';
72
 export const SET_VOLUME = 'SET_VOLUME';
73
+
74
+/**
75
+ * The type of the action which sets the list of visible remote participants in the filmstrip by storing the start and
76
+ * end index in the remote participants array.
77
+ *
78
+ * {
79
+ *      type: SET_VISIBLE_REMOTE_PARTICIPANTS,
80
+ *      startIndex: number,
81
+ *      endIndex: number
82
+ * }
83
+ */
84
+export const SET_VISIBLE_REMOTE_PARTICIPANTS = 'SET_VISIBLE_REMOTE_PARTICIPANTS';

+ 21
- 0
react/features/filmstrip/actions.web.js 查看文件

7
     SET_HORIZONTAL_VIEW_DIMENSIONS,
7
     SET_HORIZONTAL_VIEW_DIMENSIONS,
8
     SET_TILE_VIEW_DIMENSIONS,
8
     SET_TILE_VIEW_DIMENSIONS,
9
     SET_VERTICAL_VIEW_DIMENSIONS,
9
     SET_VERTICAL_VIEW_DIMENSIONS,
10
+    SET_VISIBLE_REMOTE_PARTICIPANTS,
10
     SET_VOLUME
11
     SET_VOLUME
11
 } from './actionTypes';
12
 } from './actionTypes';
12
 import {
13
 import {
153
     };
154
     };
154
 }
155
 }
155
 
156
 
157
+/**
158
+ * Sets the list of the visible participants in the filmstrip by storing the start and end index from the remote
159
+ * participants array.
160
+ *
161
+ * @param {number} startIndex - The start index from the remote participants array.
162
+ * @param {number} endIndex - The end index from the remote participants array.
163
+ * @returns {{
164
+ *      type: SET_VISIBLE_REMOTE_PARTICIPANTS,
165
+ *      startIndex: number,
166
+ *      endIndex: number
167
+ * }}
168
+ */
169
+export function setVisibleRemoteParticipants(startIndex: number, endIndex: number) {
170
+    return {
171
+        type: SET_VISIBLE_REMOTE_PARTICIPANTS,
172
+        startIndex,
173
+        endIndex
174
+    };
175
+}
176
+
156
 export * from './actions.native';
177
 export * from './actions.native';

+ 40
- 2
react/features/filmstrip/components/web/Filmstrip.js 查看文件

16
 import { showToolbox } from '../../../toolbox/actions.web';
16
 import { showToolbox } from '../../../toolbox/actions.web';
17
 import { isButtonEnabled, isToolboxVisible } from '../../../toolbox/functions.web';
17
 import { isButtonEnabled, isToolboxVisible } from '../../../toolbox/functions.web';
18
 import { LAYOUTS, getCurrentLayout } from '../../../video-layout';
18
 import { LAYOUTS, getCurrentLayout } from '../../../video-layout';
19
-import { setFilmstripVisible } from '../../actions';
19
+import { setFilmstripVisible, setVisibleRemoteParticipants } from '../../actions';
20
 import { TILE_HORIZONTAL_MARGIN, TILE_VERTICAL_MARGIN, TOOLBAR_HEIGHT } from '../../constants';
20
 import { TILE_HORIZONTAL_MARGIN, TILE_VERTICAL_MARGIN, TOOLBAR_HEIGHT } from '../../constants';
21
 import { shouldRemoteVideosBeVisible } from '../../functions';
21
 import { shouldRemoteVideosBeVisible } from '../../functions';
22
 
22
 
67
      */
67
      */
68
     _remoteParticipants: Array<Object>,
68
     _remoteParticipants: Array<Object>,
69
 
69
 
70
-
71
     /**
70
     /**
72
      * The length of the remote participants array.
71
      * The length of the remote participants array.
73
      */
72
      */
137
         this._onTabIn = this._onTabIn.bind(this);
136
         this._onTabIn = this._onTabIn.bind(this);
138
         this._gridItemKey = this._gridItemKey.bind(this);
137
         this._gridItemKey = this._gridItemKey.bind(this);
139
         this._listItemKey = this._listItemKey.bind(this);
138
         this._listItemKey = this._listItemKey.bind(this);
139
+        this._onGridItemsRendered = this._onGridItemsRendered.bind(this);
140
+        this._onListItemsRendered = this._onListItemsRendered.bind(this);
140
     }
141
     }
141
 
142
 
142
     /**
143
     /**
268
         return _remoteParticipants[index];
269
         return _remoteParticipants[index];
269
     }
270
     }
270
 
271
 
272
+    _onListItemsRendered: Object => void;
273
+
274
+    /**
275
+     * Handles items rendered changes in stage view.
276
+     *
277
+     * @param {Object} data - Information about the rendered items.
278
+     * @returns {void}
279
+     */
280
+    _onListItemsRendered({ overscanStartIndex, overscanStopIndex }) {
281
+        const { dispatch } = this.props;
282
+
283
+        dispatch(setVisibleRemoteParticipants(overscanStartIndex, overscanStopIndex));
284
+    }
285
+
286
+    _onGridItemsRendered: Object => void;
287
+
288
+    /**
289
+     * Handles items rendered changes in tile view.
290
+     *
291
+     * @param {Object} data - Information about the rendered items.
292
+     * @returns {void}
293
+     */
294
+    _onGridItemsRendered({
295
+        overscanColumnStartIndex,
296
+        overscanColumnStopIndex,
297
+        overscanRowStartIndex,
298
+        overscanRowStopIndex
299
+    }) {
300
+        const { _columns, dispatch } = this.props;
301
+        const startIndex = (overscanRowStartIndex * _columns) + overscanColumnStartIndex;
302
+        const endIndex = (overscanRowStopIndex * _columns) + overscanColumnStopIndex;
303
+
304
+        dispatch(setVisibleRemoteParticipants(startIndex, endIndex));
305
+    }
306
+
271
     /**
307
     /**
272
      * Renders the thumbnails for remote participants.
308
      * Renders the thumbnails for remote participants.
273
      *
309
      *
301
                     initialScrollLeft = { 0 }
337
                     initialScrollLeft = { 0 }
302
                     initialScrollTop = { 0 }
338
                     initialScrollTop = { 0 }
303
                     itemKey = { this._gridItemKey }
339
                     itemKey = { this._gridItemKey }
340
+                    onItemsRendered = { this._onGridItemsRendered }
304
                     rowCount = { _rows }
341
                     rowCount = { _rows }
305
                     rowHeight = { _thumbnailHeight + TILE_VERTICAL_MARGIN }
342
                     rowHeight = { _thumbnailHeight + TILE_VERTICAL_MARGIN }
306
                     width = { _filmstripWidth }>
343
                     width = { _filmstripWidth }>
318
             height: _filmstripHeight,
355
             height: _filmstripHeight,
319
             itemKey: this._listItemKey,
356
             itemKey: this._listItemKey,
320
             itemSize: 0,
357
             itemSize: 0,
358
+            onItemsRendered: this._onListItemsRendered,
321
             width: _filmstripWidth,
359
             width: _filmstripWidth,
322
             style: {
360
             style: {
323
                 willChange: 'auto'
361
                 willChange: 'auto'

+ 7
- 10
react/features/filmstrip/components/web/ThumbnailWrapper.js 查看文件

13
 type Props = {
13
 type Props = {
14
 
14
 
15
     /**
15
     /**
16
-     * The ID of the participant associated with the Thumbnail.
16
+     * The horizontal offset in px for the thumbnail. Used to center the thumbnails in the last row in tile view.
17
      */
17
      */
18
-    _participantID: ?string,
18
+     _horizontalOffset: number,
19
 
19
 
20
     /**
20
     /**
21
-     * The horizontal offset in px for the thumbnail. Used to center the thumbnails in the last row in tile view.
21
+     * The ID of the participant associated with the Thumbnail.
22
      */
22
      */
23
-    _horizontalOffset: number,
23
+    _participantID: ?string,
24
 
24
 
25
     /**
25
     /**
26
      * The index of the column in tile view.
26
      * The index of the column in tile view.
114
 
114
 
115
         if (rowIndex === rows - 1) { // center the last row
115
         if (rowIndex === rows - 1) { // center the last row
116
             const { width: thumbnailWidth } = thumbnailSize;
116
             const { width: thumbnailWidth } = thumbnailSize;
117
-            const participantsInTheLastRow = (remoteParticipantsLength + 1) % columns;
117
+            const partialLastRowParticipantsNumber = (remoteParticipantsLength + 1) % columns;
118
 
118
 
119
-            if (participantsInTheLastRow > 0) {
120
-                horizontalOffset = Math.floor((columns - participantsInTheLastRow) * (thumbnailWidth + 4) / 2);
119
+            if (partialLastRowParticipantsNumber > 0) {
120
+                horizontalOffset = Math.floor((columns - partialLastRowParticipantsNumber) * (thumbnailWidth + 4) / 2);
121
             }
121
             }
122
-
123
         }
122
         }
124
 
123
 
125
         if (index > remoteParticipantsLength) {
124
         if (index > remoteParticipantsLength) {
133
             };
132
             };
134
         }
133
         }
135
 
134
 
136
-
137
         return {
135
         return {
138
             _participantID: remoteParticipants[index],
136
             _participantID: remoteParticipants[index],
139
             _horizontalOffset: horizontalOffset
137
             _horizontalOffset: horizontalOffset
140
         };
138
         };
141
-
142
     }
139
     }
143
 
140
 
144
     const { index } = ownProps;
141
     const { index } = ownProps;

+ 58
- 2
react/features/filmstrip/reducer.js 查看文件

9
     SET_HORIZONTAL_VIEW_DIMENSIONS,
9
     SET_HORIZONTAL_VIEW_DIMENSIONS,
10
     SET_TILE_VIEW_DIMENSIONS,
10
     SET_TILE_VIEW_DIMENSIONS,
11
     SET_VERTICAL_VIEW_DIMENSIONS,
11
     SET_VERTICAL_VIEW_DIMENSIONS,
12
+    SET_VISIBLE_REMOTE_PARTICIPANTS,
12
     SET_VOLUME
13
     SET_VOLUME
13
 } from './actionTypes';
14
 } from './actionTypes';
14
 
15
 
66
      * @public
67
      * @public
67
      * @type {boolean}
68
      * @type {boolean}
68
      */
69
      */
69
-    visible: true
70
+    visible: true,
71
+
72
+    /**
73
+     * The end index in the remote participants array that is visible in the filmstrip.
74
+     *
75
+     * @public
76
+     * @type {number}
77
+     */
78
+    visibleParticipantsEndIndex: 0,
79
+
80
+    /**
81
+     * The visible participants in the filmstrip.
82
+     *
83
+     * @public
84
+     * @type {Array<string>}
85
+     */
86
+    visibleParticipants: [],
87
+
88
+
89
+    /**
90
+     * The start index in the remote participants array that is visible in the filmstrip.
91
+     *
92
+     * @public
93
+     * @type {number}
94
+     */
95
+    visibleParticipantsStartIndex: 0
70
 };
96
 };
71
 
97
 
72
 ReducerRegistry.register(
98
 ReducerRegistry.register(
112
                     [action.participantId]: action.volume
138
                     [action.participantId]: action.volume
113
                 }
139
                 }
114
             };
140
             };
141
+        case SET_VISIBLE_REMOTE_PARTICIPANTS:
142
+            return {
143
+                ...state,
144
+                visibleParticipantsStartIndex: action.startIndex,
145
+                visibleParticipantsEndIndex: action.endIndex,
146
+                visibleParticipants: state.remoteParticipants.slice(action.startIndex, action.endIndex + 1)
147
+            };
115
         case PARTICIPANT_JOINED: {
148
         case PARTICIPANT_JOINED: {
116
             const { id, local } = action.participant;
149
             const { id, local } = action.participant;
117
 
150
 
118
             if (!local) {
151
             if (!local) {
119
                 state.remoteParticipants = [ ...state.remoteParticipants, id ];
152
                 state.remoteParticipants = [ ...state.remoteParticipants, id ];
153
+
154
+                const { visibleParticipantsStartIndex: startIndex, visibleParticipantsEndIndex: endIndex } = state;
155
+
156
+                if (state.remoteParticipants.length - 1 <= endIndex) {
157
+                    state.visibleParticipants = state.remoteParticipants.slice(startIndex, endIndex + 1);
158
+                }
120
             }
159
             }
121
 
160
 
122
             return state;
161
             return state;
128
                 return state;
167
                 return state;
129
             }
168
             }
130
 
169
 
131
-            state.remoteParticipants = state.remoteParticipants.filter(participantId => participantId !== id);
170
+            let removedParticipantIndex = 0;
171
+
172
+            state.remoteParticipants = state.remoteParticipants.filter((participantId, index) => {
173
+                if (participantId === id) {
174
+                    removedParticipantIndex = index;
175
+
176
+                    return false;
177
+                }
178
+
179
+                return true;
180
+            });
181
+
182
+            const { visibleParticipantsStartIndex: startIndex, visibleParticipantsEndIndex: endIndex } = state;
183
+
184
+            if (removedParticipantIndex >= startIndex && removedParticipantIndex <= endIndex) {
185
+                state.visibleParticipants = state.remoteParticipants.slice(startIndex, endIndex + 1);
186
+            }
187
+
132
             delete state.participantsVolume[id];
188
             delete state.participantsVolume[id];
133
 
189
 
134
             return state;
190
             return state;

+ 0
- 20
react/features/large-video/actions.any.js 查看文件

3
 import type { Dispatch } from 'redux';
3
 import type { Dispatch } from 'redux';
4
 
4
 
5
 import { MEDIA_TYPE } from '../base/media';
5
 import { MEDIA_TYPE } from '../base/media';
6
-import { getParticipants } from '../base/participants';
7
-import { selectEndpoints, shouldDisplayTileView } from '../video-layout';
8
 
6
 
9
 import {
7
 import {
10
     SELECT_LARGE_VIDEO_PARTICIPANT,
8
     SELECT_LARGE_VIDEO_PARTICIPANT,
11
     UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION
9
     UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION
12
 } from './actionTypes';
10
 } from './actionTypes';
13
 
11
 
14
-/**
15
- * Signals conference to select a participant.
16
- *
17
- * @returns {Function}
18
- */
19
-export function selectParticipant() {
20
-    return (dispatch: Dispatch<any>, getState: Function) => {
21
-        const state = getState();
22
-        const ids = shouldDisplayTileView(state)
23
-            ? getParticipants(state).map(participant => participant.id)
24
-            : [ state['features/large-video'].participantId ];
25
-
26
-        dispatch(selectEndpoints(ids));
27
-    };
28
-}
29
-
30
 /**
12
 /**
31
  * Action to select the participant to be displayed in LargeVideo based on the
13
  * Action to select the participant to be displayed in LargeVideo based on the
32
  * participant id provided. If a participant id is not provided, the LargeVideo
14
  * participant id provided. If a participant id is not provided, the LargeVideo
60
                 type: SELECT_LARGE_VIDEO_PARTICIPANT,
42
                 type: SELECT_LARGE_VIDEO_PARTICIPANT,
61
                 participantId
43
                 participantId
62
             });
44
             });
63
-
64
-            dispatch(selectParticipant());
65
         }
45
         }
66
     };
46
     };
67
 }
47
 }

+ 2
- 29
react/features/large-video/middleware.js 查看文件

1
 // @flow
1
 // @flow
2
 
2
 
3
-import { CONFERENCE_JOINED } from '../base/conference';
4
 import {
3
 import {
5
     DOMINANT_SPEAKER_CHANGED,
4
     DOMINANT_SPEAKER_CHANGED,
6
     PARTICIPANT_JOINED,
5
     PARTICIPANT_JOINED,
11
 import { MiddlewareRegistry } from '../base/redux';
10
 import { MiddlewareRegistry } from '../base/redux';
12
 import { isTestModeEnabled } from '../base/testing';
11
 import { isTestModeEnabled } from '../base/testing';
13
 import {
12
 import {
14
-    getTrackByJitsiTrack,
15
     TRACK_ADDED,
13
     TRACK_ADDED,
16
-    TRACK_REMOVED,
17
-    TRACK_UPDATED
14
+    TRACK_REMOVED
18
 } from '../base/tracks';
15
 } from '../base/tracks';
19
 
16
 
20
-import { selectParticipant, selectParticipantInLargeVideo } from './actions.any';
17
+import { selectParticipantInLargeVideo } from './actions';
21
 import logger from './logger';
18
 import logger from './logger';
22
 
19
 
23
 import './subscriber';
20
 import './subscriber';
54
     case TRACK_REMOVED:
51
     case TRACK_REMOVED:
55
         store.dispatch(selectParticipantInLargeVideo());
52
         store.dispatch(selectParticipantInLargeVideo());
56
         break;
53
         break;
57
-
58
-    case CONFERENCE_JOINED:
59
-        // Ensure a participant is selected on conference join. This addresses
60
-        // the case where video tracks were received before CONFERENCE_JOINED
61
-        // fired; without the conference selection may not happen.
62
-        store.dispatch(selectParticipant());
63
-        break;
64
-
65
-    case TRACK_UPDATED:
66
-        // In order to minimize re-calculations, we need to select participant
67
-        // only if the videoType of the current participant rendered in
68
-        // LargeVideo has changed.
69
-        if ('videoType' in action.track) {
70
-            const state = store.getState();
71
-            const track
72
-                = getTrackByJitsiTrack(
73
-                    state['features/base/tracks'],
74
-                    action.track.jitsiTrack);
75
-            const participantId = state['features/large-video'].participantId;
76
-
77
-            (track.participantId === participantId)
78
-                && store.dispatch(selectParticipant());
79
-        }
80
-        break;
81
     }
54
     }
82
 
55
 
83
     return result;
56
     return result;

+ 2
- 0
react/features/toolbox/components/web/Toolbox.js 查看文件

1363
                         { showOverflowMenuButton && <OverflowMenuButton
1363
                         { showOverflowMenuButton && <OverflowMenuButton
1364
                             ariaControls = 'overflow-menu'
1364
                             ariaControls = 'overflow-menu'
1365
                             isOpen = { _overflowMenuVisible }
1365
                             isOpen = { _overflowMenuVisible }
1366
+                            key = 'overflow-menu'
1366
                             onVisibilityChange = { this._onSetOverflowVisible }>
1367
                             onVisibilityChange = { this._onSetOverflowVisible }>
1367
                             <ul
1368
                             <ul
1368
                                 aria-label = { t(toolbarAccLabel) }
1369
                                 aria-label = { t(toolbarAccLabel) }
1375
                         </OverflowMenuButton>}
1376
                         </OverflowMenuButton>}
1376
                         <HangupButton
1377
                         <HangupButton
1377
                             customClass = 'hangup-button'
1378
                             customClass = 'hangup-button'
1379
+                            key = 'hangup-button'
1378
                             visible = { this.props._shouldShowButton('hangup') } />
1380
                             visible = { this.props._shouldShowButton('hangup') } />
1379
                     </div>
1381
                     </div>
1380
                 </div>
1382
                 </div>

+ 0
- 6
react/features/video-layout/actionTypes.js 查看文件

10
 export const SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED
10
 export const SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED
11
     = 'SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED';
11
     = 'SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED';
12
 
12
 
13
-/**
14
- * The type of the action which sets the list of the endpoints to be selected for video forwarding
15
- * from the bridge.
16
- */
17
-export const SELECT_ENDPOINTS = 'SELECT_ENDPOINTS';
18
-
19
 /**
13
 /**
20
  * The type of the action which enables or disables the feature for showing
14
  * The type of the action which enables or disables the feature for showing
21
  * video thumbnails in a two-axis tile view.
15
  * video thumbnails in a two-axis tile view.

+ 0
- 18
react/features/video-layout/actions.js 查看文件

4
 
4
 
5
 import {
5
 import {
6
     SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
6
     SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
7
-    SELECT_ENDPOINTS,
8
     SET_TILE_VIEW
7
     SET_TILE_VIEW
9
 } from './actionTypes';
8
 } from './actionTypes';
10
 import { shouldDisplayTileView } from './functions';
9
 import { shouldDisplayTileView } from './functions';
11
 
10
 
12
-/**
13
- * Creates a (redux) action which signals that a new set of remote endpoints need to be selected.
14
- *
15
- * @param {Array<string>} participantIds - The remote participants that are currently selected
16
- * for video forwarding from the bridge.
17
- * @returns {{
18
- *      type: SELECT_ENDPOINTS,
19
- *      particpantsIds: Array<string>
20
- * }}
21
- */
22
-export function selectEndpoints(participantIds: Array<string>) {
23
-    return {
24
-        type: SELECT_ENDPOINTS,
25
-        participantIds
26
-    };
27
-}
28
-
29
 /**
11
 /**
30
  * Creates a (redux) action which signals that the list of known remote participants
12
  * Creates a (redux) action which signals that the list of known remote participants
31
  * with screen shares has changed.
13
  * with screen shares has changed.

+ 0
- 8
react/features/video-layout/reducer.js 查看文件

4
 
4
 
5
 import {
5
 import {
6
     SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
6
     SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
7
-    SELECT_ENDPOINTS,
8
     SET_TILE_VIEW
7
     SET_TILE_VIEW
9
 } from './actionTypes';
8
 } from './actionTypes';
10
 
9
 
35
         };
34
         };
36
     }
35
     }
37
 
36
 
38
-    case SELECT_ENDPOINTS: {
39
-        return {
40
-            ...state,
41
-            selectedEndpoints: action.participantIds
42
-        };
43
-    }
44
-
45
     case SET_TILE_VIEW:
37
     case SET_TILE_VIEW:
46
         return {
38
         return {
47
             ...state,
39
             ...state,

+ 0
- 14
react/features/video-layout/subscriber.js 查看文件

4
 
4
 
5
 import { StateListenerRegistry, equals } from '../base/redux';
5
 import { StateListenerRegistry, equals } from '../base/redux';
6
 import { isFollowMeActive } from '../follow-me';
6
 import { isFollowMeActive } from '../follow-me';
7
-import { selectParticipant } from '../large-video/actions.any';
8
 
7
 
9
 import { setRemoteParticipantsWithScreenShare } from './actions';
8
 import { setRemoteParticipantsWithScreenShare } from './actions';
10
 import { getAutoPinSetting, updateAutoPinnedParticipant } from './functions';
9
 import { getAutoPinSetting, updateAutoPinnedParticipant } from './functions';
11
 
10
 
12
-/**
13
- * StateListenerRegistry provides a reliable way of detecting changes to
14
- * preferred layout state and dispatching additional actions.
15
- */
16
-StateListenerRegistry.register(
17
-    /* selector */ state => state['features/video-layout'].tileViewEnabled,
18
-    /* listener */ (tileViewEnabled, store) => {
19
-        const { dispatch } = store;
20
-
21
-        dispatch(selectParticipant());
22
-    }
23
-);
24
-
25
 /**
11
 /**
26
  * For auto-pin mode, listen for changes to the known media tracks and look
12
  * For auto-pin mode, listen for changes to the known media tracks and look
27
  * for updates to screen shares. The listener is debounced to avoid state
13
  * for updates to screen shares. The listener is debounced to avoid state

+ 2
- 1
react/features/video-quality/constants.js 查看文件

14
     ULTRA: 2160,
14
     ULTRA: 2160,
15
     HIGH: 720,
15
     HIGH: 720,
16
     STANDARD: 360,
16
     STANDARD: 360,
17
-    LOW: 180
17
+    LOW: 180,
18
+    NONE: 0
18
 };
19
 };
19
 
20
 
20
 /**
21
 /**

+ 64
- 16
react/features/video-quality/subscriber.js 查看文件

17
 declare var APP: Object;
17
 declare var APP: Object;
18
 
18
 
19
 /**
19
 /**
20
- * StateListenerRegistry provides a reliable way of detecting changes to selected
21
- * endpoints state and dispatching additional actions. The listener is debounced
20
+ * Handles changes in the visible participants in the filmstrip. The listener is debounced
22
  * so that the client doesn't end up sending too many bridge messages when the user is
21
  * so that the client doesn't end up sending too many bridge messages when the user is
23
  * scrolling through the thumbnails prompting updates to the selected endpoints.
22
  * scrolling through the thumbnails prompting updates to the selected endpoints.
24
  */
23
  */
25
 StateListenerRegistry.register(
24
 StateListenerRegistry.register(
26
-    /* selector */ state => state['features/video-layout'].selectedEndpoints,
27
-    /* listener */ debounce((selectedEndpoints, store) => {
25
+    /* selector */ state => state['features/filmstrip'].visibleParticipants,
26
+    /* listener */ debounce((visibleParticipants, store) => {
28
         _updateReceiverVideoConstraints(store);
27
         _updateReceiverVideoConstraints(store);
29
-    }, 1000));
28
+    }, 100));
29
+
30
+/**
31
+ * Handles the use case when the on-stage participant has changed.
32
+ */
33
+StateListenerRegistry.register(
34
+    state => state['features/large-video'].participantId,
35
+    (participantId, store) => {
36
+        _updateReceiverVideoConstraints(store);
37
+    }
38
+);
39
+
40
+/**
41
+ * Handles the use case when we have set some of the constraints in redux but the conference object wasn't available
42
+ * and we haven't been able to pass the constraints to lib-jitsi-meet.
43
+ */
44
+StateListenerRegistry.register(
45
+    state => state['features/base/conference'].conference,
46
+    (conference, store) => {
47
+        _updateReceiverVideoConstraints(store);
48
+    }
49
+);
50
+
51
+/**
52
+ * Updates the receiver constraints when the layout changes. When we are in stage view we need to handle the
53
+ * on-stage participant differently.
54
+ */
55
+StateListenerRegistry.register(
56
+    /* selector */ state => state['features/video-layout'].tileViewEnabled,
57
+    /* listener */ (tileViewEnabled, store) => {
58
+        _updateReceiverVideoConstraints(store);
59
+    }
60
+);
30
 
61
 
31
 /**
62
 /**
32
  * StateListenerRegistry provides a reliable way of detecting changes to
63
  * StateListenerRegistry provides a reliable way of detecting changes to
64
             typeof APP !== 'undefined' && APP.API.notifyVideoQualityChanged(preferredVideoQuality);
95
             typeof APP !== 'undefined' && APP.API.notifyVideoQualityChanged(preferredVideoQuality);
65
         }
96
         }
66
         changedReceiverVideoQuality && _updateReceiverVideoConstraints(store);
97
         changedReceiverVideoQuality && _updateReceiverVideoConstraints(store);
98
+    }, {
99
+        deepEquals: true
67
     });
100
     });
68
 
101
 
69
 /**
102
 /**
156
     }
189
     }
157
     const { lastN } = state['features/base/lastn'];
190
     const { lastN } = state['features/base/lastn'];
158
     const { maxReceiverVideoQuality, preferredVideoQuality } = state['features/video-quality'];
191
     const { maxReceiverVideoQuality, preferredVideoQuality } = state['features/video-quality'];
159
-    const { selectedEndpoints } = state['features/video-layout'];
192
+    const { visibleParticipants } = state['features/filmstrip'];
193
+    const { participantId: largeVideoParticipantId } = state['features/large-video'];
160
     const maxFrameHeight = Math.min(maxReceiverVideoQuality, preferredVideoQuality);
194
     const maxFrameHeight = Math.min(maxReceiverVideoQuality, preferredVideoQuality);
161
     const receiverConstraints = {
195
     const receiverConstraints = {
162
         constraints: {},
196
         constraints: {},
163
-        defaultConstraints: { 'maxHeight': VIDEO_QUALITY_LEVELS.LOW },
197
+        defaultConstraints: { 'maxHeight': VIDEO_QUALITY_LEVELS.NONE },
164
         lastN,
198
         lastN,
165
         onStageEndpoints: [],
199
         onStageEndpoints: [],
166
         selectedEndpoints: []
200
         selectedEndpoints: []
167
     };
201
     };
168
 
202
 
169
-    if (!selectedEndpoints?.length) {
170
-        return;
171
-    }
203
+    // Tile view.
204
+    if (shouldDisplayTileView(state)) {
205
+        if (!visibleParticipants?.length) {
206
+            return;
207
+        }
172
 
208
 
173
-    // Stage view.
174
-    if (selectedEndpoints?.length === 1) {
175
-        receiverConstraints.constraints[selectedEndpoints[0]] = { 'maxHeight': maxFrameHeight };
176
-        receiverConstraints.onStageEndpoints = selectedEndpoints;
209
+        visibleParticipants.forEach(participantId => {
210
+            receiverConstraints.constraints[participantId] = { 'maxHeight': maxFrameHeight };
211
+        });
177
 
212
 
178
-    // Tile view.
213
+    // Stage view.
179
     } else {
214
     } else {
180
-        receiverConstraints.defaultConstraints = { 'maxHeight': maxFrameHeight };
215
+        if (!visibleParticipants?.length && !largeVideoParticipantId) {
216
+            return;
217
+        }
218
+
219
+        if (visibleParticipants?.length > 0) {
220
+            visibleParticipants.forEach(participantId => {
221
+                receiverConstraints.constraints[participantId] = { 'maxHeight': VIDEO_QUALITY_LEVELS.LOW };
222
+            });
223
+        }
224
+
225
+        if (largeVideoParticipantId) {
226
+            receiverConstraints.constraints[largeVideoParticipantId] = { 'maxHeight': maxFrameHeight };
227
+            receiverConstraints.onStageEndpoints = [ largeVideoParticipantId ];
228
+        }
181
     }
229
     }
182
 
230
 
183
     logger.info(`Setting receiver video constraints to ${JSON.stringify(receiverConstraints)}`);
231
     logger.info(`Setting receiver video constraints to ${JSON.stringify(receiverConstraints)}`);

正在加载...
取消
保存