mediasfu-shared 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/dist/ProducerClient/producerClientEmits/createDeviceClient.d.ts +1 -1
- package/dist/ProducerClient/producerClientEmits/createDeviceClient.d.ts.map +1 -1
- package/dist/ProducerClient/producerClientEmits/updateRoomParametersClient.d.ts +1 -1
- package/dist/ProducerClient/producerClientEmits/updateRoomParametersClient.d.ts.map +1 -1
- package/dist/consumers/connectIps.d.ts +1 -1
- package/dist/consumers/connectIps.d.ts.map +1 -1
- package/dist/consumers/connectRecvTransport.d.ts +1 -1
- package/dist/consumers/connectRecvTransport.d.ts.map +1 -1
- package/dist/consumers/connectSendTransport.d.ts +1 -1
- package/dist/consumers/connectSendTransport.d.ts.map +1 -1
- package/dist/consumers/connectSendTransportAudio.d.ts +1 -1
- package/dist/consumers/connectSendTransportAudio.d.ts.map +1 -1
- package/dist/consumers/connectSendTransportScreen.d.ts +1 -1
- package/dist/consumers/connectSendTransportScreen.d.ts.map +1 -1
- package/dist/consumers/connectSendTransportVideo.d.ts +1 -1
- package/dist/consumers/connectSendTransportVideo.d.ts.map +1 -1
- package/dist/consumers/createSendTransport.d.ts +1 -1
- package/dist/consumers/createSendTransport.d.ts.map +1 -1
- package/dist/consumers/disconnectSendTransportAudio.d.ts +1 -1
- package/dist/consumers/disconnectSendTransportAudio.d.ts.map +1 -1
- package/dist/consumers/disconnectSendTransportScreen.d.ts +1 -1
- package/dist/consumers/disconnectSendTransportScreen.d.ts.map +1 -1
- package/dist/consumers/disconnectSendTransportVideo.d.ts +1 -1
- package/dist/consumers/disconnectSendTransportVideo.d.ts.map +1 -1
- package/dist/consumers/index.cjs +80 -0
- package/dist/consumers/index.cjs.map +1 -0
- package/dist/consumers/index.d.ts +62 -0
- package/dist/consumers/index.d.ts.map +1 -0
- package/dist/consumers/index.js +80 -0
- package/dist/consumers/index.js.map +1 -0
- package/dist/consumers/resumeSendTransportAudio.d.ts +1 -1
- package/dist/consumers/resumeSendTransportAudio.d.ts.map +1 -1
- package/dist/consumers/signalNewConsumerTransport.d.ts +1 -1
- package/dist/consumers/signalNewConsumerTransport.d.ts.map +1 -1
- package/dist/consumers/socketReceiveMethods/joinConsumeRoom.d.ts +1 -1
- package/dist/consumers/socketReceiveMethods/joinConsumeRoom.d.ts.map +1 -1
- package/dist/consumers/socketReceiveMethods/newPipeProducer.d.ts +1 -1
- package/dist/consumers/socketReceiveMethods/newPipeProducer.d.ts.map +1 -1
- package/dist/consumers/streamSuccessAudio.d.ts +1 -1
- package/dist/consumers/streamSuccessAudio.d.ts.map +1 -1
- package/dist/consumers/streamSuccessAudioSwitch.d.ts +1 -1
- package/dist/consumers/streamSuccessAudioSwitch.d.ts.map +1 -1
- package/dist/consumers/streamSuccessVideo.d.ts +1 -1
- package/dist/consumers/streamSuccessVideo.d.ts.map +1 -1
- package/dist/getParticipantMedia-B0JS6d2b.js +3555 -0
- package/dist/getParticipantMedia-B0JS6d2b.js.map +1 -0
- package/dist/getParticipantMedia-CdcYqcbD.cjs +3554 -0
- package/dist/getParticipantMedia-CdcYqcbD.cjs.map +1 -0
- package/dist/index.cjs +299 -252
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1994 -1947
- package/dist/index.js.map +1 -1
- package/dist/index.native.cjs +230 -224
- package/dist/index.native.cjs.map +1 -1
- package/dist/index.native.js +349 -343
- package/dist/index.native.js.map +1 -1
- package/dist/joinLocalRoom-BdM1msQt.cjs +673 -0
- package/dist/joinLocalRoom-BdM1msQt.cjs.map +1 -0
- package/dist/joinLocalRoom-CvteNe4R.js +657 -0
- package/dist/joinLocalRoom-CvteNe4R.js.map +1 -0
- package/dist/joinRoomOnMediaSFU-CC8RVJgr.cjs +1222 -0
- package/dist/joinRoomOnMediaSFU-CC8RVJgr.cjs.map +1 -0
- package/dist/joinRoomOnMediaSFU-y6vJ1OBo.js +1223 -0
- package/dist/joinRoomOnMediaSFU-y6vJ1OBo.js.map +1 -0
- package/dist/methods/index.cjs +3975 -0
- package/dist/methods/index.cjs.map +1 -0
- package/dist/methods/index.js +3976 -0
- package/dist/methods/index.js.map +1 -0
- package/dist/methods/socketReceive/getDomains.d.ts +1 -1
- package/dist/methods/socketReceive/getDomains.d.ts.map +1 -1
- package/dist/methods/utils/headless/virtualBackground.d.ts +2 -2
- package/dist/methods/utils/headless/virtualBackground.d.ts.map +1 -1
- package/dist/methods/utils/virtualBackgroundCompositor.d.ts +21 -0
- package/dist/methods/utils/virtualBackgroundCompositor.d.ts.map +1 -0
- package/dist/methods/whiteboard/captureCanvasStream.d.ts +1 -1
- package/dist/methods/whiteboard/captureCanvasStream.d.ts.map +1 -1
- package/dist/producers/producerEmits/joinConRoom.d.ts +1 -1
- package/dist/producers/producerEmits/joinConRoom.d.ts.map +1 -1
- package/dist/producers/producerEmits/joinRoom.d.ts +1 -1
- package/dist/producers/producerEmits/joinRoom.d.ts.map +1 -1
- package/dist/translationConsumerSwitch-C20MfNNq.cjs +509 -0
- package/dist/translationConsumerSwitch-C20MfNNq.cjs.map +1 -0
- package/dist/translationConsumerSwitch-zKuS5wgH.js +510 -0
- package/dist/translationConsumerSwitch-zKuS5wgH.js.map +1 -0
- package/dist/types/index.cjs +85 -0
- package/dist/types/index.cjs.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +85 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/shared-base-types.d.ts +1 -1
- package/dist/types/shared-base-types.d.ts.map +1 -1
- package/dist/updateParticipantAudioDecibels-DLd8Y-Fh.js +5392 -0
- package/dist/updateParticipantAudioDecibels-DLd8Y-Fh.js.map +1 -0
- package/dist/updateParticipantAudioDecibels-DPmHiy3K.cjs +5391 -0
- package/dist/updateParticipantAudioDecibels-DPmHiy3K.cjs.map +1 -0
- package/dist/validateAlphanumeric-DKn5BsUP.cjs +15 -0
- package/dist/validateAlphanumeric-DKn5BsUP.cjs.map +1 -0
- package/dist/validateAlphanumeric-Dk1JB80W.js +16 -0
- package/dist/validateAlphanumeric-Dk1JB80W.js.map +1 -0
- package/package.json +1 -1
- package/src/ProducerClient/producerClientEmits/createDeviceClient.ts +1 -2
- package/src/ProducerClient/producerClientEmits/updateRoomParametersClient.ts +1 -1
- package/src/consumers/connectIps.ts +1 -1
- package/src/consumers/connectRecvTransport.ts +1 -1
- package/src/consumers/connectSendTransport.ts +1 -1
- package/src/consumers/connectSendTransportAudio.ts +1 -1
- package/src/consumers/connectSendTransportScreen.ts +1 -1
- package/src/consumers/connectSendTransportVideo.ts +1 -1
- package/src/consumers/createSendTransport.ts +1 -1
- package/src/consumers/disconnectSendTransportAudio.ts +1 -1
- package/src/consumers/disconnectSendTransportScreen.ts +1 -1
- package/src/consumers/disconnectSendTransportVideo.ts +1 -1
- package/src/consumers/index.ts +61 -0
- package/src/consumers/resumeSendTransportAudio.ts +1 -1
- package/src/consumers/signalNewConsumerTransport.ts +1 -2
- package/src/consumers/socketReceiveMethods/joinConsumeRoom.ts +1 -1
- package/src/consumers/socketReceiveMethods/newPipeProducer.ts +1 -1
- package/src/consumers/streamSuccessAudio.ts +1 -2
- package/src/consumers/streamSuccessAudioSwitch.ts +1 -2
- package/src/consumers/streamSuccessVideo.ts +1 -1
- package/src/index.ts +2 -0
- package/src/methods/socketReceive/getDomains.ts +1 -1
- package/src/methods/utils/headless/virtualBackground.ts +45 -30
- package/src/methods/utils/virtualBackgroundCompositor.ts +53 -0
- package/src/methods/whiteboard/captureCanvasStream.ts +2 -2
- package/src/producers/producerEmits/joinConRoom.ts +1 -1
- package/src/producers/producerEmits/joinRoom.ts +1 -1
- package/src/types/index.ts +1 -0
- package/src/types/shared-base-types.ts +2 -3
- package/dist/getParticipantMedia-D9ChmEqq.js +0 -15265
- package/dist/getParticipantMedia-D9ChmEqq.js.map +0 -1
- package/dist/getParticipantMedia-DWvIhPPY.cjs +0 -15281
- package/dist/getParticipantMedia-DWvIhPPY.cjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translationConsumerSwitch-C20MfNNq.cjs","sources":["../src/consumers/gridLayout/addVideosGrid.engine.ts","../src/consumers/gridLayout/prepopulateUserMedia.engine.ts","../src/consumers/translationConsumerSwitch.ts"],"sourcesContent":["export interface GridPlanEntry<T> {\n stream: T;\n index: number;\n}\n\nexport interface BuildAddVideosGridPlanOptions<T> {\n mainGridStreams: T[];\n altGridStreams: T[];\n numToAdd?: number;\n}\n\nexport interface AddVideosGridPlan<T> {\n mainEntries: GridPlanEntry<T>[];\n altEntries: GridPlanEntry<T>[];\n}\n\n/**\n * Pure planning engine for addVideosGrid.\n * Produces deterministic main/alt stream iteration plans without rendering concerns.\n */\nexport function buildAddVideosGridPlan<T>({\n mainGridStreams,\n altGridStreams,\n numToAdd,\n}: BuildAddVideosGridPlanOptions<T>): AddVideosGridPlan<T> {\n const safeMain = Array.isArray(mainGridStreams) ? mainGridStreams : [];\n const safeAlt = Array.isArray(altGridStreams) ? altGridStreams : [];\n\n const bounded = Math.max(0, Math.min(numToAdd ?? safeMain.length, safeMain.length));\n\n const mainEntries = safeMain.slice(0, bounded).map((stream, index) => ({\n stream,\n index,\n }));\n\n const altEntries = safeAlt.map((stream, index) => ({\n stream,\n index,\n }));\n\n return { mainEntries, altEntries };\n}\n","export interface PrepopulateParticipantLike {\n name?: string;\n islevel?: string;\n ScreenID?: string;\n ScreenOn?: boolean;\n [key: string]: any;\n}\n\nexport interface PrepopulateStreamLike {\n producerId?: string;\n stream?: any;\n [key: string]: any;\n}\n\nexport interface BuildPrepopulateUserMediaPlanOptions<\n P extends PrepopulateParticipantLike,\n S extends PrepopulateStreamLike,\n> {\n participants: P[];\n allVideoStreams: S[];\n member: string;\n islevel: string;\n shared: boolean;\n shareScreenStarted: boolean;\n eventType: string;\n screenId?: string;\n whiteboardStarted: boolean;\n whiteboardEnded: boolean;\n remoteScreenStream: S[];\n localStreamScreen: any;\n checkOrientation: () => string;\n isWideScreen: boolean;\n forceFullDisplay: boolean;\n includeWhiteboardAsScreenFlow?: boolean;\n}\n\nexport interface PrepopulateUserMediaPlan<P extends PrepopulateParticipantLike> {\n screenFlowActive: boolean;\n shouldReturnEarly: boolean;\n shouldUpdateAdminOnMainScreen: boolean;\n screenForceFullDisplay: boolean;\n host: P | null;\n hostStream: any;\n adminOnMainScreen: boolean;\n mainScreenPerson: string;\n}\n\nexport interface ResolveMainHostRenderModeOptions {\n islevel: string;\n localUIMode: boolean;\n videoAlreadyOn: boolean;\n audioAlreadyOn: boolean;\n hostVideoOn: boolean;\n hostMuted?: boolean;\n}\n\nexport type MainHostRenderMode = 'adminVideo' | 'audio' | 'mini' | 'video';\n\nexport interface ResolveHostVideoStreamOptions<TStreamLike = PrepopulateStreamLike> {\n islevel: string;\n keepBackground: boolean;\n virtualStream: any;\n localStreamVideo: any;\n oldAllStreams: TStreamLike[];\n hostVideoID?: string;\n}\n\nexport interface BuildMainScreenStateOptions {\n filled: boolean;\n adminOnMainScreen: boolean;\n mainScreenPerson: string;\n}\n\nexport interface MainScreenState {\n filled: boolean;\n adminOnMainScreen: boolean;\n mainScreenPerson: string;\n}\n\nexport interface BuildMainHostCardPlanOptions<TStreamLike = PrepopulateStreamLike> {\n islevel: string;\n localUIMode: boolean;\n videoAlreadyOn: boolean;\n audioAlreadyOn: boolean;\n hostVideoOn: boolean;\n hostMuted?: boolean;\n hostIsAdmin: boolean;\n hostName: string;\n hostVideoID?: string;\n fallbackName: string;\n member: string;\n keepBackground: boolean;\n virtualStream: any;\n localStreamVideo: any;\n oldAllStreams: TStreamLike[];\n}\n\nexport interface MainHostCardPlan {\n kind: 'video' | 'audio' | 'mini';\n key: string;\n name: string;\n initials?: string;\n remoteProducerId?: string;\n videoStream?: any;\n doMirror?: boolean;\n state: MainScreenState;\n}\n\nexport interface BuildScreenShareHostCardPlanOptions {\n hostName: string;\n hostScreenID?: string;\n hostIsAdmin: boolean;\n shared: boolean;\n hostStream: any;\n screenForceFullDisplay: boolean;\n annotateScreenStream: boolean;\n}\n\nexport interface ScreenShareHostCardPlan {\n key: string;\n name: string;\n remoteProducerId: string;\n videoStream: any;\n forceFullDisplay: boolean;\n doMirror: false;\n state: MainScreenState;\n}\n\n/**\n * Pure helper for resolving which non-screen-share host card mode should render.\n */\nexport function resolveMainHostRenderMode({\n islevel,\n localUIMode,\n videoAlreadyOn,\n audioAlreadyOn,\n hostVideoOn,\n hostMuted,\n}: ResolveMainHostRenderModeOptions): MainHostRenderMode {\n const hostVideoOffPath =\n (islevel !== '2' && !hostVideoOn)\n || (islevel === '2' && (!hostVideoOn || !videoAlreadyOn))\n || localUIMode === true;\n\n if (!hostVideoOffPath) {\n return 'video';\n }\n\n if (islevel === '2' && videoAlreadyOn) {\n return 'adminVideo';\n }\n\n const audOn =\n (islevel === '2' && audioAlreadyOn)\n || (islevel !== '2' && hostMuted === false);\n\n return audOn ? 'audio' : 'mini';\n}\n\n/**\n * Resolves the correct host video stream source for non-screen-share rendering.\n */\nexport function resolveHostVideoStream<TStreamLike extends PrepopulateStreamLike = PrepopulateStreamLike>({\n islevel,\n keepBackground,\n virtualStream,\n localStreamVideo,\n oldAllStreams,\n hostVideoID,\n}: ResolveHostVideoStreamOptions<TStreamLike>): any {\n if (islevel === '2') {\n return keepBackground && virtualStream ? virtualStream : localStreamVideo;\n }\n\n const safeOldStreams = Array.isArray(oldAllStreams) ? oldAllStreams : [];\n const matched = safeOldStreams.find((stream) => stream.producerId === hostVideoID);\n return matched?.stream ?? null;\n}\n\n/**\n * Pure helper for normalizing main-screen state updates.\n */\nexport function buildMainScreenState({\n filled,\n adminOnMainScreen,\n mainScreenPerson,\n}: BuildMainScreenStateOptions): MainScreenState {\n return {\n filled,\n adminOnMainScreen,\n mainScreenPerson,\n };\n}\n\n/**\n * Pure helper for resolving the non-screen-share host card to render on the main screen.\n */\nexport function buildMainHostCardPlan<TStreamLike extends PrepopulateStreamLike = PrepopulateStreamLike>({\n islevel,\n localUIMode,\n videoAlreadyOn,\n audioAlreadyOn,\n hostVideoOn,\n hostMuted,\n hostIsAdmin,\n hostName,\n hostVideoID,\n fallbackName,\n member,\n keepBackground,\n virtualStream,\n localStreamVideo,\n oldAllStreams,\n}: BuildMainHostCardPlanOptions<TStreamLike>): MainHostCardPlan {\n const mode = resolveMainHostRenderMode({\n islevel,\n localUIMode,\n videoAlreadyOn,\n audioAlreadyOn,\n hostVideoOn,\n hostMuted,\n });\n\n if (mode === 'adminVideo') {\n return {\n kind: 'video',\n key: hostVideoID || hostName || 'host-video',\n name: hostName,\n remoteProducerId: hostVideoID || '',\n videoStream: keepBackground && virtualStream ? virtualStream : localStreamVideo,\n doMirror: true,\n state: buildMainScreenState({\n filled: true,\n adminOnMainScreen: true,\n mainScreenPerson: hostName,\n }),\n };\n }\n\n if (mode === 'audio') {\n return {\n kind: 'audio',\n key: hostName || fallbackName,\n name: hostName,\n state: buildMainScreenState({\n filled: true,\n adminOnMainScreen: islevel === '2',\n mainScreenPerson: hostName,\n }),\n };\n }\n\n if (mode === 'mini') {\n return {\n kind: 'mini',\n key: fallbackName,\n name: hostName,\n initials: fallbackName,\n state: buildMainScreenState({\n filled: false,\n adminOnMainScreen: islevel === '2',\n mainScreenPerson: hostName,\n }),\n };\n }\n\n const hostStream = resolveHostVideoStream({\n islevel,\n keepBackground,\n virtualStream,\n localStreamVideo,\n oldAllStreams,\n hostVideoID,\n });\n\n if (!hostStream) {\n return {\n kind: 'mini',\n key: fallbackName,\n name: hostName,\n initials: fallbackName,\n state: buildMainScreenState({\n filled: false,\n adminOnMainScreen: islevel === '2',\n mainScreenPerson: hostName,\n }),\n };\n }\n\n return {\n kind: 'video',\n key: hostVideoID || hostName || 'host-video',\n name: hostName,\n remoteProducerId: hostVideoID || '',\n videoStream: hostStream,\n doMirror: member === hostName,\n state: buildMainScreenState({\n filled: true,\n adminOnMainScreen: hostIsAdmin,\n mainScreenPerson: hostName,\n }),\n };\n}\n\n/**\n * Pure helper for resolving the screen-share host card to render on the main screen.\n */\nexport function buildScreenShareHostCardPlan({\n hostName,\n hostScreenID,\n hostIsAdmin,\n shared,\n hostStream,\n screenForceFullDisplay,\n annotateScreenStream,\n}: BuildScreenShareHostCardPlanOptions): ScreenShareHostCardPlan {\n return {\n key: hostScreenID || hostName || 'host-screen',\n name: hostName,\n remoteProducerId: hostScreenID || '',\n videoStream: shared ? hostStream : hostStream?.stream ?? null,\n forceFullDisplay: annotateScreenStream && shared ? false : screenForceFullDisplay,\n doMirror: false,\n state: buildMainScreenState({\n filled: true,\n adminOnMainScreen: hostIsAdmin,\n mainScreenPerson: hostName,\n }),\n };\n}\n\n/**\n * Pure planning engine for prepopulateUserMedia host/screen-flow resolution.\n * Returns deterministic state decisions without rendering concerns.\n */\nexport function buildPrepopulateUserMediaPlan<\n P extends PrepopulateParticipantLike,\n S extends PrepopulateStreamLike,\n>({\n participants,\n allVideoStreams,\n member,\n shared,\n shareScreenStarted,\n eventType,\n screenId,\n whiteboardStarted,\n whiteboardEnded,\n remoteScreenStream,\n localStreamScreen,\n checkOrientation,\n isWideScreen,\n forceFullDisplay,\n includeWhiteboardAsScreenFlow = false,\n}: BuildPrepopulateUserMediaPlanOptions<P, S>): PrepopulateUserMediaPlan<P> {\n const safeParticipants = Array.isArray(participants) ? participants : [];\n const safeVideoStreams = Array.isArray(allVideoStreams) ? allVideoStreams : [];\n const safeRemoteScreenStreams = Array.isArray(remoteScreenStream) ? remoteScreenStream : [];\n\n const whiteboardActive = whiteboardStarted && !whiteboardEnded;\n const screenFlowActive =\n shareScreenStarted || shared || (includeWhiteboardAsScreenFlow && whiteboardActive);\n\n let screenForceFullDisplay = forceFullDisplay;\n const orientation = checkOrientation();\n if ((orientation === 'portrait' || !isWideScreen) && (shareScreenStarted || shared)) {\n screenForceFullDisplay = false;\n }\n\n if (!screenFlowActive) {\n if (eventType === 'conference') {\n return {\n screenFlowActive,\n shouldReturnEarly: true,\n shouldUpdateAdminOnMainScreen: false,\n screenForceFullDisplay,\n host: null,\n hostStream: null,\n adminOnMainScreen: false,\n mainScreenPerson: '',\n };\n }\n\n const host = safeParticipants.find((participant) => participant.islevel === '2') ?? null;\n\n return {\n screenFlowActive,\n shouldReturnEarly: false,\n shouldUpdateAdminOnMainScreen: false,\n screenForceFullDisplay,\n host,\n hostStream: null,\n adminOnMainScreen: false,\n mainScreenPerson: host?.name ?? '',\n };\n }\n\n let host: P | null = null;\n let hostStream: any = null;\n\n if (shared) {\n host = { name: member, audioID: '', videoID: '' } as unknown as P;\n hostStream = localStreamScreen;\n } else {\n host =\n safeParticipants.find(\n (participant) => participant.ScreenID === screenId && participant.ScreenOn === true,\n ) ?? null;\n\n if (whiteboardActive) {\n host = {\n name: 'WhiteboardActive',\n islevel: '2',\n audioID: '',\n videoID: '',\n } as unknown as P;\n hostStream = { producerId: 'WhiteboardActive' };\n }\n\n if (host === null) {\n host = safeParticipants.find((participant) => participant.ScreenOn === true) ?? null;\n }\n\n if (host && !String(host.name ?? '').includes('WhiteboardActive')) {\n if (safeRemoteScreenStreams.length === 0) {\n hostStream =\n safeVideoStreams.find((stream) => stream.producerId === host?.ScreenID) ?? null;\n } else {\n hostStream = safeRemoteScreenStreams[0];\n }\n }\n }\n\n return {\n screenFlowActive,\n shouldReturnEarly: false,\n shouldUpdateAdminOnMainScreen: true,\n screenForceFullDisplay,\n host,\n hostStream,\n adminOnMainScreen: (host && host.islevel === '2') ?? false,\n mainScreenPerson: host?.name ?? '',\n };\n}\n","import { BreakoutParticipant, EventType, Participant, Transport } from '../types/types';\n\nexport interface TranslationConsumerSwitchParameters {\n consumerTransports: Transport[];\n roomName: string;\n member: string;\n updateConsumerTransports: (transports: Transport[]) => void;\n breakOutRoomStarted?: boolean;\n breakOutRoomEnded?: boolean;\n breakoutRooms?: BreakoutParticipant[][];\n limitedBreakRoom?: BreakoutParticipant[];\n participants?: Participant[];\n ref_participants?: Participant[];\n islevel?: string;\n eventType?: EventType;\n hostNewRoom?: number;\n [key: string]: any;\n}\n\nexport interface PauseOriginalProducerOptions {\n originalProducerId: string;\n speakerId?: string;\n parameters: TranslationConsumerSwitchParameters;\n}\n\nexport interface ResumeOriginalProducerOptions {\n originalProducerId: string;\n speakerId?: string;\n parameters: TranslationConsumerSwitchParameters;\n}\n\nexport type PauseOriginalProducerType = (options: PauseOriginalProducerOptions) => Promise<void>;\nexport type ResumeOriginalProducerType = (options: ResumeOriginalProducerOptions) => Promise<void>;\n\nexport interface StopConsumingTranslationOptions {\n speakerId?: string;\n language: string;\n translationProducerMap: Record<string, Record<string, string>>;\n parameters: TranslationConsumerSwitchParameters;\n}\n\nexport type StopConsumingTranslationType = (options: StopConsumingTranslationOptions) => Promise<string | null>;\n\nexport const isSpeakerInMyBreakoutRoom = (\n speakerName: string,\n parameters: TranslationConsumerSwitchParameters\n): boolean => {\n const {\n breakOutRoomStarted = false,\n breakOutRoomEnded = false,\n limitedBreakRoom = [],\n participants = [],\n islevel = '1',\n eventType = 'conference',\n hostNewRoom = -1,\n breakoutRooms = [],\n member = '',\n } = parameters;\n\n if (!breakOutRoomStarted || breakOutRoomEnded) {\n return true;\n }\n\n const host = participants.find((p) => p.islevel === '2');\n const speakerIsHost = host?.name === speakerName;\n\n if (islevel !== '2') {\n if (eventType === 'webinar' && speakerIsHost) {\n return true;\n }\n\n if (eventType === 'conference' && speakerIsHost) {\n const roomMember = breakoutRooms.find((r) =>\n r.find((p) => p.name === member)\n );\n const memberBreakRoom = roomMember ? breakoutRooms.indexOf(roomMember) : -1;\n const inBreakRoom = memberBreakRoom !== -1;\n\n if (inBreakRoom) {\n return memberBreakRoom === hostNewRoom;\n }\n\n if (hostNewRoom === -1) {\n return true;\n }\n\n return hostNewRoom === memberBreakRoom && memberBreakRoom !== -1;\n }\n }\n\n return limitedBreakRoom.some((p) => p.name === speakerName);\n};\n\nexport const pauseOriginalProducer = async ({\n originalProducerId,\n speakerId,\n parameters,\n}: PauseOriginalProducerOptions): Promise<void> => {\n try {\n const { consumerTransports } = parameters;\n\n if (speakerId && !isSpeakerInMyBreakoutRoom(speakerId, parameters)) {\n return;\n }\n\n const transport = consumerTransports.find(\n (t) => t.producerId === originalProducerId && t.consumer?.kind === 'audio'\n );\n\n if (!transport?.consumer) {\n return;\n }\n\n if (transport.consumer.track) {\n transport.consumer.track.enabled = false;\n }\n\n if (transport.consumer.paused) {\n return;\n }\n\n transport.consumer.pause();\n\n transport.socket_?.emit(\n 'consumer-pause',\n { serverConsumerId: transport.serverConsumerTransportId },\n async () => {}\n );\n } catch (error) {\n console.error('[TranslationSwitch] Error pausing original producer:', error);\n }\n};\n\nexport const resumeOriginalProducer = async ({\n originalProducerId,\n speakerId,\n parameters,\n}: ResumeOriginalProducerOptions): Promise<void> => {\n try {\n const { consumerTransports } = parameters;\n\n if (speakerId && !isSpeakerInMyBreakoutRoom(speakerId, parameters)) {\n return;\n }\n\n const transport = consumerTransports.find(\n (t) => t.producerId === originalProducerId && t.consumer?.kind === 'audio'\n );\n\n if (!transport?.consumer) {\n return;\n }\n\n if (!transport.consumer.paused) {\n if (transport.consumer.track) {\n transport.consumer.track.enabled = true;\n }\n return;\n }\n\n transport.socket_?.emit(\n 'consumer-resume',\n { serverConsumerId: transport.serverConsumerTransportId },\n async ({ resumed }: { resumed: boolean }) => {\n if (resumed) {\n if (transport.consumer.track) {\n transport.consumer.track.enabled = true;\n }\n transport.consumer.resume();\n }\n }\n );\n } catch (error) {\n console.error('[TranslationSwitch] Error resuming original producer:', error);\n }\n};\n\nexport const isConsumingTranslationForSpeaker = (\n speakerId: string,\n consumerTransports: Transport[],\n translationProducerMap: Map<string, { translationProducerId: string; originalProducerId: string; language: string }>\n): { consuming: boolean; language?: string; translationProducerId?: string; originalProducerId?: string } => {\n const translationInfo = translationProducerMap.get(speakerId);\n\n if (translationInfo) {\n const hasConsumer = consumerTransports.some(\n (t) => t.producerId === translationInfo.translationProducerId\n );\n\n if (hasConsumer) {\n return {\n consuming: true,\n language: translationInfo.language,\n translationProducerId: translationInfo.translationProducerId,\n originalProducerId: translationInfo.originalProducerId,\n };\n }\n }\n\n return { consuming: false };\n};\n\nexport const getActiveTranslationConsumers = (\n translationProducerMap: Map<string, { translationProducerId: string; originalProducerId: string; language: string }>,\n consumerTransports: Transport[]\n): Array<{ speakerId: string; translationProducerId: string; originalProducerId: string; language: string }> => {\n const results: Array<{ speakerId: string; translationProducerId: string; originalProducerId: string; language: string }> = [];\n\n translationProducerMap.forEach((info, speakerId) => {\n const hasConsumer = consumerTransports.some(\n (t) => t.producerId === info.translationProducerId\n );\n\n if (hasConsumer) {\n results.push({\n speakerId,\n ...info,\n });\n }\n });\n\n return results;\n};\n\nexport const findOriginalProducerForSpeaker = (\n speakerId: string,\n allAudioStreams: Array<{ producerId: string; name?: string; [key: string]: any }>\n): string | null => {\n const stream = allAudioStreams.find(\n (s) => s.name === speakerId || s.producerId?.includes(speakerId)\n );\n return stream?.producerId || null;\n};\n\nexport const stopConsumingTranslation = async (options: StopConsumingTranslationOptions): Promise<string | null> => {\n const { language, translationProducerMap, parameters } = options;\n try {\n const { consumerTransports, updateConsumerTransports } = parameters;\n\n let originalProducerId: string | null = null;\n let translationProducerId: string | null = null;\n\n for (const [origId, langMap] of Object.entries(translationProducerMap)) {\n if (langMap && langMap[language]) {\n translationProducerId = langMap[language];\n originalProducerId = origId;\n break;\n }\n }\n\n if (!translationProducerId) {\n return originalProducerId;\n }\n\n const transportIndex = consumerTransports.findIndex(\n (t) => t.producerId === translationProducerId\n );\n\n if (transportIndex === -1) {\n return originalProducerId;\n }\n\n const transport = consumerTransports[transportIndex];\n\n if (transport.socket_ && transport.consumer) {\n transport.socket_.emit(\n 'consumer-close',\n { serverConsumerId: transport.serverConsumerTransportId },\n () => {}\n );\n }\n\n if (transport.consumer) {\n transport.consumer.close();\n }\n\n const updatedTransports = consumerTransports.filter((_, i) => i !== transportIndex);\n updateConsumerTransports(updatedTransports);\n\n return originalProducerId;\n } catch (error) {\n console.error('[TranslationSwitch] Error stopping translation consumer:', error);\n return null;\n }\n};\n\nexport const syncTranslationStateAfterBreakoutChange = async (\n translationProducerMap: Record<string, Record<string, string>>,\n speakerIdByProducerId: Record<string, string>,\n parameters: TranslationConsumerSwitchParameters\n): Promise<void> => {\n try {\n const { consumerTransports } = parameters;\n\n for (const [originalProducerId, langMap] of Object.entries(translationProducerMap)) {\n const speakerId = speakerIdByProducerId[originalProducerId];\n if (!speakerId) continue;\n\n const inMyRoom = isSpeakerInMyBreakoutRoom(speakerId, parameters);\n const hasTranslation = Object.keys(langMap).length > 0;\n\n const originalConsumer = consumerTransports.find(\n (t) => t.producerId === originalProducerId && t.consumer?.kind === 'audio'\n );\n\n if (!originalConsumer) continue;\n\n if (inMyRoom && hasTranslation) {\n if (!originalConsumer.consumer.paused) {\n await pauseOriginalProducer({\n originalProducerId,\n speakerId,\n parameters,\n });\n }\n }\n }\n } catch (error) {\n console.error('[TranslationSwitch] Error syncing translation state:', error);\n }\n};\n"],"names":["host"],"mappings":"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"}
|
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
function buildAddVideosGridPlan({
|
|
2
|
+
mainGridStreams,
|
|
3
|
+
altGridStreams,
|
|
4
|
+
numToAdd
|
|
5
|
+
}) {
|
|
6
|
+
const safeMain = Array.isArray(mainGridStreams) ? mainGridStreams : [];
|
|
7
|
+
const safeAlt = Array.isArray(altGridStreams) ? altGridStreams : [];
|
|
8
|
+
const bounded = Math.max(0, Math.min(numToAdd ?? safeMain.length, safeMain.length));
|
|
9
|
+
const mainEntries = safeMain.slice(0, bounded).map((stream, index) => ({
|
|
10
|
+
stream,
|
|
11
|
+
index
|
|
12
|
+
}));
|
|
13
|
+
const altEntries = safeAlt.map((stream, index) => ({
|
|
14
|
+
stream,
|
|
15
|
+
index
|
|
16
|
+
}));
|
|
17
|
+
return { mainEntries, altEntries };
|
|
18
|
+
}
|
|
19
|
+
function resolveMainHostRenderMode({
|
|
20
|
+
islevel,
|
|
21
|
+
localUIMode,
|
|
22
|
+
videoAlreadyOn,
|
|
23
|
+
audioAlreadyOn,
|
|
24
|
+
hostVideoOn,
|
|
25
|
+
hostMuted
|
|
26
|
+
}) {
|
|
27
|
+
const hostVideoOffPath = islevel !== "2" && !hostVideoOn || islevel === "2" && (!hostVideoOn || !videoAlreadyOn) || localUIMode === true;
|
|
28
|
+
if (!hostVideoOffPath) {
|
|
29
|
+
return "video";
|
|
30
|
+
}
|
|
31
|
+
if (islevel === "2" && videoAlreadyOn) {
|
|
32
|
+
return "adminVideo";
|
|
33
|
+
}
|
|
34
|
+
const audOn = islevel === "2" && audioAlreadyOn || islevel !== "2" && hostMuted === false;
|
|
35
|
+
return audOn ? "audio" : "mini";
|
|
36
|
+
}
|
|
37
|
+
function resolveHostVideoStream({
|
|
38
|
+
islevel,
|
|
39
|
+
keepBackground,
|
|
40
|
+
virtualStream,
|
|
41
|
+
localStreamVideo,
|
|
42
|
+
oldAllStreams,
|
|
43
|
+
hostVideoID
|
|
44
|
+
}) {
|
|
45
|
+
if (islevel === "2") {
|
|
46
|
+
return keepBackground && virtualStream ? virtualStream : localStreamVideo;
|
|
47
|
+
}
|
|
48
|
+
const safeOldStreams = Array.isArray(oldAllStreams) ? oldAllStreams : [];
|
|
49
|
+
const matched = safeOldStreams.find((stream) => stream.producerId === hostVideoID);
|
|
50
|
+
return matched?.stream ?? null;
|
|
51
|
+
}
|
|
52
|
+
function buildMainScreenState({
|
|
53
|
+
filled,
|
|
54
|
+
adminOnMainScreen,
|
|
55
|
+
mainScreenPerson
|
|
56
|
+
}) {
|
|
57
|
+
return {
|
|
58
|
+
filled,
|
|
59
|
+
adminOnMainScreen,
|
|
60
|
+
mainScreenPerson
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function buildMainHostCardPlan({
|
|
64
|
+
islevel,
|
|
65
|
+
localUIMode,
|
|
66
|
+
videoAlreadyOn,
|
|
67
|
+
audioAlreadyOn,
|
|
68
|
+
hostVideoOn,
|
|
69
|
+
hostMuted,
|
|
70
|
+
hostIsAdmin,
|
|
71
|
+
hostName,
|
|
72
|
+
hostVideoID,
|
|
73
|
+
fallbackName,
|
|
74
|
+
member,
|
|
75
|
+
keepBackground,
|
|
76
|
+
virtualStream,
|
|
77
|
+
localStreamVideo,
|
|
78
|
+
oldAllStreams
|
|
79
|
+
}) {
|
|
80
|
+
const mode = resolveMainHostRenderMode({
|
|
81
|
+
islevel,
|
|
82
|
+
localUIMode,
|
|
83
|
+
videoAlreadyOn,
|
|
84
|
+
audioAlreadyOn,
|
|
85
|
+
hostVideoOn,
|
|
86
|
+
hostMuted
|
|
87
|
+
});
|
|
88
|
+
if (mode === "adminVideo") {
|
|
89
|
+
return {
|
|
90
|
+
kind: "video",
|
|
91
|
+
key: hostVideoID || hostName || "host-video",
|
|
92
|
+
name: hostName,
|
|
93
|
+
remoteProducerId: hostVideoID || "",
|
|
94
|
+
videoStream: keepBackground && virtualStream ? virtualStream : localStreamVideo,
|
|
95
|
+
doMirror: true,
|
|
96
|
+
state: buildMainScreenState({
|
|
97
|
+
filled: true,
|
|
98
|
+
adminOnMainScreen: true,
|
|
99
|
+
mainScreenPerson: hostName
|
|
100
|
+
})
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
if (mode === "audio") {
|
|
104
|
+
return {
|
|
105
|
+
kind: "audio",
|
|
106
|
+
key: hostName || fallbackName,
|
|
107
|
+
name: hostName,
|
|
108
|
+
state: buildMainScreenState({
|
|
109
|
+
filled: true,
|
|
110
|
+
adminOnMainScreen: islevel === "2",
|
|
111
|
+
mainScreenPerson: hostName
|
|
112
|
+
})
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
if (mode === "mini") {
|
|
116
|
+
return {
|
|
117
|
+
kind: "mini",
|
|
118
|
+
key: fallbackName,
|
|
119
|
+
name: hostName,
|
|
120
|
+
initials: fallbackName,
|
|
121
|
+
state: buildMainScreenState({
|
|
122
|
+
filled: false,
|
|
123
|
+
adminOnMainScreen: islevel === "2",
|
|
124
|
+
mainScreenPerson: hostName
|
|
125
|
+
})
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const hostStream = resolveHostVideoStream({
|
|
129
|
+
islevel,
|
|
130
|
+
keepBackground,
|
|
131
|
+
virtualStream,
|
|
132
|
+
localStreamVideo,
|
|
133
|
+
oldAllStreams,
|
|
134
|
+
hostVideoID
|
|
135
|
+
});
|
|
136
|
+
if (!hostStream) {
|
|
137
|
+
return {
|
|
138
|
+
kind: "mini",
|
|
139
|
+
key: fallbackName,
|
|
140
|
+
name: hostName,
|
|
141
|
+
initials: fallbackName,
|
|
142
|
+
state: buildMainScreenState({
|
|
143
|
+
filled: false,
|
|
144
|
+
adminOnMainScreen: islevel === "2",
|
|
145
|
+
mainScreenPerson: hostName
|
|
146
|
+
})
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
kind: "video",
|
|
151
|
+
key: hostVideoID || hostName || "host-video",
|
|
152
|
+
name: hostName,
|
|
153
|
+
remoteProducerId: hostVideoID || "",
|
|
154
|
+
videoStream: hostStream,
|
|
155
|
+
doMirror: member === hostName,
|
|
156
|
+
state: buildMainScreenState({
|
|
157
|
+
filled: true,
|
|
158
|
+
adminOnMainScreen: hostIsAdmin,
|
|
159
|
+
mainScreenPerson: hostName
|
|
160
|
+
})
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function buildScreenShareHostCardPlan({
|
|
164
|
+
hostName,
|
|
165
|
+
hostScreenID,
|
|
166
|
+
hostIsAdmin,
|
|
167
|
+
shared,
|
|
168
|
+
hostStream,
|
|
169
|
+
screenForceFullDisplay,
|
|
170
|
+
annotateScreenStream
|
|
171
|
+
}) {
|
|
172
|
+
return {
|
|
173
|
+
key: hostScreenID || hostName || "host-screen",
|
|
174
|
+
name: hostName,
|
|
175
|
+
remoteProducerId: hostScreenID || "",
|
|
176
|
+
videoStream: shared ? hostStream : hostStream?.stream ?? null,
|
|
177
|
+
forceFullDisplay: annotateScreenStream && shared ? false : screenForceFullDisplay,
|
|
178
|
+
doMirror: false,
|
|
179
|
+
state: buildMainScreenState({
|
|
180
|
+
filled: true,
|
|
181
|
+
adminOnMainScreen: hostIsAdmin,
|
|
182
|
+
mainScreenPerson: hostName
|
|
183
|
+
})
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function buildPrepopulateUserMediaPlan({
|
|
187
|
+
participants,
|
|
188
|
+
allVideoStreams,
|
|
189
|
+
member,
|
|
190
|
+
shared,
|
|
191
|
+
shareScreenStarted,
|
|
192
|
+
eventType,
|
|
193
|
+
screenId,
|
|
194
|
+
whiteboardStarted,
|
|
195
|
+
whiteboardEnded,
|
|
196
|
+
remoteScreenStream,
|
|
197
|
+
localStreamScreen,
|
|
198
|
+
checkOrientation,
|
|
199
|
+
isWideScreen,
|
|
200
|
+
forceFullDisplay,
|
|
201
|
+
includeWhiteboardAsScreenFlow = false
|
|
202
|
+
}) {
|
|
203
|
+
const safeParticipants = Array.isArray(participants) ? participants : [];
|
|
204
|
+
const safeVideoStreams = Array.isArray(allVideoStreams) ? allVideoStreams : [];
|
|
205
|
+
const safeRemoteScreenStreams = Array.isArray(remoteScreenStream) ? remoteScreenStream : [];
|
|
206
|
+
const whiteboardActive = whiteboardStarted && !whiteboardEnded;
|
|
207
|
+
const screenFlowActive = shareScreenStarted || shared || includeWhiteboardAsScreenFlow && whiteboardActive;
|
|
208
|
+
let screenForceFullDisplay = forceFullDisplay;
|
|
209
|
+
const orientation = checkOrientation();
|
|
210
|
+
if ((orientation === "portrait" || !isWideScreen) && (shareScreenStarted || shared)) {
|
|
211
|
+
screenForceFullDisplay = false;
|
|
212
|
+
}
|
|
213
|
+
if (!screenFlowActive) {
|
|
214
|
+
if (eventType === "conference") {
|
|
215
|
+
return {
|
|
216
|
+
screenFlowActive,
|
|
217
|
+
shouldReturnEarly: true,
|
|
218
|
+
shouldUpdateAdminOnMainScreen: false,
|
|
219
|
+
screenForceFullDisplay,
|
|
220
|
+
host: null,
|
|
221
|
+
hostStream: null,
|
|
222
|
+
adminOnMainScreen: false,
|
|
223
|
+
mainScreenPerson: ""
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
const host2 = safeParticipants.find((participant) => participant.islevel === "2") ?? null;
|
|
227
|
+
return {
|
|
228
|
+
screenFlowActive,
|
|
229
|
+
shouldReturnEarly: false,
|
|
230
|
+
shouldUpdateAdminOnMainScreen: false,
|
|
231
|
+
screenForceFullDisplay,
|
|
232
|
+
host: host2,
|
|
233
|
+
hostStream: null,
|
|
234
|
+
adminOnMainScreen: false,
|
|
235
|
+
mainScreenPerson: host2?.name ?? ""
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
let host = null;
|
|
239
|
+
let hostStream = null;
|
|
240
|
+
if (shared) {
|
|
241
|
+
host = { name: member, audioID: "", videoID: "" };
|
|
242
|
+
hostStream = localStreamScreen;
|
|
243
|
+
} else {
|
|
244
|
+
host = safeParticipants.find(
|
|
245
|
+
(participant) => participant.ScreenID === screenId && participant.ScreenOn === true
|
|
246
|
+
) ?? null;
|
|
247
|
+
if (whiteboardActive) {
|
|
248
|
+
host = {
|
|
249
|
+
name: "WhiteboardActive",
|
|
250
|
+
islevel: "2",
|
|
251
|
+
audioID: "",
|
|
252
|
+
videoID: ""
|
|
253
|
+
};
|
|
254
|
+
hostStream = { producerId: "WhiteboardActive" };
|
|
255
|
+
}
|
|
256
|
+
if (host === null) {
|
|
257
|
+
host = safeParticipants.find((participant) => participant.ScreenOn === true) ?? null;
|
|
258
|
+
}
|
|
259
|
+
if (host && !String(host.name ?? "").includes("WhiteboardActive")) {
|
|
260
|
+
if (safeRemoteScreenStreams.length === 0) {
|
|
261
|
+
hostStream = safeVideoStreams.find((stream) => stream.producerId === host?.ScreenID) ?? null;
|
|
262
|
+
} else {
|
|
263
|
+
hostStream = safeRemoteScreenStreams[0];
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return {
|
|
268
|
+
screenFlowActive,
|
|
269
|
+
shouldReturnEarly: false,
|
|
270
|
+
shouldUpdateAdminOnMainScreen: true,
|
|
271
|
+
screenForceFullDisplay,
|
|
272
|
+
host,
|
|
273
|
+
hostStream,
|
|
274
|
+
adminOnMainScreen: (host && host.islevel === "2") ?? false,
|
|
275
|
+
mainScreenPerson: host?.name ?? ""
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
const isSpeakerInMyBreakoutRoom = (speakerName, parameters) => {
|
|
279
|
+
const {
|
|
280
|
+
breakOutRoomStarted = false,
|
|
281
|
+
breakOutRoomEnded = false,
|
|
282
|
+
limitedBreakRoom = [],
|
|
283
|
+
participants = [],
|
|
284
|
+
islevel = "1",
|
|
285
|
+
eventType = "conference",
|
|
286
|
+
hostNewRoom = -1,
|
|
287
|
+
breakoutRooms = [],
|
|
288
|
+
member = ""
|
|
289
|
+
} = parameters;
|
|
290
|
+
if (!breakOutRoomStarted || breakOutRoomEnded) {
|
|
291
|
+
return true;
|
|
292
|
+
}
|
|
293
|
+
const host = participants.find((p) => p.islevel === "2");
|
|
294
|
+
const speakerIsHost = host?.name === speakerName;
|
|
295
|
+
if (islevel !== "2") {
|
|
296
|
+
if (eventType === "webinar" && speakerIsHost) {
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
if (eventType === "conference" && speakerIsHost) {
|
|
300
|
+
const roomMember = breakoutRooms.find(
|
|
301
|
+
(r) => r.find((p) => p.name === member)
|
|
302
|
+
);
|
|
303
|
+
const memberBreakRoom = roomMember ? breakoutRooms.indexOf(roomMember) : -1;
|
|
304
|
+
const inBreakRoom = memberBreakRoom !== -1;
|
|
305
|
+
if (inBreakRoom) {
|
|
306
|
+
return memberBreakRoom === hostNewRoom;
|
|
307
|
+
}
|
|
308
|
+
if (hostNewRoom === -1) {
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
return hostNewRoom === memberBreakRoom && memberBreakRoom !== -1;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return limitedBreakRoom.some((p) => p.name === speakerName);
|
|
315
|
+
};
|
|
316
|
+
const pauseOriginalProducer = async ({
|
|
317
|
+
originalProducerId,
|
|
318
|
+
speakerId,
|
|
319
|
+
parameters
|
|
320
|
+
}) => {
|
|
321
|
+
try {
|
|
322
|
+
const { consumerTransports } = parameters;
|
|
323
|
+
if (speakerId && !isSpeakerInMyBreakoutRoom(speakerId, parameters)) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
const transport = consumerTransports.find(
|
|
327
|
+
(t) => t.producerId === originalProducerId && t.consumer?.kind === "audio"
|
|
328
|
+
);
|
|
329
|
+
if (!transport?.consumer) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (transport.consumer.track) {
|
|
333
|
+
transport.consumer.track.enabled = false;
|
|
334
|
+
}
|
|
335
|
+
if (transport.consumer.paused) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
transport.consumer.pause();
|
|
339
|
+
transport.socket_?.emit(
|
|
340
|
+
"consumer-pause",
|
|
341
|
+
{ serverConsumerId: transport.serverConsumerTransportId },
|
|
342
|
+
async () => {
|
|
343
|
+
}
|
|
344
|
+
);
|
|
345
|
+
} catch (error) {
|
|
346
|
+
console.error("[TranslationSwitch] Error pausing original producer:", error);
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
const resumeOriginalProducer = async ({
|
|
350
|
+
originalProducerId,
|
|
351
|
+
speakerId,
|
|
352
|
+
parameters
|
|
353
|
+
}) => {
|
|
354
|
+
try {
|
|
355
|
+
const { consumerTransports } = parameters;
|
|
356
|
+
if (speakerId && !isSpeakerInMyBreakoutRoom(speakerId, parameters)) {
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
const transport = consumerTransports.find(
|
|
360
|
+
(t) => t.producerId === originalProducerId && t.consumer?.kind === "audio"
|
|
361
|
+
);
|
|
362
|
+
if (!transport?.consumer) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
if (!transport.consumer.paused) {
|
|
366
|
+
if (transport.consumer.track) {
|
|
367
|
+
transport.consumer.track.enabled = true;
|
|
368
|
+
}
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
transport.socket_?.emit(
|
|
372
|
+
"consumer-resume",
|
|
373
|
+
{ serverConsumerId: transport.serverConsumerTransportId },
|
|
374
|
+
async ({ resumed }) => {
|
|
375
|
+
if (resumed) {
|
|
376
|
+
if (transport.consumer.track) {
|
|
377
|
+
transport.consumer.track.enabled = true;
|
|
378
|
+
}
|
|
379
|
+
transport.consumer.resume();
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
);
|
|
383
|
+
} catch (error) {
|
|
384
|
+
console.error("[TranslationSwitch] Error resuming original producer:", error);
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
const isConsumingTranslationForSpeaker = (speakerId, consumerTransports, translationProducerMap) => {
|
|
388
|
+
const translationInfo = translationProducerMap.get(speakerId);
|
|
389
|
+
if (translationInfo) {
|
|
390
|
+
const hasConsumer = consumerTransports.some(
|
|
391
|
+
(t) => t.producerId === translationInfo.translationProducerId
|
|
392
|
+
);
|
|
393
|
+
if (hasConsumer) {
|
|
394
|
+
return {
|
|
395
|
+
consuming: true,
|
|
396
|
+
language: translationInfo.language,
|
|
397
|
+
translationProducerId: translationInfo.translationProducerId,
|
|
398
|
+
originalProducerId: translationInfo.originalProducerId
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
return { consuming: false };
|
|
403
|
+
};
|
|
404
|
+
const getActiveTranslationConsumers = (translationProducerMap, consumerTransports) => {
|
|
405
|
+
const results = [];
|
|
406
|
+
translationProducerMap.forEach((info, speakerId) => {
|
|
407
|
+
const hasConsumer = consumerTransports.some(
|
|
408
|
+
(t) => t.producerId === info.translationProducerId
|
|
409
|
+
);
|
|
410
|
+
if (hasConsumer) {
|
|
411
|
+
results.push({
|
|
412
|
+
speakerId,
|
|
413
|
+
...info
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
return results;
|
|
418
|
+
};
|
|
419
|
+
const findOriginalProducerForSpeaker = (speakerId, allAudioStreams) => {
|
|
420
|
+
const stream = allAudioStreams.find(
|
|
421
|
+
(s) => s.name === speakerId || s.producerId?.includes(speakerId)
|
|
422
|
+
);
|
|
423
|
+
return stream?.producerId || null;
|
|
424
|
+
};
|
|
425
|
+
const stopConsumingTranslation = async (options) => {
|
|
426
|
+
const { language, translationProducerMap, parameters } = options;
|
|
427
|
+
try {
|
|
428
|
+
const { consumerTransports, updateConsumerTransports } = parameters;
|
|
429
|
+
let originalProducerId = null;
|
|
430
|
+
let translationProducerId = null;
|
|
431
|
+
for (const [origId, langMap] of Object.entries(translationProducerMap)) {
|
|
432
|
+
if (langMap && langMap[language]) {
|
|
433
|
+
translationProducerId = langMap[language];
|
|
434
|
+
originalProducerId = origId;
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
if (!translationProducerId) {
|
|
439
|
+
return originalProducerId;
|
|
440
|
+
}
|
|
441
|
+
const transportIndex = consumerTransports.findIndex(
|
|
442
|
+
(t) => t.producerId === translationProducerId
|
|
443
|
+
);
|
|
444
|
+
if (transportIndex === -1) {
|
|
445
|
+
return originalProducerId;
|
|
446
|
+
}
|
|
447
|
+
const transport = consumerTransports[transportIndex];
|
|
448
|
+
if (transport.socket_ && transport.consumer) {
|
|
449
|
+
transport.socket_.emit(
|
|
450
|
+
"consumer-close",
|
|
451
|
+
{ serverConsumerId: transport.serverConsumerTransportId },
|
|
452
|
+
() => {
|
|
453
|
+
}
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
if (transport.consumer) {
|
|
457
|
+
transport.consumer.close();
|
|
458
|
+
}
|
|
459
|
+
const updatedTransports = consumerTransports.filter((_, i) => i !== transportIndex);
|
|
460
|
+
updateConsumerTransports(updatedTransports);
|
|
461
|
+
return originalProducerId;
|
|
462
|
+
} catch (error) {
|
|
463
|
+
console.error("[TranslationSwitch] Error stopping translation consumer:", error);
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
const syncTranslationStateAfterBreakoutChange = async (translationProducerMap, speakerIdByProducerId, parameters) => {
|
|
468
|
+
try {
|
|
469
|
+
const { consumerTransports } = parameters;
|
|
470
|
+
for (const [originalProducerId, langMap] of Object.entries(translationProducerMap)) {
|
|
471
|
+
const speakerId = speakerIdByProducerId[originalProducerId];
|
|
472
|
+
if (!speakerId) continue;
|
|
473
|
+
const inMyRoom = isSpeakerInMyBreakoutRoom(speakerId, parameters);
|
|
474
|
+
const hasTranslation = Object.keys(langMap).length > 0;
|
|
475
|
+
const originalConsumer = consumerTransports.find(
|
|
476
|
+
(t) => t.producerId === originalProducerId && t.consumer?.kind === "audio"
|
|
477
|
+
);
|
|
478
|
+
if (!originalConsumer) continue;
|
|
479
|
+
if (inMyRoom && hasTranslation) {
|
|
480
|
+
if (!originalConsumer.consumer.paused) {
|
|
481
|
+
await pauseOriginalProducer({
|
|
482
|
+
originalProducerId,
|
|
483
|
+
speakerId,
|
|
484
|
+
parameters
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
} catch (error) {
|
|
490
|
+
console.error("[TranslationSwitch] Error syncing translation state:", error);
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
export {
|
|
494
|
+
resolveHostVideoStream as a,
|
|
495
|
+
buildAddVideosGridPlan as b,
|
|
496
|
+
buildMainScreenState as c,
|
|
497
|
+
buildMainHostCardPlan as d,
|
|
498
|
+
buildScreenShareHostCardPlan as e,
|
|
499
|
+
buildPrepopulateUserMediaPlan as f,
|
|
500
|
+
resumeOriginalProducer as g,
|
|
501
|
+
isConsumingTranslationForSpeaker as h,
|
|
502
|
+
isSpeakerInMyBreakoutRoom as i,
|
|
503
|
+
getActiveTranslationConsumers as j,
|
|
504
|
+
findOriginalProducerForSpeaker as k,
|
|
505
|
+
syncTranslationStateAfterBreakoutChange as l,
|
|
506
|
+
pauseOriginalProducer as p,
|
|
507
|
+
resolveMainHostRenderMode as r,
|
|
508
|
+
stopConsumingTranslation as s
|
|
509
|
+
};
|
|
510
|
+
//# sourceMappingURL=translationConsumerSwitch-zKuS5wgH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translationConsumerSwitch-zKuS5wgH.js","sources":["../src/consumers/gridLayout/addVideosGrid.engine.ts","../src/consumers/gridLayout/prepopulateUserMedia.engine.ts","../src/consumers/translationConsumerSwitch.ts"],"sourcesContent":["export interface GridPlanEntry<T> {\n stream: T;\n index: number;\n}\n\nexport interface BuildAddVideosGridPlanOptions<T> {\n mainGridStreams: T[];\n altGridStreams: T[];\n numToAdd?: number;\n}\n\nexport interface AddVideosGridPlan<T> {\n mainEntries: GridPlanEntry<T>[];\n altEntries: GridPlanEntry<T>[];\n}\n\n/**\n * Pure planning engine for addVideosGrid.\n * Produces deterministic main/alt stream iteration plans without rendering concerns.\n */\nexport function buildAddVideosGridPlan<T>({\n mainGridStreams,\n altGridStreams,\n numToAdd,\n}: BuildAddVideosGridPlanOptions<T>): AddVideosGridPlan<T> {\n const safeMain = Array.isArray(mainGridStreams) ? mainGridStreams : [];\n const safeAlt = Array.isArray(altGridStreams) ? altGridStreams : [];\n\n const bounded = Math.max(0, Math.min(numToAdd ?? safeMain.length, safeMain.length));\n\n const mainEntries = safeMain.slice(0, bounded).map((stream, index) => ({\n stream,\n index,\n }));\n\n const altEntries = safeAlt.map((stream, index) => ({\n stream,\n index,\n }));\n\n return { mainEntries, altEntries };\n}\n","export interface PrepopulateParticipantLike {\n name?: string;\n islevel?: string;\n ScreenID?: string;\n ScreenOn?: boolean;\n [key: string]: any;\n}\n\nexport interface PrepopulateStreamLike {\n producerId?: string;\n stream?: any;\n [key: string]: any;\n}\n\nexport interface BuildPrepopulateUserMediaPlanOptions<\n P extends PrepopulateParticipantLike,\n S extends PrepopulateStreamLike,\n> {\n participants: P[];\n allVideoStreams: S[];\n member: string;\n islevel: string;\n shared: boolean;\n shareScreenStarted: boolean;\n eventType: string;\n screenId?: string;\n whiteboardStarted: boolean;\n whiteboardEnded: boolean;\n remoteScreenStream: S[];\n localStreamScreen: any;\n checkOrientation: () => string;\n isWideScreen: boolean;\n forceFullDisplay: boolean;\n includeWhiteboardAsScreenFlow?: boolean;\n}\n\nexport interface PrepopulateUserMediaPlan<P extends PrepopulateParticipantLike> {\n screenFlowActive: boolean;\n shouldReturnEarly: boolean;\n shouldUpdateAdminOnMainScreen: boolean;\n screenForceFullDisplay: boolean;\n host: P | null;\n hostStream: any;\n adminOnMainScreen: boolean;\n mainScreenPerson: string;\n}\n\nexport interface ResolveMainHostRenderModeOptions {\n islevel: string;\n localUIMode: boolean;\n videoAlreadyOn: boolean;\n audioAlreadyOn: boolean;\n hostVideoOn: boolean;\n hostMuted?: boolean;\n}\n\nexport type MainHostRenderMode = 'adminVideo' | 'audio' | 'mini' | 'video';\n\nexport interface ResolveHostVideoStreamOptions<TStreamLike = PrepopulateStreamLike> {\n islevel: string;\n keepBackground: boolean;\n virtualStream: any;\n localStreamVideo: any;\n oldAllStreams: TStreamLike[];\n hostVideoID?: string;\n}\n\nexport interface BuildMainScreenStateOptions {\n filled: boolean;\n adminOnMainScreen: boolean;\n mainScreenPerson: string;\n}\n\nexport interface MainScreenState {\n filled: boolean;\n adminOnMainScreen: boolean;\n mainScreenPerson: string;\n}\n\nexport interface BuildMainHostCardPlanOptions<TStreamLike = PrepopulateStreamLike> {\n islevel: string;\n localUIMode: boolean;\n videoAlreadyOn: boolean;\n audioAlreadyOn: boolean;\n hostVideoOn: boolean;\n hostMuted?: boolean;\n hostIsAdmin: boolean;\n hostName: string;\n hostVideoID?: string;\n fallbackName: string;\n member: string;\n keepBackground: boolean;\n virtualStream: any;\n localStreamVideo: any;\n oldAllStreams: TStreamLike[];\n}\n\nexport interface MainHostCardPlan {\n kind: 'video' | 'audio' | 'mini';\n key: string;\n name: string;\n initials?: string;\n remoteProducerId?: string;\n videoStream?: any;\n doMirror?: boolean;\n state: MainScreenState;\n}\n\nexport interface BuildScreenShareHostCardPlanOptions {\n hostName: string;\n hostScreenID?: string;\n hostIsAdmin: boolean;\n shared: boolean;\n hostStream: any;\n screenForceFullDisplay: boolean;\n annotateScreenStream: boolean;\n}\n\nexport interface ScreenShareHostCardPlan {\n key: string;\n name: string;\n remoteProducerId: string;\n videoStream: any;\n forceFullDisplay: boolean;\n doMirror: false;\n state: MainScreenState;\n}\n\n/**\n * Pure helper for resolving which non-screen-share host card mode should render.\n */\nexport function resolveMainHostRenderMode({\n islevel,\n localUIMode,\n videoAlreadyOn,\n audioAlreadyOn,\n hostVideoOn,\n hostMuted,\n}: ResolveMainHostRenderModeOptions): MainHostRenderMode {\n const hostVideoOffPath =\n (islevel !== '2' && !hostVideoOn)\n || (islevel === '2' && (!hostVideoOn || !videoAlreadyOn))\n || localUIMode === true;\n\n if (!hostVideoOffPath) {\n return 'video';\n }\n\n if (islevel === '2' && videoAlreadyOn) {\n return 'adminVideo';\n }\n\n const audOn =\n (islevel === '2' && audioAlreadyOn)\n || (islevel !== '2' && hostMuted === false);\n\n return audOn ? 'audio' : 'mini';\n}\n\n/**\n * Resolves the correct host video stream source for non-screen-share rendering.\n */\nexport function resolveHostVideoStream<TStreamLike extends PrepopulateStreamLike = PrepopulateStreamLike>({\n islevel,\n keepBackground,\n virtualStream,\n localStreamVideo,\n oldAllStreams,\n hostVideoID,\n}: ResolveHostVideoStreamOptions<TStreamLike>): any {\n if (islevel === '2') {\n return keepBackground && virtualStream ? virtualStream : localStreamVideo;\n }\n\n const safeOldStreams = Array.isArray(oldAllStreams) ? oldAllStreams : [];\n const matched = safeOldStreams.find((stream) => stream.producerId === hostVideoID);\n return matched?.stream ?? null;\n}\n\n/**\n * Pure helper for normalizing main-screen state updates.\n */\nexport function buildMainScreenState({\n filled,\n adminOnMainScreen,\n mainScreenPerson,\n}: BuildMainScreenStateOptions): MainScreenState {\n return {\n filled,\n adminOnMainScreen,\n mainScreenPerson,\n };\n}\n\n/**\n * Pure helper for resolving the non-screen-share host card to render on the main screen.\n */\nexport function buildMainHostCardPlan<TStreamLike extends PrepopulateStreamLike = PrepopulateStreamLike>({\n islevel,\n localUIMode,\n videoAlreadyOn,\n audioAlreadyOn,\n hostVideoOn,\n hostMuted,\n hostIsAdmin,\n hostName,\n hostVideoID,\n fallbackName,\n member,\n keepBackground,\n virtualStream,\n localStreamVideo,\n oldAllStreams,\n}: BuildMainHostCardPlanOptions<TStreamLike>): MainHostCardPlan {\n const mode = resolveMainHostRenderMode({\n islevel,\n localUIMode,\n videoAlreadyOn,\n audioAlreadyOn,\n hostVideoOn,\n hostMuted,\n });\n\n if (mode === 'adminVideo') {\n return {\n kind: 'video',\n key: hostVideoID || hostName || 'host-video',\n name: hostName,\n remoteProducerId: hostVideoID || '',\n videoStream: keepBackground && virtualStream ? virtualStream : localStreamVideo,\n doMirror: true,\n state: buildMainScreenState({\n filled: true,\n adminOnMainScreen: true,\n mainScreenPerson: hostName,\n }),\n };\n }\n\n if (mode === 'audio') {\n return {\n kind: 'audio',\n key: hostName || fallbackName,\n name: hostName,\n state: buildMainScreenState({\n filled: true,\n adminOnMainScreen: islevel === '2',\n mainScreenPerson: hostName,\n }),\n };\n }\n\n if (mode === 'mini') {\n return {\n kind: 'mini',\n key: fallbackName,\n name: hostName,\n initials: fallbackName,\n state: buildMainScreenState({\n filled: false,\n adminOnMainScreen: islevel === '2',\n mainScreenPerson: hostName,\n }),\n };\n }\n\n const hostStream = resolveHostVideoStream({\n islevel,\n keepBackground,\n virtualStream,\n localStreamVideo,\n oldAllStreams,\n hostVideoID,\n });\n\n if (!hostStream) {\n return {\n kind: 'mini',\n key: fallbackName,\n name: hostName,\n initials: fallbackName,\n state: buildMainScreenState({\n filled: false,\n adminOnMainScreen: islevel === '2',\n mainScreenPerson: hostName,\n }),\n };\n }\n\n return {\n kind: 'video',\n key: hostVideoID || hostName || 'host-video',\n name: hostName,\n remoteProducerId: hostVideoID || '',\n videoStream: hostStream,\n doMirror: member === hostName,\n state: buildMainScreenState({\n filled: true,\n adminOnMainScreen: hostIsAdmin,\n mainScreenPerson: hostName,\n }),\n };\n}\n\n/**\n * Pure helper for resolving the screen-share host card to render on the main screen.\n */\nexport function buildScreenShareHostCardPlan({\n hostName,\n hostScreenID,\n hostIsAdmin,\n shared,\n hostStream,\n screenForceFullDisplay,\n annotateScreenStream,\n}: BuildScreenShareHostCardPlanOptions): ScreenShareHostCardPlan {\n return {\n key: hostScreenID || hostName || 'host-screen',\n name: hostName,\n remoteProducerId: hostScreenID || '',\n videoStream: shared ? hostStream : hostStream?.stream ?? null,\n forceFullDisplay: annotateScreenStream && shared ? false : screenForceFullDisplay,\n doMirror: false,\n state: buildMainScreenState({\n filled: true,\n adminOnMainScreen: hostIsAdmin,\n mainScreenPerson: hostName,\n }),\n };\n}\n\n/**\n * Pure planning engine for prepopulateUserMedia host/screen-flow resolution.\n * Returns deterministic state decisions without rendering concerns.\n */\nexport function buildPrepopulateUserMediaPlan<\n P extends PrepopulateParticipantLike,\n S extends PrepopulateStreamLike,\n>({\n participants,\n allVideoStreams,\n member,\n shared,\n shareScreenStarted,\n eventType,\n screenId,\n whiteboardStarted,\n whiteboardEnded,\n remoteScreenStream,\n localStreamScreen,\n checkOrientation,\n isWideScreen,\n forceFullDisplay,\n includeWhiteboardAsScreenFlow = false,\n}: BuildPrepopulateUserMediaPlanOptions<P, S>): PrepopulateUserMediaPlan<P> {\n const safeParticipants = Array.isArray(participants) ? participants : [];\n const safeVideoStreams = Array.isArray(allVideoStreams) ? allVideoStreams : [];\n const safeRemoteScreenStreams = Array.isArray(remoteScreenStream) ? remoteScreenStream : [];\n\n const whiteboardActive = whiteboardStarted && !whiteboardEnded;\n const screenFlowActive =\n shareScreenStarted || shared || (includeWhiteboardAsScreenFlow && whiteboardActive);\n\n let screenForceFullDisplay = forceFullDisplay;\n const orientation = checkOrientation();\n if ((orientation === 'portrait' || !isWideScreen) && (shareScreenStarted || shared)) {\n screenForceFullDisplay = false;\n }\n\n if (!screenFlowActive) {\n if (eventType === 'conference') {\n return {\n screenFlowActive,\n shouldReturnEarly: true,\n shouldUpdateAdminOnMainScreen: false,\n screenForceFullDisplay,\n host: null,\n hostStream: null,\n adminOnMainScreen: false,\n mainScreenPerson: '',\n };\n }\n\n const host = safeParticipants.find((participant) => participant.islevel === '2') ?? null;\n\n return {\n screenFlowActive,\n shouldReturnEarly: false,\n shouldUpdateAdminOnMainScreen: false,\n screenForceFullDisplay,\n host,\n hostStream: null,\n adminOnMainScreen: false,\n mainScreenPerson: host?.name ?? '',\n };\n }\n\n let host: P | null = null;\n let hostStream: any = null;\n\n if (shared) {\n host = { name: member, audioID: '', videoID: '' } as unknown as P;\n hostStream = localStreamScreen;\n } else {\n host =\n safeParticipants.find(\n (participant) => participant.ScreenID === screenId && participant.ScreenOn === true,\n ) ?? null;\n\n if (whiteboardActive) {\n host = {\n name: 'WhiteboardActive',\n islevel: '2',\n audioID: '',\n videoID: '',\n } as unknown as P;\n hostStream = { producerId: 'WhiteboardActive' };\n }\n\n if (host === null) {\n host = safeParticipants.find((participant) => participant.ScreenOn === true) ?? null;\n }\n\n if (host && !String(host.name ?? '').includes('WhiteboardActive')) {\n if (safeRemoteScreenStreams.length === 0) {\n hostStream =\n safeVideoStreams.find((stream) => stream.producerId === host?.ScreenID) ?? null;\n } else {\n hostStream = safeRemoteScreenStreams[0];\n }\n }\n }\n\n return {\n screenFlowActive,\n shouldReturnEarly: false,\n shouldUpdateAdminOnMainScreen: true,\n screenForceFullDisplay,\n host,\n hostStream,\n adminOnMainScreen: (host && host.islevel === '2') ?? false,\n mainScreenPerson: host?.name ?? '',\n };\n}\n","import { BreakoutParticipant, EventType, Participant, Transport } from '../types/types';\n\nexport interface TranslationConsumerSwitchParameters {\n consumerTransports: Transport[];\n roomName: string;\n member: string;\n updateConsumerTransports: (transports: Transport[]) => void;\n breakOutRoomStarted?: boolean;\n breakOutRoomEnded?: boolean;\n breakoutRooms?: BreakoutParticipant[][];\n limitedBreakRoom?: BreakoutParticipant[];\n participants?: Participant[];\n ref_participants?: Participant[];\n islevel?: string;\n eventType?: EventType;\n hostNewRoom?: number;\n [key: string]: any;\n}\n\nexport interface PauseOriginalProducerOptions {\n originalProducerId: string;\n speakerId?: string;\n parameters: TranslationConsumerSwitchParameters;\n}\n\nexport interface ResumeOriginalProducerOptions {\n originalProducerId: string;\n speakerId?: string;\n parameters: TranslationConsumerSwitchParameters;\n}\n\nexport type PauseOriginalProducerType = (options: PauseOriginalProducerOptions) => Promise<void>;\nexport type ResumeOriginalProducerType = (options: ResumeOriginalProducerOptions) => Promise<void>;\n\nexport interface StopConsumingTranslationOptions {\n speakerId?: string;\n language: string;\n translationProducerMap: Record<string, Record<string, string>>;\n parameters: TranslationConsumerSwitchParameters;\n}\n\nexport type StopConsumingTranslationType = (options: StopConsumingTranslationOptions) => Promise<string | null>;\n\nexport const isSpeakerInMyBreakoutRoom = (\n speakerName: string,\n parameters: TranslationConsumerSwitchParameters\n): boolean => {\n const {\n breakOutRoomStarted = false,\n breakOutRoomEnded = false,\n limitedBreakRoom = [],\n participants = [],\n islevel = '1',\n eventType = 'conference',\n hostNewRoom = -1,\n breakoutRooms = [],\n member = '',\n } = parameters;\n\n if (!breakOutRoomStarted || breakOutRoomEnded) {\n return true;\n }\n\n const host = participants.find((p) => p.islevel === '2');\n const speakerIsHost = host?.name === speakerName;\n\n if (islevel !== '2') {\n if (eventType === 'webinar' && speakerIsHost) {\n return true;\n }\n\n if (eventType === 'conference' && speakerIsHost) {\n const roomMember = breakoutRooms.find((r) =>\n r.find((p) => p.name === member)\n );\n const memberBreakRoom = roomMember ? breakoutRooms.indexOf(roomMember) : -1;\n const inBreakRoom = memberBreakRoom !== -1;\n\n if (inBreakRoom) {\n return memberBreakRoom === hostNewRoom;\n }\n\n if (hostNewRoom === -1) {\n return true;\n }\n\n return hostNewRoom === memberBreakRoom && memberBreakRoom !== -1;\n }\n }\n\n return limitedBreakRoom.some((p) => p.name === speakerName);\n};\n\nexport const pauseOriginalProducer = async ({\n originalProducerId,\n speakerId,\n parameters,\n}: PauseOriginalProducerOptions): Promise<void> => {\n try {\n const { consumerTransports } = parameters;\n\n if (speakerId && !isSpeakerInMyBreakoutRoom(speakerId, parameters)) {\n return;\n }\n\n const transport = consumerTransports.find(\n (t) => t.producerId === originalProducerId && t.consumer?.kind === 'audio'\n );\n\n if (!transport?.consumer) {\n return;\n }\n\n if (transport.consumer.track) {\n transport.consumer.track.enabled = false;\n }\n\n if (transport.consumer.paused) {\n return;\n }\n\n transport.consumer.pause();\n\n transport.socket_?.emit(\n 'consumer-pause',\n { serverConsumerId: transport.serverConsumerTransportId },\n async () => {}\n );\n } catch (error) {\n console.error('[TranslationSwitch] Error pausing original producer:', error);\n }\n};\n\nexport const resumeOriginalProducer = async ({\n originalProducerId,\n speakerId,\n parameters,\n}: ResumeOriginalProducerOptions): Promise<void> => {\n try {\n const { consumerTransports } = parameters;\n\n if (speakerId && !isSpeakerInMyBreakoutRoom(speakerId, parameters)) {\n return;\n }\n\n const transport = consumerTransports.find(\n (t) => t.producerId === originalProducerId && t.consumer?.kind === 'audio'\n );\n\n if (!transport?.consumer) {\n return;\n }\n\n if (!transport.consumer.paused) {\n if (transport.consumer.track) {\n transport.consumer.track.enabled = true;\n }\n return;\n }\n\n transport.socket_?.emit(\n 'consumer-resume',\n { serverConsumerId: transport.serverConsumerTransportId },\n async ({ resumed }: { resumed: boolean }) => {\n if (resumed) {\n if (transport.consumer.track) {\n transport.consumer.track.enabled = true;\n }\n transport.consumer.resume();\n }\n }\n );\n } catch (error) {\n console.error('[TranslationSwitch] Error resuming original producer:', error);\n }\n};\n\nexport const isConsumingTranslationForSpeaker = (\n speakerId: string,\n consumerTransports: Transport[],\n translationProducerMap: Map<string, { translationProducerId: string; originalProducerId: string; language: string }>\n): { consuming: boolean; language?: string; translationProducerId?: string; originalProducerId?: string } => {\n const translationInfo = translationProducerMap.get(speakerId);\n\n if (translationInfo) {\n const hasConsumer = consumerTransports.some(\n (t) => t.producerId === translationInfo.translationProducerId\n );\n\n if (hasConsumer) {\n return {\n consuming: true,\n language: translationInfo.language,\n translationProducerId: translationInfo.translationProducerId,\n originalProducerId: translationInfo.originalProducerId,\n };\n }\n }\n\n return { consuming: false };\n};\n\nexport const getActiveTranslationConsumers = (\n translationProducerMap: Map<string, { translationProducerId: string; originalProducerId: string; language: string }>,\n consumerTransports: Transport[]\n): Array<{ speakerId: string; translationProducerId: string; originalProducerId: string; language: string }> => {\n const results: Array<{ speakerId: string; translationProducerId: string; originalProducerId: string; language: string }> = [];\n\n translationProducerMap.forEach((info, speakerId) => {\n const hasConsumer = consumerTransports.some(\n (t) => t.producerId === info.translationProducerId\n );\n\n if (hasConsumer) {\n results.push({\n speakerId,\n ...info,\n });\n }\n });\n\n return results;\n};\n\nexport const findOriginalProducerForSpeaker = (\n speakerId: string,\n allAudioStreams: Array<{ producerId: string; name?: string; [key: string]: any }>\n): string | null => {\n const stream = allAudioStreams.find(\n (s) => s.name === speakerId || s.producerId?.includes(speakerId)\n );\n return stream?.producerId || null;\n};\n\nexport const stopConsumingTranslation = async (options: StopConsumingTranslationOptions): Promise<string | null> => {\n const { language, translationProducerMap, parameters } = options;\n try {\n const { consumerTransports, updateConsumerTransports } = parameters;\n\n let originalProducerId: string | null = null;\n let translationProducerId: string | null = null;\n\n for (const [origId, langMap] of Object.entries(translationProducerMap)) {\n if (langMap && langMap[language]) {\n translationProducerId = langMap[language];\n originalProducerId = origId;\n break;\n }\n }\n\n if (!translationProducerId) {\n return originalProducerId;\n }\n\n const transportIndex = consumerTransports.findIndex(\n (t) => t.producerId === translationProducerId\n );\n\n if (transportIndex === -1) {\n return originalProducerId;\n }\n\n const transport = consumerTransports[transportIndex];\n\n if (transport.socket_ && transport.consumer) {\n transport.socket_.emit(\n 'consumer-close',\n { serverConsumerId: transport.serverConsumerTransportId },\n () => {}\n );\n }\n\n if (transport.consumer) {\n transport.consumer.close();\n }\n\n const updatedTransports = consumerTransports.filter((_, i) => i !== transportIndex);\n updateConsumerTransports(updatedTransports);\n\n return originalProducerId;\n } catch (error) {\n console.error('[TranslationSwitch] Error stopping translation consumer:', error);\n return null;\n }\n};\n\nexport const syncTranslationStateAfterBreakoutChange = async (\n translationProducerMap: Record<string, Record<string, string>>,\n speakerIdByProducerId: Record<string, string>,\n parameters: TranslationConsumerSwitchParameters\n): Promise<void> => {\n try {\n const { consumerTransports } = parameters;\n\n for (const [originalProducerId, langMap] of Object.entries(translationProducerMap)) {\n const speakerId = speakerIdByProducerId[originalProducerId];\n if (!speakerId) continue;\n\n const inMyRoom = isSpeakerInMyBreakoutRoom(speakerId, parameters);\n const hasTranslation = Object.keys(langMap).length > 0;\n\n const originalConsumer = consumerTransports.find(\n (t) => t.producerId === originalProducerId && t.consumer?.kind === 'audio'\n );\n\n if (!originalConsumer) continue;\n\n if (inMyRoom && hasTranslation) {\n if (!originalConsumer.consumer.paused) {\n await pauseOriginalProducer({\n originalProducerId,\n speakerId,\n parameters,\n });\n }\n }\n }\n } catch (error) {\n console.error('[TranslationSwitch] Error syncing translation state:', error);\n }\n};\n"],"names":["host"],"mappings":"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"}
|