Browse Source

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 years ago
parent
commit
d3fe246f61
No account linked to committer's email address
33 changed files with 365 additions and 301 deletions
  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 View File

56
 } from './react/features/base/conference';
56
 } from './react/features/base/conference';
57
 import {
57
 import {
58
     getReplaceParticipant,
58
     getReplaceParticipant,
59
-    getMultipleVideoSupportFeatureFlag,
60
-    getSourceNameSignalingFeatureFlag
59
+    getMultipleVideoSendingSupportFeatureFlag
61
 } from './react/features/base/config/functions';
60
 } from './react/features/base/config/functions';
62
 import {
61
 import {
63
     checkAndNotifyForNewDevice,
62
     checkAndNotifyForNewDevice,
97
     dominantSpeakerChanged,
96
     dominantSpeakerChanged,
98
     getLocalParticipant,
97
     getLocalParticipant,
99
     getNormalizedDisplayName,
98
     getNormalizedDisplayName,
100
-    getScreenshareParticipantByOwnerId,
99
+    getVirtualScreenshareParticipantByOwnerId,
101
     localParticipantAudioLevelChanged,
100
     localParticipantAudioLevelChanged,
102
     localParticipantConnectionStatusChanged,
101
     localParticipantConnectionStatusChanged,
103
     localParticipantRoleChanged,
102
     localParticipantRoleChanged,
1472
 
1471
 
1473
                 // In the multi-stream mode, add the track to the conference if there is no existing track, replace it
1472
                 // In the multi-stream mode, add the track to the conference if there is no existing track, replace it
1474
                 // otherwise.
1473
                 // otherwise.
1475
-                if (getMultipleVideoSupportFeatureFlag(state)) {
1474
+                if (getMultipleVideoSendingSupportFeatureFlag(state)) {
1476
                     const trackAction = oldTrack
1475
                     const trackAction = oldTrack
1477
                         ? replaceLocalTrack(oldTrack, newTrack, room)
1476
                         ? replaceLocalTrack(oldTrack, newTrack, room)
1478
                         : addLocalTrack(newTrack);
1477
                         : addLocalTrack(newTrack);
2265
                     name: formattedDisplayName
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
                 APP.API.notifyDisplayNameChanged(id, {
2275
                 APP.API.notifyDisplayNameChanged(id, {

+ 14
- 2
modules/UI/videolayout/LargeVideoManager.js View File

9
 import { createScreenSharingIssueEvent, sendAnalytics } from '../../../react/features/analytics';
9
 import { createScreenSharingIssueEvent, sendAnalytics } from '../../../react/features/analytics';
10
 import { Avatar } from '../../../react/features/base/avatar';
10
 import { Avatar } from '../../../react/features/base/avatar';
11
 import theme from '../../../react/features/base/components/themes/participantsPaneTheme.json';
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
 import { i18next } from '../../../react/features/base/i18n';
16
 import { i18next } from '../../../react/features/base/i18n';
14
 import { JitsiTrackEvents } from '../../../react/features/base/lib-jitsi-meet';
17
 import { JitsiTrackEvents } from '../../../react/features/base/lib-jitsi-meet';
15
 import { VIDEO_TYPE } from '../../../react/features/base/media';
18
 import { VIDEO_TYPE } from '../../../react/features/base/media';
283
             }
286
             }
284
 
287
 
285
             const isAudioOnly = APP.conference.isAudioOnly();
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
             const showAvatar
298
             const showAvatar
287
                 = isVideoContainer
299
                 = isVideoContainer
288
-                    && ((isAudioOnly && videoType !== VIDEO_TYPE.DESKTOP) || !isVideoRenderable);
300
+                    && ((isAudioOnly && videoType !== VIDEO_TYPE.DESKTOP) || !isVideoRenderable || legacyScreenshare);
289
 
301
 
290
             let promise;
302
             let promise;
291
 
303
 

+ 4
- 4
modules/UI/videolayout/VideoLayout.js View File

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

+ 2
- 2
react/features/base/conference/middleware.web.js View File

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

+ 12
- 3
react/features/base/config/functions.any.js View File

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
  * @param {Object} state - The global state.
56
  * @param {Object} state - The global state.
57
  * @returns {boolean}
57
  * @returns {boolean}
58
  */
58
  */
59
 export function getMultipleVideoSupportFeatureFlag(state: Object) {
59
 export function getMultipleVideoSupportFeatureFlag(state: Object) {
60
     return getFeatureFlag(state, FEATURE_FLAGS.MULTIPLE_VIDEO_STREAMS_SUPPORT)
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 View File

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

+ 2
- 2
react/features/base/media/middleware.js View File

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

+ 31
- 0
react/features/base/participants/actions.js View File

25
 } from './constants';
25
 } from './constants';
26
 import {
26
 import {
27
     getLocalParticipant,
27
     getLocalParticipant,
28
+    getVirtualScreenshareParticipantOwnerId,
28
     getNormalizedDisplayName,
29
     getNormalizedDisplayName,
29
     getParticipantDisplayName,
30
     getParticipantDisplayName,
30
     getParticipantById
31
     getParticipantById
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
  * Action to signal that a participant had been kicked.
538
  * Action to signal that a participant had been kicked.
508
  *
539
  *

+ 20
- 21
react/features/base/participants/functions.js View File

6
 import { i18next } from '../../base/i18n';
6
 import { i18next } from '../../base/i18n';
7
 import { isStageFilmstripAvailable } from '../../filmstrip/functions';
7
 import { isStageFilmstripAvailable } from '../../filmstrip/functions';
8
 import { GRAVATAR_BASE_URL, isCORSAvatarURL } from '../avatar';
8
 import { GRAVATAR_BASE_URL, isCORSAvatarURL } from '../avatar';
9
-import { getSourceNameSignalingFeatureFlag } from '../config';
9
+import { getMultipleVideoSupportFeatureFlag, getSourceNameSignalingFeatureFlag } from '../config';
10
 import { JitsiParticipantConnectionStatus } from '../lib-jitsi-meet';
10
 import { JitsiParticipantConnectionStatus } from '../lib-jitsi-meet';
11
 import { MEDIA_TYPE, shouldRenderVideoTrack } from '../media';
11
 import { MEDIA_TYPE, shouldRenderVideoTrack } from '../media';
12
 import { toState } from '../redux';
12
 import { toState } from '../redux';
13
-import { getTrackByMediaTypeAndParticipant } from '../tracks';
13
+import { getScreenShareTrack, getTrackByMediaTypeAndParticipant } from '../tracks';
14
 import { createDeferred } from '../util';
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
 import { preloadImage } from './preloadImage';
17
 import { preloadImage } from './preloadImage';
22
 
18
 
23
-
24
 /**
19
 /**
25
  * Temp structures for avatar urls to be checked/preloaded.
20
  * Temp structures for avatar urls to be checked/preloaded.
26
  */
21
  */
114
  * @param {string} id - The owner ID of the screenshare participant to retrieve.
109
  * @param {string} id - The owner ID of the screenshare participant to retrieve.
115
  * @returns {(Participant|undefined)}
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
         local,
185
         local,
187
         remote,
186
         remote,
188
         fakeParticipants,
187
         fakeParticipants,
189
-        sortedRemoteFakeScreenShareParticipants
188
+        sortedRemoteVirtualScreenshareParticipants
190
     } = state['features/base/participants'];
189
     } = state['features/base/participants'];
191
 
190
 
192
     if (getSourceNameSignalingFeatureFlag(state)) {
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
     return remote.size - fakeParticipants.size + (local ? 1 : 0);
195
     return remote.size - fakeParticipants.size + (local ? 1 : 0);
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
  * @private
203
  * @private
205
  * @returns {(string|undefined)}
204
  * @returns {(string|undefined)}
206
  */
205
  */
207
-export function getFakeScreenShareParticipantOwnerId(id: string) {
206
+export function getVirtualScreenshareParticipantOwnerId(id: string) {
208
     return id.split('-')[0];
207
     return id.split('-')[0];
209
 }
208
 }
210
 
209
 
232
     const state = toState(stateful)['features/base/participants'];
231
     const state = toState(stateful)['features/base/participants'];
233
 
232
 
234
     if (getSourceNameSignalingFeatureFlag(state)) {
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
     return state.remote.size;
237
     return state.remote.size;
274
     } = toState(stateful)['features/base/config'];
273
     } = toState(stateful)['features/base/config'];
275
 
274
 
276
     if (participant) {
275
     if (participant) {
277
-        if (participant.isFakeScreenShareParticipant) {
276
+        if (participant.isVirtualScreenshareParticipant) {
278
             return getScreenshareParticipantDisplayName(stateful, id);
277
             return getScreenshareParticipantDisplayName(stateful, id);
279
         }
278
         }
280
 
279
 
299
  * @returns {string}
298
  * @returns {string}
300
  */
299
  */
301
 export function getScreenshareParticipantDisplayName(stateful: Object | Function, id: string) {
300
 export function getScreenshareParticipantDisplayName(stateful: Object | Function, id: string) {
302
-    const owner = getParticipantById(stateful, getFakeScreenShareParticipantOwnerId(id));
301
+    const owner = getParticipantById(stateful, getVirtualScreenshareParticipantOwnerId(id));
303
     const name = owner.name;
302
     const name = owner.name;
304
 
303
 
305
     return i18next.t('screenshareDisplayName', { name });
304
     return i18next.t('screenshareDisplayName', { name });

+ 6
- 5
react/features/base/participants/middleware.js View File

69
     isLocalParticipantModerator
69
     isLocalParticipantModerator
70
 } from './functions';
70
 } from './functions';
71
 import { PARTICIPANT_JOINED_FILE, PARTICIPANT_LEFT_FILE } from './sounds';
71
 import { PARTICIPANT_JOINED_FILE, PARTICIPANT_LEFT_FILE } from './sounds';
72
+import './subscriber';
72
 
73
 
73
 declare var APP: Object;
74
 declare var APP: Object;
74
 
75
 
210
     }
211
     }
211
 
212
 
212
     case PARTICIPANT_JOINED: {
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
         return _participantJoinedOrUpdated(store, next, action);
219
         return _participantJoinedOrUpdated(store, next, action);
219
     }
220
     }
220
 
221
 
221
     case PARTICIPANT_LEFT: {
222
     case PARTICIPANT_LEFT: {
222
-        const { isFakeScreenShareParticipant } = action.participant;
223
+        const { isVirtualScreenshareParticipant } = action.participant;
223
 
224
 
224
         // Do not play sounds when a tile for screenshare is removed.
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
         break;
228
         break;
228
     }
229
     }

+ 26
- 19
react/features/base/participants/reducer.js View File

66
     pinnedParticipant: undefined,
66
     pinnedParticipant: undefined,
67
     raisedHandsQueue: [],
67
     raisedHandsQueue: [],
68
     remote: new Map(),
68
     remote: new Map(),
69
-    sortedRemoteFakeScreenShareParticipants: new Map(),
69
+    sortedRemoteVirtualScreenshareParticipants: new Map(),
70
     sortedRemoteParticipants: new Map(),
70
     sortedRemoteParticipants: new Map(),
71
     sortedRemoteScreenshares: new Map(),
71
     sortedRemoteScreenshares: new Map(),
72
     speakersList: new Map()
72
     speakersList: new Map()
213
     case SCREENSHARE_PARTICIPANT_NAME_CHANGED: {
213
     case SCREENSHARE_PARTICIPANT_NAME_CHANGED: {
214
         const { id, name } = action;
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
         return { ...state };
227
         return { ...state };
229
 
229
 
230
     case PARTICIPANT_JOINED: {
230
     case PARTICIPANT_JOINED: {
231
         const participant = _participantJoined(action);
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
         const { pinnedParticipant, dominantSpeaker } = state;
240
         const { pinnedParticipant, dominantSpeaker } = state;
234
 
241
 
235
         if (pinned) {
242
         if (pinned) {
282
         // The sort order of participants is preserved since Map remembers the original insertion order of the keys.
289
         // The sort order of participants is preserved since Map remembers the original insertion order of the keys.
283
         state.sortedRemoteParticipants = new Map(sortedRemoteParticipants);
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
         if (isFakeParticipant) {
300
         if (isFakeParticipant) {
294
             state.fakeParticipants.set(id, participant);
301
             state.fakeParticipants.set(id, participant);
306
         const { conference, id } = action.participant;
313
         const { conference, id } = action.participant;
307
         const {
314
         const {
308
             fakeParticipants,
315
             fakeParticipants,
309
-            sortedRemoteFakeScreenShareParticipants,
316
+            sortedRemoteVirtualScreenshareParticipants,
310
             remote,
317
             remote,
311
             local,
318
             local,
312
             localScreenShare,
319
             localScreenShare,
372
             fakeParticipants.delete(id);
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
         return { ...state };
387
         return { ...state };
500
         dominantSpeaker,
507
         dominantSpeaker,
501
         email,
508
         email,
502
         isFakeParticipant,
509
         isFakeParticipant,
503
-        isFakeScreenShareParticipant,
510
+        isVirtualScreenshareParticipant,
504
         isLocalScreenShare,
511
         isLocalScreenShare,
505
         isReplacing,
512
         isReplacing,
506
         isJigasi,
513
         isJigasi,
534
         email,
541
         email,
535
         id,
542
         id,
536
         isFakeParticipant,
543
         isFakeParticipant,
537
-        isFakeScreenShareParticipant,
544
+        isVirtualScreenshareParticipant,
538
         isLocalScreenShare,
545
         isLocalScreenShare,
539
         isReplacing,
546
         isReplacing,
540
         isJigasi,
547
         isJigasi,

+ 0
- 0
react/features/base/participants/subscriber.native.js View File


+ 69
- 0
react/features/base/participants/subscriber.web.js View File

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 View File

107
  */
107
  */
108
 export const TRACK_UPDATED = 'TRACK_UPDATED';
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
  * The type of redux action dispatched when a local track starts being created
111
  * The type of redux action dispatched when a local track starts being created
124
  * via a WebRTC {@code getUserMedia} call. The action's payload includes an
112
  * via a WebRTC {@code getUserMedia} call. The action's payload includes an

+ 7
- 29
react/features/base/tracks/actions.js View File

6
 } from '../../analytics';
6
 } from '../../analytics';
7
 import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification, showNotification } from '../../notifications';
7
 import { NOTIFICATION_TIMEOUT_TYPE, showErrorNotification, showNotification } from '../../notifications';
8
 import { getCurrentConference } from '../conference';
8
 import { getCurrentConference } from '../conference';
9
-import { getMultipleVideoSupportFeatureFlag, getSourceNameSignalingFeatureFlag } from '../config';
9
+import { getMultipleVideoSendingSupportFeatureFlag } from '../config';
10
 import { JitsiTrackErrors, JitsiTrackEvents } from '../lib-jitsi-meet';
10
 import { JitsiTrackErrors, JitsiTrackEvents } from '../lib-jitsi-meet';
11
 import { createLocalTrack } from '../lib-jitsi-meet/functions';
11
 import { createLocalTrack } from '../lib-jitsi-meet/functions';
12
 import {
12
 import {
22
 import { updateSettings } from '../settings';
22
 import { updateSettings } from '../settings';
23
 
23
 
24
 import {
24
 import {
25
-    SCREENSHARE_TRACK_MUTED_UPDATED,
26
     SET_NO_SRC_DATA_NOTIFICATION_UID,
25
     SET_NO_SRC_DATA_NOTIFICATION_UID,
27
     TOGGLE_SCREENSHARING,
26
     TOGGLE_SCREENSHARING,
28
     TRACK_ADDED,
27
     TRACK_ADDED,
60
         }
59
         }
61
 
60
 
62
         const setMuted = newTrack.isVideoTrack()
61
         const setMuted = newTrack.isVideoTrack()
63
-            ? getMultipleVideoSupportFeatureFlag(getState())
62
+            ? getMultipleVideoSendingSupportFeatureFlag(getState())
64
             && newTrack.getVideoType() === VIDEO_TYPE.DESKTOP
63
             && newTrack.getVideoType() === VIDEO_TYPE.DESKTOP
65
                 ? setScreenshareMuted
64
                 ? setScreenshareMuted
66
                 : setVideoMuted
65
                 : setVideoMuted
371
             // state. If this is not done, the current mute state of the app will be reflected on the track,
370
             // state. If this is not done, the current mute state of the app will be reflected on the track,
372
             // not vice-versa.
371
             // not vice-versa.
373
             const setMuted = newTrack.isVideoTrack()
372
             const setMuted = newTrack.isVideoTrack()
374
-                ? getMultipleVideoSupportFeatureFlag(getState()) && newTrack.getVideoType() === VIDEO_TYPE.DESKTOP
373
+                ? getMultipleVideoSendingSupportFeatureFlag(getState())
374
+                    && newTrack.getVideoType() === VIDEO_TYPE.DESKTOP
375
                     ? setScreenshareMuted
375
                     ? setScreenshareMuted
376
                     : setVideoMuted
376
                     : setVideoMuted
377
                 : setAudioMuted;
377
                 : setAudioMuted;
397
     return async (dispatch, getState) => {
397
     return async (dispatch, getState) => {
398
         track.on(
398
         track.on(
399
             JitsiTrackEvents.TRACK_MUTE_CHANGED,
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
         track.on(
401
         track.on(
407
             JitsiTrackEvents.TRACK_VIDEOTYPE_CHANGED,
402
             JitsiTrackEvents.TRACK_VIDEOTYPE_CHANGED,
408
             type => dispatch(trackVideoTypeChanged(track, type)));
403
             type => dispatch(trackVideoTypeChanged(track, type)));
409
 
404
 
410
         // participantId
405
         // participantId
411
         const local = track.isLocal();
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
             ? MEDIA_TYPE.SCREENSHARE
409
             ? MEDIA_TYPE.SCREENSHARE
414
             : track.getType();
410
             : track.getType();
415
         let isReceivingData, noDataFromSourceNotificationInfo, participantId;
411
         let isReceivingData, noDataFromSourceNotificationInfo, participantId;
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
  * Create an action for when a track's muted state change action has failed. This could happen because of
498
  * Create an action for when a track's muted state change action has failed. This could happen because of
521
  * {@code getUserMedia} errors during unmute or replace track errors at the peerconnection level.
499
  * {@code getUserMedia} errors during unmute or replace track errors at the peerconnection level.

+ 52
- 18
react/features/base/tracks/functions.js View File

1
 /* global APP */
1
 /* global APP */
2
 
2
 
3
-import { getMultipleVideoSupportFeatureFlag } from '../config/functions.any';
3
+import {
4
+    getMultipleVideoSendingSupportFeatureFlag,
5
+    getMultipleVideoSupportFeatureFlag
6
+} from '../config/functions.any';
4
 import { isMobileBrowser } from '../environment/utils';
7
 import { isMobileBrowser } from '../environment/utils';
5
 import JitsiMeetJS, { JitsiTrackErrors, browser } from '../lib-jitsi-meet';
8
 import JitsiMeetJS, { JitsiTrackErrors, browser } from '../lib-jitsi-meet';
6
 import { MEDIA_TYPE, VIDEO_TYPE, setAudioMuted } from '../media';
9
 import { MEDIA_TYPE, VIDEO_TYPE, setAudioMuted } from '../media';
7
-import { getFakeScreenShareParticipantOwnerId } from '../participants';
10
+import { getVirtualScreenshareParticipantOwnerId } from '../participants';
8
 import { toState } from '../redux';
11
 import { toState } from '../redux';
9
 import {
12
 import {
10
     getUserSelectedCameraDeviceId,
13
     getUserSelectedCameraDeviceId,
426
         return;
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
 }
454
 }
459
 
455
 
460
 /**
456
 /**
461
- * Returns track of given fakeScreenshareParticipantId.
457
+ * Returns screenshare track of given virtualScreenshareParticipantId.
462
  *
458
  *
463
  * @param {Track[]} tracks - List of all tracks.
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
  * @returns {(Track|undefined)}
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
     // browser's 'Stop sharing' button, the local stream is stopped before the inactive stream handler is fired.
644
     // browser's 'Stop sharing' button, the local stream is stopped before the inactive stream handler is fired.
611
     // We still need to proceed here and remove the track from the peerconnection.
645
     // We still need to proceed here and remove the track from the peerconnection.
612
     if (track.isMuted() === muted
646
     if (track.isMuted() === muted
613
-        && !(track.getVideoType() === VIDEO_TYPE.DESKTOP && getMultipleVideoSupportFeatureFlag(state))) {
647
+        && !(track.getVideoType() === VIDEO_TYPE.DESKTOP && getMultipleVideoSendingSupportFeatureFlag(state))) {
614
         return Promise.resolve();
648
         return Promise.resolve();
615
     }
649
     }
616
 
650
 

+ 11
- 88
react/features/base/tracks/middleware.js View File

9
 import { hideNotification, isModerationNotificationDisplayed } from '../../notifications';
9
 import { hideNotification, isModerationNotificationDisplayed } from '../../notifications';
10
 import { isPrejoinPageVisible } from '../../prejoin/functions';
10
 import { isPrejoinPageVisible } from '../../prejoin/functions';
11
 import { getCurrentConference } from '../conference/functions';
11
 import { getCurrentConference } from '../conference/functions';
12
-import { getMultipleVideoSupportFeatureFlag, getSourceNameSignalingFeatureFlag } from '../config';
12
+import { getMultipleVideoSendingSupportFeatureFlag } from '../config';
13
 import { getAvailableDevices } from '../devices/actions';
13
 import { getAvailableDevices } from '../devices/actions';
14
 import {
14
 import {
15
     CAMERA_FACING_MODE,
15
     CAMERA_FACING_MODE,
25
     setScreenshareMuted,
25
     setScreenshareMuted,
26
     SCREENSHARE_MUTISM_AUTHORITY
26
     SCREENSHARE_MUTISM_AUTHORITY
27
 } from '../media';
27
 } from '../media';
28
-import { participantLeft, participantJoined, getParticipantById } from '../participants';
29
 import { MiddlewareRegistry, StateListenerRegistry } from '../redux';
28
 import { MiddlewareRegistry, StateListenerRegistry } from '../redux';
30
 
29
 
31
 import {
30
 import {
32
-    SCREENSHARE_TRACK_MUTED_UPDATED,
33
     TOGGLE_SCREENSHARING,
31
     TOGGLE_SCREENSHARING,
34
     TRACK_ADDED,
32
     TRACK_ADDED,
35
     TRACK_MUTE_UNMUTE_FAILED,
33
     TRACK_MUTE_UNMUTE_FAILED,
53
     isUserInteractionRequiredForUnmute,
51
     isUserInteractionRequiredForUnmute,
54
     setTrackMuted
52
     setTrackMuted
55
 } from './functions';
53
 } from './functions';
56
-import logger from './logger';
57
 
54
 
58
 import './subscriber';
55
 import './subscriber';
59
 
56
 
70
 MiddlewareRegistry.register(store => next => action => {
67
 MiddlewareRegistry.register(store => next => action => {
71
     switch (action.type) {
68
     switch (action.type) {
72
     case TRACK_ADDED: {
69
     case TRACK_ADDED: {
73
-        const state = store.getState();
74
-        const { jitsiTrack, local } = action.track;
70
+        const { local } = action.track;
75
 
71
 
76
         // The devices list needs to be refreshed when no initial video permissions
72
         // The devices list needs to be refreshed when no initial video permissions
77
         // were granted and a local video track is added by umuting the video.
73
         // were granted and a local video track is added by umuting the video.
79
             store.dispatch(getAvailableDevices());
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
     case TRACK_NO_DATA_FROM_SOURCE: {
80
     case TRACK_NO_DATA_FROM_SOURCE: {
101
         const result = next(action);
81
         const result = next(action);
105
         return result;
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
     case TRACK_REMOVED: {
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
         _removeNoDataFromSourceNotification(store, action.track);
89
         _removeNoDataFromSourceNotification(store, action.track);
142
         break;
90
         break;
143
     }
91
     }
223
 
171
 
224
             const { enabled, audioOnly, ignoreDidHaveVideo } = action;
172
             const { enabled, audioOnly, ignoreDidHaveVideo } = action;
225
 
173
 
226
-            if (!getMultipleVideoSupportFeatureFlag(store.getState())) {
174
+            if (!getMultipleVideoSendingSupportFeatureFlag(store.getState())) {
227
                 APP.UI.emitEvent(UIEvents.TOGGLE_SCREENSHARING,
175
                 APP.UI.emitEvent(UIEvents.TOGGLE_SCREENSHARING,
228
                     {
176
                     {
229
                         enabled,
177
                         enabled,
241
 
189
 
242
         if (typeof APP !== 'undefined') {
190
         if (typeof APP !== 'undefined') {
243
             if (isVideoTrack && jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP
191
             if (isVideoTrack && jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP
244
-                && getMultipleVideoSupportFeatureFlag(store.getState())) {
192
+                && getMultipleVideoSendingSupportFeatureFlag(store.getState())) {
245
                 store.dispatch(setScreenshareMuted(!muted));
193
                 store.dispatch(setScreenshareMuted(!muted));
246
             } else if (isVideoTrack) {
194
             } else if (isVideoTrack) {
247
                 APP.conference.setVideoMuteStatus();
195
                 APP.conference.setVideoMuteStatus();
256
         const { jitsiTrack } = action.track;
204
         const { jitsiTrack } = action.track;
257
 
205
 
258
         if (typeof APP !== 'undefined'
206
         if (typeof APP !== 'undefined'
259
-            && getMultipleVideoSupportFeatureFlag(store.getState())
207
+            && getMultipleVideoSendingSupportFeatureFlag(store.getState())
260
             && jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP) {
208
             && jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP) {
261
             store.dispatch(toggleScreensharing(false));
209
             store.dispatch(toggleScreensharing(false));
262
         }
210
         }
286
                 } else if (jitsiTrack.isLocal() && !(jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP)) {
234
                 } else if (jitsiTrack.isLocal() && !(jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP)) {
287
                     APP.conference.setVideoMuteStatus();
235
                     APP.conference.setVideoMuteStatus();
288
                 } else if (jitsiTrack.isLocal() && muted && jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP) {
236
                 } else if (jitsiTrack.isLocal() && muted && jitsiTrack.getVideoType() === VIDEO_TYPE.DESKTOP) {
289
-                    !getMultipleVideoSupportFeatureFlag(state)
237
+                    !getMultipleVideoSendingSupportFeatureFlag(state)
290
                         && store.dispatch(toggleScreensharing(false, false, true));
238
                         && store.dispatch(toggleScreensharing(false, false, true));
291
                 } else {
239
                 } else {
292
                     APP.UI.setVideoMuted(participantID);
240
                     APP.UI.setVideoMuted(participantID);
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
  * Gets the local track associated with a specific {@code MEDIA_TYPE} in a
336
  * Gets the local track associated with a specific {@code MEDIA_TYPE} in a
415
  * specific redux store.
337
  * specific redux store.
472
     const state = getState();
394
     const state = getState();
473
 
395
 
474
     if (mediaType === MEDIA_TYPE.SCREENSHARE
396
     if (mediaType === MEDIA_TYPE.SCREENSHARE
475
-        && getMultipleVideoSupportFeatureFlag(state)
397
+        && getMultipleVideoSendingSupportFeatureFlag(state)
476
         && !muted) {
398
         && !muted) {
477
         return;
399
         return;
478
     }
400
     }
487
 
409
 
488
         // Screenshare cannot be unmuted using the video mute button unless it is muted by audioOnly in the legacy
410
         // Screenshare cannot be unmuted using the video mute button unless it is muted by audioOnly in the legacy
489
         // screensharing mode.
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
             setTrackMuted(jitsiTrack, muted, state).catch(() => dispatch(trackMuteUnmuteFailed(localTrack, muted)));
415
             setTrackMuted(jitsiTrack, muted, state).catch(() => dispatch(trackMuteUnmuteFailed(localTrack, muted)));
493
         }
416
         }
494
     } else if (!muted && ensureTrack && (typeof APP === 'undefined' || isPrejoinPageVisible(state))) {
417
     } else if (!muted && ensureTrack && (typeof APP === 'undefined' || isPrejoinPageVisible(state))) {

+ 3
- 3
react/features/connection-indicator/components/web/ConnectionIndicator.js View File

12
 import { Popover } from '../../../base/popover';
12
 import { Popover } from '../../../base/popover';
13
 import { connect } from '../../../base/redux';
13
 import { connect } from '../../../base/redux';
14
 import {
14
 import {
15
-    getFakeScreenshareParticipantTrack,
15
+    getVirtualScreenshareParticipantTrack,
16
     getTrackByMediaTypeAndParticipant } from '../../../base/tracks';
16
     getTrackByMediaTypeAndParticipant } from '../../../base/tracks';
17
 import {
17
 import {
18
     isParticipantConnectionStatusInactive,
18
     isParticipantConnectionStatusInactive,
374
 
374
 
375
     let firstVideoTrack;
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
     } else {
379
     } else {
380
         firstVideoTrack = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, participantId);
380
         firstVideoTrack = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, participantId);
381
     }
381
     }

+ 3
- 3
react/features/connection-indicator/components/web/ConnectionIndicatorContent.js View File

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

+ 3
- 3
react/features/connection-stats/components/ConnectionStatsTable.js View File

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

+ 15
- 14
react/features/filmstrip/components/web/Thumbnail.js View File

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

+ 4
- 4
react/features/filmstrip/components/web/ThumbnailTopIndicators.js View File

36
     isHovered: boolean,
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
      * Whether or not the indicators are for the local participant.
44
      * Whether or not the indicators are for the local participant.
81
 const ThumbnailTopIndicators = ({
81
 const ThumbnailTopIndicators = ({
82
     hidePopover,
82
     hidePopover,
83
     indicatorsClassName,
83
     indicatorsClassName,
84
-    isFakeScreenShareParticipant,
84
+    isVirtualScreenshareParticipant,
85
     isHovered,
85
     isHovered,
86
     local,
86
     local,
87
     participantId,
87
     participantId,
101
     const sourceNameSignalingEnabled = useSelector(getSourceNameSignalingFeatureFlag);
101
     const sourceNameSignalingEnabled = useSelector(getSourceNameSignalingFeatureFlag);
102
     const showConnectionIndicator = isHovered || !_connectionIndicatorAutoHideEnabled;
102
     const showConnectionIndicator = isHovered || !_connectionIndicatorAutoHideEnabled;
103
 
103
 
104
-    if (sourceNameSignalingEnabled && isFakeScreenShareParticipant) {
104
+    if (sourceNameSignalingEnabled && isVirtualScreenshareParticipant) {
105
         return (
105
         return (
106
             <div className = { styles.container }>
106
             <div className = { styles.container }>
107
                 {!_connectionIndicatorDisabled
107
                 {!_connectionIndicatorDisabled

react/features/filmstrip/components/web/FakeScreenShareParticipant.js → react/features/filmstrip/components/web/VirtualScreenshareParticipant.js View File

68
     onTouchStart: Function,
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
     participantId: string,
73
     participantId: string,
74
 
74
 
88
     videoTrack: Object
88
     videoTrack: Object
89
 }
89
 }
90
 
90
 
91
-const FakeScreenShareParticipant = ({
91
+const VirtualScreenshareParticipant = ({
92
     classes,
92
     classes,
93
     containerClassName,
93
     containerClassName,
94
     isHovered,
94
     isHovered,
141
                 ) }>
141
                 ) }>
142
                 <ThumbnailTopIndicators
142
                 <ThumbnailTopIndicators
143
                     currentLayout = { currentLayout }
143
                     currentLayout = { currentLayout }
144
-                    isFakeScreenShareParticipant = { true }
145
                     isHovered = { isHovered }
144
                     isHovered = { isHovered }
145
+                    isVirtualScreenshareParticipant = { true }
146
                     participantId = { participantId }
146
                     participantId = { participantId }
147
                     thumbnailType = { thumbnailType } />
147
                     thumbnailType = { thumbnailType } />
148
             </div>
148
             </div>
161
         </span>);
161
         </span>);
162
 };
162
 };
163
 
163
 
164
-export default FakeScreenShareParticipant;
164
+export default VirtualScreenshareParticipant;

+ 7
- 7
react/features/filmstrip/functions.any.js View File

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

+ 18
- 5
react/features/filmstrip/functions.web.js View File

509
         isActiveParticipant,
509
         isActiveParticipant,
510
         isAudioOnly,
510
         isAudioOnly,
511
         isCurrentlyOnLargeVideo,
511
         isCurrentlyOnLargeVideo,
512
-        isFakeScreenShareParticipant,
512
+        isVirtualScreenshareParticipant,
513
         isScreenSharing,
513
         isScreenSharing,
514
         canPlayEventReceived,
514
         canPlayEventReceived,
515
         isRemoteParticipant,
515
         isRemoteParticipant,
516
+        multipleVideoSupport,
516
         stageParticipantsVisible,
517
         stageParticipantsVisible,
517
         stageFilmstrip,
518
         stageFilmstrip,
518
         tileViewActive
519
         tileViewActive
519
     } = input;
520
     } = input;
520
     const adjustedIsVideoPlayable = input.isVideoPlayable && (!isRemoteParticipant || canPlayEventReceived);
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
     if (!tileViewActive && ((isScreenSharing && isRemoteParticipant)
537
     if (!tileViewActive && ((isScreenSharing && isRemoteParticipant)
551
         _isActiveParticipant,
562
         _isActiveParticipant,
552
         _isAudioOnly,
563
         _isAudioOnly,
553
         _isCurrentlyOnLargeVideo,
564
         _isCurrentlyOnLargeVideo,
554
-        _isFakeScreenShareParticipant,
565
+        _isVirtualScreenshareParticipant,
555
         _isScreenSharing,
566
         _isScreenSharing,
556
         _isVideoPlayable,
567
         _isVideoPlayable,
568
+        _multipleVideoSupport,
557
         _participant,
569
         _participant,
558
         _stageParticipantsVisible,
570
         _stageParticipantsVisible,
559
         _videoTrack,
571
         _videoTrack,
573
         videoStream: Boolean(_videoTrack),
585
         videoStream: Boolean(_videoTrack),
574
         isRemoteParticipant: !_participant?.isFakeParticipant && !_participant?.local,
586
         isRemoteParticipant: !_participant?.isFakeParticipant && !_participant?.local,
575
         isScreenSharing: _isScreenSharing,
587
         isScreenSharing: _isScreenSharing,
576
-        isFakeScreenShareParticipant: _isFakeScreenShareParticipant,
588
+        isVirtualScreenshareParticipant: _isVirtualScreenshareParticipant,
589
+        multipleVideoSupport: _multipleVideoSupport,
577
         stageParticipantsVisible: _stageParticipantsVisible,
590
         stageParticipantsVisible: _stageParticipantsVisible,
578
         stageFilmstrip,
591
         stageFilmstrip,
579
         videoStreamMuted: _videoTrack ? _videoTrack.muted : 'no stream'
592
         videoStreamMuted: _videoTrack ? _videoTrack.muted : 'no stream'

+ 2
- 2
react/features/filmstrip/subscriber.any.js View File

16
  * Listens for changes to the remote screenshare participants to recompute the reordered list of the remote endpoints.
16
  * Listens for changes to the remote screenshare participants to recompute the reordered list of the remote endpoints.
17
  */
17
  */
18
 StateListenerRegistry.register(
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
  * Listens for changes to the dominant speaker to recompute the reordered list of the remote endpoints.
23
  * Listens for changes to the dominant speaker to recompute the reordered list of the remote endpoints.

+ 4
- 4
react/features/notifications/middleware.js View File

128
         const { participant: p } = action;
128
         const { participant: p } = action;
129
         const { conference } = state['features/base/conference'];
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
         if (conference
132
         if (conference
133
             && !p.local
133
             && !p.local
134
-            && !p.isFakeScreenShareParticipant
134
+            && !p.isVirtualScreenshareParticipant
135
             && !joinLeaveNotificationsDisabled()
135
             && !joinLeaveNotificationsDisabled()
136
             && !p.isReplacing) {
136
             && !p.isReplacing) {
137
             dispatch(showParticipantJoinedNotification(
137
             dispatch(showParticipantJoinedNotification(
148
                 action.participant.id
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
             if (participant
152
             if (participant
153
                 && !participant.local
153
                 && !participant.local
154
-                && !participant.isFakeScreenShareParticipant
154
+                && !participant.isVirtualScreenshareParticipant
155
                 && !action.participant.isReplaced) {
155
                 && !action.participant.isReplaced) {
156
                 dispatch(showParticipantLeftNotification(
156
                 dispatch(showParticipantLeftNotification(
157
                     getParticipantDisplayName(state, participant.id)
157
                     getParticipantDisplayName(state, participant.id)

+ 2
- 2
react/features/screen-share/actions.js View File

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

+ 3
- 3
react/features/video-layout/actionTypes.ts View File

11
     = 'SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED';
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
  * @returns {{
16
  * @returns {{
17
- *     type: FAKE_SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
17
+ *     type: VIRTUAL_SCREENSHARE_REMOTE_PARTICIPANTS_UPDATED,
18
  *     participantIds: Array<string>
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
  * The type of the action which enables or disables the feature for showing
24
  * The type of the action which enables or disables the feature for showing

+ 8
- 7
react/features/video-layout/actions.js View File

3
 import type { Dispatch } from 'redux';
3
 import type { Dispatch } from 'redux';
4
 
4
 
5
 import {
5
 import {
6
-    FAKE_SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
7
     SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
6
     SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
8
-    SET_TILE_VIEW
7
+    SET_TILE_VIEW,
8
+    VIRTUAL_SCREENSHARE_REMOTE_PARTICIPANTS_UPDATED
9
 } from './actionTypes';
9
 } from './actionTypes';
10
 import { shouldDisplayTileView } from './functions';
10
 import { shouldDisplayTileView } from './functions';
11
 
11
 
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
  * @returns {{
35
  * @returns {{
35
- *     type: FAKE_SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
36
+ *     type: VIRTUAL_SCREENSHARE_REMOTE_PARTICIPANTS_UPDATED,
36
  *     participantIds: Array<string>
37
  *     participantIds: Array<string>
37
  * }}
38
  * }}
38
  */
39
  */
39
-export function fakeScreenshareParticipantsUpdated(participantIds: Array<string>) {
40
+export function virtualScreenshareParticipantsUpdated(participantIds: Array<string>) {
40
     return {
41
     return {
41
-        type: FAKE_SCREEN_SHARE_REMOTE_PARTICIPANTS_UPDATED,
42
+        type: VIRTUAL_SCREENSHARE_REMOTE_PARTICIPANTS_UPDATED,
42
         participantIds
43
         participantIds
43
     };
44
     };
44
 }
45
 }

+ 4
- 4
react/features/video-layout/reducer.js View File

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

+ 8
- 8
react/features/video-layout/subscriber.js View File

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

+ 10
- 9
react/features/video-quality/subscriber.js View File

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

Loading…
Cancel
Save