Kaynağa Gözat

refactor(multi-stream) refactor virtual screenshare creation and support plan-b clients (#11445)

* fix(multi-stream) update selector to find ss track by videoType or mediaType

* ref(multi-stream) move fake ss creation logic and support video type changed

* refactor(multi-stream) decouple sending and receiving multiple screenshare streams

* fix(multi-stream) fix receiver constraints with signaling and without multi-stream

* fix(mutli-stream) ensure plan b original SS thumbnail displays avatar

* fix(multi-stream) show fake SS for plan b sender

* refactor(multi-stream) poc for moving SS creation to state listener

* remove reference to fake SS creation

* fix lint errors

* rename to virtual screenshare participants

* fix minor bugs

* rename participant subscriber to specify web support only
master
William Liang 3 yıl önce
ebeveyn
işleme
d3fe246f61
No account linked to committer's email address
33 değiştirilmiş dosya ile 365 ekleme ve 301 silme
  1. 8
    11
      conference.js
  2. 14
    2
      modules/UI/videolayout/LargeVideoManager.js
  3. 4
    4
      modules/UI/videolayout/VideoLayout.js
  4. 2
    2
      react/features/base/conference/middleware.web.js
  5. 12
    3
      react/features/base/config/functions.any.js
  6. 3
    3
      react/features/base/lastn/middleware.js
  7. 2
    2
      react/features/base/media/middleware.js
  8. 31
    0
      react/features/base/participants/actions.js
  9. 20
    21
      react/features/base/participants/functions.js
  10. 6
    5
      react/features/base/participants/middleware.js
  11. 26
    19
      react/features/base/participants/reducer.js
  12. 0
    0
      react/features/base/participants/subscriber.native.js
  13. 69
    0
      react/features/base/participants/subscriber.web.js
  14. 0
    12
      react/features/base/tracks/actionTypes.ts
  15. 7
    29
      react/features/base/tracks/actions.js
  16. 52
    18
      react/features/base/tracks/functions.js
  17. 11
    88
      react/features/base/tracks/middleware.js
  18. 3
    3
      react/features/connection-indicator/components/web/ConnectionIndicator.js
  19. 3
    3
      react/features/connection-indicator/components/web/ConnectionIndicatorContent.js
  20. 3
    3
      react/features/connection-stats/components/ConnectionStatsTable.js
  21. 15
    14
      react/features/filmstrip/components/web/Thumbnail.js
  22. 4
    4
      react/features/filmstrip/components/web/ThumbnailTopIndicators.js
  23. 4
    4
      react/features/filmstrip/components/web/VirtualScreenshareParticipant.js
  24. 7
    7
      react/features/filmstrip/functions.any.js
  25. 18
    5
      react/features/filmstrip/functions.web.js
  26. 2
    2
      react/features/filmstrip/subscriber.any.js
  27. 4
    4
      react/features/notifications/middleware.js
  28. 2
    2
      react/features/screen-share/actions.js
  29. 3
    3
      react/features/video-layout/actionTypes.ts
  30. 8
    7
      react/features/video-layout/actions.js
  31. 4
    4
      react/features/video-layout/reducer.js
  32. 8
    8
      react/features/video-layout/subscriber.js
  33. 10
    9
      react/features/video-quality/subscriber.js

+ 8
- 11
conference.js Dosyayı Görüntüle

@@ -56,8 +56,7 @@ import {
56 56
 } from './react/features/base/conference';
57 57
 import {
58 58
     getReplaceParticipant,
59
-    getMultipleVideoSupportFeatureFlag,
60
-    getSourceNameSignalingFeatureFlag
59
+    getMultipleVideoSendingSupportFeatureFlag
61 60
 } from './react/features/base/config/functions';
62 61
 import {
63 62
     checkAndNotifyForNewDevice,
@@ -97,7 +96,7 @@ import {
97 96
     dominantSpeakerChanged,
98 97
     getLocalParticipant,
99 98
     getNormalizedDisplayName,
100
-    getScreenshareParticipantByOwnerId,
99
+    getVirtualScreenshareParticipantByOwnerId,
101 100
     localParticipantAudioLevelChanged,
102 101
     localParticipantConnectionStatusChanged,
103 102
     localParticipantRoleChanged,
@@ -1472,7 +1471,7 @@ export default {
1472 1471
 
1473 1472
                 // In the multi-stream mode, add the track to the conference if there is no existing track, replace it
1474 1473
                 // otherwise.
1475
-                if (getMultipleVideoSupportFeatureFlag(state)) {
1474
+                if (getMultipleVideoSendingSupportFeatureFlag(state)) {
1476 1475
                     const trackAction = oldTrack
1477 1476
                         ? replaceLocalTrack(oldTrack, newTrack, room)
1478 1477
                         : addLocalTrack(newTrack);
@@ -2265,14 +2264,12 @@ export default {
2265 2264
                     name: formattedDisplayName
2266 2265
                 }));
2267 2266
 
2268
-                if (getSourceNameSignalingFeatureFlag(state)) {
2269
-                    const screenshareParticipantId = getScreenshareParticipantByOwnerId(state, id)?.id;
2267
+                const virtualScreenshareParticipantId = getVirtualScreenshareParticipantByOwnerId(state, id)?.id;
2270 2268
 
2271
-                    if (screenshareParticipantId) {
2272
-                        APP.store.dispatch(
2273
-                            screenshareParticipantDisplayNameChanged(screenshareParticipantId, formattedDisplayName)
2274
-                        );
2275
-                    }
2269
+                if (virtualScreenshareParticipantId) {
2270
+                    APP.store.dispatch(
2271
+                        screenshareParticipantDisplayNameChanged(virtualScreenshareParticipantId, formattedDisplayName)
2272
+                    );
2276 2273
                 }
2277 2274
 
2278 2275
                 APP.API.notifyDisplayNameChanged(id, {

+ 14
- 2
modules/UI/videolayout/LargeVideoManager.js Dosyayı Görüntüle

@@ -9,7 +9,10 @@ import { Provider } from 'react-redux';
9 9
 import { createScreenSharingIssueEvent, sendAnalytics } from '../../../react/features/analytics';
10 10
 import { Avatar } from '../../../react/features/base/avatar';
11 11
 import theme from '../../../react/features/base/components/themes/participantsPaneTheme.json';
12
-import { getSourceNameSignalingFeatureFlag } from '../../../react/features/base/config';
12
+import {
13
+    getMultipleVideoSupportFeatureFlag,
14
+    getSourceNameSignalingFeatureFlag
15
+} from '../../../react/features/base/config';
13 16
 import { i18next } from '../../../react/features/base/i18n';
14 17
 import { JitsiTrackEvents } from '../../../react/features/base/lib-jitsi-meet';
15 18
 import { VIDEO_TYPE } from '../../../react/features/base/media';
@@ -283,9 +286,18 @@ export default class LargeVideoManager {
283 286
             }
284 287
 
285 288
             const isAudioOnly = APP.conference.isAudioOnly();
289
+
290
+            // Multi-stream is not supported on plan-b endpoints even if its is enabled via config.js. A virtual
291
+            // screenshare tile is still created when a remote endpoint starts screenshare to keep the behavior
292
+            // consistent and an avatar is displayed on the original participant thumbnail as long as screenshare is in
293
+            // progress.
294
+            const legacyScreenshare = getMultipleVideoSupportFeatureFlag(state)
295
+                                        && videoType === VIDEO_TYPE.DESKTOP
296
+                                        && !participant.isVirtualScreenshareParticipant;
297
+
286 298
             const showAvatar
287 299
                 = isVideoContainer
288
-                    && ((isAudioOnly && videoType !== VIDEO_TYPE.DESKTOP) || !isVideoRenderable);
300
+                    && ((isAudioOnly && videoType !== VIDEO_TYPE.DESKTOP) || !isVideoRenderable || legacyScreenshare);
289 301
 
290 302
             let promise;
291 303
 

+ 4
- 4
modules/UI/videolayout/VideoLayout.js Dosyayı Görüntüle

@@ -10,7 +10,7 @@ import {
10 10
 } from '../../../react/features/base/participants';
11 11
 import {
12 12
     getTrackByMediaTypeAndParticipant,
13
-    getFakeScreenshareParticipantTrack
13
+    getVirtualScreenshareParticipantTrack
14 14
 } from '../../../react/features/base/tracks';
15 15
 
16 16
 import LargeVideoManager from './LargeVideoManager';
@@ -95,7 +95,7 @@ const VideoLayout = {
95 95
             return VIDEO_TYPE.CAMERA;
96 96
         }
97 97
 
98
-        if (getSourceNameSignalingFeatureFlag(state) && participant?.isFakeScreenShareParticipant) {
98
+        if (getSourceNameSignalingFeatureFlag(state) && participant?.isVirtualScreenshareParticipant) {
99 99
             return VIDEO_TYPE.DESKTOP;
100 100
         }
101 101
 
@@ -190,8 +190,8 @@ const VideoLayout = {
190 190
 
191 191
         let videoTrack;
192 192
 
193
-        if (getSourceNameSignalingFeatureFlag(state) && participant?.isFakeScreenShareParticipant) {
194
-            videoTrack = getFakeScreenshareParticipantTrack(tracks, id);
193
+        if (getSourceNameSignalingFeatureFlag(state) && participant?.isVirtualScreenshareParticipant) {
194
+            videoTrack = getVirtualScreenshareParticipantTrack(tracks, id);
195 195
         } else {
196 196
             videoTrack = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, id);
197 197
         }

+ 2
- 2
react/features/base/conference/middleware.web.js Dosyayı Görüntüle

@@ -9,7 +9,7 @@ import {
9 9
 import { setScreenAudioShareState, setScreenshareAudioTrack } from '../../screen-share';
10 10
 import { AudioMixerEffect } from '../../stream-effects/audio-mixer/AudioMixerEffect';
11 11
 import { setAudioOnly } from '../audio-only';
12
-import { getMultipleVideoSupportFeatureFlag } from '../config/functions.any';
12
+import { getMultipleVideoSendingSupportFeatureFlag } from '../config/functions.any';
13 13
 import { JitsiConferenceErrors, JitsiTrackErrors } from '../lib-jitsi-meet';
14 14
 import { MEDIA_TYPE, setScreenshareMuted, VIDEO_TYPE } from '../media';
15 15
 import { MiddlewareRegistry } from '../redux';
@@ -51,7 +51,7 @@ MiddlewareRegistry.register(store => next => action => {
51 51
         break;
52 52
     }
53 53
     case TOGGLE_SCREENSHARING: {
54
-        getMultipleVideoSupportFeatureFlag(getState()) && _toggleScreenSharing(action, store);
54
+        getMultipleVideoSendingSupportFeatureFlag(getState()) && _toggleScreenSharing(action, store);
55 55
 
56 56
         break;
57 57
     }

+ 12
- 3
react/features/base/config/functions.any.js Dosyayı Görüntüle

@@ -51,15 +51,24 @@ export function getMeetingRegion(state: Object) {
51 51
 }
52 52
 
53 53
 /**
54
- * Selector used to get the sendMultipleVideoStreams feature flag.
54
+ * Selector for determining if receiving multiple stream support is enabled.
55 55
  *
56 56
  * @param {Object} state - The global state.
57 57
  * @returns {boolean}
58 58
  */
59 59
 export function getMultipleVideoSupportFeatureFlag(state: Object) {
60 60
     return getFeatureFlag(state, FEATURE_FLAGS.MULTIPLE_VIDEO_STREAMS_SUPPORT)
61
-        && getSourceNameSignalingFeatureFlag(state)
62
-        && isUnifiedPlanEnabled(state);
61
+        && getSourceNameSignalingFeatureFlag(state);
62
+}
63
+
64
+/**
65
+ * Selector for determining if sending multiple stream support is enabled.
66
+ *
67
+ * @param {Object} state - The global state.
68
+ * @returns {boolean}
69
+ */
70
+export function getMultipleVideoSendingSupportFeatureFlag(state: Object) {
71
+    return getMultipleVideoSupportFeatureFlag(state) && isUnifiedPlanEnabled(state);
63 72
 }
64 73
 
65 74
 /**

+ 3
- 3
react/features/base/lastn/middleware.js Dosyayı Görüntüle

@@ -6,9 +6,9 @@ import { SET_FILMSTRIP_ENABLED } from '../../filmstrip/actionTypes';
6 6
 import { SELECT_LARGE_VIDEO_PARTICIPANT } from '../../large-video/actionTypes';
7 7
 import { APP_STATE_CHANGED } from '../../mobile/background/actionTypes';
8 8
 import {
9
-    FAKE_SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
10 9
     SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
11
-    SET_TILE_VIEW
10
+    SET_TILE_VIEW,
11
+    VIRTUAL_SCREENSHARE_REMOTE_PARTICIPANTS_UPDATED
12 12
 } from '../../video-layout/actionTypes';
13 13
 import { SET_AUDIO_ONLY } from '../audio-only/actionTypes';
14 14
 import { CONFERENCE_JOINED } from '../conference/actionTypes';
@@ -95,7 +95,6 @@ MiddlewareRegistry.register(store => next => action => {
95 95
     switch (action.type) {
96 96
     case APP_STATE_CHANGED:
97 97
     case CONFERENCE_JOINED:
98
-    case FAKE_SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED:
99 98
     case PARTICIPANT_JOINED:
100 99
     case PARTICIPANT_KICKED:
101 100
     case PARTICIPANT_LEFT:
@@ -104,6 +103,7 @@ MiddlewareRegistry.register(store => next => action => {
104 103
     case SET_AUDIO_ONLY:
105 104
     case SET_FILMSTRIP_ENABLED:
106 105
     case SET_TILE_VIEW:
106
+    case VIRTUAL_SCREENSHARE_REMOTE_PARTICIPANTS_UPDATED:
107 107
         _updateLastN(store);
108 108
         break;
109 109
     }

+ 2
- 2
react/features/base/media/middleware.js Dosyayı Görüntüle

@@ -16,7 +16,7 @@ import { isForceMuted } from '../../participants-pane/functions';
16 16
 import { isScreenMediaShared } from '../../screen-share/functions';
17 17
 import { SET_AUDIO_ONLY, setAudioOnly } from '../audio-only';
18 18
 import { isRoomValid, SET_ROOM } from '../conference';
19
-import { getMultipleVideoSupportFeatureFlag } from '../config';
19
+import { getMultipleVideoSendingSupportFeatureFlag } from '../config';
20 20
 import { getLocalParticipant } from '../participants';
21 21
 import { MiddlewareRegistry } from '../redux';
22 22
 import { getPropertyValue } from '../settings';
@@ -192,7 +192,7 @@ function _setAudioOnly({ dispatch, getState }, next, action) {
192 192
 
193 193
     // Make sure we mute both the desktop and video tracks.
194 194
     dispatch(setVideoMuted(audioOnly, MEDIA_TYPE.VIDEO, VIDEO_MUTISM_AUTHORITY.AUDIO_ONLY, ensureVideoTrack));
195
-    if (getMultipleVideoSupportFeatureFlag(state)) {
195
+    if (getMultipleVideoSendingSupportFeatureFlag(state)) {
196 196
         dispatch(setScreenshareMuted(audioOnly, MEDIA_TYPE.SCREENSHARE, SCREENSHARE_MUTISM_AUTHORITY.AUDIO_ONLY));
197 197
     } else if (navigator.product !== 'ReactNative') {
198 198
         dispatch(setVideoMuted(audioOnly, MEDIA_TYPE.PRESENTER, VIDEO_MUTISM_AUTHORITY.AUDIO_ONLY, ensureVideoTrack));

+ 31
- 0
react/features/base/participants/actions.js Dosyayı Görüntüle

@@ -25,6 +25,7 @@ import {
25 25
 } from './constants';
26 26
 import {
27 27
     getLocalParticipant,
28
+    getVirtualScreenshareParticipantOwnerId,
28 29
     getNormalizedDisplayName,
29 30
     getParticipantDisplayName,
30 31
     getParticipantById
@@ -503,6 +504,36 @@ export function participantMutedUs(participant, track) {
503 504
     };
504 505
 }
505 506
 
507
+/**
508
+ * Action to create a virtual screenshare participant.
509
+ *
510
+ * @param {(string)} sourceName - JitsiTrack instance.
511
+ * @param {(boolean)} local - JitsiTrack instance.
512
+ * @returns {Function}
513
+ */
514
+export function createVirtualScreenshareParticipant(sourceName, local) {
515
+    return (dispatch, getState) => {
516
+        const state = getState();
517
+        const ownerId = getVirtualScreenshareParticipantOwnerId(sourceName);
518
+        const owner = getParticipantById(state, ownerId);
519
+        const ownerName = owner.name;
520
+
521
+        if (!ownerName) {
522
+            logger.error(`Failed to create a screenshare participant for sourceName: ${sourceName}`);
523
+
524
+            return;
525
+        }
526
+
527
+        dispatch(participantJoined({
528
+            conference: state['features/base/conference'].conference,
529
+            id: sourceName,
530
+            isVirtualScreenshareParticipant: true,
531
+            isLocalScreenShare: local,
532
+            name: ownerName
533
+        }));
534
+    };
535
+}
536
+
506 537
 /**
507 538
  * Action to signal that a participant had been kicked.
508 539
  *

+ 20
- 21
react/features/base/participants/functions.js Dosyayı Görüntüle

@@ -6,21 +6,16 @@ import type { Store } from 'redux';
6 6
 import { i18next } from '../../base/i18n';
7 7
 import { isStageFilmstripAvailable } from '../../filmstrip/functions';
8 8
 import { GRAVATAR_BASE_URL, isCORSAvatarURL } from '../avatar';
9
-import { getSourceNameSignalingFeatureFlag } from '../config';
9
+import { getMultipleVideoSupportFeatureFlag, getSourceNameSignalingFeatureFlag } from '../config';
10 10
 import { JitsiParticipantConnectionStatus } from '../lib-jitsi-meet';
11 11
 import { MEDIA_TYPE, shouldRenderVideoTrack } from '../media';
12 12
 import { toState } from '../redux';
13
-import { getTrackByMediaTypeAndParticipant } from '../tracks';
13
+import { getScreenShareTrack, getTrackByMediaTypeAndParticipant } from '../tracks';
14 14
 import { createDeferred } from '../util';
15 15
 
16
-import {
17
-    JIGASI_PARTICIPANT_ICON,
18
-    MAX_DISPLAY_NAME_LENGTH,
19
-    PARTICIPANT_ROLE
20
-} from './constants';
16
+import { JIGASI_PARTICIPANT_ICON, MAX_DISPLAY_NAME_LENGTH, PARTICIPANT_ROLE } from './constants';
21 17
 import { preloadImage } from './preloadImage';
22 18
 
23
-
24 19
 /**
25 20
  * Temp structures for avatar urls to be checked/preloaded.
26 21
  */
@@ -114,12 +109,16 @@ export function getLocalScreenShareParticipant(stateful: Object | Function) {
114 109
  * @param {string} id - The owner ID of the screenshare participant to retrieve.
115 110
  * @returns {(Participant|undefined)}
116 111
  */
117
-export function getScreenshareParticipantByOwnerId(stateful: Object | Function, id: string) {
118
-    const track = getTrackByMediaTypeAndParticipant(
119
-        toState(stateful)['features/base/tracks'], MEDIA_TYPE.SCREENSHARE, id
120
-    );
112
+export function getVirtualScreenshareParticipantByOwnerId(stateful: Object | Function, id: string) {
113
+    const state = toState(stateful);
114
+
115
+    if (getMultipleVideoSupportFeatureFlag(state)) {
116
+        const track = getScreenShareTrack(state['features/base/tracks'], id);
117
+
118
+        return getParticipantById(stateful, track?.jitsiTrack.getSourceName());
119
+    }
121 120
 
122
-    return getParticipantById(stateful, track?.jitsiTrack.getSourceName());
121
+    return;
123 122
 }
124 123
 
125 124
 /**
@@ -186,11 +185,11 @@ export function getParticipantCount(stateful: Object | Function) {
186 185
         local,
187 186
         remote,
188 187
         fakeParticipants,
189
-        sortedRemoteFakeScreenShareParticipants
188
+        sortedRemoteVirtualScreenshareParticipants
190 189
     } = state['features/base/participants'];
191 190
 
192 191
     if (getSourceNameSignalingFeatureFlag(state)) {
193
-        return remote.size - fakeParticipants.size - sortedRemoteFakeScreenShareParticipants.size + (local ? 1 : 0);
192
+        return remote.size - fakeParticipants.size - sortedRemoteVirtualScreenshareParticipants.size + (local ? 1 : 0);
194 193
     }
195 194
 
196 195
     return remote.size - fakeParticipants.size + (local ? 1 : 0);
@@ -198,13 +197,13 @@ export function getParticipantCount(stateful: Object | Function) {
198 197
 }
199 198
 
200 199
 /**
201
- * Returns participant ID of the owner of a fake screenshare participant.
200
+ * Returns participant ID of the owner of a virtual screenshare participant.
202 201
  *
203
- * @param {string} id - The ID of the fake screenshare participant.
202
+ * @param {string} id - The ID of the virtual screenshare participant.
204 203
  * @private
205 204
  * @returns {(string|undefined)}
206 205
  */
207
-export function getFakeScreenShareParticipantOwnerId(id: string) {
206
+export function getVirtualScreenshareParticipantOwnerId(id: string) {
208 207
     return id.split('-')[0];
209 208
 }
210 209
 
@@ -232,7 +231,7 @@ export function getRemoteParticipantCount(stateful: Object | Function) {
232 231
     const state = toState(stateful)['features/base/participants'];
233 232
 
234 233
     if (getSourceNameSignalingFeatureFlag(state)) {
235
-        return state.remote.size - state.sortedRemoteFakeScreenShareParticipants.size;
234
+        return state.remote.size - state.sortedRemoteVirtualScreenshareParticipants.size;
236 235
     }
237 236
 
238 237
     return state.remote.size;
@@ -274,7 +273,7 @@ export function getParticipantDisplayName(stateful: Object | Function, id: strin
274 273
     } = toState(stateful)['features/base/config'];
275 274
 
276 275
     if (participant) {
277
-        if (participant.isFakeScreenShareParticipant) {
276
+        if (participant.isVirtualScreenshareParticipant) {
278 277
             return getScreenshareParticipantDisplayName(stateful, id);
279 278
         }
280 279
 
@@ -299,7 +298,7 @@ export function getParticipantDisplayName(stateful: Object | Function, id: strin
299 298
  * @returns {string}
300 299
  */
301 300
 export function getScreenshareParticipantDisplayName(stateful: Object | Function, id: string) {
302
-    const owner = getParticipantById(stateful, getFakeScreenShareParticipantOwnerId(id));
301
+    const owner = getParticipantById(stateful, getVirtualScreenshareParticipantOwnerId(id));
303 302
     const name = owner.name;
304 303
 
305 304
     return i18next.t('screenshareDisplayName', { name });

+ 6
- 5
react/features/base/participants/middleware.js Dosyayı Görüntüle

@@ -69,6 +69,7 @@ import {
69 69
     isLocalParticipantModerator
70 70
 } from './functions';
71 71
 import { PARTICIPANT_JOINED_FILE, PARTICIPANT_LEFT_FILE } from './sounds';
72
+import './subscriber';
72 73
 
73 74
 declare var APP: Object;
74 75
 
@@ -210,19 +211,19 @@ MiddlewareRegistry.register(store => next => action => {
210 211
     }
211 212
 
212 213
     case PARTICIPANT_JOINED: {
213
-        const { isFakeScreenShareParticipant } = action.participant;
214
+        const { isVirtualScreenshareParticipant } = action.participant;
214 215
 
215
-        // Do not play sounds when a fake participant tile is created for screenshare.
216
-        !isFakeScreenShareParticipant && _maybePlaySounds(store, action);
216
+        // Do not play sounds when a virtual participant tile is created for screenshare.
217
+        !isVirtualScreenshareParticipant && _maybePlaySounds(store, action);
217 218
 
218 219
         return _participantJoinedOrUpdated(store, next, action);
219 220
     }
220 221
 
221 222
     case PARTICIPANT_LEFT: {
222
-        const { isFakeScreenShareParticipant } = action.participant;
223
+        const { isVirtualScreenshareParticipant } = action.participant;
223 224
 
224 225
         // Do not play sounds when a tile for screenshare is removed.
225
-        !isFakeScreenShareParticipant && _maybePlaySounds(store, action);
226
+        !isVirtualScreenshareParticipant && _maybePlaySounds(store, action);
226 227
 
227 228
         break;
228 229
     }

+ 26
- 19
react/features/base/participants/reducer.js Dosyayı Görüntüle

@@ -66,7 +66,7 @@ const DEFAULT_STATE = {
66 66
     pinnedParticipant: undefined,
67 67
     raisedHandsQueue: [],
68 68
     remote: new Map(),
69
-    sortedRemoteFakeScreenShareParticipants: new Map(),
69
+    sortedRemoteVirtualScreenshareParticipants: new Map(),
70 70
     sortedRemoteParticipants: new Map(),
71 71
     sortedRemoteScreenshares: new Map(),
72 72
     speakersList: new Map()
@@ -213,15 +213,15 @@ ReducerRegistry.register('features/base/participants', (state = DEFAULT_STATE, a
213 213
     case SCREENSHARE_PARTICIPANT_NAME_CHANGED: {
214 214
         const { id, name } = action;
215 215
 
216
-        if (state.sortedRemoteFakeScreenShareParticipants.has(id)) {
217
-            state.sortedRemoteFakeScreenShareParticipants.delete(id);
216
+        if (state.sortedRemoteVirtualScreenshareParticipants.has(id)) {
217
+            state.sortedRemoteVirtualScreenshareParticipants.delete(id);
218 218
 
219
-            const sortedRemoteFakeScreenShareParticipants = [ ...state.sortedRemoteFakeScreenShareParticipants ];
219
+            const sortedRemoteVirtualScreenshareParticipants = [ ...state.sortedRemoteVirtualScreenshareParticipants ];
220 220
 
221
-            sortedRemoteFakeScreenShareParticipants.push([ id, name ]);
222
-            sortedRemoteFakeScreenShareParticipants.sort((a, b) => a[1].localeCompare(b[1]));
221
+            sortedRemoteVirtualScreenshareParticipants.push([ id, name ]);
222
+            sortedRemoteVirtualScreenshareParticipants.sort((a, b) => a[1].localeCompare(b[1]));
223 223
 
224
-            state.sortedRemoteFakeScreenShareParticipants = new Map(sortedRemoteFakeScreenShareParticipants);
224
+            state.sortedRemoteVirtualScreenshareParticipants = new Map(sortedRemoteVirtualScreenshareParticipants);
225 225
         }
226 226
 
227 227
         return { ...state };
@@ -229,7 +229,14 @@ ReducerRegistry.register('features/base/participants', (state = DEFAULT_STATE, a
229 229
 
230 230
     case PARTICIPANT_JOINED: {
231 231
         const participant = _participantJoined(action);
232
-        const { id, isFakeParticipant, isFakeScreenShareParticipant, isLocalScreenShare, name, pinned } = participant;
232
+        const {
233
+            id,
234
+            isFakeParticipant,
235
+            isLocalScreenShare,
236
+            isVirtualScreenshareParticipant,
237
+            name,
238
+            pinned
239
+        } = participant;
233 240
         const { pinnedParticipant, dominantSpeaker } = state;
234 241
 
235 242
         if (pinned) {
@@ -282,13 +289,13 @@ ReducerRegistry.register('features/base/participants', (state = DEFAULT_STATE, a
282 289
         // The sort order of participants is preserved since Map remembers the original insertion order of the keys.
283 290
         state.sortedRemoteParticipants = new Map(sortedRemoteParticipants);
284 291
 
285
-        if (isFakeScreenShareParticipant) {
286
-            const sortedRemoteFakeScreenShareParticipants = [ ...state.sortedRemoteFakeScreenShareParticipants ];
292
+        if (isVirtualScreenshareParticipant) {
293
+            const sortedRemoteVirtualScreenshareParticipants = [ ...state.sortedRemoteVirtualScreenshareParticipants ];
287 294
 
288
-            sortedRemoteFakeScreenShareParticipants.push([ id, name ]);
289
-            sortedRemoteFakeScreenShareParticipants.sort((a, b) => a[1].localeCompare(b[1]));
295
+            sortedRemoteVirtualScreenshareParticipants.push([ id, name ]);
296
+            sortedRemoteVirtualScreenshareParticipants.sort((a, b) => a[1].localeCompare(b[1]));
290 297
 
291
-            state.sortedRemoteFakeScreenShareParticipants = new Map(sortedRemoteFakeScreenShareParticipants);
298
+            state.sortedRemoteVirtualScreenshareParticipants = new Map(sortedRemoteVirtualScreenshareParticipants);
292 299
         }
293 300
         if (isFakeParticipant) {
294 301
             state.fakeParticipants.set(id, participant);
@@ -306,7 +313,7 @@ ReducerRegistry.register('features/base/participants', (state = DEFAULT_STATE, a
306 313
         const { conference, id } = action.participant;
307 314
         const {
308 315
             fakeParticipants,
309
-            sortedRemoteFakeScreenShareParticipants,
316
+            sortedRemoteVirtualScreenshareParticipants,
310 317
             remote,
311 318
             local,
312 319
             localScreenShare,
@@ -372,9 +379,9 @@ ReducerRegistry.register('features/base/participants', (state = DEFAULT_STATE, a
372 379
             fakeParticipants.delete(id);
373 380
         }
374 381
 
375
-        if (sortedRemoteFakeScreenShareParticipants.has(id)) {
376
-            sortedRemoteFakeScreenShareParticipants.delete(id);
377
-            state.sortedRemoteFakeScreenShareParticipants = new Map(sortedRemoteFakeScreenShareParticipants);
382
+        if (sortedRemoteVirtualScreenshareParticipants.has(id)) {
383
+            sortedRemoteVirtualScreenshareParticipants.delete(id);
384
+            state.sortedRemoteVirtualScreenshareParticipants = new Map(sortedRemoteVirtualScreenshareParticipants);
378 385
         }
379 386
 
380 387
         return { ...state };
@@ -500,7 +507,7 @@ function _participantJoined({ participant }) {
500 507
         dominantSpeaker,
501 508
         email,
502 509
         isFakeParticipant,
503
-        isFakeScreenShareParticipant,
510
+        isVirtualScreenshareParticipant,
504 511
         isLocalScreenShare,
505 512
         isReplacing,
506 513
         isJigasi,
@@ -534,7 +541,7 @@ function _participantJoined({ participant }) {
534 541
         email,
535 542
         id,
536 543
         isFakeParticipant,
537
-        isFakeScreenShareParticipant,
544
+        isVirtualScreenshareParticipant,
538 545
         isLocalScreenShare,
539 546
         isReplacing,
540 547
         isJigasi,

+ 0
- 0
react/features/base/participants/subscriber.native.js Dosyayı Görüntüle


+ 69
- 0
react/features/base/participants/subscriber.web.js Dosyayı Görüntüle

@@ -0,0 +1,69 @@
1
+// @flow
2
+
3
+import _ from 'lodash';
4
+
5
+import { getCurrentConference } from '../conference';
6
+import { getMultipleVideoSupportFeatureFlag } from '../config';
7
+import { StateListenerRegistry } from '../redux';
8
+
9
+import { createVirtualScreenshareParticipant, participantLeft } from './actions';
10
+
11
+StateListenerRegistry.register(
12
+    /* selector */ state => state['features/base/tracks'],
13
+    /* listener */(tracks, store) => _updateScreenshareParticipants(store)
14
+);
15
+
16
+/**
17
+ * Handles creating and removing virtual screenshare participants.
18
+ *
19
+ * @param {*} store - The redux store.
20
+ * @returns {void}
21
+ */
22
+function _updateScreenshareParticipants({ getState, dispatch }) {
23
+    const state = getState();
24
+
25
+    if (!getMultipleVideoSupportFeatureFlag(state)) {
26
+        return;
27
+    }
28
+
29
+    const conference = getCurrentConference(state);
30
+    const tracks = state['features/base/tracks'];
31
+    const { sortedRemoteVirtualScreenshareParticipants, localScreenShare } = state['features/base/participants'];
32
+    const previousScreenshareSourceNames = [ ...sortedRemoteVirtualScreenshareParticipants.keys() ];
33
+
34
+    let newLocalSceenshareSourceName;
35
+
36
+    const currentScreenshareSourceNames = tracks.reduce((acc, track) => {
37
+        if (track.videoType === 'desktop' && !track.jitsiTrack.isMuted()) {
38
+            const sourceName = track.jitsiTrack.getSourceName();
39
+
40
+            if (track.local) {
41
+                newLocalSceenshareSourceName = sourceName;
42
+            } else {
43
+                acc.push(sourceName);
44
+            }
45
+        }
46
+
47
+        return acc;
48
+    }, []);
49
+
50
+    if (!localScreenShare && newLocalSceenshareSourceName) {
51
+        dispatch(createVirtualScreenshareParticipant(newLocalSceenshareSourceName, true));
52
+    }
53
+
54
+    if (localScreenShare && !newLocalSceenshareSourceName) {
55
+        dispatch(participantLeft(localScreenShare.id, conference));
56
+    }
57
+
58
+    const removedScreenshareSourceNames = _.difference(previousScreenshareSourceNames, currentScreenshareSourceNames);
59
+    const addedScreenshareSourceNames = _.difference(currentScreenshareSourceNames, previousScreenshareSourceNames);
60
+
61
+    if (removedScreenshareSourceNames.length) {
62
+        removedScreenshareSourceNames.forEach(id => dispatch(participantLeft(id, conference)));
63
+    }
64
+
65
+    if (addedScreenshareSourceNames.length) {
66
+        addedScreenshareSourceNames.forEach(id => dispatch(createVirtualScreenshareParticipant(id, false)));
67
+
68
+    }
69
+}

+ 0
- 12
react/features/base/tracks/actionTypes.ts Dosyayı Görüntüle

@@ -107,18 +107,6 @@ export const TRACK_STOPPED = 'TRACK_STOPPED';
107 107
  */
108 108
 export const TRACK_UPDATED = 'TRACK_UPDATED';
109 109
 
110
-/**
111
- * The type of redux action dispatched when a screenshare track's muted property were updated.
112
- *
113
- * {
114
- *     type: SCREENSHARE_TRACK_MUTED_UPDATED,
115
- *     track: Track,
116
- *     muted: Boolean
117
- *  
118
- * }
119
- */
120
- export const SCREENSHARE_TRACK_MUTED_UPDATED = 'SCREENSHARE_TRACK_MUTED_UPDATED';
121
-
122 110
 /**
123 111
  * The type of redux action dispatched when a local track starts being created
124 112
  * via a WebRTC {@code getUserMedia} call. The action's payload includes an

+ 7
- 29
react/features/base/tracks/actions.js Dosyayı Görüntüle

@@ -6,7 +6,7 @@ import {
6 6
 } from '../../analytics';
7 7
 import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification, showNotification } from '../../notifications';
8 8
 import { getCurrentConference } from '../conference';
9
-import { getMultipleVideoSupportFeatureFlag, getSourceNameSignalingFeatureFlag } from '../config';
9
+import { getMultipleVideoSendingSupportFeatureFlag } from '../config';
10 10
 import { JitsiTrackErrors, JitsiTrackEvents } from '../lib-jitsi-meet';
11 11
 import { createLocalTrack } from '../lib-jitsi-meet/functions';
12 12
 import {
@@ -22,7 +22,6 @@ import { getLocalParticipant } from '../participants';
22 22
 import { updateSettings } from '../settings';
23 23
 
24 24
 import {
25
-    SCREENSHARE_TRACK_MUTED_UPDATED,
26 25
     SET_NO_SRC_DATA_NOTIFICATION_UID,
27 26
     TOGGLE_SCREENSHARING,
28 27
     TRACK_ADDED,
@@ -60,7 +59,7 @@ export function addLocalTrack(newTrack) {
60 59
         }
61 60
 
62 61
         const setMuted = newTrack.isVideoTrack()
63
-            ? getMultipleVideoSupportFeatureFlag(getState())
62
+            ? getMultipleVideoSendingSupportFeatureFlag(getState())
64 63
             && newTrack.getVideoType() === VIDEO_TYPE.DESKTOP
65 64
                 ? setScreenshareMuted
66 65
                 : setVideoMuted
@@ -371,7 +370,8 @@ function replaceStoredTracks(oldTrack, newTrack) {
371 370
             // state. If this is not done, the current mute state of the app will be reflected on the track,
372 371
             // not vice-versa.
373 372
             const setMuted = newTrack.isVideoTrack()
374
-                ? getMultipleVideoSupportFeatureFlag(getState()) && newTrack.getVideoType() === VIDEO_TYPE.DESKTOP
373
+                ? getMultipleVideoSendingSupportFeatureFlag(getState())
374
+                    && newTrack.getVideoType() === VIDEO_TYPE.DESKTOP
375 375
                     ? setScreenshareMuted
376 376
                     : setVideoMuted
377 377
                 : setAudioMuted;
@@ -397,19 +397,15 @@ export function trackAdded(track) {
397 397
     return async (dispatch, getState) => {
398 398
         track.on(
399 399
             JitsiTrackEvents.TRACK_MUTE_CHANGED,
400
-        () => {
401
-            if (getSourceNameSignalingFeatureFlag(getState()) && track.getVideoType() === VIDEO_TYPE.DESKTOP) {
402
-                dispatch(screenshareTrackMutedChanged(track));
403
-            }
404
-            dispatch(trackMutedChanged(track));
405
-        });
400
+            () => dispatch(trackMutedChanged(track)));
406 401
         track.on(
407 402
             JitsiTrackEvents.TRACK_VIDEOTYPE_CHANGED,
408 403
             type => dispatch(trackVideoTypeChanged(track, type)));
409 404
 
410 405
         // participantId
411 406
         const local = track.isLocal();
412
-        const mediaType = getMultipleVideoSupportFeatureFlag(getState()) && track.getVideoType() === VIDEO_TYPE.DESKTOP
407
+        const mediaType = getMultipleVideoSendingSupportFeatureFlag(getState())
408
+            && track.getVideoType() === VIDEO_TYPE.DESKTOP
413 409
             ? MEDIA_TYPE.SCREENSHARE
414 410
             : track.getType();
415 411
         let isReceivingData, noDataFromSourceNotificationInfo, participantId;
@@ -498,24 +494,6 @@ export function trackMutedChanged(track) {
498 494
     };
499 495
 }
500 496
 
501
-/**
502
- * Create an action for when a screenshare track's muted state has been signaled to be changed.
503
- *
504
- * @param {(JitsiLocalTrack|JitsiRemoteTrack)} track - JitsiTrack instance.
505
- * @returns {{
506
- *     type: TRACK_UPDATED,
507
- *     track: Track,
508
- *     muted: boolean
509
- * }}
510
- */
511
-export function screenshareTrackMutedChanged(track) {
512
-    return {
513
-        type: SCREENSHARE_TRACK_MUTED_UPDATED,
514
-        track: { jitsiTrack: track },
515
-        muted: track.isMuted()
516
-    };
517
-}
518
-
519 497
 /**
520 498
  * Create an action for when a track's muted state change action has failed. This could happen because of
521 499
  * {@code getUserMedia} errors during unmute or replace track errors at the peerconnection level.

+ 52
- 18
react/features/base/tracks/functions.js Dosyayı Görüntüle

@@ -1,10 +1,13 @@
1 1
 /* global APP */
2 2
 
3
-import { getMultipleVideoSupportFeatureFlag } from '../config/functions.any';
3
+import {
4
+    getMultipleVideoSendingSupportFeatureFlag,
5
+    getMultipleVideoSupportFeatureFlag
6
+} from '../config/functions.any';
4 7
 import { isMobileBrowser } from '../environment/utils';
5 8
 import JitsiMeetJS, { JitsiTrackErrors, browser } from '../lib-jitsi-meet';
6 9
 import { MEDIA_TYPE, VIDEO_TYPE, setAudioMuted } from '../media';
7
-import { getFakeScreenShareParticipantOwnerId } from '../participants';
10
+import { getVirtualScreenshareParticipantOwnerId } from '../participants';
8 11
 import { toState } from '../redux';
9 12
 import {
10 13
     getUserSelectedCameraDeviceId,
@@ -426,18 +429,11 @@ export function getVideoTrackByParticipant(
426 429
         return;
427 430
     }
428 431
 
429
-    let participantId;
430
-    let mediaType;
431
-
432
-    if (participant?.isFakeScreenShareParticipant) {
433
-        participantId = getFakeScreenShareParticipantOwnerId(participant.id);
434
-        mediaType = MEDIA_TYPE.SCREENSHARE;
435
-    } else {
436
-        participantId = participant.id;
437
-        mediaType = MEDIA_TYPE.VIDEO;
432
+    if (participant?.isVirtualScreenshareParticipant) {
433
+        return getVirtualScreenshareParticipantTrack(tracks, participant.id);
438 434
     }
439 435
 
440
-    return getTrackByMediaTypeAndParticipant(tracks, mediaType, participantId);
436
+    return getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, participant.id);
441 437
 }
442 438
 
443 439
 /**
@@ -458,16 +454,54 @@ export function getTrackByMediaTypeAndParticipant(
458 454
 }
459 455
 
460 456
 /**
461
- * Returns track of given fakeScreenshareParticipantId.
457
+ * Returns screenshare track of given virtualScreenshareParticipantId.
462 458
  *
463 459
  * @param {Track[]} tracks - List of all tracks.
464
- * @param {string} fakeScreenshareParticipantId - Fake Screenshare Participant ID.
460
+ * @param {string} virtualScreenshareParticipantId - Virtual Screenshare Participant ID.
465 461
  * @returns {(Track|undefined)}
466 462
  */
467
-export function getFakeScreenshareParticipantTrack(tracks, fakeScreenshareParticipantId) {
468
-    const participantId = getFakeScreenShareParticipantOwnerId(fakeScreenshareParticipantId);
463
+export function getVirtualScreenshareParticipantTrack(tracks, virtualScreenshareParticipantId) {
464
+    const ownderId = getVirtualScreenshareParticipantOwnerId(virtualScreenshareParticipantId);
469 465
 
470
-    return getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.SCREENSHARE, participantId);
466
+    return getScreenShareTrack(tracks, ownderId);
467
+}
468
+
469
+/**
470
+ * Returns track source names of given screen share participant ids.
471
+ *
472
+ * @param {Object} state - The entire redux state.
473
+ * @param {string[]} screenShareParticipantIds - Participant ID.
474
+ * @returns {(string[])}
475
+ */
476
+export function getRemoteScreenSharesSourceNames(state, screenShareParticipantIds = []) {
477
+    const tracks = state['features/base/tracks'];
478
+
479
+    return getMultipleVideoSupportFeatureFlag(state)
480
+        ? screenShareParticipantIds
481
+        : screenShareParticipantIds.reduce((acc, id) => {
482
+            const sourceName = getScreenShareTrack(tracks, id)?.jitsiTrack.getSourceName();
483
+
484
+            if (sourceName) {
485
+                acc.push(sourceName);
486
+            }
487
+
488
+            return acc;
489
+        }, []);
490
+}
491
+
492
+/**
493
+ * Returns screenshare track of given owner ID.
494
+ *
495
+ * @param {Track[]} tracks - List of all tracks.
496
+ * @param {string} ownerId - Screenshare track owner ID.
497
+ * @returns {(Track|undefined)}
498
+ */
499
+export function getScreenShareTrack(tracks, ownerId) {
500
+    return tracks.find(
501
+        t => Boolean(t.jitsiTrack)
502
+        && t.participantId === ownerId
503
+        && (t.mediaType === MEDIA_TYPE.SCREENSHARE || t.videoType === VIDEO_TYPE.DESKTOP)
504
+    );
471 505
 }
472 506
 
473 507
 /**
@@ -610,7 +644,7 @@ export function setTrackMuted(track, muted, state) {
610 644
     // browser's 'Stop sharing' button, the local stream is stopped before the inactive stream handler is fired.
611 645
     // We still need to proceed here and remove the track from the peerconnection.
612 646
     if (track.isMuted() === muted
613
-        && !(track.getVideoType() === VIDEO_TYPE.DESKTOP && getMultipleVideoSupportFeatureFlag(state))) {
647
+        && !(track.getVideoType() === VIDEO_TYPE.DESKTOP && getMultipleVideoSendingSupportFeatureFlag(state))) {
614 648
         return Promise.resolve();
615 649
     }
616 650
 

+ 11
- 88
react/features/base/tracks/middleware.js Dosyayı Görüntüle

@@ -9,7 +9,7 @@ import { _RESET_BREAKOUT_ROOMS } from '../../breakout-rooms/actionTypes';
9 9
 import { hideNotification, isModerationNotificationDisplayed } from '../../notifications';
10 10
 import { isPrejoinPageVisible } from '../../prejoin/functions';
11 11
 import { getCurrentConference } from '../conference/functions';
12
-import { getMultipleVideoSupportFeatureFlag, getSourceNameSignalingFeatureFlag } from '../config';
12
+import { getMultipleVideoSendingSupportFeatureFlag } from '../config';
13 13
 import { getAvailableDevices } from '../devices/actions';
14 14
 import {
15 15
     CAMERA_FACING_MODE,
@@ -25,11 +25,9 @@ import {
25 25
     setScreenshareMuted,
26 26
     SCREENSHARE_MUTISM_AUTHORITY
27 27
 } from '../media';
28
-import { participantLeft, participantJoined, getParticipantById } from '../participants';
29 28
 import { MiddlewareRegistry, StateListenerRegistry } from '../redux';
30 29
 
31 30
 import {
32
-    SCREENSHARE_TRACK_MUTED_UPDATED,
33 31
     TOGGLE_SCREENSHARING,
34 32
     TRACK_ADDED,
35 33
     TRACK_MUTE_UNMUTE_FAILED,
@@ -53,7 +51,6 @@ import {
53 51
     isUserInteractionRequiredForUnmute,
54 52
     setTrackMuted
55 53
 } from './functions';
56
-import logger from './logger';
57 54
 
58 55
 import './subscriber';
59 56
 
@@ -70,8 +67,7 @@ declare var APP: Object;
70 67
 MiddlewareRegistry.register(store => next => action => {
71 68
     switch (action.type) {
72 69
     case TRACK_ADDED: {
73
-        const state = store.getState();
74
-        const { jitsiTrack, local } = action.track;
70
+        const { local } = action.track;
75 71
 
76 72
         // The devices list needs to be refreshed when no initial video permissions
77 73
         // were granted and a local video track is added by umuting the video.
@@ -79,23 +75,7 @@ MiddlewareRegistry.register(store => next => action => {
79 75
             store.dispatch(getAvailableDevices());
80 76
         }
81 77
 
82
-        // Call next before the creation of a fake screenshare participant to ensure a video track is available when
83
-        // the participant is auto pinned.
84
-        const result = next(action);
85
-
86
-        // The TRACK_ADDED action is dispatched when a presenter starts a screenshare. Do not create a local fake
87
-        // screenshare participant when multiple stream is not enabled.
88
-        const skipCreateFakeScreenShareParticipant = local && !getMultipleVideoSupportFeatureFlag(state);
89
-
90
-        if (getSourceNameSignalingFeatureFlag(state)
91
-            && jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP
92
-            && !jitsiTrack.isMuted()
93
-            && !skipCreateFakeScreenShareParticipant
94
-        ) {
95
-            createFakeScreenShareParticipant(store, action);
96
-        }
97
-
98
-        return result;
78
+        break;
99 79
     }
100 80
     case TRACK_NO_DATA_FROM_SOURCE: {
101 81
         const result = next(action);
@@ -105,39 +85,7 @@ MiddlewareRegistry.register(store => next => action => {
105 85
         return result;
106 86
     }
107 87
 
108
-    case SCREENSHARE_TRACK_MUTED_UPDATED: {
109
-        const state = store.getState();
110
-
111
-        if (!getSourceNameSignalingFeatureFlag(state)) {
112
-            return;
113
-        }
114
-
115
-        const { track, muted } = action;
116
-
117
-        if (muted) {
118
-            const conference = getCurrentConference(state);
119
-            const participantId = track?.jitsiTrack.getSourceName();
120
-
121
-            store.dispatch(participantLeft(participantId, conference));
122
-        }
123
-
124
-        if (!muted) {
125
-            createFakeScreenShareParticipant(store, action);
126
-        }
127
-
128
-        break;
129
-    }
130
-
131 88
     case TRACK_REMOVED: {
132
-        const state = store.getState();
133
-
134
-        if (getSourceNameSignalingFeatureFlag(state) && action.track.jitsiTrack.videoType === VIDEO_TYPE.DESKTOP) {
135
-            const conference = getCurrentConference(state);
136
-            const participantId = action.track.jitsiTrack.getSourceName();
137
-
138
-            store.dispatch(participantLeft(participantId, conference));
139
-        }
140
-
141 89
         _removeNoDataFromSourceNotification(store, action.track);
142 90
         break;
143 91
     }
@@ -223,7 +171,7 @@ MiddlewareRegistry.register(store => next => action => {
223 171
 
224 172
             const { enabled, audioOnly, ignoreDidHaveVideo } = action;
225 173
 
226
-            if (!getMultipleVideoSupportFeatureFlag(store.getState())) {
174
+            if (!getMultipleVideoSendingSupportFeatureFlag(store.getState())) {
227 175
                 APP.UI.emitEvent(UIEvents.TOGGLE_SCREENSHARING,
228 176
                     {
229 177
                         enabled,
@@ -241,7 +189,7 @@ MiddlewareRegistry.register(store => next => action => {
241 189
 
242 190
         if (typeof APP !== 'undefined') {
243 191
             if (isVideoTrack && jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP
244
-                && getMultipleVideoSupportFeatureFlag(store.getState())) {
192
+                && getMultipleVideoSendingSupportFeatureFlag(store.getState())) {
245 193
                 store.dispatch(setScreenshareMuted(!muted));
246 194
             } else if (isVideoTrack) {
247 195
                 APP.conference.setVideoMuteStatus();
@@ -256,7 +204,7 @@ MiddlewareRegistry.register(store => next => action => {
256 204
         const { jitsiTrack } = action.track;
257 205
 
258 206
         if (typeof APP !== 'undefined'
259
-            && getMultipleVideoSupportFeatureFlag(store.getState())
207
+            && getMultipleVideoSendingSupportFeatureFlag(store.getState())
260 208
             && jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP) {
261 209
             store.dispatch(toggleScreensharing(false));
262 210
         }
@@ -286,7 +234,7 @@ MiddlewareRegistry.register(store => next => action => {
286 234
                 } else if (jitsiTrack.isLocal() && !(jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP)) {
287 235
                     APP.conference.setVideoMuteStatus();
288 236
                 } else if (jitsiTrack.isLocal() && muted && jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP) {
289
-                    !getMultipleVideoSupportFeatureFlag(state)
237
+                    !getMultipleVideoSendingSupportFeatureFlag(state)
290 238
                         && store.dispatch(toggleScreensharing(false, false, true));
291 239
                 } else {
292 240
                     APP.UI.setVideoMuted(participantID);
@@ -384,32 +332,6 @@ function _handleNoDataFromSourceErrors(store, action) {
384 332
     }
385 333
 }
386 334
 
387
-/**
388
- * Creates a fake participant for screen share using the track's source name as the participant id.
389
- *
390
- * @param {Store} store - The redux store in which the specified action is dispatched.
391
- * @param {Action} action - The redux action dispatched in the specified store.
392
- * @private
393
- * @returns {void}
394
- */
395
-function createFakeScreenShareParticipant({ dispatch, getState }, { track }) {
396
-    const state = getState();
397
-    const participantId = track.jitsiTrack?.getParticipantId?.();
398
-    const participant = getParticipantById(state, participantId);
399
-
400
-    if (participant.name) {
401
-        dispatch(participantJoined({
402
-            conference: state['features/base/conference'].conference,
403
-            id: track.jitsiTrack.getSourceName(),
404
-            isFakeScreenShareParticipant: true,
405
-            isLocalScreenShare: track?.jitsiTrack.isLocal(),
406
-            name: participant.name
407
-        }));
408
-    } else {
409
-        logger.error(`Failed to create a screenshare participant for participantId: ${participantId}`);
410
-    }
411
-}
412
-
413 335
 /**
414 336
  * Gets the local track associated with a specific {@code MEDIA_TYPE} in a
415 337
  * specific redux store.
@@ -472,7 +394,7 @@ async function _setMuted(store, { ensureTrack, authority, muted }, mediaType: ME
472 394
     const state = getState();
473 395
 
474 396
     if (mediaType === MEDIA_TYPE.SCREENSHARE
475
-        && getMultipleVideoSupportFeatureFlag(state)
397
+        && getMultipleVideoSendingSupportFeatureFlag(state)
476 398
         && !muted) {
477 399
         return;
478 400
     }
@@ -487,8 +409,9 @@ async function _setMuted(store, { ensureTrack, authority, muted }, mediaType: ME
487 409
 
488 410
         // Screenshare cannot be unmuted using the video mute button unless it is muted by audioOnly in the legacy
489 411
         // screensharing mode.
490
-        if (jitsiTrack
491
-            && (jitsiTrack.videoType !== 'desktop' || isAudioOnly || getMultipleVideoSupportFeatureFlag(state))) {
412
+        if (jitsiTrack && (
413
+            jitsiTrack.videoType !== 'desktop' || isAudioOnly || getMultipleVideoSendingSupportFeatureFlag(state))
414
+        ) {
492 415
             setTrackMuted(jitsiTrack, muted, state).catch(() => dispatch(trackMuteUnmuteFailed(localTrack, muted)));
493 416
         }
494 417
     } else if (!muted && ensureTrack && (typeof APP === 'undefined' || isPrejoinPageVisible(state))) {

+ 3
- 3
react/features/connection-indicator/components/web/ConnectionIndicator.js Dosyayı Görüntüle

@@ -12,7 +12,7 @@ import { getLocalParticipant, getParticipantById } from '../../../base/participa
12 12
 import { Popover } from '../../../base/popover';
13 13
 import { connect } from '../../../base/redux';
14 14
 import {
15
-    getFakeScreenshareParticipantTrack,
15
+    getVirtualScreenshareParticipantTrack,
16 16
     getTrackByMediaTypeAndParticipant } from '../../../base/tracks';
17 17
 import {
18 18
     isParticipantConnectionStatusInactive,
@@ -374,8 +374,8 @@ export function _mapStateToProps(state: Object, ownProps: Props) {
374 374
 
375 375
     let firstVideoTrack;
376 376
 
377
-    if (sourceNameSignalingEnabled && participant?.isFakeScreenShareParticipant) {
378
-        firstVideoTrack = getFakeScreenshareParticipantTrack(tracks, participantId);
377
+    if (sourceNameSignalingEnabled && participant?.isVirtualScreenshareParticipant) {
378
+        firstVideoTrack = getVirtualScreenshareParticipantTrack(tracks, participantId);
379 379
     } else {
380 380
         firstVideoTrack = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, participantId);
381 381
     }

+ 3
- 3
react/features/connection-indicator/components/web/ConnectionIndicatorContent.js Dosyayı Görüntüle

@@ -91,7 +91,7 @@ type Props = AbstractProps & {
91 91
      * Whether or not the displays stats are for screen share. This prop is behind the sourceNameSignaling feature
92 92
      * flag.
93 93
      */
94
-    _isFakeScreenShareParticipant: Boolean,
94
+    _isVirtualScreenshareParticipant: Boolean,
95 95
 
96 96
     /**
97 97
      * Whether or not the displays stats are for local video.
@@ -205,8 +205,8 @@ class ConnectionIndicatorContent extends AbstractConnectionIndicator<Props, Stat
205 205
                 e2eRtt = { e2eRtt }
206 206
                 enableSaveLogs = { this.props._enableSaveLogs }
207 207
                 framerate = { framerate }
208
-                isFakeScreenShareParticipant = { this.props._isFakeScreenShareParticipant }
209 208
                 isLocalVideo = { this.props._isLocalVideo }
209
+                isVirtualScreenshareParticipant = { this.props._isVirtualScreenshareParticipant }
210 210
                 maxEnabledResolution = { maxEnabledResolution }
211 211
                 onSaveLogs = { this.props._onSaveLogs }
212 212
                 onShowMore = { this._onToggleShowMore }
@@ -343,7 +343,7 @@ export function _mapStateToProps(state: Object, ownProps: Props) {
343 343
         _disableShowMoreStats: state['features/base/config'].disableShowMoreStats,
344 344
         _isConnectionStatusInactive,
345 345
         _isConnectionStatusInterrupted,
346
-        _isFakeScreenShareParticipant: sourceNameSignalingEnabled && participant?.isFakeScreenShareParticipant,
346
+        _isVirtualScreenshareParticipant: sourceNameSignalingEnabled && participant?.isVirtualScreenshareParticipant,
347 347
         _isLocalVideo: participant?.local,
348 348
         _region: participant?.region
349 349
     };

+ 3
- 3
react/features/connection-stats/components/ConnectionStatsTable.js Dosyayı Görüntüle

@@ -94,7 +94,7 @@ type Props = {
94 94
     /**
95 95
      * Whether or not the statistics are for screen share.
96 96
      */
97
-    isFakeScreenShareParticipant: boolean,
97
+    isVirtualScreenshareParticipant: boolean,
98 98
 
99 99
     /**
100 100
      * The send-side max enabled resolution (aka the highest layer that is not
@@ -240,12 +240,12 @@ class ConnectionStatsTable extends Component<Props> {
240 240
             classes,
241 241
             disableShowMoreStats,
242 242
             enableSaveLogs,
243
-            isFakeScreenShareParticipant,
243
+            isVirtualScreenshareParticipant,
244 244
             isLocalVideo
245 245
         } = this.props;
246 246
         const className = clsx(classes.connectionStatsTable, { [classes.mobile]: isMobileBrowser() });
247 247
 
248
-        if (isFakeScreenShareParticipant) {
248
+        if (isVirtualScreenshareParticipant) {
249 249
             return this._renderScreenShareStatus();
250 250
         }
251 251
 

+ 15
- 14
react/features/filmstrip/components/web/Thumbnail.js Dosyayı Görüntüle

@@ -7,7 +7,7 @@ import React, { Component } from 'react';
7 7
 
8 8
 import { createScreenSharingIssueEvent, sendAnalytics } from '../../../analytics';
9 9
 import { Avatar } from '../../../base/avatar';
10
-import { getSourceNameSignalingFeatureFlag } from '../../../base/config';
10
+import { getMultipleVideoSupportFeatureFlag, getSourceNameSignalingFeatureFlag } from '../../../base/config';
11 11
 import { isMobileBrowser } from '../../../base/environment/utils';
12 12
 import { JitsiTrackEvents } from '../../../base/lib-jitsi-meet';
13 13
 import { MEDIA_TYPE, VideoTrack } from '../../../base/media';
@@ -24,7 +24,7 @@ import {
24 24
     getLocalAudioTrack,
25 25
     getLocalVideoTrack,
26 26
     getTrackByMediaTypeAndParticipant,
27
-    getFakeScreenshareParticipantTrack,
27
+    getVirtualScreenshareParticipantTrack,
28 28
     updateLastTrackVideoMediaEvent,
29 29
     trackStreamingStatusChanged
30 30
 } from '../../../base/tracks';
@@ -51,10 +51,10 @@ import {
51 51
     showGridInVerticalView
52 52
 } from '../../functions';
53 53
 
54
-import FakeScreenShareParticipant from './FakeScreenShareParticipant';
55 54
 import ThumbnailAudioIndicator from './ThumbnailAudioIndicator';
56 55
 import ThumbnailBottomIndicators from './ThumbnailBottomIndicators';
57 56
 import ThumbnailTopIndicators from './ThumbnailTopIndicators';
57
+import VirtualScreenshareParticipant from './VirtualScreenshareParticipant';
58 58
 
59 59
 
60 60
 declare var interfaceConfig: Object;
@@ -137,10 +137,10 @@ export type Props = {|
137 137
     _isCurrentlyOnLargeVideo: boolean,
138 138
 
139 139
     /**
140
-     * Indicates whether the participant is a fake screen share participant. This prop is behind the
140
+     * Indicates whether the participant is a virtual screen share participant. This prop is behind the
141 141
      * sourceNameSignaling feature flag.
142 142
      */
143
-    _isFakeScreenShareParticipant: boolean,
143
+    _isVirtualScreenshareParticipant: boolean,
144 144
 
145 145
     /**
146 146
      * Whether we are currently running in a mobile browser.
@@ -626,7 +626,7 @@ class Thumbnail extends Component<Props, State> {
626 626
         const {
627 627
             _disableTileEnlargement,
628 628
             _height,
629
-            _isFakeScreenShareParticipant,
629
+            _isVirtualScreenshareParticipant,
630 630
             _isHidden,
631 631
             _isScreenSharing,
632 632
             _participant,
@@ -665,7 +665,7 @@ class Thumbnail extends Component<Props, State> {
665 665
             || _disableTileEnlargement
666 666
             || _isScreenSharing;
667 667
 
668
-        if (canPlayEventReceived || _participant.local || _isFakeScreenShareParticipant) {
668
+        if (canPlayEventReceived || _participant.local || _isVirtualScreenshareParticipant) {
669 669
             videoStyles = {
670 670
                 objectFit: doNotStretchVideo ? 'contain' : 'cover'
671 671
             };
@@ -1107,7 +1107,7 @@ class Thumbnail extends Component<Props, State> {
1107 1107
      * @returns {ReactElement}
1108 1108
      */
1109 1109
     render() {
1110
-        const { _participant, _isFakeScreenShareParticipant } = this.props;
1110
+        const { _participant, _isVirtualScreenshareParticipant } = this.props;
1111 1111
 
1112 1112
         if (!_participant) {
1113 1113
             return null;
@@ -1123,12 +1123,12 @@ class Thumbnail extends Component<Props, State> {
1123 1123
             return this._renderFakeParticipant();
1124 1124
         }
1125 1125
 
1126
-        if (_isFakeScreenShareParticipant) {
1126
+        if (_isVirtualScreenshareParticipant) {
1127 1127
             const { isHovered } = this.state;
1128 1128
             const { _videoTrack, _isMobile, classes, _thumbnailType } = this.props;
1129 1129
 
1130 1130
             return (
1131
-                <FakeScreenShareParticipant
1131
+                <VirtualScreenshareParticipant
1132 1132
                     classes = { classes }
1133 1133
                     containerClassName = { this._getContainerClassName() }
1134 1134
                     isHovered = { isHovered }
@@ -1170,8 +1170,8 @@ function _mapStateToProps(state, ownProps): Object {
1170 1170
 
1171 1171
     let _videoTrack;
1172 1172
 
1173
-    if (sourceNameSignalingEnabled && participant?.isFakeScreenShareParticipant) {
1174
-        _videoTrack = getFakeScreenshareParticipantTrack(tracks, id);
1173
+    if (sourceNameSignalingEnabled && participant?.isVirtualScreenshareParticipant) {
1174
+        _videoTrack = getVirtualScreenshareParticipantTrack(tracks, id);
1175 1175
     } else {
1176 1176
         _videoTrack = isLocal
1177 1177
             ? getLocalVideoTrack(tracks) : getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, participantID);
@@ -1193,7 +1193,6 @@ function _mapStateToProps(state, ownProps): Object {
1193 1193
     const activeParticipants = getActiveParticipantsIds(state);
1194 1194
     const tileType = getThumbnailTypeFromLayout(_currentLayout, stageFilmstrip);
1195 1195
 
1196
-
1197 1196
     switch (tileType) {
1198 1197
     case THUMBNAIL_TYPE.VERTICAL:
1199 1198
     case THUMBNAIL_TYPE.HORIZONTAL: {
@@ -1263,6 +1262,7 @@ function _mapStateToProps(state, ownProps): Object {
1263 1262
 
1264 1263
     return {
1265 1264
         _audioTrack,
1265
+        _currentLayout,
1266 1266
         _defaultLocalDisplayName: defaultLocalDisplayName,
1267 1267
         _disableLocalVideoFlip: Boolean(disableLocalVideoFlip),
1268 1268
         _disableTileEnlargement: Boolean(disableTileEnlargement),
@@ -1271,13 +1271,14 @@ function _mapStateToProps(state, ownProps): Object {
1271 1271
         _isAudioOnly: Boolean(state['features/base/audio-only'].enabled),
1272 1272
         _isCurrentlyOnLargeVideo: state['features/large-video']?.participantId === id,
1273 1273
         _isDominantSpeakerDisabled: interfaceConfig.DISABLE_DOMINANT_SPEAKER_INDICATOR,
1274
-        _isFakeScreenShareParticipant: sourceNameSignalingEnabled && participant?.isFakeScreenShareParticipant,
1275 1274
         _isMobile,
1276 1275
         _isMobilePortrait,
1277 1276
         _isScreenSharing: _videoTrack?.videoType === 'desktop',
1278 1277
         _isTestModeEnabled: isTestModeEnabled(state),
1279 1278
         _isVideoPlayable: id && isVideoPlayable(state, id),
1279
+        _isVirtualScreenshareParticipant: sourceNameSignalingEnabled && participant?.isVirtualScreenshareParticipant,
1280 1280
         _localFlipX: Boolean(localFlipX),
1281
+        _multipleVideoSupport: getMultipleVideoSupportFeatureFlag(state),
1281 1282
         _participant: participant,
1282 1283
         _raisedHand: hasRaisedHand(participant),
1283 1284
         _stageFilmstripLayout: isStageFilmstripAvailable(state),

+ 4
- 4
react/features/filmstrip/components/web/ThumbnailTopIndicators.js Dosyayı Görüntüle

@@ -36,9 +36,9 @@ type Props = {
36 36
     isHovered: boolean,
37 37
 
38 38
     /**
39
-     * Whether or not the thumbnail is a fake screen share participant.
39
+     * Whether or not the thumbnail is a virtual screen share participant.
40 40
      */
41
-    isFakeScreenShareParticipant: boolean,
41
+    isVirtualScreenshareParticipant: boolean,
42 42
 
43 43
     /**
44 44
      * Whether or not the indicators are for the local participant.
@@ -81,7 +81,7 @@ const useStyles = makeStyles(() => {
81 81
 const ThumbnailTopIndicators = ({
82 82
     hidePopover,
83 83
     indicatorsClassName,
84
-    isFakeScreenShareParticipant,
84
+    isVirtualScreenshareParticipant,
85 85
     isHovered,
86 86
     local,
87 87
     participantId,
@@ -101,7 +101,7 @@ const ThumbnailTopIndicators = ({
101 101
     const sourceNameSignalingEnabled = useSelector(getSourceNameSignalingFeatureFlag);
102 102
     const showConnectionIndicator = isHovered || !_connectionIndicatorAutoHideEnabled;
103 103
 
104
-    if (sourceNameSignalingEnabled && isFakeScreenShareParticipant) {
104
+    if (sourceNameSignalingEnabled && isVirtualScreenshareParticipant) {
105 105
         return (
106 106
             <div className = { styles.container }>
107 107
                 {!_connectionIndicatorDisabled

react/features/filmstrip/components/web/FakeScreenShareParticipant.js → react/features/filmstrip/components/web/VirtualScreenshareParticipant.js Dosyayı Görüntüle

@@ -68,7 +68,7 @@ type Props = {
68 68
     onTouchStart: Function,
69 69
 
70 70
     /**
71
-     * The ID of the fake screen share participant.
71
+     * The ID of the virtual screen share participant.
72 72
      */
73 73
     participantId: string,
74 74
 
@@ -88,7 +88,7 @@ type Props = {
88 88
     videoTrack: Object
89 89
 }
90 90
 
91
-const FakeScreenShareParticipant = ({
91
+const VirtualScreenshareParticipant = ({
92 92
     classes,
93 93
     containerClassName,
94 94
     isHovered,
@@ -141,8 +141,8 @@ const FakeScreenShareParticipant = ({
141 141
                 ) }>
142 142
                 <ThumbnailTopIndicators
143 143
                     currentLayout = { currentLayout }
144
-                    isFakeScreenShareParticipant = { true }
145 144
                     isHovered = { isHovered }
145
+                    isVirtualScreenshareParticipant = { true }
146 146
                     participantId = { participantId }
147 147
                     thumbnailType = { thumbnailType } />
148 148
             </div>
@@ -161,4 +161,4 @@ const FakeScreenShareParticipant = ({
161 161
         </span>);
162 162
 };
163 163
 
164
-export default FakeScreenShareParticipant;
164
+export default VirtualScreenshareParticipant;

+ 7
- 7
react/features/filmstrip/functions.any.js Dosyayı Görüntüle

@@ -1,7 +1,7 @@
1 1
 // @flow
2 2
 
3 3
 import { getSourceNameSignalingFeatureFlag } from '../base/config';
4
-import { getFakeScreenShareParticipantOwnerId } from '../base/participants';
4
+import { getVirtualScreenshareParticipantOwnerId } from '../base/participants';
5 5
 
6 6
 import { setRemoteParticipants } from './actions';
7 7
 import { isReorderingEnabled } from './functions';
@@ -18,9 +18,9 @@ export function updateRemoteParticipants(store: Object, participantId: ?number)
18 18
     const state = store.getState();
19 19
     let reorderedParticipants = [];
20 20
 
21
-    const { sortedRemoteFakeScreenShareParticipants } = state['features/base/participants'];
21
+    const { sortedRemoteVirtualScreenshareParticipants } = state['features/base/participants'];
22 22
 
23
-    if (!isReorderingEnabled(state) && !sortedRemoteFakeScreenShareParticipants.size) {
23
+    if (!isReorderingEnabled(state) && !sortedRemoteVirtualScreenshareParticipants.size) {
24 24
         if (participantId) {
25 25
             const { remoteParticipants } = state['features/filmstrip'];
26 26
 
@@ -39,14 +39,14 @@ export function updateRemoteParticipants(store: Object, participantId: ?number)
39 39
     } = state['features/base/participants'];
40 40
     const remoteParticipants = new Map(sortedRemoteParticipants);
41 41
     const screenShares = new Map(sortedRemoteScreenshares);
42
-    const screenShareParticipants = sortedRemoteFakeScreenShareParticipants
43
-        ? [ ...sortedRemoteFakeScreenShareParticipants.keys() ] : [];
42
+    const screenShareParticipants = sortedRemoteVirtualScreenshareParticipants
43
+        ? [ ...sortedRemoteVirtualScreenshareParticipants.keys() ] : [];
44 44
     const sharedVideos = fakeParticipants ? Array.from(fakeParticipants.keys()) : [];
45 45
     const speakers = new Map(speakersList);
46 46
 
47 47
     if (getSourceNameSignalingFeatureFlag(state)) {
48 48
         for (const screenshare of screenShareParticipants) {
49
-            const ownerId = getFakeScreenShareParticipantOwnerId(screenshare);
49
+            const ownerId = getVirtualScreenshareParticipantOwnerId(screenshare);
50 50
 
51 51
             remoteParticipants.delete(ownerId);
52 52
             remoteParticipants.delete(screenshare);
@@ -72,7 +72,7 @@ export function updateRemoteParticipants(store: Object, participantId: ?number)
72 72
     if (getSourceNameSignalingFeatureFlag(state)) {
73 73
         // Always update the order of the thumnails.
74 74
         const participantsWithScreenShare = screenShareParticipants.reduce((acc, screenshare) => {
75
-            const ownerId = getFakeScreenShareParticipantOwnerId(screenshare);
75
+            const ownerId = getVirtualScreenshareParticipantOwnerId(screenshare);
76 76
 
77 77
             acc.push(ownerId);
78 78
             acc.push(screenshare);

+ 18
- 5
react/features/filmstrip/functions.web.js Dosyayı Görüntüle

@@ -509,18 +509,29 @@ export function computeDisplayModeFromInput(input: Object) {
509 509
         isActiveParticipant,
510 510
         isAudioOnly,
511 511
         isCurrentlyOnLargeVideo,
512
-        isFakeScreenShareParticipant,
512
+        isVirtualScreenshareParticipant,
513 513
         isScreenSharing,
514 514
         canPlayEventReceived,
515 515
         isRemoteParticipant,
516
+        multipleVideoSupport,
516 517
         stageParticipantsVisible,
517 518
         stageFilmstrip,
518 519
         tileViewActive
519 520
     } = input;
520 521
     const adjustedIsVideoPlayable = input.isVideoPlayable && (!isRemoteParticipant || canPlayEventReceived);
521 522
 
522
-    if (isFakeScreenShareParticipant) {
523
-        return DISPLAY_VIDEO;
523
+    if (multipleVideoSupport) {
524
+        // Display video for virtual screen share participants in all layouts.
525
+        if (isVirtualScreenshareParticipant) {
526
+            return DISPLAY_VIDEO;
527
+        }
528
+
529
+        // Multi-stream is not supported on plan-b endpoints even if its is enabled via config.js. A virtual
530
+        // screenshare tile is still created when a remote endpoint starts screenshare to keep the behavior consistent
531
+        // and an avatar is displayed on the original participant thumbnail as long as screenshare is in progress.
532
+        if (isScreenSharing) {
533
+            return DISPLAY_AVATAR;
534
+        }
524 535
     }
525 536
 
526 537
     if (!tileViewActive && ((isScreenSharing && isRemoteParticipant)
@@ -551,9 +562,10 @@ export function getDisplayModeInput(props: Object, state: Object) {
551 562
         _isActiveParticipant,
552 563
         _isAudioOnly,
553 564
         _isCurrentlyOnLargeVideo,
554
-        _isFakeScreenShareParticipant,
565
+        _isVirtualScreenshareParticipant,
555 566
         _isScreenSharing,
556 567
         _isVideoPlayable,
568
+        _multipleVideoSupport,
557 569
         _participant,
558 570
         _stageParticipantsVisible,
559 571
         _videoTrack,
@@ -573,7 +585,8 @@ export function getDisplayModeInput(props: Object, state: Object) {
573 585
         videoStream: Boolean(_videoTrack),
574 586
         isRemoteParticipant: !_participant?.isFakeParticipant && !_participant?.local,
575 587
         isScreenSharing: _isScreenSharing,
576
-        isFakeScreenShareParticipant: _isFakeScreenShareParticipant,
588
+        isVirtualScreenshareParticipant: _isVirtualScreenshareParticipant,
589
+        multipleVideoSupport: _multipleVideoSupport,
577 590
         stageParticipantsVisible: _stageParticipantsVisible,
578 591
         stageFilmstrip,
579 592
         videoStreamMuted: _videoTrack ? _videoTrack.muted : 'no stream'

+ 2
- 2
react/features/filmstrip/subscriber.any.js Dosyayı Görüntüle

@@ -16,8 +16,8 @@ StateListenerRegistry.register(
16 16
  * Listens for changes to the remote screenshare participants to recompute the reordered list of the remote endpoints.
17 17
  */
18 18
 StateListenerRegistry.register(
19
-    /* selector */ state => state['features/base/participants'].sortedRemoteFakeScreenShareParticipants,
20
-    /* listener */ (sortedRemoteFakeScreenShareParticipants, store) => updateRemoteParticipants(store));
19
+    /* selector */ state => state['features/base/participants'].sortedRemoteVirtualScreenshareParticipants,
20
+    /* listener */ (sortedRemoteVirtualScreenshareParticipants, store) => updateRemoteParticipants(store));
21 21
 
22 22
 /**
23 23
  * Listens for changes to the dominant speaker to recompute the reordered list of the remote endpoints.

+ 4
- 4
react/features/notifications/middleware.js Dosyayı Görüntüle

@@ -128,10 +128,10 @@ MiddlewareRegistry.register(store => next => action => {
128 128
         const { participant: p } = action;
129 129
         const { conference } = state['features/base/conference'];
130 130
 
131
-        // Do not display notifications for the fake screenshare tiles.
131
+        // Do not display notifications for the virtual screenshare tiles.
132 132
         if (conference
133 133
             && !p.local
134
-            && !p.isFakeScreenShareParticipant
134
+            && !p.isVirtualScreenshareParticipant
135 135
             && !joinLeaveNotificationsDisabled()
136 136
             && !p.isReplacing) {
137 137
             dispatch(showParticipantJoinedNotification(
@@ -148,10 +148,10 @@ MiddlewareRegistry.register(store => next => action => {
148 148
                 action.participant.id
149 149
             );
150 150
 
151
-            // Do not display notifications for the fake screenshare tiles.
151
+            // Do not display notifications for the virtual screenshare tiles.
152 152
             if (participant
153 153
                 && !participant.local
154
-                && !participant.isFakeScreenShareParticipant
154
+                && !participant.isVirtualScreenshareParticipant
155 155
                 && !action.participant.isReplaced) {
156 156
                 dispatch(showParticipantLeftNotification(
157 157
                     getParticipantDisplayName(state, participant.id)

+ 2
- 2
react/features/screen-share/actions.js Dosyayı Görüntüle

@@ -1,6 +1,6 @@
1 1
 // @flow
2 2
 
3
-import { getMultipleVideoSupportFeatureFlag } from '../base/config/functions.any';
3
+import { getMultipleVideoSendingSupportFeatureFlag } from '../base/config/functions.any';
4 4
 import { openDialog } from '../base/dialog/actions';
5 5
 import { browser } from '../base/lib-jitsi-meet';
6 6
 import { shouldHideShareAudioHelper } from '../base/settings';
@@ -86,7 +86,7 @@ export function startAudioScreenShareFlow() {
86 86
         // available for audio screen sharing, namely full window audio.
87 87
         // If we're already sharing audio, toggle off.
88 88
         if (shouldHideShareAudioHelper(state) || browser.isElectron() || audioOnlySharing) {
89
-            if (getMultipleVideoSupportFeatureFlag(state)) {
89
+            if (getMultipleVideoSendingSupportFeatureFlag(state)) {
90 90
                 dispatch(toggleScreensharing(!audioOnlySharing, true));
91 91
 
92 92
                 return;

+ 3
- 3
react/features/video-layout/actionTypes.ts Dosyayı Görüntüle

@@ -11,14 +11,14 @@ export const SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED
11 11
     = 'SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED';
12 12
 
13 13
 /**
14
- * The type of the action which sets the list of known remote fake screen share participant IDs.
14
+ * The type of the action which sets the list of known remote virtual screen share participant IDs.
15 15
  *
16 16
  * @returns {{
17
- *     type: FAKE_SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
17
+ *     type: VIRTUAL_SCREENSHARE_REMOTE_PARTICIPANTS_UPDATED,
18 18
  *     participantIds: Array<string>
19 19
  * }}
20 20
  */
21
-export const FAKE_SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED = 'FAKE_SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED';
21
+export const VIRTUAL_SCREENSHARE_REMOTE_PARTICIPANTS_UPDATED = 'VIRTUAL_SCREENSHARE_REMOTE_PARTICIPANTS_UPDATED';
22 22
 
23 23
 /**
24 24
  * The type of the action which enables or disables the feature for showing

+ 8
- 7
react/features/video-layout/actions.js Dosyayı Görüntüle

@@ -3,9 +3,9 @@
3 3
 import type { Dispatch } from 'redux';
4 4
 
5 5
 import {
6
-    FAKE_SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
7 6
     SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
8
-    SET_TILE_VIEW
7
+    SET_TILE_VIEW,
8
+    VIRTUAL_SCREENSHARE_REMOTE_PARTICIPANTS_UPDATED
9 9
 } from './actionTypes';
10 10
 import { shouldDisplayTileView } from './functions';
11 11
 
@@ -28,17 +28,18 @@ export function setRemoteParticipantsWithScreenShare(participantIds: Array<strin
28 28
 }
29 29
 
30 30
 /**
31
- * Creates a (redux) action which signals that the list of known remote fake screen share participant ids has changed.
31
+ * Creates a (redux) action which signals that the list of known remote virtual screen share participant ids has
32
+ * changed.
32 33
  *
33
- * @param {string} participantIds - The remote fake screen share participants.
34
+ * @param {string} participantIds - The remote virtual screen share participants.
34 35
  * @returns {{
35
- *     type: FAKE_SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
36
+ *     type: VIRTUAL_SCREENSHARE_REMOTE_PARTICIPANTS_UPDATED,
36 37
  *     participantIds: Array<string>
37 38
  * }}
38 39
  */
39
-export function fakeScreenshareParticipantsUpdated(participantIds: Array<string>) {
40
+export function virtualScreenshareParticipantsUpdated(participantIds: Array<string>) {
40 41
     return {
41
-        type: FAKE_SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
42
+        type: VIRTUAL_SCREENSHARE_REMOTE_PARTICIPANTS_UPDATED,
42 43
         participantIds
43 44
     };
44 45
 }

+ 4
- 4
react/features/video-layout/reducer.js Dosyayı Görüntüle

@@ -3,9 +3,9 @@
3 3
 import { ReducerRegistry } from '../base/redux';
4 4
 
5 5
 import {
6
-    FAKE_SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
7 6
     SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
8
-    SET_TILE_VIEW
7
+    SET_TILE_VIEW,
8
+    VIRTUAL_SCREENSHARE_REMOTE_PARTICIPANTS_UPDATED
9 9
 } from './actionTypes';
10 10
 
11 11
 const DEFAULT_STATE = {
@@ -28,8 +28,8 @@ const STORE_NAME = 'features/video-layout';
28 28
 
29 29
 ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
30 30
     switch (action.type) {
31
-    case FAKE_SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED:
32
-    case SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED: {
31
+    case SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED:
32
+    case VIRTUAL_SCREENSHARE_REMOTE_PARTICIPANTS_UPDATED: {
33 33
         return {
34 34
             ...state,
35 35
             remoteScreenShares: action.participantIds

+ 8
- 8
react/features/video-layout/subscriber.js Dosyayı Görüntüle

@@ -2,22 +2,22 @@
2 2
 
3 3
 import debounce from 'lodash/debounce';
4 4
 
5
-import { getSourceNameSignalingFeatureFlag } from '../base/config';
5
+import { getMultipleVideoSupportFeatureFlag } from '../base/config';
6 6
 import { StateListenerRegistry, equals } from '../base/redux';
7 7
 import { isFollowMeActive } from '../follow-me';
8 8
 
9
-import { setRemoteParticipantsWithScreenShare, fakeScreenshareParticipantsUpdated } from './actions';
9
+import { setRemoteParticipantsWithScreenShare, virtualScreenshareParticipantsUpdated } from './actions';
10 10
 import { getAutoPinSetting, updateAutoPinnedParticipant } from './functions';
11 11
 
12 12
 StateListenerRegistry.register(
13
-    /* selector */ state => state['features/base/participants'].sortedRemoteFakeScreenShareParticipants,
14
-    /* listener */ (sortedRemoteFakeScreenShareParticipants, store) => {
15
-        if (!getAutoPinSetting() || isFollowMeActive(store) || !getSourceNameSignalingFeatureFlag(store.getState())) {
13
+    /* selector */ state => state['features/base/participants'].sortedRemoteVirtualScreenshareParticipants,
14
+    /* listener */ (sortedRemoteVirtualScreenshareParticipants, store) => {
15
+        if (!getAutoPinSetting() || isFollowMeActive(store) || !getMultipleVideoSupportFeatureFlag(store.getState())) {
16 16
             return;
17 17
         }
18 18
 
19 19
         const oldScreenSharesOrder = store.getState()['features/video-layout'].remoteScreenShares || [];
20
-        const knownSharingParticipantIds = [ ...sortedRemoteFakeScreenShareParticipants.keys() ];
20
+        const knownSharingParticipantIds = [ ...sortedRemoteVirtualScreenshareParticipants.keys() ];
21 21
 
22 22
         // Filter out any participants which are no longer screen sharing
23 23
         // by looping through the known sharing participants and removing any
@@ -34,7 +34,7 @@ StateListenerRegistry.register(
34 34
         });
35 35
 
36 36
         if (!equals(oldScreenSharesOrder, newScreenSharesOrder)) {
37
-            store.dispatch(fakeScreenshareParticipantsUpdated(newScreenSharesOrder));
37
+            store.dispatch(virtualScreenshareParticipantsUpdated(newScreenSharesOrder));
38 38
 
39 39
             updateAutoPinnedParticipant(oldScreenSharesOrder, store);
40 40
         }
@@ -53,7 +53,7 @@ StateListenerRegistry.register(
53 53
         // possible to have screen sharing participant that has already left in the remoteScreenShares array.
54 54
         // This can lead to rendering a thumbnails for already left participants since the remoteScreenShares
55 55
         // array is used for building the ordered list of remote participants.
56
-        if (!getAutoPinSetting() || isFollowMeActive(store) || getSourceNameSignalingFeatureFlag(store.getState())) {
56
+        if (!getAutoPinSetting() || isFollowMeActive(store) || getMultipleVideoSupportFeatureFlag(store.getState())) {
57 57
             return;
58 58
         }
59 59
 

+ 10
- 9
react/features/video-quality/subscriber.js Dosyayı Görüntüle

@@ -7,7 +7,7 @@ import { getSourceNameSignalingFeatureFlag } from '../base/config';
7 7
 import { MEDIA_TYPE } from '../base/media';
8 8
 import { getLocalParticipant, getParticipantCount } from '../base/participants';
9 9
 import { StateListenerRegistry } from '../base/redux';
10
-import { getTrackSourceNameByMediaTypeAndParticipant } from '../base/tracks';
10
+import { getRemoteScreenSharesSourceNames, getTrackSourceNameByMediaTypeAndParticipant } from '../base/tracks';
11 11
 import { reportError } from '../base/util';
12 12
 import { getActiveParticipantsIds } from '../filmstrip/functions.web';
13 13
 import {
@@ -238,6 +238,8 @@ function _updateReceiverVideoConstraints({ getState }) {
238 238
     let receiverConstraints;
239 239
 
240 240
     if (sourceNameSignaling) {
241
+        const remoteScreenSharesSourceNames = getRemoteScreenSharesSourceNames(state, remoteScreenShares);
242
+
241 243
         receiverConstraints = {
242 244
             constraints: {},
243 245
             defaultConstraints: { 'maxHeight': VIDEO_QUALITY_LEVELS.NONE },
@@ -253,7 +255,7 @@ function _updateReceiverVideoConstraints({ getState }) {
253 255
             visibleRemoteParticipants.forEach(participantId => {
254 256
                 let sourceName;
255 257
 
256
-                if (remoteScreenShares.includes(participantId)) {
258
+                if (remoteScreenSharesSourceNames.includes(participantId)) {
257 259
                     sourceName = participantId;
258 260
                 } else {
259 261
                     sourceName = getTrackSourceNameByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, participantId);
@@ -269,12 +271,11 @@ function _updateReceiverVideoConstraints({ getState }) {
269 271
         }
270 272
 
271 273
         if (localParticipantId !== largeVideoParticipantId) {
272
-            if (remoteScreenShares.includes(largeVideoParticipantId)) {
274
+            if (remoteScreenSharesSourceNames.includes(largeVideoParticipantId)) {
273 275
                 largeVideoSourceName = largeVideoParticipantId;
274 276
             } else {
275 277
                 largeVideoSourceName = getTrackSourceNameByMediaTypeAndParticipant(
276
-                    tracks, MEDIA_TYPE.VIDEO,
277
-                    largeVideoParticipantId
278
+                    tracks, MEDIA_TYPE.VIDEO, largeVideoParticipantId
278 279
                 );
279 280
             }
280 281
         }
@@ -290,8 +291,8 @@ function _updateReceiverVideoConstraints({ getState }) {
290 291
             });
291 292
 
292 293
             // Prioritize screenshare in tile view.
293
-            if (remoteScreenShares?.length) {
294
-                receiverConstraints.selectedSources = remoteScreenShares;
294
+            if (remoteScreenSharesSourceNames?.length) {
295
+                receiverConstraints.selectedSources = remoteScreenSharesSourceNames;
295 296
             }
296 297
 
297 298
         // Stage view.
@@ -325,8 +326,8 @@ function _updateReceiverVideoConstraints({ getState }) {
325 326
             }
326 327
         }
327 328
 
328
-        if (remoteScreenShares?.length) {
329
-            remoteScreenShares.forEach(sourceName => {
329
+        if (remoteScreenSharesSourceNames?.length) {
330
+            remoteScreenSharesSourceNames.forEach(sourceName => {
330 331
                 receiverConstraints.constraints[sourceName] = { 'maxHeight': VIDEO_QUALITY_LEVELS.ULTRA };
331 332
             });
332 333
         }

Loading…
İptal
Kaydet