From d0c22806ec2c362406db6a7cfee73fb8d89f28d5 Mon Sep 17 00:00:00 2001 From: Mihaela Dumitru Date: Thu, 6 Oct 2022 14:12:57 +0300 Subject: [PATCH] ref(participants) use enum type to store fake participants (#12316) --- modules/UI/videolayout/LargeVideoManager.js | 25 +++--- modules/UI/videolayout/VideoLayout.js | 11 ++- react/features/base/participants/actions.ts | 15 ++-- .../components/ParticipantView.native.js | 16 ++-- react/features/base/participants/functions.ts | 84 ++++++++++++++++--- .../features/base/participants/middleware.ts | 24 +++--- react/features/base/participants/reducer.ts | 30 +++---- .../features/base/participants/subscriber.ts | 9 +- react/features/base/participants/types.ts | 14 ++-- react/features/base/testing/functions.ts | 8 +- react/features/base/tracks/functions.ts | 19 +++-- .../components/web/ConnectionIndicator.tsx | 8 +- .../web/ConnectionIndicatorContent.js | 4 +- .../components/native/DisplayNameLabel.tsx | 2 +- .../web/StageParticipantNameLabel.tsx | 8 +- react/features/e2ee/middleware.js | 9 +- react/features/external-api/middleware.js | 12 +-- .../filmstrip/components/native/Thumbnail.js | 26 +++--- .../components/web/StatusIndicators.js | 11 ++- .../filmstrip/components/web/Thumbnail.tsx | 24 ++++-- .../web/ThumbnailBottomIndicators.tsx | 11 ++- .../components/web/ThumbnailTopIndicators.tsx | 10 +-- .../web/VirtualScreenshareParticipant.js | 2 - react/features/filmstrip/functions.web.js | 8 +- react/features/filmstrip/middleware.web.js | 5 +- .../components/LargeVideo.native.js | 2 +- .../large-video/components/LargeVideo.web.js | 4 +- react/features/large-video/subscriber.web.js | 3 +- .../mobile/external-api/middleware.js | 7 +- react/features/notifications/middleware.ts | 12 +-- .../native/MeetingParticipantItem.js | 13 +-- .../web/MeetingParticipantContextMenu.js | 2 +- .../components/web/MeetingParticipantItem.js | 6 +- .../components/web/MeetingParticipants.tsx | 4 +- react/features/remote-control/subscriber.js | 5 +- react/features/shared-video/middleware.any.js | 5 +- react/features/video-layout/functions.any.js | 2 +- react/features/video-layout/middleware.any.js | 2 +- .../web/FakeParticipantContextMenu.tsx | 13 +-- .../web/RemoteVideoMenuTriggerButton.tsx | 2 +- react/features/whiteboard/middleware.ts | 10 +-- 41 files changed, 294 insertions(+), 193 deletions(-) diff --git a/modules/UI/videolayout/LargeVideoManager.js b/modules/UI/videolayout/LargeVideoManager.js index 410dc3a2b0..87bfae5181 100644 --- a/modules/UI/videolayout/LargeVideoManager.js +++ b/modules/UI/videolayout/LargeVideoManager.js @@ -19,7 +19,9 @@ import { JitsiTrackEvents } from '../../../react/features/base/lib-jitsi-meet'; import { VIDEO_TYPE } from '../../../react/features/base/media'; import { getParticipantById, - getParticipantDisplayName + getParticipantDisplayName, + isLocalScreenshareParticipant, + isScreenShareParticipant } from '../../../react/features/base/participants'; import { getVideoTrackByParticipant, @@ -265,8 +267,7 @@ export default class LargeVideoManager { let isVideoRenderable; if (getSourceNameSignalingFeatureFlag(state)) { - const tracks = state['features/base/tracks']; - const videoTrack = getVideoTrackByParticipant(tracks, participant); + const videoTrack = getVideoTrackByParticipant(state, participant); // Remove track streaming status listener from the old track and add it to the new track, // in order to stop updating track streaming status for the old track and start it for the new track. @@ -292,7 +293,10 @@ export default class LargeVideoManager { const streamingStatusActive = isTrackStreamingStatusActive(videoTrack); isVideoRenderable = !isVideoMuted - && (APP.conference.isLocalId(id) || participant?.isLocalScreenShare || streamingStatusActive); + && (APP.conference.isLocalId(id) + || isLocalScreenshareParticipant(participant) + || streamingStatusActive + ); this.videoTrack?.jitsiTrack?.getVideoType() === VIDEO_TYPE.DESKTOP && logger.debug(`Remote track ${videoTrack?.jitsiTrack}, isVideoMuted=${isVideoMuted},` + ` streamingStatusActive=${streamingStatusActive}, isVideoRenderable=${isVideoRenderable}`); @@ -309,7 +313,7 @@ export default class LargeVideoManager { // progress. const legacyScreenshare = getMultipleVideoSupportFeatureFlag(state) && videoType === VIDEO_TYPE.DESKTOP - && !participant.isVirtualScreenshareParticipant; + && !isScreenShareParticipant(participant); const showAvatar = isVideoContainer @@ -329,11 +333,10 @@ export default class LargeVideoManager { if ((!shouldDisplayTileView(state) || participant?.pinned) // In theory the tile view may not be // enabled yet when we auto pin the participant. - && participant && !participant.local && !participant.isFakeParticipant) { + && participant && !participant.local && !participant.fakeParticipant) { // remote participant only - const tracks = state['features/base/tracks']; - const track = getVideoTrackByParticipant(tracks, participant); + const track = getVideoTrackByParticipant(state, participant); const isScreenSharing = track?.videoType === 'desktop'; @@ -365,8 +368,7 @@ export default class LargeVideoManager { let messageKey; if (getSourceNameSignalingFeatureFlag(state)) { - const tracks = state['features/base/tracks']; - const videoTrack = getVideoTrackByParticipant(tracks, participant); + const videoTrack = getVideoTrackByParticipant(state, participant); messageKey = isTrackStreamingStatusInactive(videoTrack) ? 'connection.LOW_BANDWIDTH' : null; } else { @@ -619,8 +621,7 @@ export default class LargeVideoManager { const state = APP.store.getState(); if (getSourceNameSignalingFeatureFlag(state)) { - const tracks = state['features/base/tracks']; - const videoTrack = getVideoTrackByParticipant(tracks, participant); + const videoTrack = getVideoTrackByParticipant(state, participant); // eslint-disable-next-line no-param-reassign show = !APP.conference.isLocalId(this.id) diff --git a/modules/UI/videolayout/VideoLayout.js b/modules/UI/videolayout/VideoLayout.js index 749d48b1d4..15c83241ca 100644 --- a/modules/UI/videolayout/VideoLayout.js +++ b/modules/UI/videolayout/VideoLayout.js @@ -6,7 +6,9 @@ import { getMultipleVideoSupportFeatureFlag } from '../../../react/features/base import { MEDIA_TYPE, VIDEO_TYPE } from '../../../react/features/base/media'; import { getParticipantById, - getPinnedParticipant + getPinnedParticipant, + isScreenShareParticipant, + isScreenShareParticipantById } from '../../../react/features/base/participants'; import { getTrackByMediaTypeAndParticipant, @@ -90,12 +92,13 @@ const VideoLayout = { getRemoteVideoType(id) { const state = APP.store.getState(); const participant = getParticipantById(state, id); + const isScreenShare = isScreenShareParticipantById(state, id); - if (participant?.isFakeParticipant) { + if (participant?.fakeParticipant && !isScreenShare) { return VIDEO_TYPE.CAMERA; } - if (getMultipleVideoSupportFeatureFlag(state) && participant?.isVirtualScreenshareParticipant) { + if (getMultipleVideoSupportFeatureFlag(state) && isScreenShare) { return VIDEO_TYPE.DESKTOP; } @@ -190,7 +193,7 @@ const VideoLayout = { let videoTrack; - if (getMultipleVideoSupportFeatureFlag(state) && participant?.isVirtualScreenshareParticipant) { + if (getMultipleVideoSupportFeatureFlag(state) && isScreenShareParticipant(participant)) { videoTrack = getVirtualScreenshareParticipantTrack(tracks, id); } else { videoTrack = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, id); diff --git a/react/features/base/participants/actions.ts b/react/features/base/participants/actions.ts index 76a6b5f60e..8924767eb6 100644 --- a/react/features/base/participants/actions.ts +++ b/react/features/base/participants/actions.ts @@ -36,7 +36,7 @@ import { getVirtualScreenshareParticipantOwnerId } from './functions'; import logger from './logger'; -import { Participant } from './types'; +import { FakeParticipant, Participant } from './types'; /** * Create an action for when dominant speaker changes. @@ -386,10 +386,8 @@ export function hiddenParticipantLeft(id: string) { * instance. * @param {Object} participantLeftProps - Other participant properties. * @typedef {Object} participantLeftProps + * @param {FakeParticipant|undefined} participantLeftProps.fakeParticipant - The type of fake participant. * @param {boolean} participantLeftProps.isReplaced - Whether the participant is to be replaced in the meeting. - * @param {boolean} participantLeftProps.isVirtualScreenshareParticipant - Whether the participant is a - * virtual screen share participant. - * @param {boolean} participantLeftProps.isFakeParticipant - Whether the participant is a fake participant. * * @returns {{ * type: PARTICIPANT_LEFT, @@ -404,11 +402,9 @@ export function participantLeft(id: string, conference: any, participantLeftProp type: PARTICIPANT_LEFT, participant: { conference, + fakeParticipant: participantLeftProps.fakeParticipant, id, - isReplaced: participantLeftProps.isReplaced, - isVirtualScreenshareParticipant: participantLeftProps.isVirtualScreenshareParticipant, - isWhiteboard: participantLeftProps.isWhiteboard, - isFakeParticipant: participantLeftProps.isFakeParticipant + isReplaced: participantLeftProps.isReplaced } }; } @@ -538,9 +534,8 @@ export function createVirtualScreenshareParticipant(sourceName: string, local: b dispatch(participantJoined({ conference: state['features/base/conference'].conference, + fakeParticipant: local ? FakeParticipant.LocalScreenShare : FakeParticipant.RemoteScreenShare, id: sourceName, - isVirtualScreenshareParticipant: true, - isLocalScreenShare: local, name: ownerName })); }; diff --git a/react/features/base/participants/components/ParticipantView.native.js b/react/features/base/participants/components/ParticipantView.native.js index 4989e80e92..1e4f068a93 100644 --- a/react/features/base/participants/components/ParticipantView.native.js +++ b/react/features/base/participants/components/ParticipantView.native.js @@ -13,6 +13,7 @@ import { connect } from '../../redux'; import { TestHint } from '../../testing/components'; import { getVideoTrackByParticipant } from '../../tracks'; import { getParticipantById, shouldRenderParticipantVideo } from '../functions'; +import { FakeParticipant } from '../types'; import styles from './styles'; @@ -31,11 +32,11 @@ type Props = { _connectionStatus: string, /** - * True if the participant which this component represents is fake. + * The type of participant if the participant which this component represents is fake. * * @private */ - _isFakeParticipant: boolean, + _fakeParticipant?: FakeParticipant, /** * The name of the participant which this component represents. @@ -174,7 +175,7 @@ class ParticipantView extends Component { render() { const { _connectionStatus: connectionStatus, - _isFakeParticipant, + _fakeParticipant, _renderVideo: renderVideo, _videoTrack: videoTrack, disableVideo, @@ -190,7 +191,7 @@ class ParticipantView extends Component { ? this.props.testHintId : `org.jitsi.meet.Participant#${this.props.participantId}`; - const renderSharedVideo = _isFakeParticipant && !disableVideo; + const renderSharedVideo = _fakeParticipant && !disableVideo; return ( { { renderSharedVideo && } - { !_isFakeParticipant && renderVideo + { !_fakeParticipant && renderVideo && { function _mapStateToProps(state, ownProps) { const { disableVideo, participantId } = ownProps; const participant = getParticipantById(state, participantId); - const tracks = state['features/base/tracks']; - const videoTrack = getVideoTrackByParticipant(tracks, participant); + const videoTrack = getVideoTrackByParticipant(state, participant); let connectionStatus; let participantName; @@ -257,7 +257,7 @@ function _mapStateToProps(state, ownProps) { _connectionStatus: connectionStatus || JitsiParticipantConnectionStatus.ACTIVE, - _isFakeParticipant: participant && participant.isFakeParticipant, + _fakeParticipant: participant?.fakeParticipant, _participantName: participantName, _renderVideo: shouldRenderParticipantVideo(state, participantId) && !disableVideo, _videoTrack: videoTrack diff --git a/react/features/base/participants/functions.ts b/react/features/base/participants/functions.ts index f7ce821095..7fab3f8231 100644 --- a/react/features/base/participants/functions.ts +++ b/react/features/base/participants/functions.ts @@ -2,7 +2,7 @@ // @ts-ignore import { getGravatarURL } from '@jitsi/js-utils/avatar'; -import { IStore } from '../../app/types'; +import { IState, IStore } from '../../app/types'; // @ts-ignore import { isStageFilmstripAvailable } from '../../filmstrip/functions'; import { IStateful } from '../app/types'; @@ -24,7 +24,7 @@ import { } from './constants'; // @ts-ignore import { preloadImage } from './preloadImage'; -import { Participant } from './types'; +import { FakeParticipant, Participant } from './types'; /** * Temp structures for avatar urls to be checked/preloaded. @@ -34,10 +34,10 @@ const AVATAR_CHECKED_URLS = new Map(); /* eslint-disable arrow-body-style, no-unused-vars */ const AVATAR_CHECKER_FUNCTIONS = [ (participant: Participant) => { - return participant?.isJigasi ? JIGASI_PARTICIPANT_ICON : null; + return isJigasiParticipant(participant) ? JIGASI_PARTICIPANT_ICON : null; }, (participant: Participant) => { - return participant?.isWhiteboard ? WHITEBOARD_PARTICIPANT_ICON : null; + return isWhiteboardParticipant(participant) ? WHITEBOARD_PARTICIPANT_ICON : null; }, (participant: Participant) => { return participant?.avatarURL ? participant.avatarURL : null; @@ -115,7 +115,7 @@ export function getActiveSpeakersToBeDisplayed(stateful: IStateful) { } } - // Remove shared video from the count. + // Remove fake participants from the count. if (fakeParticipants) { availableSlotsForActiveSpeakers -= fakeParticipants.size; } @@ -301,6 +301,69 @@ export function getFakeParticipants(stateful: IStateful) { return toState(stateful)['features/base/participants'].fakeParticipants; } +/** + * Returns whether the fake participant is Jigasi. + * + * @param {Participant|undefined} participant - The participant entity. + * @returns {boolean} - True if it's a Jigasi participant. + */ +function isJigasiParticipant(participant?: Participant): boolean { + return participant?.fakeParticipant === FakeParticipant.Jigasi; +} + +/** + * Returns whether the fake participant is a local screenshare. + * + * @param {Participant|undefined} participant - The participant entity. + * @returns {boolean} - True if it's a local screenshare participant. + */ +export function isLocalScreenshareParticipant(participant?: Participant): boolean { + return participant?.fakeParticipant === FakeParticipant.LocalScreenShare; +} + +/** + * Returns whether the fake participant is a remote screenshare. + * + * @param {Participant|undefined} participant - The participant entity. + * @returns {boolean} - True if it's a remote screenshare participant. + */ +export function isRemoteScreenshareParticipant(participant?: Participant): boolean { + return participant?.fakeParticipant === FakeParticipant.RemoteScreenShare; +} + +/** + * Returns whether the fake participant is of local or virtual screenshare type. + * + * @param {IState} state - The (whole) redux state, or redux's. + * @param {string|undefined} participantId - The participant id. + * @returns {boolean} - True if it's one of the two. + */ +export function isScreenShareParticipantById(state: IState, participantId?: string): boolean { + const participant = getParticipantByIdOrUndefined(state, participantId); + + return isScreenShareParticipant(participant); +} + +/** + * Returns whether the fake participant is of local or virtual screenshare type. + * + * @param {Participant|undefined} participant - The participant entity. + * @returns {boolean} - True if it's one of the two. + */ +export function isScreenShareParticipant(participant?: Participant): boolean { + return isLocalScreenshareParticipant(participant) || isRemoteScreenshareParticipant(participant); +} + +/** + * Returns whether the fake participant is a whiteboard. + * + * @param {Participant|undefined} participant - The participant entity. + * @returns {boolean} - True if it's a whiteboard participant. + */ +export function isWhiteboardParticipant(participant?: Participant): boolean { + return participant?.fakeParticipant === FakeParticipant.Whiteboard; +} + /** * Returns a count of the known remote participants in the passed in redux state. * @@ -349,15 +412,16 @@ export function getParticipantCountWithFake(stateful: IStateful) { * @returns {string} */ export function getParticipantDisplayName(stateful: IStateful, id: string): string { - const participant = getParticipantById(stateful, id); + const state = toState(stateful); + const participant = getParticipantById(state, id); const { defaultLocalDisplayName, defaultRemoteDisplayName - } = toState(stateful)['features/base/config']; + } = state['features/base/config']; if (participant) { - if (participant.isVirtualScreenshareParticipant) { - return getScreenshareParticipantDisplayName(stateful, id); + if (isScreenShareParticipant(participant)) { + return getScreenshareParticipantDisplayName(state, id); } if (participant.name) { @@ -546,7 +610,7 @@ export function shouldRenderParticipantVideo(stateful: IStateful, id: string) { } /* First check if we have an unmuted video track. */ - const videoTrack = getVideoTrackByParticipant(state['features/base/tracks'], participant); + const videoTrack = getVideoTrackByParticipant(state, participant); if (!shouldRenderVideoTrack(videoTrack, /* waitForVideoStarted */ false)) { return false; diff --git a/react/features/base/participants/middleware.ts b/react/features/base/participants/middleware.ts index 4d1238fff7..f5bd4275ff 100644 --- a/react/features/base/participants/middleware.ts +++ b/react/features/base/participants/middleware.ts @@ -74,11 +74,13 @@ import { getRaiseHandsQueue, getRemoteParticipants, hasRaisedHand, - isLocalParticipantModerator + isLocalParticipantModerator, + isScreenShareParticipant, + isWhiteboardParticipant } from './functions'; import logger from './logger'; import { PARTICIPANT_JOINED_FILE, PARTICIPANT_LEFT_FILE } from './sounds'; -import { IJitsiParticipant } from './types'; +import { FakeParticipant, IJitsiParticipant } from './types'; import './subscriber'; @@ -267,19 +269,19 @@ MiddlewareRegistry.register(store => next => action => { } case PARTICIPANT_JOINED: { - const { isVirtualScreenshareParticipant, isWhiteboard } = action.participant; - - // Do not play sounds when a virtual participant tile is created for screenshare. - (!isVirtualScreenshareParticipant && !isWhiteboard) && _maybePlaySounds(store, action); + // Do not play sounds when a screenshare or whiteboard participant tile is created for screenshare. + (!isScreenShareParticipant(action.participant) + && !isWhiteboardParticipant(action.participant) + ) && _maybePlaySounds(store, action); return _participantJoinedOrUpdated(store, next, action); } case PARTICIPANT_LEFT: { - const { isVirtualScreenshareParticipant, isWhiteboard } = action.participant; - - // Do not play sounds when a tile for screenshare is removed. - (!isVirtualScreenshareParticipant && !isWhiteboard) && _maybePlaySounds(store, action); + // Do not play sounds when a tile for screenshare or whiteboard is removed. + (!isScreenShareParticipant(action.participant) + && !isWhiteboardParticipant(action.participant) + ) && _maybePlaySounds(store, action); break; } @@ -436,7 +438,7 @@ StateListenerRegistry.register( store.dispatch(participantUpdated({ conference, id: participant.getId(), - isJigasi: value + fakeParticipant: value ? FakeParticipant.Jigasi : undefined })), // eslint-disable-next-line @typescript-eslint/no-unused-vars 'features_screen-sharing': (participant: IJitsiParticipant, value: string) => diff --git a/react/features/base/participants/reducer.ts b/react/features/base/participants/reducer.ts index 94c8420601..2edc240fe4 100644 --- a/react/features/base/participants/reducer.ts +++ b/react/features/base/participants/reducer.ts @@ -18,7 +18,12 @@ import { SET_LOADABLE_AVATAR_URL } from './actionTypes'; import { LOCAL_PARTICIPANT_DEFAULT_ID, PARTICIPANT_ROLE } from './constants'; -import { isParticipantModerator } from './functions'; +import { + isLocalScreenshareParticipant, + isParticipantModerator, + isRemoteScreenshareParticipant, + isScreenShareParticipant +} from './functions'; import { LocalParticipant, Participant } from './types'; /** @@ -241,10 +246,8 @@ ReducerRegistry.register('features/base/participants', case PARTICIPANT_JOINED: { const participant = _participantJoined(action); const { + fakeParticipant, id, - isFakeParticipant, - isLocalScreenShare, - isVirtualScreenshareParticipant, name, pinned } = participant; @@ -281,7 +284,7 @@ ReducerRegistry.register('features/base/participants', }; } - if (isLocalScreenShare) { + if (isLocalScreenshareParticipant(participant)) { return { ...state, localScreenShare: participant @@ -300,7 +303,7 @@ ReducerRegistry.register('features/base/participants', // The sort order of participants is preserved since Map remembers the original insertion order of the keys. state.sortedRemoteParticipants = new Map(sortedRemoteParticipants); - if (isVirtualScreenshareParticipant) { + if (isRemoteScreenshareParticipant(participant)) { const sortedRemoteVirtualScreenshareParticipants = [ ...state.sortedRemoteVirtualScreenshareParticipants ]; sortedRemoteVirtualScreenshareParticipants.push([ id, name ?? '' ]); @@ -308,7 +311,8 @@ ReducerRegistry.register('features/base/participants', state.sortedRemoteVirtualScreenshareParticipants = new Map(sortedRemoteVirtualScreenshareParticipants); } - if (isFakeParticipant) { + // Exclude the screenshare participant from the fake participant count to avoid duplicates. + if (fakeParticipant && !isScreenShareParticipant(participant)) { state.fakeParticipants.set(id, participant); } @@ -509,12 +513,8 @@ function _participantJoined({ participant }: { participant: Participant; }) { connectionStatus, dominantSpeaker, email, - isFakeParticipant, - isVirtualScreenshareParticipant, - isLocalScreenShare, + fakeParticipant, isReplacing, - isJigasi, - isWhiteboard, loadableAvatarUrl, local, name, @@ -543,13 +543,9 @@ function _participantJoined({ participant }: { participant: Participant; }) { connectionStatus, dominantSpeaker: dominantSpeaker || false, email, + fakeParticipant, id, - isFakeParticipant, - isVirtualScreenshareParticipant, - isLocalScreenShare, isReplacing, - isJigasi, - isWhiteboard, loadableAvatarUrl, local: local || false, name, diff --git a/react/features/base/participants/subscriber.ts b/react/features/base/participants/subscriber.ts index eeb8e2770b..5d8935be68 100644 --- a/react/features/base/participants/subscriber.ts +++ b/react/features/base/participants/subscriber.ts @@ -9,6 +9,7 @@ import { import StateListenerRegistry from '../redux/StateListenerRegistry'; import { createVirtualScreenshareParticipant, participantLeft } from './actions'; +import { FakeParticipant } from './types'; StateListenerRegistry.register( /* selector */ state => state['features/base/tracks'], @@ -56,8 +57,8 @@ function _updateScreenshareParticipants({ getState, dispatch }: IStore) { if (localScreenShare && !newLocalSceenshareSourceName) { dispatch(participantLeft(localScreenShare.id, conference, { - isReplaced: undefined, - isVirtualScreenshareParticipant: true + fakeParticipant: FakeParticipant.LocalScreenShare, + isReplaced: undefined })); } } @@ -67,8 +68,8 @@ function _updateScreenshareParticipants({ getState, dispatch }: IStore) { if (removedScreenshareSourceNames.length) { removedScreenshareSourceNames.forEach(id => dispatch(participantLeft(id, conference, { - isReplaced: undefined, - isVirtualScreenshareParticipant: true + fakeParticipant: FakeParticipant.RemoteScreenShare, + isReplaced: undefined }))); } diff --git a/react/features/base/participants/types.ts b/react/features/base/participants/types.ts index 59cb953afa..c7210bb53d 100644 --- a/react/features/base/participants/types.ts +++ b/react/features/base/participants/types.ts @@ -1,3 +1,11 @@ +export enum FakeParticipant { + Jigasi = 'Jigasi', + LocalScreenShare = 'LocalScreenShare', + RemoteScreenShare = 'RemoteScreenShare', + SharedVideo = 'SharedVideo', + Whiteboard = 'Whiteboard' +} + export interface Participant { avatarURL?: string; botType?: string; @@ -8,18 +16,14 @@ export interface Participant { e2eeEnabled?: boolean; e2eeSupported?: boolean; email?: string; + fakeParticipant?: FakeParticipant; features?: { 'screen-sharing'?: boolean | string; }; getId?: Function; id: string; - isFakeParticipant?: boolean; - isJigasi?: boolean; - isLocalScreenShare?: boolean; isReplaced?: boolean; isReplacing?: number; - isVirtualScreenshareParticipant?: boolean; - isWhiteboard?: boolean; jwtId?: string; loadableAvatarUrl?: string; loadableAvatarUrlUseCORS?: boolean; diff --git a/react/features/base/testing/functions.ts b/react/features/base/testing/functions.ts index 0086e22095..6b4c9561d4 100644 --- a/react/features/base/testing/functions.ts +++ b/react/features/base/testing/functions.ts @@ -1,7 +1,7 @@ import { IState, IStore } from '../../app/types'; import { getMultipleVideoSupportFeatureFlag } from '../config/functions.any'; import { MEDIA_TYPE, VIDEO_TYPE } from '../media/constants'; -import { getParticipantById } from '../participants/functions'; +import { getParticipantById, isScreenShareParticipant } from '../participants/functions'; // eslint-disable-next-line lines-around-comment // @ts-ignore import { getTrackByMediaTypeAndParticipant, getVirtualScreenshareParticipantTrack } from '../tracks'; @@ -31,7 +31,7 @@ export function getRemoteVideoType({ getState }: IStore, id: string) { const state = getState(); const participant = getParticipantById(state, id); - if (getMultipleVideoSupportFeatureFlag(state) && participant?.isVirtualScreenshareParticipant) { + if (getMultipleVideoSupportFeatureFlag(state) && isScreenShareParticipant(participant)) { return VIDEO_TYPE.DESKTOP; } @@ -51,7 +51,7 @@ export function isLargeVideoReceived({ getState }: IStore): boolean { const tracks = state['features/base/tracks']; let videoTrack; - if (getMultipleVideoSupportFeatureFlag(state) && largeVideoParticipant?.isVirtualScreenshareParticipant) { + if (getMultipleVideoSupportFeatureFlag(state) && isScreenShareParticipant(largeVideoParticipant)) { videoTrack = getVirtualScreenshareParticipantTrack(tracks, largeVideoParticipantId); } else { videoTrack = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, largeVideoParticipantId); @@ -75,7 +75,7 @@ export function isRemoteVideoReceived({ getState }: IStore, id: string): boolean const participant = getParticipantById(state, id); let videoTrack; - if (getMultipleVideoSupportFeatureFlag(state) && participant?.isVirtualScreenshareParticipant) { + if (getMultipleVideoSupportFeatureFlag(state) && isScreenShareParticipant(participant)) { videoTrack = getVirtualScreenshareParticipantTrack(tracks, id); } else { videoTrack = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, id); diff --git a/react/features/base/tracks/functions.ts b/react/features/base/tracks/functions.ts index 7db2eaa635..58f4d7ac2d 100644 --- a/react/features/base/tracks/functions.ts +++ b/react/features/base/tracks/functions.ts @@ -8,7 +8,11 @@ import { isMobileBrowser } from '../environment/utils'; import JitsiMeetJS, { JitsiTrackErrors, browser } from '../lib-jitsi-meet'; import { setAudioMuted } from '../media/actions'; import { MEDIA_TYPE, MediaType, VIDEO_TYPE } from '../media/constants'; -import { getParticipantByIdOrUndefined, getVirtualScreenshareParticipantOwnerId } from '../participants/functions'; +import { + getParticipantByIdOrUndefined, + getVirtualScreenshareParticipantOwnerId, + isScreenShareParticipant +} from '../participants/functions'; import { Participant } from '../participants/types'; import { toState } from '../redux/functions'; import { @@ -47,7 +51,7 @@ export function isParticipantMediaMuted(participant: Participant, mediaType: Med if (participant?.local) { return isLocalTrackMuted(tracks, mediaType); - } else if (!participant?.isFakeParticipant) { + } else if (!participant?.fakeParticipant) { return isRemoteTrackMuted(tracks, mediaType, participant.id); } @@ -420,19 +424,21 @@ export function getLocalJitsiAudioTrack(state: IState) { /** * Returns track of specified media type for specified participant. * - * @param {ITrack[]} tracks - List of all tracks. + * @param {IState} state - The redux state. * @param {Participant} participant - Participant Object. * @returns {(Track|undefined)} */ export function getVideoTrackByParticipant( - tracks: ITrack[], + state: IState, participant?: Participant) { if (!participant) { return; } - if (participant?.isVirtualScreenshareParticipant) { + const tracks = state['features/base/tracks']; + + if (isScreenShareParticipant(participant)) { return getVirtualScreenshareParticipantTrack(tracks, participant.id); } @@ -448,8 +454,7 @@ export function getVideoTrackByParticipant( */ export function getSourceNameByParticipantId(state: IState, participantId: string) { const participant = getParticipantByIdOrUndefined(state, participantId); - const tracks = state['features/base/tracks']; - const track = getVideoTrackByParticipant(tracks, participant); + const track = getVideoTrackByParticipant(state, participant); return track?.jitsiTrack?.getSourceName(); } diff --git a/react/features/connection-indicator/components/web/ConnectionIndicator.tsx b/react/features/connection-indicator/components/web/ConnectionIndicator.tsx index 4f121b150e..8a5d9a1995 100644 --- a/react/features/connection-indicator/components/web/ConnectionIndicator.tsx +++ b/react/features/connection-indicator/components/web/ConnectionIndicator.tsx @@ -13,7 +13,11 @@ import { IState } from '../../../app/types'; import { getSourceNameSignalingFeatureFlag } from '../../../base/config'; import { translate } from '../../../base/i18n/functions'; import { MEDIA_TYPE } from '../../../base/media/constants'; -import { getLocalParticipant, getParticipantById } from '../../../base/participants/functions'; +import { + getLocalParticipant, + getParticipantById, + isScreenShareParticipant +} from '../../../base/participants/functions'; // @ts-ignore import { Popover } from '../../../base/popover'; import { @@ -401,7 +405,7 @@ export function _mapStateToProps(state: IState, ownProps: Props) { let firstVideoTrack; - if (sourceNameSignalingEnabled && participant?.isVirtualScreenshareParticipant) { + if (sourceNameSignalingEnabled && isScreenShareParticipant(participant)) { firstVideoTrack = getVirtualScreenshareParticipantTrack(tracks, participantId); } else { firstVideoTrack = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, participantId); diff --git a/react/features/connection-indicator/components/web/ConnectionIndicatorContent.js b/react/features/connection-indicator/components/web/ConnectionIndicatorContent.js index 2cd4fae709..690956e2bc 100644 --- a/react/features/connection-indicator/components/web/ConnectionIndicatorContent.js +++ b/react/features/connection-indicator/components/web/ConnectionIndicatorContent.js @@ -6,7 +6,7 @@ import type { Dispatch } from 'redux'; import { getSourceNameSignalingFeatureFlag } from '../../../base/config'; import { translate } from '../../../base/i18n'; import { MEDIA_TYPE } from '../../../base/media'; -import { getLocalParticipant, getParticipantById } from '../../../base/participants'; +import { getLocalParticipant, getParticipantById, isScreenShareParticipant } from '../../../base/participants'; import { connect } from '../../../base/redux'; import { getSourceNameByParticipantId, getTrackByMediaTypeAndParticipant } from '../../../base/tracks'; import { ConnectionStatsTable } from '../../../connection-stats'; @@ -352,7 +352,7 @@ export function _mapStateToProps(state: Object, ownProps: Props) { _disableShowMoreStats: state['features/base/config'].disableShowMoreStats, _isConnectionStatusInactive, _isConnectionStatusInterrupted, - _isVirtualScreenshareParticipant: sourceNameSignalingEnabled && participant?.isVirtualScreenshareParticipant, + _isVirtualScreenshareParticipant: sourceNameSignalingEnabled && isScreenShareParticipant(participant), _isLocalVideo: participant?.local, _region: participant?.region, _sourceName: getSourceNameByParticipantId(state, participantId), diff --git a/react/features/display-name/components/native/DisplayNameLabel.tsx b/react/features/display-name/components/native/DisplayNameLabel.tsx index 564b3bc644..963623305f 100644 --- a/react/features/display-name/components/native/DisplayNameLabel.tsx +++ b/react/features/display-name/components/native/DisplayNameLabel.tsx @@ -72,7 +72,7 @@ function _mapStateToProps(state: IState, ownProps: Partial) { return { _participantName: getParticipantDisplayName(state, ownProps.participantId ?? ''), - _render: participant && (!participant?.local || ownProps.contained) && !participant?.isFakeParticipant + _render: participant && (!participant?.local || ownProps.contained) && !participant?.fakeParticipant }; } diff --git a/react/features/display-name/components/web/StageParticipantNameLabel.tsx b/react/features/display-name/components/web/StageParticipantNameLabel.tsx index dac2125716..e88e8a4cc1 100644 --- a/react/features/display-name/components/web/StageParticipantNameLabel.tsx +++ b/react/features/display-name/components/web/StageParticipantNameLabel.tsx @@ -8,7 +8,11 @@ import { makeStyles } from 'tss-react/mui'; import { IState } from '../../../app/types'; // @ts-ignore import { isDisplayNameVisible } from '../../../base/config/functions.any'; -import { getLocalParticipant, getParticipantDisplayName } from '../../../base/participants/functions'; +import { + getLocalParticipant, + getParticipantDisplayName, + isWhiteboardParticipant +} from '../../../base/participants/functions'; import { Participant } from '../../../base/participants/types'; import { withPixelLineHeight } from '../../../base/styles/functions.web'; // @ts-ignore @@ -64,7 +68,7 @@ const StageParticipantNameLabel = () => { && nameToDisplay && selectedId !== localId && !isTileView - && !largeVideoParticipant?.isWhiteboard + && !isWhiteboardParticipant(largeVideoParticipant) ) { return (
next => action => { } case PARTICIPANT_JOINED: { const result = next(action); - const { e2eeEnabled, e2eeSupported, isVirtualScreenshareParticipant, local } = action.participant; + const { e2eeEnabled, e2eeSupported, local } = action.participant; const { everyoneEnabledE2EE } = getState()['features/e2ee']; const participantCount = getParticipantCount(getState); - if (isVirtualScreenshareParticipant) { + if (isScreenShareParticipant(action.participant)) { return result; } @@ -138,9 +139,9 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => { const participant = getParticipantById(previosState, action.participant?.id) || {}; const result = next(action); const newState = getState(); - const { e2eeEnabled = false, e2eeSupported = false, isVirtualScreenshareParticipant } = participant; + const { e2eeEnabled = false, e2eeSupported = false } = participant; - if (isVirtualScreenshareParticipant) { + if (isScreenShareParticipant(participant)) { return result; } diff --git a/react/features/external-api/middleware.js b/react/features/external-api/middleware.js index b0f3236243..13bf042f6b 100644 --- a/react/features/external-api/middleware.js +++ b/react/features/external-api/middleware.js @@ -163,10 +163,10 @@ MiddlewareRegistry.register(store => next => action => { case PARTICIPANT_LEFT: { const { participant } = action; - const { isFakeParticipant, isVirtualScreenshareParticipant, isWhiteboard } = participant; + const { fakeParticipant } = participant; - // Skip sending participant left event for fake or virtual screenshare participants. - if (isFakeParticipant || isVirtualScreenshareParticipant || isWhiteboard) { + // Skip sending participant left event for fake participants. + if (fakeParticipant) { break; } @@ -177,13 +177,13 @@ MiddlewareRegistry.register(store => next => action => { const state = store.getState(); const { defaultRemoteDisplayName } = state['features/base/config']; const { participant } = action; - const { id, isFakeParticipant, isVirtualScreenshareParticipant, local, name } = participant; + const { fakeParticipant, id, local, name } = participant; // The version of external api outside of middleware did not emit // the local participant being created. if (!local) { - // Skip sending participant joined event for fake or virtual screenshare participants. - if (isFakeParticipant || isVirtualScreenshareParticipant) { + // Skip sending participant joined event for fake participants. + if (fakeParticipant) { break; } diff --git a/react/features/filmstrip/components/native/Thumbnail.js b/react/features/filmstrip/components/native/Thumbnail.js index 99b6063f04..402181e5c4 100644 --- a/react/features/filmstrip/components/native/Thumbnail.js +++ b/react/features/filmstrip/components/native/Thumbnail.js @@ -15,8 +15,10 @@ import { getParticipantCount, hasRaisedHand, isEveryoneModerator, + isScreenShareParticipant, pinParticipant } from '../../../base/participants'; +import { FakeParticipant } from '../../../base/participants/types'; import { Container } from '../../../base/react'; import { connect } from '../../../base/redux'; import { @@ -57,9 +59,9 @@ type Props = { _gifSrc: ?string, /** - * Indicates whether the participant is fake. + * The type of participant if the participant is fake. */ - _isFakeParticipant: boolean, + _fakeParticipant?: FakeParticipant, /** * Indicates whether the participant is screen sharing. @@ -189,13 +191,13 @@ class Thumbnail extends PureComponent { * @returns {void} */ _onThumbnailLongPress() { - const { _participantId, _local, _isFakeParticipant, _localVideoOwner, dispatch } = this.props; + const { _fakeParticipant, _participantId, _local, _localVideoOwner, dispatch } = this.props; - if (_isFakeParticipant && _localVideoOwner) { + if (_fakeParticipant && _localVideoOwner) { dispatch(showSharedVideoMenu(_participantId)); } - if (!_isFakeParticipant) { + if (!_fakeParticipant) { dispatch(showContextMenuDetails(_participantId, _local)); } } @@ -208,9 +210,9 @@ class Thumbnail extends PureComponent { _renderIndicators() { const { _audioMuted: audioMuted, + _fakeParticipant, _isScreenShare: isScreenShare, _isVirtualScreenshare, - _isFakeParticipant, _renderModeratorIndicator: renderModeratorIndicator, _participantId: participantId, _pinned, @@ -219,7 +221,7 @@ class Thumbnail extends PureComponent { } = this.props; const indicators = []; - if (!_isFakeParticipant) { + if (!_fakeParticipant) { indicators.push( { */ render() { const { + _fakeParticipant, _gifSrc, - _isFakeParticipant, _isScreenShare: isScreenShare, _isVirtualScreenshare, _participantId: participantId, @@ -378,7 +380,7 @@ class Thumbnail extends PureComponent { : <> { @@ -406,7 +408,7 @@ function _mapStateToProps(state, ownProps) { const localParticipantId = getLocalParticipant(state).id; const id = participant?.id; const audioTrack = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.AUDIO, id); - const videoTrack = getVideoTrackByParticipant(tracks, participant); + const videoTrack = getVideoTrackByParticipant(state, participant); const isMultiStreamSupportEnabled = getMultipleVideoSupportFeatureFlag(state); const isScreenShare = videoTrack?.videoType === VIDEO_TYPE.DESKTOP; const participantCount = getParticipantCount(state); @@ -419,10 +421,10 @@ function _mapStateToProps(state, ownProps) { return { _audioMuted: audioTrack?.muted ?? true, + _fakeParticipant: participant?.fakeParticipant, _gifSrc: mode === 'chat' ? null : gifSrc, - _isFakeParticipant: participant?.isFakeParticipant, _isScreenShare: isScreenShare, - _isVirtualScreenshare: isMultiStreamSupportEnabled && participant?.isVirtualScreenshareParticipant, + _isVirtualScreenshare: isMultiStreamSupportEnabled && isScreenShareParticipant(participant), _local: participant?.local, _localVideoOwner: Boolean(ownerId === localParticipantId), _participantId: id, diff --git a/react/features/filmstrip/components/web/StatusIndicators.js b/react/features/filmstrip/components/web/StatusIndicators.js index 251a536757..aa2e91384d 100644 --- a/react/features/filmstrip/components/web/StatusIndicators.js +++ b/react/features/filmstrip/components/web/StatusIndicators.js @@ -3,7 +3,11 @@ import React, { Component } from 'react'; import { MEDIA_TYPE } from '../../../base/media'; -import { PARTICIPANT_ROLE, getParticipantByIdOrUndefined } from '../../../base/participants'; +import { + PARTICIPANT_ROLE, + getParticipantByIdOrUndefined, + isScreenShareParticipantById +} from '../../../base/participants'; import { connect } from '../../../base/redux'; import { getVideoTrackByParticipant, @@ -104,8 +108,9 @@ function _mapStateToProps(state, ownProps) { if (participant?.local) { isAudioMuted = isLocalTrackMuted(tracks, MEDIA_TYPE.AUDIO); - } else if (!participant?.isFakeParticipant) { // remote participants excluding shared video - const track = getVideoTrackByParticipant(tracks, participant); + } else if (!participant?.fakeParticipant || isScreenShareParticipantById(state, participantID)) { + // remote participants excluding shared video + const track = getVideoTrackByParticipant(state, participant); isScreenSharing = track?.videoType === 'desktop'; isAudioMuted = isRemoteTrackMuted(tracks, MEDIA_TYPE.AUDIO, participantID); diff --git a/react/features/filmstrip/components/web/Thumbnail.tsx b/react/features/filmstrip/components/web/Thumbnail.tsx index 7a512fe040..c8f6548ee8 100644 --- a/react/features/filmstrip/components/web/Thumbnail.tsx +++ b/react/features/filmstrip/components/web/Thumbnail.tsx @@ -22,7 +22,10 @@ import { pinParticipant } from '../../../base/participants/actions'; import { getLocalParticipant, getParticipantByIdOrUndefined, - hasRaisedHand + hasRaisedHand, + isLocalScreenshareParticipant, + isScreenShareParticipant, + isWhiteboardParticipant } from '../../../base/participants/functions'; import { Participant } from '../../../base/participants/types'; import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants'; @@ -1050,7 +1053,7 @@ class Thumbnail extends Component { _thumbnailType === THUMBNAIL_TYPE.TILE && 'tile-view-mode' ) }> { ) }>
{!_gifSrc && this._renderAvatar(styles.avatar) } @@ -1115,13 +1117,16 @@ class Thumbnail extends Component { return null; } - const { isFakeParticipant, isLocalScreenShare, isWhiteboard, local } = _participant; + const { fakeParticipant, local } = _participant; if (local) { return this._renderParticipant(true); } - if (isFakeParticipant && !isWhiteboard) { + if (fakeParticipant + && !isWhiteboardParticipant(_participant) + && !_isVirtualScreenshareParticipant + ) { return this._renderFakeParticipant(); } @@ -1141,7 +1146,7 @@ class Thumbnail extends Component { classes = { classes } containerClassName = { this._getContainerClassName() } isHovered = { isHovered } - isLocal = { isLocalScreenShare } + isLocal = { isLocalScreenshareParticipant(_participant) } isMobile = { _isMobile } onClick = { this._onClick } onMouseEnter = { this._onMouseEnter } @@ -1177,11 +1182,12 @@ function _mapStateToProps(state: IState, ownProps: any): Object { const isLocal = participant?.local ?? true; const multipleVideoSupportEnabled = getMultipleVideoSupportFeatureFlag(state); const sourceNameSignalingEnabled = getSourceNameSignalingFeatureFlag(state); + const _isVirtualScreenshareParticipant = multipleVideoSupportEnabled && isScreenShareParticipant(participant); const tracks = state['features/base/tracks']; let _videoTrack; - if (multipleVideoSupportEnabled && participant?.isVirtualScreenshareParticipant) { + if (_isVirtualScreenshareParticipant) { _videoTrack = getVirtualScreenshareParticipantTrack(tracks, id); } else { _videoTrack = isLocal @@ -1304,7 +1310,7 @@ function _mapStateToProps(state: IState, ownProps: any): Object { _isScreenSharing: _videoTrack?.videoType === 'desktop', _isTestModeEnabled: isTestModeEnabled(state), _isVideoPlayable: id && isVideoPlayable(state, id), - _isVirtualScreenshareParticipant: multipleVideoSupportEnabled && participant?.isVirtualScreenshareParticipant, + _isVirtualScreenshareParticipant, _localFlipX: Boolean(localFlipX), _multipleVideoSupport: multipleVideoSupportEnabled, _participant: participant, diff --git a/react/features/filmstrip/components/web/ThumbnailBottomIndicators.tsx b/react/features/filmstrip/components/web/ThumbnailBottomIndicators.tsx index 6b5de5580b..16fdaf9c13 100644 --- a/react/features/filmstrip/components/web/ThumbnailBottomIndicators.tsx +++ b/react/features/filmstrip/components/web/ThumbnailBottomIndicators.tsx @@ -4,12 +4,14 @@ import React from 'react'; import { useSelector } from 'react-redux'; import { makeStyles } from 'tss-react/mui'; +import { IState } from '../../../app/types'; import { getMultipleVideoSupportFeatureFlag, isDisplayNameVisible, isNameReadOnly // @ts-ignore } from '../../../base/config/functions.any'; +import { isScreenShareParticipantById } from '../../../base/participants/functions'; // @ts-ignore import DisplayName from '../../../display-name/components/web/DisplayName'; import { THUMBNAIL_TYPE } from '../../constants'; @@ -26,11 +28,6 @@ type Props = { */ className: string; - /** - * Whether it is a virtual screenshare participant thumbnail. - */ - isVirtualScreenshareParticipant: boolean; - /** * Whether or not the indicators are for the local participant. */ @@ -73,7 +70,6 @@ const useStyles = makeStyles()(() => { const ThumbnailBottomIndicators = ({ className, - isVirtualScreenshareParticipant, local, participantId, showStatusIndicators = true, @@ -84,6 +80,9 @@ const ThumbnailBottomIndicators = ({ const _defaultLocalDisplayName = interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME; const _isMultiStreamEnabled = useSelector(getMultipleVideoSupportFeatureFlag); const _showDisplayName = useSelector(isDisplayNameVisible); + const isVirtualScreenshareParticipant = useSelector( + (state: IState) => isScreenShareParticipantById(state, participantId) + ); return (
{ diff --git a/react/features/filmstrip/components/web/ThumbnailTopIndicators.tsx b/react/features/filmstrip/components/web/ThumbnailTopIndicators.tsx index e8cc3ff4ea..d8aef05814 100644 --- a/react/features/filmstrip/components/web/ThumbnailTopIndicators.tsx +++ b/react/features/filmstrip/components/web/ThumbnailTopIndicators.tsx @@ -8,6 +8,7 @@ import { IState } from '../../../app/types'; // @ts-ignore import { getMultipleVideoSupportFeatureFlag } from '../../../base/config'; import { isMobileBrowser } from '../../../base/environment/utils'; +import { isScreenShareParticipantById } from '../../../base/participants/functions'; // @ts-ignore import ConnectionIndicator from '../../../connection-indicator/components/web/ConnectionIndicator'; import { STATS_POPOVER_POSITION, THUMBNAIL_TYPE } from '../../constants'; @@ -46,11 +47,6 @@ type Props = { */ isHovered: boolean; - /** - * Whether or not the thumbnail is a virtual screen share participant. - */ - isVirtualScreenshareParticipant?: boolean; - /** * Whether or not the indicators are for the local participant. */ @@ -93,7 +89,6 @@ const ThumbnailTopIndicators = ({ disableConnectionIndicator, hidePopover, indicatorsClassName, - isVirtualScreenshareParticipant, isHovered, local, participantId, @@ -112,6 +107,9 @@ const ThumbnailTopIndicators = ({ || Boolean(useSelector((state: IState) => state['features/base/config'].connectionIndicators?.disabled)); const _isMultiStreamEnabled = useSelector(getMultipleVideoSupportFeatureFlag); const showConnectionIndicator = isHovered || !_connectionIndicatorAutoHideEnabled; + const isVirtualScreenshareParticipant = useSelector( + (state: IState) => isScreenShareParticipantById(state, participantId) + ); if (_isMultiStreamEnabled && isVirtualScreenshareParticipant) { return ( diff --git a/react/features/filmstrip/components/web/VirtualScreenshareParticipant.js b/react/features/filmstrip/components/web/VirtualScreenshareParticipant.js index c789cb17de..da4dbdac88 100644 --- a/react/features/filmstrip/components/web/VirtualScreenshareParticipant.js +++ b/react/features/filmstrip/components/web/VirtualScreenshareParticipant.js @@ -147,7 +147,6 @@ const VirtualScreenshareParticipant = ({
@@ -159,7 +158,6 @@ const VirtualScreenshareParticipant = ({ diff --git a/react/features/filmstrip/functions.web.js b/react/features/filmstrip/functions.web.js index 5ff126b0b2..2392622479 100644 --- a/react/features/filmstrip/functions.web.js +++ b/react/features/filmstrip/functions.web.js @@ -8,7 +8,8 @@ import { getParticipantById, getParticipantCount, getParticipantCountWithFake, - getPinnedParticipant + getPinnedParticipant, + isScreenShareParticipant } from '../base/participants'; import { toState } from '../base/redux'; import { shouldHideSelfView } from '../base/settings/functions.any'; @@ -129,7 +130,8 @@ export function isVideoPlayable(stateful: Object | Function, id: String) { const isVideoMuted = isLocalTrackMuted(tracks, MEDIA_TYPE.VIDEO); isPlayable = Boolean(videoTrack) && !isVideoMuted && !isAudioOnly; - } else if (!participant?.isFakeParticipant) { // remote participants excluding shared video + } else if (!participant?.fakeParticipant || isScreenShareParticipant(participant)) { + // remote participants excluding shared video const isVideoMuted = isRemoteTrackMuted(tracks, MEDIA_TYPE.VIDEO, id); if (getSourceNameSignalingFeatureFlag(state)) { @@ -589,7 +591,7 @@ export function getDisplayModeInput(props: Object, state: Object) { connectionStatus: _participant?.connectionStatus, canPlayEventReceived, videoStream: Boolean(_videoTrack), - isRemoteParticipant: !_participant?.isFakeParticipant && !_participant?.local, + isRemoteParticipant: !_participant?.fakeParticipant && !_participant?.local, isScreenSharing: _isScreenSharing, isVirtualScreenshareParticipant: _isVirtualScreenshareParticipant, multipleVideoSupport: _multipleVideoSupport, diff --git a/react/features/filmstrip/middleware.web.js b/react/features/filmstrip/middleware.web.js index b5a869ecd9..4ad6fd722b 100644 --- a/react/features/filmstrip/middleware.web.js +++ b/react/features/filmstrip/middleware.web.js @@ -9,7 +9,8 @@ import { PARTICIPANT_LEFT, getDominantSpeakerParticipant, getLocalParticipant, - getLocalScreenShareParticipant + getLocalScreenShareParticipant, + isScreenShareParticipant } from '../base/participants'; import { MiddlewareRegistry } from '../base/redux'; import { CLIENT_RESIZED } from '../base/responsive-ui'; @@ -108,7 +109,7 @@ MiddlewareRegistry.register(store => next => action => { } case PARTICIPANT_JOINED: { result = next(action); - if (action.participant?.isLocalScreenShare) { + if (isScreenShareParticipant(action.participant)) { break; } diff --git a/react/features/large-video/components/LargeVideo.native.js b/react/features/large-video/components/LargeVideo.native.js index 93d9695450..c9e1e548be 100644 --- a/react/features/large-video/components/LargeVideo.native.js +++ b/react/features/large-video/components/LargeVideo.native.js @@ -255,7 +255,7 @@ function _mapStateToProps(state) { const { participantId } = state['features/large-video']; const participant = getParticipantById(state, participantId); const { clientHeight: height, clientWidth: width } = state['features/base/responsive-ui']; - const videoTrack = getVideoTrackByParticipant(state['features/base/tracks'], participant); + const videoTrack = getVideoTrackByParticipant(state, participant); let disableVideo = false; if (participant?.local) { diff --git a/react/features/large-video/components/LargeVideo.web.js b/react/features/large-video/components/LargeVideo.web.js index 7fd27cd052..7955f53414 100644 --- a/react/features/large-video/components/LargeVideo.web.js +++ b/react/features/large-video/components/LargeVideo.web.js @@ -5,7 +5,7 @@ import React, { Component } from 'react'; import VideoLayout from '../../../../modules/UI/videolayout/VideoLayout'; import { getMultipleVideoSupportFeatureFlag } from '../../base/config'; import { MEDIA_TYPE, VIDEO_TYPE } from '../../base/media'; -import { getLocalParticipant } from '../../base/participants'; +import { getLocalParticipant, isScreenShareParticipant } from '../../base/participants'; import { Watermarks } from '../../base/react'; import { connect } from '../../base/redux'; import { getTrackByMediaTypeAndParticipant, getVirtualScreenshareParticipantTrack } from '../../base/tracks'; @@ -346,7 +346,7 @@ function _mapStateToProps(state) { const largeVideoParticipant = getLargeVideoParticipant(state); let videoTrack; - if (getMultipleVideoSupportFeatureFlag(state) && largeVideoParticipant?.isVirtualScreenshareParticipant) { + if (getMultipleVideoSupportFeatureFlag(state) && isScreenShareParticipant(largeVideoParticipant)) { videoTrack = getVirtualScreenshareParticipantTrack(tracks, largeVideoParticipant?.id); } else { videoTrack = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, largeVideoParticipant?.id); diff --git a/react/features/large-video/subscriber.web.js b/react/features/large-video/subscriber.web.js index 79afdac9dd..31f228f662 100644 --- a/react/features/large-video/subscriber.web.js +++ b/react/features/large-video/subscriber.web.js @@ -3,6 +3,7 @@ import VideoLayout from '../../../modules/UI/videolayout/VideoLayout'; import { getMultipleVideoSupportFeatureFlag } from '../base/config'; import { MEDIA_TYPE } from '../base/media'; +import { isScreenShareParticipant } from '../base/participants'; import { StateListenerRegistry } from '../base/redux'; import { getTrackByMediaTypeAndParticipant, getVirtualScreenshareParticipantTrack } from '../base/tracks'; @@ -27,7 +28,7 @@ StateListenerRegistry.register( const tracks = state['features/base/tracks']; let videoTrack; - if (getMultipleVideoSupportFeatureFlag(state) && largeVideoParticipant?.isVirtualScreenshareParticipant) { + if (getMultipleVideoSupportFeatureFlag(state) && isScreenShareParticipant(largeVideoParticipant)) { videoTrack = getVirtualScreenshareParticipantTrack(tracks, largeVideoParticipant?.id); } else { videoTrack = getTrackByMediaTypeAndParticipant(tracks, MEDIA_TYPE.VIDEO, largeVideoParticipant?.id); diff --git a/react/features/mobile/external-api/middleware.js b/react/features/mobile/external-api/middleware.js index 1e20b0f9d9..2b4c158823 100644 --- a/react/features/mobile/external-api/middleware.js +++ b/react/features/mobile/external-api/middleware.js @@ -32,7 +32,8 @@ import { PARTICIPANT_LEFT, getLocalParticipant, getParticipantById, - getRemoteParticipants + getRemoteParticipants, + isScreenShareParticipant } from '../../base/participants'; import { MiddlewareRegistry, StateListenerRegistry } from '../../base/redux'; import { getLocalTracks, isLocalTrackMuted, toggleScreensharing } from '../../base/tracks'; @@ -182,7 +183,7 @@ MiddlewareRegistry.register(store => next => action => { const { participant } = action; - if (participant.isVirtualScreenshareParticipant) { + if (isScreenShareParticipant(participant)) { break; } @@ -343,7 +344,7 @@ function _registerForNativeEvents(store) { participantsInfo.push(_participantToParticipantInfo(localParticipant)); remoteParticipants.forEach(participant => { - if (!participant.isFakeParticipant) { + if (!participant.fakeParticipant) { participantsInfo.push(_participantToParticipantInfo(participant)); } }); diff --git a/react/features/notifications/middleware.ts b/react/features/notifications/middleware.ts index 4f1161ad37..fa009f0d90 100644 --- a/react/features/notifications/middleware.ts +++ b/react/features/notifications/middleware.ts @@ -9,7 +9,9 @@ import { PARTICIPANT_ROLE } from '../base/participants/constants'; import { getLocalParticipant, getParticipantById, - getParticipantDisplayName + getParticipantDisplayName, + isScreenShareParticipant, + isWhiteboardParticipant } from '../base/participants/functions'; import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; import StateListenerRegistry from '../base/redux/StateListenerRegistry'; @@ -132,8 +134,8 @@ MiddlewareRegistry.register(store => next => action => { // Do not display notifications for the virtual screenshare and whiteboard tiles. if (conference && !p.local - && !p.isVirtualScreenshareParticipant - && !p.isWhiteboard + && !isScreenShareParticipant(p) + && !isWhiteboardParticipant(p) && !joinLeaveNotificationsDisabled() && !p.isReplacing) { dispatch(showParticipantJoinedNotification( @@ -153,8 +155,8 @@ MiddlewareRegistry.register(store => next => action => { // Do not display notifications for the virtual screenshare tiles. if (participant && !participant.local - && !participant.isVirtualScreenshareParticipant - && !participant.isWhiteboard + && !isScreenShareParticipant(participant) + && !isWhiteboardParticipant(participant) && !action.participant.isReplaced) { dispatch(showParticipantLeftNotification( getParticipantDisplayName(state, participant.id) diff --git a/react/features/participants-pane/components/native/MeetingParticipantItem.js b/react/features/participants-pane/components/native/MeetingParticipantItem.js index 0633db26dc..7c9e1249ec 100644 --- a/react/features/participants-pane/components/native/MeetingParticipantItem.js +++ b/react/features/participants-pane/components/native/MeetingParticipantItem.js @@ -10,6 +10,7 @@ import { hasRaisedHand, isParticipantModerator } from '../../../base/participants'; +import { FakeParticipant } from '../../../base/participants/types'; import { connect } from '../../../base/redux'; import { isParticipantAudioMuted, @@ -40,9 +41,9 @@ type Props = { _displayName: string, /** - * True if the participant is fake. + * The type of fake participant. */ - _isFakeParticipant: boolean, + _fakeParticipant: FakeParticipant, /** * Whether or not the user is a moderator. @@ -110,16 +111,16 @@ class MeetingParticipantItem extends PureComponent { */ _onPress() { const { + _fakeParticipant, _local, _localVideoOwner, - _isFakeParticipant, _participantID, dispatch } = this.props; - if (_isFakeParticipant && _localVideoOwner) { + if (_fakeParticipant && _localVideoOwner) { dispatch(showSharedVideoMenu(_participantID)); - } else if (!_isFakeParticipant) { + } else if (!_fakeParticipant) { if (_local) { dispatch(showConnectionStatus(_participantID)); } else { @@ -188,8 +189,8 @@ function mapStateToProps(state, ownProps): Object { _audioMediaState: audioMediaState, _disableModeratorIndicator: disableModeratorIndicator, _displayName: getParticipantDisplayName(state, participant?.id), + _fakeParticipant: participant?.fakeParticipant, _isAudioMuted, - _isFakeParticipant: Boolean(participant?.isFakeParticipant), _isModerator: isParticipantModerator(participant), _local: Boolean(participant?.local), _localVideoOwner: Boolean(ownerId === localParticipantId), diff --git a/react/features/participants-pane/components/web/MeetingParticipantContextMenu.js b/react/features/participants-pane/components/web/MeetingParticipantContextMenu.js index 0a4cff0f08..617971a135 100644 --- a/react/features/participants-pane/components/web/MeetingParticipantContextMenu.js +++ b/react/features/participants-pane/components/web/MeetingParticipantContextMenu.js @@ -102,7 +102,7 @@ class MeetingParticipantContextMenu extends Component { thumbnailMenu: false }; - if (_participant?.isFakeParticipant) { + if (_participant?.fakeParticipant) { return ( - {!overflowDrawer && !_participant?.isFakeParticipant + {!overflowDrawer && !_participant?.fakeParticipant && <> {!isInBreakoutRoom && ( } - {!overflowDrawer && (_localVideoOwner || _participant?.isWhiteboard) && _participant?.isFakeParticipant && ( + {!overflowDrawer && (_localVideoOwner || _participant?.fakeParticipant) && ( diff --git a/react/features/participants-pane/components/web/MeetingParticipants.tsx b/react/features/participants-pane/components/web/MeetingParticipants.tsx index 83a86bcd74..83940d8925 100644 --- a/react/features/participants-pane/components/web/MeetingParticipants.tsx +++ b/react/features/participants-pane/components/web/MeetingParticipants.tsx @@ -13,7 +13,7 @@ import participantsPaneTheme from '../../../base/components/themes/participantsP // @ts-ignore import { isToolbarButtonEnabled } from '../../../base/config/functions.web'; import { MEDIA_TYPE } from '../../../base/media/constants'; -import { getParticipantById } from '../../../base/participants/functions'; +import { getParticipantById, isScreenShareParticipant } from '../../../base/participants/functions'; import { connect } from '../../../base/redux/functions'; import { withPixelLineHeight } from '../../../base/styles/functions.web'; import Input from '../../../base/ui/components/web/Input'; @@ -174,7 +174,7 @@ function _mapStateToProps(state: IState): Object { sortedParticipantIds = sortedParticipantIds.filter((id: any) => { const participant = getParticipantById(state, id); - return !participant?.isVirtualScreenshareParticipant; + return !isScreenShareParticipant(participant); }); const participantsCount = sortedParticipantIds.length; diff --git a/react/features/remote-control/subscriber.js b/react/features/remote-control/subscriber.js index 9ea739b182..449d3e950d 100644 --- a/react/features/remote-control/subscriber.js +++ b/react/features/remote-control/subscriber.js @@ -3,7 +3,8 @@ import { getParticipantById, getVirtualScreenshareParticipantByOwnerId, - getVirtualScreenshareParticipantOwnerId + getVirtualScreenshareParticipantOwnerId, + isScreenShareParticipant } from '../base/participants'; import { StateListenerRegistry } from '../base/redux'; @@ -24,7 +25,7 @@ StateListenerRegistry.register( const participant = getParticipantById(state, participantId); - if (participant?.isVirtualScreenshareParticipant) { + if (isScreenShareParticipant(participant)) { // multistream support is enabled and the user has selected the desktop sharing thumbnail. const id = getVirtualScreenshareParticipantOwnerId(participantId); diff --git a/react/features/shared-video/middleware.any.js b/react/features/shared-video/middleware.any.js index 7c5158192c..4ea1f7f4dc 100644 --- a/react/features/shared-video/middleware.any.js +++ b/react/features/shared-video/middleware.any.js @@ -13,6 +13,7 @@ import { participantLeft, pinParticipant } from '../base/participants'; +import { FakeParticipant } from '../base/participants/types'; import { MiddlewareRegistry } from '../base/redux'; import { RESET_SHARED_VIDEO_STATUS, SET_SHARED_VIDEO_STATUS } from './actionTypes'; @@ -55,7 +56,7 @@ MiddlewareRegistry.register(store => next => action => { const videoParticipant = getParticipantById(state, value); dispatch(participantLeft(value, conference, { - isFakeParticipant: videoParticipant?.isFakeParticipant + fakeParticipant: videoParticipant?.fakeParticipant })); if (localParticipantId !== from) { @@ -162,8 +163,8 @@ function handleSharingVideoStatus(store, videoUrl, { state, time, from, muted }, dispatch(participantJoined({ conference, + fakeParticipant: FakeParticipant.SharedVideo, id: videoUrl, - isFakeParticipant: true, avatarURL, name: VIDEO_PLAYER_PARTICIPANT_NAME })); diff --git a/react/features/video-layout/functions.any.js b/react/features/video-layout/functions.any.js index b79de4740e..dc1cdb3f83 100644 --- a/react/features/video-layout/functions.any.js +++ b/react/features/video-layout/functions.any.js @@ -124,7 +124,7 @@ export function updateAutoPinnedParticipant( const pinned = getPinnedParticipant(getState); // if the pinned participant is shared video or some other fake participant we want to skip auto-pinning - if (pinned?.isFakeParticipant) { + if (pinned?.fakeParticipant) { return; } diff --git a/react/features/video-layout/middleware.any.js b/react/features/video-layout/middleware.any.js index 5f94d3281c..416049bbbd 100644 --- a/react/features/video-layout/middleware.any.js +++ b/react/features/video-layout/middleware.any.js @@ -39,7 +39,7 @@ MiddlewareRegistry.register(store => next => action => { if (!getAutoPinSetting() || isFollowMeActive(store)) { break; } - shouldUpdateAutoPin = getParticipantById(store.getState(), action.participant.id)?.isFakeParticipant; + shouldUpdateAutoPin = Boolean(getParticipantById(store.getState(), action.participant.id)?.fakeParticipant); break; } } diff --git a/react/features/video-menu/components/web/FakeParticipantContextMenu.tsx b/react/features/video-menu/components/web/FakeParticipantContextMenu.tsx index b2426a590b..3cd85cb091 100644 --- a/react/features/video-menu/components/web/FakeParticipantContextMenu.tsx +++ b/react/features/video-menu/components/web/FakeParticipantContextMenu.tsx @@ -9,6 +9,7 @@ import TogglePinToStageButton from '../../../../features/video-menu/components/w // @ts-ignore import { Avatar } from '../../../base/avatar'; import { IconShareVideo } from '../../../base/icons/svg'; +import { isWhiteboardParticipant } from '../../../base/participants/functions'; import { Participant } from '../../../base/participants/types'; import ContextMenu from '../../../base/ui/components/web/ContextMenu'; import ContextMenuItemGroup from '../../../base/ui/components/web/ContextMenuItemGroup'; @@ -106,7 +107,7 @@ const FakeParticipantContextMenu = ({ }, [ setWhiteboardOpen ]); const _getActions = useCallback(() => { - if (participant.isWhiteboard) { + if (isWhiteboardParticipant(participant)) { return [ { accessibilityLabel: t('toolbar.hideWhiteboard'), icon: IconShareVideo, @@ -123,7 +124,7 @@ const FakeParticipantContextMenu = ({ text: t('toolbar.stopSharedVideo') } ]; } - }, [ localVideoOwner, participant.isWhiteboard ]); + }, [ localVideoOwner, participant.fakeParticipant ]); return ( - {participant.isWhiteboard && } + {isWhiteboardParticipant(participant) && ( + + )} diff --git a/react/features/video-menu/components/web/RemoteVideoMenuTriggerButton.tsx b/react/features/video-menu/components/web/RemoteVideoMenuTriggerButton.tsx index 331e650410..9ea0b278b3 100644 --- a/react/features/video-menu/components/web/RemoteVideoMenuTriggerButton.tsx +++ b/react/features/video-menu/components/web/RemoteVideoMenuTriggerButton.tsx @@ -250,7 +250,7 @@ class RemoteVideoMenuTriggerButton extends Component { thumbnailMenu: true }; - if (_participant?.isFakeParticipant) { + if (_participant?.fakeParticipant) { return ( { const { dispatch, getState } = store; @@ -32,9 +33,8 @@ const focusWhiteboard = (store: IStore) => { if (!isPresent) { dispatch(participantJoined({ conference, + fakeParticipant: FakeParticipant.Whiteboard, id: WHITEBOARD_ID, - isFakeParticipant: true, - isWhiteboard: true, name: WHITEBOARD_PARTICIPANT_NAME })); } @@ -85,11 +85,11 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => async (action return; } - dispatch(participantLeft(WHITEBOARD_ID, conference, { isWhiteboard: true })); + dispatch(participantLeft(WHITEBOARD_ID, conference, { fakeParticipant: FakeParticipant.Whiteboard })); break; } case RESET_WHITEBOARD: { - dispatch(participantLeft(WHITEBOARD_ID, conference, { isWhiteboard: true })); + dispatch(participantLeft(WHITEBOARD_ID, conference, { fakeParticipant: FakeParticipant.Whiteboard })); break; } }