浏览代码

fix: Fixes selecting screen share when shared video stopped.

master
damencho 4 年前
父节点
当前提交
5f657a7d6c

+ 61
- 3
react/features/video-layout/functions.js 查看文件

1
 // @flow
1
 // @flow
2
+import type { Dispatch } from 'redux';
2
 
3
 
3
 import { getFeatureFlag, TILE_VIEW_ENABLED } from '../base/flags';
4
 import { getFeatureFlag, TILE_VIEW_ENABLED } from '../base/flags';
4
-import { getPinnedParticipant, getParticipantCount } from '../base/participants';
5
+import {
6
+    getPinnedParticipant,
7
+    getParticipantCount,
8
+    pinParticipant
9
+} from '../base/participants';
5
 import {
10
 import {
6
     ASPECT_RATIO_BREAKPOINT,
11
     ASPECT_RATIO_BREAKPOINT,
7
     DEFAULT_MAX_COLUMNS,
12
     DEFAULT_MAX_COLUMNS,
15
 
20
 
16
 declare var interfaceConfig: Object;
21
 declare var interfaceConfig: Object;
17
 
22
 
23
+/**
24
+ * A selector for retrieving the current automatic pinning setting.
25
+ *
26
+ * @private
27
+ * @returns {string|undefined} The string "remote-only" is returned if only
28
+ * remote screen sharing should be automatically pinned, any other truthy value
29
+ * means automatically pin all screen shares. Falsy means do not automatically
30
+ * pin any screen shares.
31
+ */
32
+export function getAutoPinSetting() {
33
+    return typeof interfaceConfig === 'object'
34
+        ? interfaceConfig.AUTO_PIN_LATEST_SCREEN_SHARE
35
+        : 'remote-only';
36
+}
37
+
18
 /**
38
 /**
19
  * Returns the {@code LAYOUTS} constant associated with the layout
39
  * Returns the {@code LAYOUTS} constant associated with the layout
20
  * the application should currently be in.
40
  * the application should currently be in.
72
  * which rows will be added but no more columns.
92
  * which rows will be added but no more columns.
73
  *
93
  *
74
  * @param {Object} state - The redux store state.
94
  * @param {Object} state - The redux store state.
75
- * @param {number} maxColumns - The maximum number of columns that can be
76
- * displayed.
77
  * @returns {Object} An object is return with the desired number of columns,
95
  * @returns {Object} An object is return with the desired number of columns,
78
  * rows, and visible rows (the rest should overflow) for the tile view layout.
96
  * rows, and visible rows (the rest should overflow) for the tile view layout.
79
  */
97
  */
148
 
166
 
149
     return !shouldDisplayNormalMode;
167
     return !shouldDisplayNormalMode;
150
 }
168
 }
169
+
170
+/**
171
+ * Private helper to automatically pin the latest screen share stream or unpin
172
+ * if there are no more screen share streams.
173
+ *
174
+ * @param {Array<string>} screenShares - Array containing the list of all the screen sharing endpoints
175
+ * before the update was triggered (including the ones that have been removed from redux because of the update).
176
+ * @param {Store} store - The redux store.
177
+ * @returns {void}
178
+ */
179
+export function updateAutoPinnedParticipant(
180
+        screenShares: Array<string>, { dispatch, getState }: { dispatch: Dispatch<any>, getState: Function }) {
181
+    const state = getState();
182
+    const remoteScreenShares = state['features/video-layout'].remoteScreenShares;
183
+    const pinned = getPinnedParticipant(getState);
184
+
185
+    // if the pinned participant is shared video or some other fake participant we want to skip auto-pinning
186
+    if (pinned?.isFakeParticipant) {
187
+        return;
188
+    }
189
+
190
+    // Unpin the screen share when the screen sharing participant leaves. Switch to tile view if no other
191
+    // participant was pinned before screen share was auto-pinned, pin the previously pinned participant otherwise.
192
+    if (!remoteScreenShares?.length) {
193
+        let participantId = null;
194
+
195
+        if (pinned && !screenShares.find(share => share === pinned.id)) {
196
+            participantId = pinned.id;
197
+        }
198
+        dispatch(pinParticipant(participantId));
199
+
200
+        return;
201
+    }
202
+
203
+    const latestScreenShareParticipantId = remoteScreenShares[remoteScreenShares.length - 1];
204
+
205
+    if (latestScreenShareParticipantId) {
206
+        dispatch(pinParticipant(latestScreenShareParticipantId));
207
+    }
208
+}

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

1
 // @flow
1
 // @flow
2
 
2
 
3
 import { getCurrentConference } from '../base/conference';
3
 import { getCurrentConference } from '../base/conference';
4
-import { PIN_PARTICIPANT, pinParticipant, getPinnedParticipant } from '../base/participants';
4
+import {
5
+    PARTICIPANT_LEFT,
6
+    PIN_PARTICIPANT,
7
+    pinParticipant,
8
+    getParticipantById,
9
+    getPinnedParticipant
10
+} from '../base/participants';
5
 import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
11
 import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
6
 import { SET_DOCUMENT_EDITING_STATUS } from '../etherpad';
12
 import { SET_DOCUMENT_EDITING_STATUS } from '../etherpad';
13
+import { isFollowMeActive } from '../follow-me';
7
 
14
 
8
 import { SET_TILE_VIEW } from './actionTypes';
15
 import { SET_TILE_VIEW } from './actionTypes';
9
 import { setTileView } from './actions';
16
 import { setTileView } from './actions';
17
+import { getAutoPinSetting, updateAutoPinnedParticipant } from './functions';
10
 
18
 
11
 import './subscriber';
19
 import './subscriber';
12
 
20
 
19
  * @returns {Function}
27
  * @returns {Function}
20
  */
28
  */
21
 MiddlewareRegistry.register(store => next => action => {
29
 MiddlewareRegistry.register(store => next => action => {
30
+
31
+    // we want to extract the leaving participant and check its type before actually the participant being removed.
32
+    let shouldUpdateAutoPin = false;
33
+
34
+    switch (action.type) {
35
+    case PARTICIPANT_LEFT: {
36
+        if (!getAutoPinSetting() || isFollowMeActive(store)) {
37
+            break;
38
+        }
39
+        shouldUpdateAutoPin = getParticipantById(store.getState(), action.participant.id)?.isFakeParticipant;
40
+        break;
41
+    }
42
+    }
43
+
22
     const result = next(action);
44
     const result = next(action);
23
 
45
 
24
     switch (action.type) {
46
     switch (action.type) {
50
         }
72
         }
51
     }
73
     }
52
 
74
 
75
+    if (shouldUpdateAutoPin) {
76
+        const screenShares = store.getState()['features/video-layout'].remoteScreenShares || [];
77
+
78
+        updateAutoPinnedParticipant(screenShares, store);
79
+    }
53
 
80
 
54
     return result;
81
     return result;
55
 });
82
 });
69
     });
96
     });
70
 
97
 
71
 /**
98
 /**
72
- * Respores tile view state, if it wasn't updated since then.
99
+ * Restores tile view state, if it wasn't updated since then.
73
  *
100
  *
74
  * @param {Object} store - The Redux Store.
101
  * @param {Object} store - The Redux Store.
75
  * @returns {void}
102
  * @returns {void}

+ 5
- 62
react/features/video-layout/subscriber.js 查看文件

2
 
2
 
3
 import debounce from 'lodash/debounce';
3
 import debounce from 'lodash/debounce';
4
 
4
 
5
-import { pinParticipant, getPinnedParticipant } from '../base/participants';
6
 import { StateListenerRegistry, equals } from '../base/redux';
5
 import { StateListenerRegistry, equals } from '../base/redux';
7
 import { isFollowMeActive } from '../follow-me';
6
 import { isFollowMeActive } from '../follow-me';
8
-import { selectParticipant } from '../large-video/actions';
7
+import { selectParticipant } from '../large-video/actions.any';
9
 
8
 
10
 import { setRemoteParticipantsWithScreenShare } from './actions';
9
 import { setRemoteParticipantsWithScreenShare } from './actions';
11
-
12
-declare var APP: Object;
13
-declare var interfaceConfig: Object;
10
+import { getAutoPinSetting, updateAutoPinnedParticipant } from './functions';
14
 
11
 
15
 /**
12
 /**
16
  * StateListenerRegistry provides a reliable way of detecting changes to
13
  * StateListenerRegistry provides a reliable way of detecting changes to
33
 StateListenerRegistry.register(
30
 StateListenerRegistry.register(
34
     /* selector */ state => state['features/base/tracks'],
31
     /* selector */ state => state['features/base/tracks'],
35
     /* listener */ debounce((tracks, store) => {
32
     /* listener */ debounce((tracks, store) => {
36
-        if (!_getAutoPinSetting() || isFollowMeActive(store)) {
33
+        if (!getAutoPinSetting() || isFollowMeActive(store)) {
37
             return;
34
             return;
38
         }
35
         }
39
 
36
 
40
         const oldScreenSharesOrder = store.getState()['features/video-layout'].remoteScreenShares || [];
37
         const oldScreenSharesOrder = store.getState()['features/video-layout'].remoteScreenShares || [];
41
         const knownSharingParticipantIds = tracks.reduce((acc, track) => {
38
         const knownSharingParticipantIds = tracks.reduce((acc, track) => {
42
             if (track.mediaType === 'video' && track.videoType === 'desktop') {
39
             if (track.mediaType === 'video' && track.videoType === 'desktop') {
43
-                const skipTrack = _getAutoPinSetting() === 'remote-only' && track.local;
40
+                const skipTrack = getAutoPinSetting() === 'remote-only' && track.local;
44
 
41
 
45
                 if (!skipTrack) {
42
                 if (!skipTrack) {
46
                     acc.push(track.participantId);
43
                     acc.push(track.participantId);
68
             store.dispatch(
65
             store.dispatch(
69
                 setRemoteParticipantsWithScreenShare(newScreenSharesOrder));
66
                 setRemoteParticipantsWithScreenShare(newScreenSharesOrder));
70
 
67
 
71
-            _updateAutoPinnedParticipant(oldScreenSharesOrder, store);
68
+            updateAutoPinnedParticipant(oldScreenSharesOrder, store);
72
         }
69
         }
73
     }, 100));
70
     }, 100));
74
-
75
-/**
76
- * A selector for retrieving the current automatic pinning setting.
77
- *
78
- * @private
79
- * @returns {string|undefined} The string "remote-only" is returned if only
80
- * remote screensharing should be automatically pinned, any other truthy value
81
- * means automatically pin all screenshares. Falsy means do not automatically
82
- * pin any screenshares.
83
- */
84
-function _getAutoPinSetting() {
85
-    return typeof interfaceConfig === 'object'
86
-        ? interfaceConfig.AUTO_PIN_LATEST_SCREEN_SHARE
87
-        : 'remote-only';
88
-}
89
-
90
-/**
91
- * Private helper to automatically pin the latest screen share stream or unpin
92
- * if there are no more screen share streams.
93
- *
94
- * @param {Array<string>} screenShares - Array containing the list of all the screensharing endpoints
95
- * before the update was triggered (including the ones that have been removed from redux because of the update).
96
- * @param {Store} store - The redux store.
97
- * @returns {void}
98
- */
99
-function _updateAutoPinnedParticipant(screenShares, { dispatch, getState }) {
100
-    const state = getState();
101
-    const remoteScreenShares = state['features/video-layout'].remoteScreenShares;
102
-    const pinned = getPinnedParticipant(getState);
103
-
104
-    // if the pinned participant is shared video or some other fake participant we want to skip auto-pinning
105
-    if (pinned?.isFakeParticipant) {
106
-        return;
107
-    }
108
-
109
-    // Unpin the screenshare when the screensharing participant leaves. Switch to tile view if no other
110
-    // participant was pinned before screenshare was auto-pinned, pin the previously pinned participant otherwise.
111
-    if (!remoteScreenShares?.length) {
112
-        let participantId = null;
113
-
114
-        if (pinned && !screenShares.find(share => share === pinned.id)) {
115
-            participantId = pinned.id;
116
-        }
117
-        dispatch(pinParticipant(participantId));
118
-
119
-        return;
120
-    }
121
-
122
-    const latestScreenshareParticipantId = remoteScreenShares[remoteScreenShares.length - 1];
123
-
124
-    if (latestScreenshareParticipantId) {
125
-        dispatch(pinParticipant(latestScreenshareParticipantId));
126
-    }
127
-}

正在加载...
取消
保存