@defcomm/meetingsdk 0.1.2 → 0.1.4

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react/useLocalParticipant.tsx","../src/react/MeetingProvider.tsx","../src/config/ws.ts","../src/core/ActiveSpeakerDetector.ts","../src/core/MeetingState.ts","../src/core/SFUClient.ts","../src/core/VideoCore.ts","../src/react/useMeetingStore.ts","../src/react/useMeeting.ts","../src/react/useParticipants.ts","../src/react/useRemoteMedia.ts","../src/react/useMeetingPreview.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useMeetingContext } from \"./MeetingProvider\";\nimport { Participant } from \"../types/meeting\";\n\nexport const useLocalParticipant = () => {\n const { sdk } = useMeetingContext();\n\n // Guard the initial state to ensure it matches Participant | null\n const [localParticipant, setLocalParticipant] = useState<Participant | null>(\n () => {\n const current = sdk.state.localParticipant;\n return current && current.id ? (current as Participant) : null;\n },\n );\n\n useEffect(() => {\n const unsubscribe = sdk.state.subscribe(\"localParticipant\", () => {\n const current = sdk.state.localParticipant;\n\n // Safe Type-Guard: Only update if the object has a finalized id\n if (current && current.id) {\n setLocalParticipant({ ...current } as Participant);\n } else {\n setLocalParticipant(null);\n }\n });\n\n return unsubscribe;\n }, [sdk]);\n\n const lastStreamRef = useRef<MediaStream | null>(null);\n\n const videoRef = useCallback(\n (video: HTMLVideoElement | null) => {\n if (!video) return;\n\n const stream = localParticipant?.media?.stream;\n if (!stream) return;\n\n if (lastStreamRef.current === stream) return;\n lastStreamRef.current = stream;\n\n video.srcObject = stream;\n video.autoplay = true;\n video.playsInline = true;\n\n video.play().catch((err) => {\n console.warn(`Autoplay failed for local view:`, err);\n });\n },\n [localParticipant?.media?.stream],\n );\n\n return {\n participant: localParticipant,\n videoRef,\n };\n};\n","import React, { createContext, useContext, useMemo, useRef } from \"react\";\nimport { VideoSDKCore } from \"../core/VideoCore\";\nimport {\n ChatInput,\n ChatMessage,\n MeetingConfig,\n Participant,\n PubSubTopic,\n Recording,\n} from \"../types/meeting\";\nimport { useMeetingStore } from \"./useMeetingStore\";\n\ntype PubSubHandle = {\n messages: ChatMessage[];\n publish: (input: ChatInput) => void;\n};\n\ntype MeetingContextValue = {\n sdk: VideoSDKCore;\n join: (config?: MeetingConfig) => Promise<void>;\n leave: () => void;\n createRoom: (input: {\n name: string;\n description?: string;\n capacity?: number;\n is_private?: boolean;\n }) => Promise<any>;\n getRoom: (roomCode: string) => Promise<any>;\n deleteRoom: (roomCode: string) => Promise<any>;\n\n toggleMic: () => void;\n toggleCam: () => void;\n\n startScreenShare: () => Promise<MediaStream>;\n stopScreenShare: () => void;\n\n sendMessage: (input: ChatInput) => void;\n\n room: { id: string | null; name: string | null };\n localParticipant: Participant | null;\n participants: Map<string, Participant>;\n messages: ChatMessage[];\n presenterId: string | null;\n activeSpeakerIds: string[];\n usePubSub: (topic: PubSubTopic) => PubSubHandle;\n approveJoinRequest: (requestId: string) => void;\n rejectJoinRequest: (requestId: string) => void;\n startRecording: () => Promise<void>;\n stopRecording: () => Promise<void>;\n getRecordingStatus: () => Promise<any>;\n onError: (cb: (err: any) => void) => () => void;\n onEntryRequested: (cb: (req: any) => void) => () => void;\n onEntryResponded: (cb: (payload: any, decision?: any) => void) => () => void;\n onMeetingLeft: (cb: () => void) => () => void;\n onTrackStateChanged: (cb: (track: any) => void) => () => void;\n onRecordingStarted: (cb: (recording: Recording) => void) => () => void;\n onRecordingStopped: (cb: (recording: any) => void) => () => void;\n onActiveSpeakersChanged: (\n cb: (participantIds: string[]) => void,\n ) => () => void;\n};\n\nconst MeetingContext = createContext<MeetingContextValue | null>(null);\n\nexport const MeetingProvider = ({\n config,\n children,\n}: {\n config: MeetingConfig;\n children: React.ReactNode;\n}) => {\n const sdkRef = useRef<VideoSDKCore | null>(null);\n const errorListeners = useRef(new Set<(err: any) => void>());\n const entryRequestListeners = useRef(new Set<(req: any) => void>());\n const entryResponseListeners = useRef(\n new Set<(payload: any, decision?: any) => void>(),\n );\n const meetingLeftListeners = useRef(new Set<() => void>());\n const trackStateListeners = useRef(new Set<(track: any) => void>());\n const recordingStartedListeners = useRef(new Set<(recording: any) => void>());\n const recordingStoppedListeners = useRef(new Set<(recording: any) => void>());\n const activeSpeakerListeners = useRef(\n new Set<(participantIds: string[]) => void>(),\n );\n\n if (!sdkRef.current) {\n sdkRef.current = new VideoSDKCore({\n onError: (err) => errorListeners.current.forEach((fn) => fn(err)),\n onEntryRequested: (req) =>\n entryRequestListeners.current.forEach((fn) => fn(req)),\n onEntryResponded: (p, d) =>\n entryResponseListeners.current.forEach((fn) => fn(p, d)),\n onMeetingLeft: () => meetingLeftListeners.current.forEach((fn) => fn()),\n onTrackStateChanged: (track) =>\n trackStateListeners.current.forEach((fn) => fn(track)),\n onRecordingStarted: (recording: {\n recording_id: string;\n started_at: string;\n }) => recordingStartedListeners.current.forEach((fn) => fn(recording)),\n onRecordingStopped: (recording: {\n recording_id: string;\n stopped_at: string;\n }) => recordingStoppedListeners.current.forEach((fn) => fn(recording)),\n });\n }\n\n const sdk = sdkRef.current;\n const activeSpeakerIds = useMeetingStore(sdk.state, \"activeSpeakers\", (s) =>\n Array.from(s.activeSpeakerIds),\n );\n const presenterId = useMeetingStore(\n sdk.state,\n \"presenter\",\n (s) => s.presenterId,\n );\n const participants = useMeetingStore(\n sdk.state,\n \"participants\",\n (s) => s.participants,\n );\n const localParticipant = useMeetingStore(\n sdk.state,\n \"localParticipant\",\n (s) => s.localParticipant,\n );\n const messages = useMeetingStore(sdk.state, \"chat\", (s) =>\n s.getChatMessages(),\n );\n\n const value = useMemo<MeetingContextValue>(() => {\n if (!sdkRef.current) {\n sdkRef.current = new VideoSDKCore({\n onError: (err) => {\n errorListeners.current.forEach((fn) => fn(err));\n },\n });\n }\n\n return {\n sdk,\n\n join: (joinConfig?: MeetingConfig) =>\n sdk.joinMeeting({\n ...config,\n ...joinConfig,\n }),\n leave: () => sdk.disconnect(),\n createRoom: sdk.createRoom.bind(sdk),\n getRoom: sdk.getRoom.bind(sdk),\n deleteRoom: sdk.deleteRoom.bind(sdk),\n toggleMic: sdk.toggleMic.bind(sdk),\n toggleCam: sdk.toggleCam.bind(sdk),\n startScreenShare: sdk.startScreenShare.bind(sdk),\n stopScreenShare: sdk.stopScreenShare.bind(sdk),\n sendMessage: sdk.sendChatMessage.bind(sdk),\n\n room: sdk.getMeeting(),\n localParticipant,\n participants,\n messages,\n presenterId,\n activeSpeakerIds,\n usePubSub: (topic: PubSubTopic) => {\n if (topic !== \"SECURE_CHAT\") {\n throw new Error(`Unsupported PubSub argument: \"${topic}\"`);\n }\n return {\n messages: sdk.state.getChatMessages(),\n publish: sdk.sendChatMessage.bind(sdk),\n };\n },\n approveJoinRequest: sdk.approveJoinRequest.bind(sdk),\n rejectJoinRequest: sdk.rejectJoinRequest.bind(sdk),\n startRecording: sdk.startRecording.bind(sdk),\n stopRecording: sdk.stopRecording.bind(sdk),\n getRecordingStatus: sdk.getRecordingStatus.bind(sdk),\n\n onError: (cb: (err: any) => void) => {\n errorListeners.current.add(cb);\n\n return () => {\n errorListeners.current.delete(cb);\n };\n },\n\n onEntryRequested: (cb: (err: any) => void) => {\n entryRequestListeners.current.add(cb);\n\n return () => {\n entryRequestListeners.current.delete(cb);\n };\n },\n onEntryResponded: (cb: (err: any) => void) => {\n entryResponseListeners.current.add(cb);\n\n return () => {\n entryResponseListeners.current.delete(cb);\n };\n },\n onMeetingLeft: (cb: () => void) => {\n meetingLeftListeners.current.add(cb);\n return () => {\n meetingLeftListeners.current.delete(cb);\n };\n },\n onTrackStateChanged: (cb: (track: any) => void) => {\n trackStateListeners.current.add(cb);\n return () => trackStateListeners.current.delete(cb);\n },\n onRecordingStarted: (cb: (recording: any) => void) => {\n recordingStartedListeners.current.add(cb);\n return () => recordingStartedListeners.current.delete(cb);\n },\n onRecordingStopped: (cb: (recording: any) => void) => {\n recordingStoppedListeners.current.add(cb);\n return () => recordingStoppedListeners.current.delete(cb);\n },\n onActiveSpeakersChanged: (cb) => {\n activeSpeakerListeners.current.add(cb);\n\n return () => {\n activeSpeakerListeners.current.delete(cb);\n };\n },\n };\n }, [config, sdk, localParticipant, participants, messages, presenterId]);\n\n return (\n <MeetingContext.Provider value={value}>{children}</MeetingContext.Provider>\n );\n};\n\nexport const useMeetingContext = () => {\n const ctx = useContext(MeetingContext);\n if (!ctx)\n throw new Error(\"useMeetingContext must be used inside <MeetingProvider>\");\n return ctx;\n};\n","/**\n * SDK Configuration for WebSocket and SFU connections\n * Updated to support the new Selective Forwarding Unit (SFU) architecture\n */\n\nexport interface SDKConfig {\n apiBase: string;\n wsBase: string;\n iceServers?: RTCIceServer[];\n connectionTimeout?: number;\n maxReconnectAttempts?: number;\n}\n\nexport const SDK_CONFIG: SDKConfig = {\n apiBase: \"https://sfu-server.duckdns.org/api\",\n wsBase: \"wss://sfu-server.duckdns.org/ws\",\n // Public STUN/TURN servers (fallback)\n iceServers: [\n { urls: [\"stun:stun.l.google.com:19302\"] },\n { urls: [\"stun:stun1.l.google.com:19302\"] },\n ],\n // Connection and reconnection settings\n connectionTimeout: 10000,\n maxReconnectAttempts: 5,\n};\n","type SpeakerState = {\n participantId: string;\n track: MediaStreamTrack;\n stream: MediaStream;\n source: MediaStreamAudioSourceNode;\n analyser: AnalyserNode;\n data: Float32Array<ArrayBuffer>;\n active: boolean;\n lastActiveAt: number;\n};\n\nexport interface ActiveSpeakerDetectorOptions {\n intervalMs?: number;\n threshold?: number;\n releaseThreshold?: number;\n releaseMs?: number;\n onActiveSpeakersChanged?: (participantIds: string[]) => void;\n}\n\nexport class ActiveSpeakerDetector {\n private audioContext: AudioContext | null = null;\n\n private speakers = new Map<string, SpeakerState>();\n\n private timer: ReturnType<typeof setInterval> | null = null;\n\n private readonly intervalMs: number;\n private readonly threshold: number;\n private readonly releaseThreshold: number;\n private readonly releaseMs: number;\n\n private onActiveSpeakersChanged: (participantIds: string[]) => void;\n\n private lastEmitted = \"\";\n\n constructor(options: ActiveSpeakerDetectorOptions = {}) {\n this.intervalMs = options.intervalMs ?? 100;\n this.threshold = options.threshold ?? 0.025;\n this.releaseThreshold = options.releaseThreshold ?? 0.015;\n this.releaseMs = options.releaseMs ?? 600;\n\n this.onActiveSpeakersChanged =\n options.onActiveSpeakersChanged ?? (() => {});\n }\n\n private ensureAudioContext(): AudioContext {\n if (!this.audioContext) {\n const AudioContextClass =\n window.AudioContext ||\n (\n window as typeof window & {\n webkitAudioContext?: typeof AudioContext;\n }\n ).webkitAudioContext;\n\n if (!AudioContextClass) {\n throw new Error(\"Web Audio API is not supported by this browser\");\n }\n\n this.audioContext = new AudioContextClass();\n }\n\n return this.audioContext;\n }\n\n async resume() {\n if (!this.audioContext) return;\n\n if (this.audioContext.state === \"suspended\") {\n try {\n await this.audioContext.resume();\n } catch {\n // Browser may require a user gesture.\n }\n }\n }\n\n addTrack(participantId: string, track: MediaStreamTrack) {\n if (!participantId) return;\n\n if (track.kind !== \"audio\") return;\n\n this.removeParticipant(participantId);\n const context = this.ensureAudioContext();\n const stream = new MediaStream([track]);\n const source = context.createMediaStreamSource(stream);\n const analyser = context.createAnalyser();\n\n analyser.fftSize = 512;\n analyser.smoothingTimeConstant = 0.65;\n analyser.minDecibels = -90;\n analyser.maxDecibels = -10;\n\n source.connect(analyser);\n\n const data = new Float32Array(analyser.fftSize);\n\n const state: SpeakerState = {\n participantId,\n track,\n stream,\n source,\n analyser,\n data,\n active: false,\n lastActiveAt: 0,\n };\n\n this.speakers.set(participantId, state);\n\n track.addEventListener(\n \"ended\",\n () => {\n this.removeParticipant(participantId);\n },\n { once: true },\n );\n\n this.start();\n\n void this.resume();\n }\n\n removeParticipant(participantId: string) {\n const state = this.speakers.get(participantId);\n\n if (!state) return;\n\n state.active = false;\n\n try {\n state.source.disconnect();\n } catch {\n // Already disconnected.\n }\n\n state.stream.getTracks().forEach((track) => {\n if (track !== state.track) {\n track.stop();\n }\n });\n\n this.speakers.delete(participantId);\n\n this.emitIfChanged();\n }\n\n removeTrack(track: MediaStreamTrack) {\n for (const [participantId, state] of this.speakers) {\n if (state.track === track) {\n this.removeParticipant(participantId);\n }\n }\n }\n\n clear() {\n for (const participantId of this.speakers.keys()) {\n this.removeParticipant(participantId);\n }\n\n this.speakers.clear();\n\n this.stop();\n\n this.emitIfChanged(true);\n }\n\n start() {\n if (this.timer) return;\n\n this.timer = setInterval(() => this.sample(), this.intervalMs);\n }\n\n stop() {\n if (!this.timer) return;\n\n clearInterval(this.timer);\n this.timer = null;\n }\n\n private sample() {\n const now = performance.now();\n\n for (const state of this.speakers.values()) {\n if (\n state.track.readyState !== \"live\" ||\n state.track.muted ||\n !state.track.enabled\n ) {\n if (state.active) {\n state.active = false;\n }\n\n continue;\n }\n\n state.analyser.getFloatTimeDomainData(state.data);\n\n let sumSquares = 0;\n\n for (let i = 0; i < state.data.length; i++) {\n const sample = state.data[i];\n sumSquares += sample * sample;\n }\n\n const rms = Math.sqrt(sumSquares / state.data.length);\n\n if (!state.active) {\n if (rms >= this.threshold) {\n state.active = true;\n state.lastActiveAt = now;\n }\n } else {\n if (rms >= this.releaseThreshold) {\n state.lastActiveAt = now;\n } else if (now - state.lastActiveAt >= this.releaseMs) {\n state.active = false;\n }\n }\n }\n\n this.emitIfChanged();\n }\n\n private getActiveSpeakerIds(): string[] {\n return Array.from(this.speakers.values())\n .filter((speaker) => speaker.active)\n .map((speaker) => speaker.participantId);\n }\n\n private emitIfChanged(force = false) {\n const ids = this.getActiveSpeakerIds().sort();\n\n const key = ids.join(\"|\");\n\n if (!force && key === this.lastEmitted) {\n return;\n }\n\n this.lastEmitted = key;\n\n this.onActiveSpeakersChanged(ids);\n }\n\n async destroy() {\n this.clear();\n\n if (this.audioContext) {\n try {\n await this.audioContext.close();\n } catch {\n // Ignore already closed context.\n }\n\n this.audioContext = null;\n }\n }\n}\n","import {\n ChatMessage,\n Listener,\n Participant,\n ParticipantMedia,\n StateScope,\n} from \"../types/meeting\";\n\ntype LocalParticipantPatch = {\n id?: string;\n name?: string;\n media?: Partial<ParticipantMedia>;\n};\n\nexport class MeetingState {\n participants = new Map<string, Participant>();\n localParticipant: Participant | null = null;\n localStream: MediaStream | null = null;\n chatMessages = new Map<string, ChatMessage>();\n presenterId: string | null = null;\n activeSpeakerIds = new Set<string>();\n\n private listeners = new Map<StateScope, Set<Listener>>();\n\n // ---- reactive system ----\n\n subscribe(scope: StateScope, fn: Listener): () => void {\n if (!this.listeners.has(scope)) {\n this.listeners.set(scope, new Set());\n }\n this.listeners.get(scope)!.add(fn);\n\n return () => {\n this.listeners.get(scope)?.delete(fn);\n };\n }\n\n notify(scope: StateScope) {\n this.listeners.get(scope)?.forEach((fn) => fn());\n }\n\n setPresenterId(id: string | null) {\n if (this.presenterId === id) return;\n this.presenterId = id;\n this.notify(\"presenter\");\n this.notify(\"participants\");\n }\n\n setActiveSpeakers(ids: string[]) {\n const next = new Set(ids);\n\n if (\n next.size === this.activeSpeakerIds.size &&\n [...next].every((id) => this.activeSpeakerIds.has(id))\n ) {\n return;\n }\n\n this.activeSpeakerIds = next;\n\n this.notify(\"activeSpeakers\");\n }\n\n // ---- participants ----\n\n addParticipant(p: Participant) {\n if (this.participants.has(p.id)) return false;\n // Fix: Immutable Map update\n const next = new Map(this.participants);\n next.set(p.id, p);\n this.participants = next;\n\n this.notify(\"participants\");\n return true;\n }\n\n removeParticipant(id: string) {\n // Fix: Immutable Map update\n const next = new Map(this.participants);\n next.delete(id);\n this.participants = next;\n\n this.notify(\"participants\");\n }\n\n updateParticipantMedia(\n id: string,\n patch: Partial<NonNullable<Participant[\"media\"]>>,\n ) {\n const p = this.participants.get(id);\n if (!p) return;\n\n const updated: Participant = {\n ...p,\n media: {\n stream: null,\n screenStream: undefined,\n cameraTrack: undefined,\n screenTrack: undefined,\n audioTrack: undefined,\n micEnabled: true,\n camEnabled: true,\n isScreenSharing: false,\n ...p.media,\n ...patch,\n },\n };\n\n // Keep your clean immutable map update\n const next = new Map(this.participants);\n next.set(id, updated);\n this.participants = next;\n\n this.notify(`participant:${id}`);\n this.notify(\"participants\");\n }\n\n updateLocalParticipant(patch: LocalParticipantPatch) {\n const prev = this.localParticipant;\n\n if (!prev) {\n this.localParticipant = {\n id: patch.id ?? \"\",\n name: patch.name ?? \"\",\n media: {\n stream: patch.media?.stream ?? null, // ◄ FIX: Capture the stream from the patch here\n screenStream: patch.media?.screenStream,\n cameraTrack: patch.media?.cameraTrack,\n screenTrack: patch.media?.screenTrack,\n audioTrack: patch.media?.audioTrack,\n micEnabled: patch.media?.micEnabled ?? true,\n camEnabled: patch.media?.camEnabled ?? true,\n isScreenSharing: patch.media?.isScreenSharing ?? false,\n },\n };\n\n this.notify(\"localParticipant\");\n return;\n }\n\n const prevMedia = prev.media ?? {\n stream: null,\n screenStream: undefined,\n cameraTrack: undefined,\n screenTrack: undefined,\n audioTrack: undefined,\n micEnabled: true,\n camEnabled: true,\n isScreenSharing: false,\n };\n\n const nextMedia: ParticipantMedia = {\n stream: patch.media?.stream ?? prevMedia.stream,\n screenStream: patch.media?.screenStream ?? prevMedia.screenStream,\n cameraTrack: patch.media?.cameraTrack ?? prevMedia.cameraTrack,\n screenTrack: patch.media?.screenTrack ?? prevMedia.screenTrack,\n audioTrack: patch.media?.audioTrack ?? prevMedia.audioTrack,\n micEnabled: patch.media?.micEnabled ?? prevMedia.micEnabled,\n camEnabled: patch.media?.camEnabled ?? prevMedia.camEnabled,\n isScreenSharing:\n patch.media?.isScreenSharing ?? prevMedia.isScreenSharing,\n };\n\n this.localParticipant = {\n ...prev,\n id: patch.id ?? prev.id,\n name: patch.name ?? prev.name,\n media: nextMedia,\n };\n\n this.notify(\"localParticipant\");\n }\n\n // ---- chat ----\n\n addChatMessage(msg: ChatMessage) {\n this.chatMessages.set(msg.id, msg);\n this.notify(\"chat\");\n }\n\n getChatMessages() {\n return Array.from(this.chatMessages.values()).sort(\n (a, b) => a.timestamp - b.timestamp,\n );\n }\n\n clearChat() {\n this.chatMessages.clear();\n this.notify(\"chat\");\n }\n\n // ---- helpers ----\n\n getParticipants() {\n return Array.from(this.participants.values());\n }\n\n getParticipant(id: string) {\n return this.participants.get(id) ?? null;\n }\n\n resetRemoteState() {\n this.participants.clear();\n this.chatMessages.clear();\n this.presenterId = null;\n this.activeSpeakerIds = new Set();\n this.notify(\"participants\");\n this.notify(\"chat\");\n this.notify(\"presenter\");\n this.notify(\"activeSpeakers\");\n }\n}\n","/**\n * DefComm SFU client.\n *\n * Signaling is authoritative for admission/session state.\n * WebRTC peer connections are transport state and are recreated only after a\n * successful join/resume. A transient WebSocket close therefore does NOT\n * destroy the local MediaStream or immediately declare the participant gone.\n */\n\nexport type SFUConnectionState =\n | \"idle\"\n | \"connecting\"\n | \"joining\"\n | \"waiting_approval\"\n | \"connected\"\n | \"reconnecting\"\n | \"leaving\"\n | \"disconnected\";\n\nexport interface TrackInfo {\n track_id: string;\n participant_id: string;\n kind: \"audio\" | \"video\";\n source?: \"camera\" | \"screen\" | \"audio\" | string;\n [key: string]: any;\n}\n\nexport interface ParticipantInfo {\n participant_id: string;\n user_metadata?: { name?: string; [key: string]: any };\n display_name?: string;\n [key: string]: any;\n}\n\nexport interface JoinPendingInfo {\n request_id: string;\n room_code?: string;\n message?: string;\n}\n\ninterface SFUClientOptions {\n apiBase?: string;\n wsBase?: string;\n userId?: string;\n onStateChange?: (state: SFUConnectionState) => void;\n onParticipantJoined?: (participant: ParticipantInfo) => void;\n onParticipantLeft?: (participant: string | ParticipantInfo) => void;\n onParticipantPresence?: (participantId: string, presence: string) => void;\n onTrackPublished?: (track: TrackInfo) => void;\n onTrackUnpublished?: (track: TrackInfo) => void;\n onRemoteTrack?: (\n track: MediaStreamTrack,\n stream: MediaStream,\n metadata: TrackInfo,\n ) => void;\n onConnected?: (payload: any, resumed: boolean) => void;\n onDisconnected?: () => void;\n onReconnecting?: (attempt: number) => void;\n onJoinPending?: (info: JoinPendingInfo) => void;\n onJoinApproved?: (requestId: string) => void;\n onJoinRejected?: (requestId: string, reason?: string) => void;\n onJoinRequested?: (request: any) => void;\n onScreenShareStarted?: (participantId: string, track?: TrackInfo) => void;\n onScreenShareStopped?: (participantId: string, trackId?: string) => void;\n onTrackStateChanged?: (track: TrackInfo) => void;\n onRecordingStarted?: (recording: { recording_id: string; started_at: string }) => void;\n onRecordingStopped?: (recording: { recording_id: string; stopped_at: string }) => void;\n onError?: (error: any) => void;\n autoSubscribe?: boolean;\n}\n\ntype PeerName = \"publisher\" | \"subscriber\";\ntype JoinWaiter = {\n resolve: (value: any) => void;\n reject: (error: any) => void;\n};\n\nexport class SFUClient {\n private apiBase: string;\n private wsBase: string;\n private userId: string;\n\n private ws: WebSocket | null = null;\n private publisher: RTCPeerConnection | null = null;\n private subscriber: RTCPeerConnection | null = null;\n\n private localStream: MediaStream | null = null;\n private screenStream: MediaStream | null = null;\n private videoSender: RTCRtpSender | null = null;\n private audioSender: RTCRtpSender | null = null;\n private screenSender: RTCRtpSender | null = null;\n\n private iceServers: RTCIceServer[] = [];\n private requestId = 0;\n private publisherRevision = 0;\n private currentParticipantId: string | null = null;\n private token: string | null = null;\n private room: string | null = null;\n private resumeToken: string | null = null;\n private pendingJoinRequestId: string | null = null;\n private joinOptions: {\n displayName?: string;\n avatarUrl?: string;\n } = {};\n\n private state: SFUConnectionState = \"idle\";\n private intentionalClose = false;\n private leaveAcknowledged = false;\n private joiningWithResume = false;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private reconnectAttempt = 0;\n private maxReconnectAttempts = 8;\n private reconnectBaseMs = 750;\n private joinWaiter: JoinWaiter | null = null;\n\n private pendingIce: Record<PeerName, RTCIceCandidateInit[]> = {\n publisher: [],\n subscriber: [],\n };\n\n private subscriberNegotiating = false;\n private offerQueue: any[] = [];\n private subscriptionQueue: string[] = [];\n private subscriptionRunning = false;\n private subscriptionWaiters: Array<{\n resolve: () => void;\n reject: (error: any) => void;\n }> = [];\n\n private subscribedTracks = new Set<string>();\n private trackMetadata = new Map<string, TrackInfo>();\n private participants = new Map<string, ParticipantInfo>();\n private remoteStreams = new Map<string, MediaStream>();\n private trackToParticipant = new Map<string, string>();\n private trackToSource = new Map<string, string>();\n private localTrackIds = new Map<\"audio\" | \"camera\" | \"screen\", string>();\n\n private subscriberStatsTimer: ReturnType<typeof setInterval> | null = null;\n\n private onStateChange: (state: SFUConnectionState) => void;\n private onParticipantJoined: (p: ParticipantInfo) => void;\n private onParticipantLeft: (p: string | ParticipantInfo) => void;\n private onParticipantPresence: (id: string, presence: string) => void;\n private onTrackPublished: (t: TrackInfo) => void;\n private onTrackUnpublished: (t: TrackInfo) => void;\n private onRemoteTrack: (\n t: MediaStreamTrack,\n s: MediaStream,\n m: TrackInfo,\n ) => void;\n private onConnected: (p: any, resumed: boolean) => void;\n private onDisconnected: () => void;\n private onReconnecting: (attempt: number) => void;\n private onJoinPending: (info: JoinPendingInfo) => void;\n private onJoinApproved: (requestId: string) => void;\n private onJoinRejected: (requestId: string, reason?: string) => void;\n private onJoinRequested: (request: any) => void;\n private onScreenShareStarted: (participantId: string, track?: TrackInfo) => void;\n private onScreenShareStopped: (participantId: string, trackId?: string) => void;\n private onTrackStateChanged: (track: TrackInfo) => void;\n private onRecordingStarted: (recording: { recording_id: string; started_at: string }) => void;\n private onRecordingStopped: (recording: { recording_id: string; stopped_at: string }) => void;\n private onError: (e: any) => void;\n private autoSubscribe: boolean;\n\n constructor(options: SFUClientOptions = {}) {\n this.apiBase = options.apiBase || \"https://api.example.com/api\";\n this.wsBase = options.wsBase || \"wss://api.example.com/ws\";\n this.userId = options.userId || this.createId();\n\n this.onStateChange = options.onStateChange || (() => {});\n this.onParticipantJoined = options.onParticipantJoined || (() => {});\n this.onParticipantLeft = options.onParticipantLeft || (() => {});\n this.onParticipantPresence = options.onParticipantPresence || (() => {});\n this.onTrackPublished = options.onTrackPublished || (() => {});\n this.onTrackUnpublished = options.onTrackUnpublished || (() => {});\n this.onRemoteTrack = options.onRemoteTrack || (() => {});\n this.onConnected = options.onConnected || (() => {});\n this.onDisconnected = options.onDisconnected || (() => {});\n this.onReconnecting = options.onReconnecting || (() => {});\n this.onJoinPending = options.onJoinPending || (() => {});\n this.onJoinApproved = options.onJoinApproved || (() => {});\n this.onJoinRejected = options.onJoinRejected || (() => {});\n this.onJoinRequested = options.onJoinRequested || (() => {});\n this.onScreenShareStarted = options.onScreenShareStarted || (() => {});\n this.onScreenShareStopped = options.onScreenShareStopped || (() => {});\n this.onTrackStateChanged = options.onTrackStateChanged || (() => {});\n this.onRecordingStarted = options.onRecordingStarted || (() => {});\n this.onRecordingStopped = options.onRecordingStopped || (() => {});\n this.onError = options.onError || console.error;\n this.autoSubscribe = options.autoSubscribe !== false;\n }\n\n private createId(): string {\n return typeof crypto !== \"undefined\" && crypto.randomUUID\n ? crypto.randomUUID()\n : `id_${Math.random().toString(36).slice(2)}_${Date.now()}`;\n }\n\n private resumeStorageKey(roomCode: string) {\n return `defcomm:sfu:resume:${roomCode}`;\n }\n\n private loadResumeToken(roomCode: string): string | null {\n try {\n return localStorage.getItem(this.resumeStorageKey(roomCode));\n } catch {\n return null;\n }\n }\n\n private saveResumeToken(roomCode: string, token: string) {\n try {\n localStorage.setItem(this.resumeStorageKey(roomCode), token);\n } catch {\n // Storage can be unavailable in private/SSR environments.\n }\n }\n\n private clearResumeToken(roomCode: string | null) {\n if (!roomCode) return;\n try {\n localStorage.removeItem(this.resumeStorageKey(roomCode));\n } catch {\n // ignore\n }\n }\n\n private setState(next: SFUConnectionState) {\n if (this.state === next) return;\n this.state = next;\n this.onStateChange(next);\n }\n\n getConnectionState(): SFUConnectionState {\n return this.state;\n }\n\n getParticipantId(): string | null {\n return this.currentParticipantId;\n }\n\n getResumeToken(): string | null {\n return this.resumeToken;\n }\n\n getLocalStream(): MediaStream | null {\n return this.localStream;\n }\n\n getScreenStream(): MediaStream | null {\n return this.screenStream;\n }\n\n setLocalStream(stream: MediaStream | null) {\n this.localStream = stream;\n }\n\n private nextRequestId(): string {\n return (++this.requestId).toString();\n }\n\n private async request(url: string, options: RequestInit = {}) {\n const res = await fetch(url, {\n headers: { \"Content-Type\": \"application/json\" },\n ...options,\n });\n\n if (!res.ok) {\n let body: any = {};\n try {\n body = await res.json();\n } catch {\n // ignore non-json error bodies\n }\n throw new Error(body.message || res.statusText);\n }\n\n return res.json();\n }\n\n async createRoom(input: {\n name: string;\n description?: string;\n capacity?: number;\n is_private?: boolean;\n }) {\n return this.request(`${this.apiBase}/rooms`, {\n method: \"POST\",\n body: JSON.stringify({\n name: input.name,\n description: input.description ?? \"\",\n capacity: input.capacity ?? 20,\n is_private: input.is_private ?? false,\n }),\n });\n }\n\n async getRoom(roomCode: string) {\n return this.request(`${this.apiBase}/rooms/${encodeURIComponent(roomCode)}`);\n }\n\n async deleteRoom(roomCode: string) {\n return this.request(`${this.apiBase}/rooms/${encodeURIComponent(roomCode)}`, {\n method: \"DELETE\",\n });\n }\n\n async getToken(\n roomCode: string,\n options: {\n displayName?: string;\n avatarUrl?: string;\n userId?: string;\n } = {},\n ) {\n const nextRoom = roomCode.trim();\n if (this.room && this.room !== nextRoom) {\n this.resumeToken = null;\n }\n\n this.room = nextRoom;\n this.joinOptions = {\n displayName: options.displayName,\n avatarUrl: options.avatarUrl,\n };\n if (options.userId) this.userId = options.userId;\n if (!this.resumeToken) {\n this.resumeToken = this.loadResumeToken(this.room);\n }\n\n const data = await this.request(`${this.apiBase}/token`, {\n method: \"POST\",\n body: JSON.stringify({\n room_code: this.room,\n user_id: this.userId,\n display_name: options.displayName,\n avatar_url: options.avatarUrl,\n }),\n });\n\n this.token = data?.token;\n if (!this.token) throw new Error(\"Token endpoint returned no token\");\n\n return this.connect(this.token, this.joinOptions);\n }\n\n private async refreshAccessToken() {\n if (!this.room) throw new Error(\"Cannot refresh token without a room\");\n\n const data = await this.request(`${this.apiBase}/token`, {\n method: \"POST\",\n body: JSON.stringify({\n room_code: this.room,\n user_id: this.userId,\n display_name: this.joinOptions.displayName,\n avatar_url: this.joinOptions.avatarUrl,\n }),\n });\n\n if (!data?.token) throw new Error(\"Token refresh returned no token\");\n this.token = data.token;\n return this.token;\n }\n\n private connect(token: string, options: any = {}) {\n this.token = token;\n this.intentionalClose = false;\n this.setState(this.reconnectAttempt > 0 ? \"reconnecting\" : \"connecting\");\n\n return new Promise<void>((resolve, reject) => {\n this.joinWaiter = { resolve, reject };\n this.openWebSocket(options);\n });\n }\n\n private openWebSocket(options: any = {}) {\n if (!this.token || !this.room) {\n const error = new Error(\"Cannot connect without token and room\");\n this.failJoin(error);\n return;\n }\n\n if (this.ws) {\n try {\n this.ws.onclose = null;\n this.ws.close();\n } catch {\n // ignore\n }\n }\n\n const ws = new WebSocket(\n `${this.wsBase}?access_token=${encodeURIComponent(this.token)}`,\n );\n this.ws = ws;\n\n ws.onopen = () => {\n this.setState(\"joining\");\n this.joiningWithResume = Boolean(this.resumeToken);\n\n const joinPayload: any = {\n token: this.token,\n room_code: this.room,\n resume_token: this.resumeToken,\n display_name: options.displayName,\n avatar_url: options.avatarUrl,\n };\n\n // After approval the Rust server requires the original pending request id.\n if (this.pendingJoinRequestId) {\n this.send({\n type: \"join\",\n request_id: this.pendingJoinRequestId,\n payload: joinPayload,\n });\n } else {\n this.send({ type: \"join\", payload: joinPayload });\n }\n };\n\n ws.onerror = (event) => {\n this.onError(event);\n };\n\n ws.onclose = () => {\n if (this.ws !== ws) return;\n this.ws = null;\n\n if (this.intentionalClose || this.state === \"leaving\") {\n this.setState(\"disconnected\");\n this.onDisconnected();\n return;\n }\n\n // Keep MediaStreams and logical participant state alive.\n this.setState(\"reconnecting\");\n this.onDisconnected();\n this.scheduleReconnect();\n };\n\n ws.onmessage = async (event) => {\n if (this.ws !== ws) return;\n try {\n const message = JSON.parse(event.data);\n await this.handleServerMessage(message);\n } catch (error) {\n this.onError(error);\n }\n };\n }\n\n private scheduleReconnect() {\n if (this.reconnectTimer || this.intentionalClose) return;\n if (this.reconnectAttempt >= this.maxReconnectAttempts) {\n this.setState(\"disconnected\");\n this.failJoin(new Error(\"SFU reconnect attempts exhausted\"));\n return;\n }\n\n this.reconnectAttempt += 1;\n const delay = Math.min(\n 15000,\n this.reconnectBaseMs * Math.pow(2, this.reconnectAttempt - 1),\n );\n\n this.onReconnecting(this.reconnectAttempt);\n\n this.reconnectTimer = setTimeout(async () => {\n this.reconnectTimer = null;\n try {\n await this.refreshAccessToken();\n this.openWebSocket(this.joinOptions);\n } catch (error) {\n this.onError(error);\n this.scheduleReconnect();\n }\n }, delay);\n }\n\n private failJoin(error: any) {\n if (this.joinWaiter) {\n const waiter = this.joinWaiter;\n this.joinWaiter = null;\n waiter.reject(error);\n }\n }\n\n private resolveJoin(value: any) {\n if (!this.joinWaiter) return;\n const waiter = this.joinWaiter;\n this.joinWaiter = null;\n waiter.resolve(value);\n }\n\n private async handleServerMessage(message: any) {\n const type = message?.type;\n const payload = message?.payload || {};\n\n switch (type) {\n case \"joined\": {\n await this.handleJoined(payload);\n break;\n }\n\n case \"left\": {\n this.leaveAcknowledged = true;\n break;\n }\n\n case \"join_pending\": {\n const requestId = payload.request_id || message.request_id;\n if (!requestId) throw new Error(\"join_pending has no request_id\");\n\n this.pendingJoinRequestId = requestId;\n this.setState(\"waiting_approval\");\n this.onJoinPending({\n request_id: requestId,\n room_code: payload.room_code || this.room || undefined,\n message: payload.message,\n });\n break;\n }\n\n case \"join_approved\": {\n const requestId = payload.request_id || message.request_id;\n if (!requestId) break;\n this.pendingJoinRequestId = requestId;\n this.onJoinApproved(requestId);\n\n // Approval is a direct signal to the waiting session. Continue the join\n // with the same request id; the Rust Room layer performs the admission.\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.setState(\"joining\");\n this.send({\n type: \"join\",\n request_id: requestId,\n payload: {\n token: this.token,\n room_code: this.room,\n resume_token: this.resumeToken,\n display_name: this.joinOptions.displayName,\n avatar_url: this.joinOptions.avatarUrl,\n },\n });\n }\n break;\n }\n\n case \"join_rejected\": {\n const requestId = payload.request_id || message.request_id;\n const reason = payload.reason;\n this.onJoinRejected(requestId, reason);\n this.pendingJoinRequestId = null;\n this.intentionalClose = true;\n this.failJoin(new Error(reason || \"Join request rejected\"));\n break;\n }\n\n case \"join_requested\":\n case \"join_request\": {\n this.onJoinRequested(payload.request || payload);\n break;\n }\n\n case \"publish_answer\": {\n if (!this.publisher) break;\n await this.publisher.setRemoteDescription({\n type: \"answer\",\n sdp: payload.sdp,\n });\n await this.flushPendingIce(\"publisher\");\n break;\n }\n\n case \"subscribe_offer\": {\n this.offerQueue.push(payload);\n if (!this.subscriberNegotiating) await this.processOfferQueue();\n break;\n }\n\n case \"ice_candidate\":\n case \"publisher_ice_candidate\":\n case \"subscriber_ice_candidate\": {\n const candidatePayload = {\n ...payload,\n peer:\n payload.peer ||\n (type === \"publisher_ice_candidate\" ? \"publisher\" : \"subscriber\"),\n };\n await this.handleIce(candidatePayload);\n break;\n }\n\n case \"participant_joined\": {\n const participant = payload.participant || payload;\n const participantId =\n participant?.participant_id || payload.participant_id;\n if (!participantId || participantId === this.currentParticipantId) break;\n\n if (participant) this.participants.set(participantId, participant);\n this.onParticipantJoined(participant);\n break;\n }\n\n case \"participant_left\": {\n const participantId = payload.participant_id;\n if (!participantId) break;\n this.participants.delete(participantId);\n this.removeRemoteParticipant(participantId);\n this.onParticipantLeft(participantId);\n break;\n }\n\n case \"participant_presence\":\n case \"participant_presence_changed\": {\n const participantId = payload.participant_id;\n const presence = payload.presence;\n if (participantId && presence) {\n this.onParticipantPresence(participantId, String(presence));\n }\n break;\n }\n\n case \"track_published\": {\n const track: TrackInfo = payload.track || payload;\n if (!track?.track_id) break;\n this.rememberTrack(track);\n\n if (track.participant_id === this.currentParticipantId) {\n if (track.source === \"audio\") {\n this.localTrackIds.set(\"audio\", track.track_id);\n const muted = !(this.localStream?.getAudioTracks()[0]?.enabled ?? true);\n this.send({ type: \"track_state\", payload: { track_id: track.track_id, muted } });\n }\n if (track.source === \"camera\") {\n this.localTrackIds.set(\"camera\", track.track_id);\n const muted = !(this.localStream?.getVideoTracks()[0]?.enabled ?? true);\n this.send({ type: \"track_state\", payload: { track_id: track.track_id, muted } });\n }\n if (track.source === \"screen\") this.localTrackIds.set(\"screen\", track.track_id);\n break;\n }\n\n this.onTrackPublished(track);\n if (this.autoSubscribe) await this.subscribe(track.track_id);\n break;\n }\n\n case \"track_unpublished\": {\n const trackId = payload.track_id || payload.track?.track_id;\n if (!trackId) break;\n const track =\n this.trackMetadata.get(trackId) ||\n ({\n track_id: trackId,\n participant_id: this.trackToParticipant.get(trackId) || \"\",\n source: this.trackToSource.get(trackId),\n kind: \"video\",\n } as TrackInfo);\n\n this.trackMetadata.delete(trackId);\n this.subscribedTracks.delete(trackId);\n this.trackToParticipant.delete(trackId);\n this.trackToSource.delete(trackId);\n\n for (const [source, localId] of this.localTrackIds) {\n if (localId === trackId) this.localTrackIds.delete(source);\n }\n\n if (track.participant_id === this.currentParticipantId) break;\n this.onTrackUnpublished(track);\n break;\n }\n\n case \"track_state_changed\": {\n const trackId = payload.track_id || payload.track?.track_id;\n if (!trackId) break;\n\n const existing = this.trackMetadata.get(trackId);\n const track: TrackInfo = {\n ...(existing || {}),\n ...(payload.track || {}),\n track_id: trackId,\n participant_id:\n payload.participant_id ||\n existing?.participant_id ||\n payload.track?.participant_id,\n kind:\n payload.kind ||\n payload.track?.kind ||\n existing?.kind ||\n \"video\",\n source:\n payload.source ||\n payload.track?.source ||\n existing?.source,\n muted: Boolean(payload.muted),\n };\n\n if (!track.participant_id) break;\n this.rememberTrack(track);\n this.onTrackStateChanged(track);\n break;\n }\n\n case \"subscription_updated\": {\n // Authoritative acknowledgement of the current subscriber set.\n break;\n }\n\n case \"recording_started\": {\n this.onRecordingStarted({\n recording_id: payload.recording_id,\n started_at: payload.started_at,\n });\n break;\n }\n\n case \"recording_stopped\": {\n this.onRecordingStopped({\n recording_id: payload.recording_id,\n stopped_at: payload.stopped_at,\n });\n break;\n }\n\n case \"reconnecting\": {\n this.setState(\"reconnecting\");\n break;\n }\n\n case \"screen_share_started\": {\n const participantId = payload.participant_id;\n const track = payload.track as TrackInfo | undefined;\n if (track) this.rememberTrack(track);\n if (participantId) this.onScreenShareStarted(participantId, track);\n break;\n }\n\n case \"screen_share_stopped\": {\n const participantId = payload.participant_id;\n const stream = participantId ? this.remoteStreams.get(participantId) : null;\n const trackId = payload.track_id;\n\n if (stream) {\n for (const track of stream.getVideoTracks()) {\n const source = this.trackToSource.get(this.normalizeRemoteTrackId(track.id));\n if (!trackId || this.normalizeRemoteTrackId(track.id) === String(trackId) || source === \"screen\") {\n stream.removeTrack(track);\n track.stop();\n }\n }\n }\n\n this.onScreenShareStopped(participantId, trackId);\n break;\n }\n\n case \"error\": {\n const error = new Error(payload.message || \"SFU signaling error\");\n this.onError(error);\n if (this.state === \"joining\" || this.state === \"waiting_approval\") {\n this.failJoin(error);\n }\n break;\n }\n\n default:\n // Unknown messages must not tear down the signaling state machine.\n console.debug(\"[SFU] Ignoring unknown server message\", message);\n }\n }\n\n private rememberTrack(track: TrackInfo) {\n this.trackMetadata.set(track.track_id, track);\n this.trackToParticipant.set(track.track_id, track.participant_id);\n if (track.source) this.trackToSource.set(track.track_id, track.source);\n }\n\n private async handleJoined(payload: any) {\n const resumed = this.joiningWithResume;\n this.joiningWithResume = false;\n\n this.iceServers = payload.ice_servers || this.iceServers || [];\n this.currentParticipantId = payload.participant_id;\n this.resumeToken = payload.resume_token || payload.resumeToken || this.resumeToken;\n if (this.room && this.resumeToken) {\n this.saveResumeToken(this.room, this.resumeToken);\n }\n this.pendingJoinRequestId = null;\n this.reconnectAttempt = 0;\n\n this.participants.clear();\n this.trackMetadata.clear();\n this.trackToParticipant.clear();\n this.trackToSource.clear();\n this.localTrackIds.clear();\n\n for (const participant of payload.participants || []) {\n if (participant?.participant_id) {\n this.participants.set(participant.participant_id, participant);\n }\n }\n\n for (const track of payload.tracks || []) {\n if (track?.track_id) this.rememberTrack(track);\n }\n\n await this.initializePeerConnections();\n this.setState(\"connected\");\n this.onConnected(payload, resumed);\n\n for (const participant of this.participants.values()) {\n if (participant.participant_id !== this.currentParticipantId) {\n this.onParticipantJoined(participant);\n }\n }\n\n // A reconnect/resume needs a fresh publisher negotiation and subscription\n // reconciliation because the WebSocket transport was replaced.\n if (this.localStream) {\n await this.publishExistingTracks();\n }\n\n if (this.autoSubscribe) {\n const trackIds = [...this.trackMetadata.values()]\n .filter((track) => track.participant_id !== this.currentParticipantId)\n .map((track) => track.track_id);\n if (trackIds.length) await this.subscribeMultiple(trackIds);\n }\n\n this.resolveJoin(payload);\n }\n\n private async initializePeerConnections() {\n this.closePeerConnectionsOnly();\n this.publisherRevision = 0;\n\n const config: RTCConfiguration = { iceServers: this.iceServers };\n this.publisher = new RTCPeerConnection(config);\n this.subscriber = new RTCPeerConnection(config);\n\n this.publisher.onicecandidate = (event) => {\n if (event.candidate) this.sendCandidate(\"publisher\", event.candidate);\n };\n\n this.subscriber.onicecandidate = (event) => {\n if (event.candidate) this.sendCandidate(\"subscriber\", event.candidate);\n };\n\n this.publisher.onconnectionstatechange = () => {\n const state = this.publisher?.connectionState;\n if (state === \"failed\") {\n this.onError(new Error(\"Publisher PeerConnection failed\"));\n }\n };\n\n this.subscriber.onconnectionstatechange = () => {\n const state = this.subscriber?.connectionState;\n if (state === \"failed\") {\n this.onError(new Error(\"Subscriber PeerConnection failed\"));\n }\n };\n\n this.subscriber.ontrack = (event) => {\n void this.handleRemoteTrack(event);\n };\n\n if (!this.subscriberStatsTimer) {\n this.subscriberStatsTimer = setInterval(() => {\n void this.logSubscriberVideoStats();\n }, 3000);\n }\n }\n\n private async handleRemoteTrack(event: RTCTrackEvent) {\n const stream = event.streams?.[0] || null;\n const metadata = this.resolveRemoteTrackMetadata(event.track, stream);\n\n if (!metadata?.participant_id) {\n this.onError(\n new Error(\n `Remote ${event.track.kind} track ${event.track.id} has no SFU participant mapping`,\n ),\n );\n return;\n }\n\n const participantId = metadata.participant_id;\n let remoteStream = this.remoteStreams.get(participantId);\n\n if (!remoteStream) {\n remoteStream = new MediaStream();\n this.remoteStreams.set(participantId, remoteStream);\n }\n\n // Camera/audio use one participant stream. Screen tracks are kept separate.\n const source = metadata.source || this.trackToSource.get(metadata.track_id);\n if (source === \"screen\") {\n for (const existing of remoteStream.getVideoTracks()) {\n if (existing.id !== event.track.id && this.trackToSource.get(existing.id) === \"screen\") {\n remoteStream.removeTrack(existing);\n existing.stop();\n }\n }\n } else {\n for (const existing of remoteStream.getTracks()) {\n if (existing.kind === event.track.kind && existing.id !== event.track.id) {\n remoteStream.removeTrack(existing);\n existing.stop();\n }\n }\n }\n\n if (!remoteStream.getTracks().some((track) => track.id === event.track.id)) {\n remoteStream.addTrack(event.track);\n }\n\n event.track.onended = () => {\n try {\n remoteStream?.removeTrack(event.track);\n } catch {\n // ignore\n }\n };\n\n if (source === \"screen\") {\n this.onScreenShareStarted(participantId, metadata);\n }\n\n this.onRemoteTrack(event.track, remoteStream, metadata);\n }\n\n private normalizeRemoteTrackId(browserTrackId: string): string {\n return browserTrackId?.startsWith(\"track-\")\n ? browserTrackId.slice(\"track-\".length)\n : browserTrackId;\n }\n\n private resolveRemoteTrackMetadata(\n track: MediaStreamTrack,\n stream: MediaStream | null,\n ): TrackInfo | null {\n const sfuTrackId = this.normalizeRemoteTrackId(track.id);\n const exact = this.trackMetadata.get(sfuTrackId);\n if (exact) return exact;\n\n const byTrackId = this.trackMetadata.get(track.id);\n if (byTrackId) return byTrackId;\n\n // Some WebRTC stacks expose a browser-generated receiver track id. The\n // SFU metadata still gives us the authoritative ownership mapping.\n const matching = [...this.trackMetadata.values()].find(\n (entry) => entry.kind === track.kind,\n );\n if (matching) return matching;\n\n if (stream?.id) {\n const participant = this.participants.get(stream.id);\n if (participant) {\n return (\n [...this.trackMetadata.values()].find(\n (entry) => entry.participant_id === participant.participant_id && entry.kind === track.kind,\n ) || null\n );\n }\n }\n\n return null;\n }\n\n private sendCandidate(peer: PeerName, candidate: RTCIceCandidate) {\n this.send({\n type: \"ice_candidate\",\n payload: {\n peer,\n candidate: candidate.candidate,\n sdp_mid: candidate.sdpMid,\n sdp_mline_index: candidate.sdpMLineIndex,\n username_fragment: candidate.usernameFragment,\n },\n });\n }\n\n private async handleIce(payload: any) {\n const peer: PeerName = payload.peer === \"publisher\" ? \"publisher\" : \"subscriber\";\n const pc = peer === \"publisher\" ? this.publisher : this.subscriber;\n\n const candidate: RTCIceCandidateInit = {\n candidate: payload.candidate,\n sdpMid: payload.sdp_mid ?? payload.sdpMid ?? null,\n sdpMLineIndex: payload.sdp_mline_index ?? payload.sdpMLineIndex ?? null,\n usernameFragment: payload.username_fragment ?? payload.usernameFragment ?? null,\n };\n\n if (!pc || !pc.remoteDescription) {\n this.pendingIce[peer].push(candidate);\n return;\n }\n\n try {\n await pc.addIceCandidate(candidate);\n } catch (error) {\n this.onError(new Error(`Failed to add ${peer} ICE candidate: ${String(error)}`));\n }\n }\n\n private async flushPendingIce(peer: PeerName) {\n const pc = peer === \"publisher\" ? this.publisher : this.subscriber;\n if (!pc || !pc.remoteDescription) return;\n\n const queue = this.pendingIce[peer];\n while (queue.length) {\n const candidate = queue.shift()!;\n try {\n await pc.addIceCandidate(candidate);\n } catch (error) {\n this.onError(new Error(`Failed to add queued ${peer} ICE candidate: ${String(error)}`));\n }\n }\n }\n\n private async processOfferQueue() {\n if (!this.subscriber) return;\n\n while (this.offerQueue.length) {\n if (this.subscriberNegotiating) return;\n this.subscriberNegotiating = true;\n const offer = this.offerQueue.shift();\n\n try {\n await this.subscriber.setRemoteDescription({\n type: \"offer\",\n sdp: offer.sdp,\n });\n await this.flushPendingIce(\"subscriber\");\n\n const answer = await this.subscriber.createAnswer();\n await this.subscriber.setLocalDescription(answer);\n\n this.send({\n type: \"subscribe_answer\",\n payload: {\n revision: offer.revision,\n sdp: answer.sdp,\n },\n });\n\n const waiters = this.subscriptionWaiters.splice(0);\n waiters.forEach((w) => w.resolve());\n } catch (error) {\n const waiters = this.subscriptionWaiters.splice(0);\n waiters.forEach((w) => w.reject(error));\n this.onError(new Error(`Failed to process subscriber offer: ${String(error)}`));\n } finally {\n this.subscriberNegotiating = false;\n }\n }\n }\n\n private async subscribe(trackId: string) {\n if (!trackId || this.subscribedTracks.has(trackId)) return;\n this.subscribedTracks.add(trackId);\n this.subscriptionQueue.push(trackId);\n if (!this.subscriptionRunning) await this.processSubscriptionQueue();\n }\n\n private async subscribeMultiple(trackIds: string[]) {\n const uniqueIds = [...new Set(trackIds.filter(Boolean))].filter(\n (id) => !this.subscribedTracks.has(id),\n );\n if (!uniqueIds.length || !this.isSocketOpen()) return;\n\n uniqueIds.forEach((id) => this.subscribedTracks.add(id));\n return new Promise<void>((resolve, reject) => {\n this.subscriptionWaiters.push({ resolve, reject });\n this.send({\n type: \"subscribe\",\n payload: { track_ids: uniqueIds },\n });\n });\n }\n\n private async processSubscriptionQueue() {\n this.subscriptionRunning = true;\n try {\n while (this.subscriptionQueue.length) {\n const trackId = this.subscriptionQueue.shift()!;\n if (!this.isSocketOpen()) {\n this.subscribedTracks.delete(trackId);\n continue;\n }\n\n await new Promise<void>((resolve, reject) => {\n this.subscriptionWaiters.push({ resolve, reject });\n this.send({\n type: \"subscribe\",\n payload: { track_ids: [trackId] },\n });\n });\n }\n } finally {\n this.subscriptionRunning = false;\n }\n }\n\n async publish({ audio = true, video = true } = {}) {\n if (!this.publisher) throw new Error(\"Publisher PeerConnection is not initialized\");\n\n if (!this.localStream) {\n this.localStream = await navigator.mediaDevices.getUserMedia({ audio, video });\n }\n\n await this.publishExistingTracks(audio, video);\n return this.localStream;\n }\n\n private async publishExistingTracks(audio = true, video = true) {\n if (!this.publisher || !this.localStream) return;\n\n // Recreated publisher PCs start with no senders. Never duplicate senders on\n // the same PC.\n this.audioSender = null;\n this.videoSender = null;\n\n for (const track of this.localStream.getTracks()) {\n if (track.kind === \"audio\" && !audio) continue;\n if (track.kind === \"video\" && !video) continue;\n\n const sender = this.publisher.addTrack(track, this.localStream);\n if (track.kind === \"audio\") this.audioSender = sender;\n if (track.kind === \"video\") this.videoSender = sender;\n }\n\n if (this.screenStream?.getVideoTracks()[0]) {\n const screenTrack = this.screenStream.getVideoTracks()[0];\n this.screenSender = this.publisher.addTrack(screenTrack, this.screenStream);\n }\n\n if (!this.publisher.getSenders().length) return;\n\n const offer = await this.publisher.createOffer();\n await this.publisher.setLocalDescription(offer);\n\n this.send({\n type: \"publish_offer\",\n payload: {\n revision: ++this.publisherRevision,\n sdp: offer.sdp,\n },\n });\n\n if (this.screenStream?.getVideoTracks()[0]) {\n this.send({ type: \"start_screen_share\" });\n }\n }\n\n async shareScreen() {\n if (!this.publisher) throw new Error(\"Publisher PeerConnection is not initialized\");\n if (this.screenStream) return this.screenStream;\n\n this.screenStream = await navigator.mediaDevices.getDisplayMedia({ video: true });\n const screenTrack = this.screenStream.getVideoTracks()[0];\n if (!screenTrack) throw new Error(\"Screen share returned no video track\");\n\n this.screenSender = this.publisher.addTrack(screenTrack, this.screenStream);\n\n const offer = await this.publisher.createOffer();\n await this.publisher.setLocalDescription(offer);\n this.send({\n type: \"publish_offer\",\n payload: {\n revision: ++this.publisherRevision,\n sdp: offer.sdp,\n },\n });\n\n this.send({ type: \"start_screen_share\" });\n\n screenTrack.onended = () => {\n void this.stopScreenShare();\n };\n\n return this.screenStream;\n }\n\n async stopScreenShare() {\n if (!this.screenStream) return;\n\n const screenTrack = this.screenStream.getVideoTracks()[0];\n if (screenTrack) screenTrack.onended = null;\n\n if (this.screenSender && this.publisher) {\n try {\n this.publisher.removeTrack(this.screenSender);\n } catch {\n // ignore a sender already detached by the browser\n }\n this.screenSender = null;\n\n // Removing the sender changes the publisher SDP and must be negotiated.\n try {\n const offer = await this.publisher.createOffer();\n await this.publisher.setLocalDescription(offer);\n this.send({\n type: \"publish_offer\",\n payload: {\n revision: ++this.publisherRevision,\n sdp: offer.sdp,\n },\n });\n\n this.send({ type: \"stop_screen_share\" });\n } catch (error) {\n this.onError(error);\n }\n }\n\n this.screenStream.getTracks().forEach((track) => track.stop());\n this.screenStream = null;\n }\n\n muteAudio(muted: boolean) {\n this.localStream?.getAudioTracks().forEach((track) => {\n track.enabled = !muted;\n });\n\n const trackId = this.localTrackIds.get(\"audio\");\n if (trackId) {\n this.send({\n type: \"track_state\",\n payload: {\n track_id: trackId,\n muted,\n },\n });\n }\n }\n\n muteVideo(muted: boolean) {\n this.localStream?.getVideoTracks().forEach((track) => {\n track.enabled = !muted;\n });\n\n const trackId = this.localTrackIds.get(\"camera\");\n if (trackId) {\n this.send({\n type: \"track_state\",\n payload: {\n track_id: trackId,\n muted,\n },\n });\n }\n }\n\n async startRecording() {\n if (!this.send({ type: \"start_recording\" })) {\n throw new Error(\"SFU signaling is not connected\");\n }\n }\n\n async stopRecording() {\n if (!this.send({ type: \"stop_recording\" })) {\n throw new Error(\"SFU signaling is not connected\");\n }\n }\n\n async getRecordingStatus() {\n if (!this.room || !this.token) {\n throw new Error(\"SFU client is not connected\");\n }\n\n return this.request(\n `${this.apiBase}/rooms/${encodeURIComponent(this.room)}/recording`,\n {\n headers: {\n Authorization: `Bearer ${this.token}`,\n },\n },\n );\n }\n\n async approveJoinRequest(requestId: string) {\n if (!requestId) throw new Error(\"requestId is required\");\n if (!this.send({ type: \"approve_join\", payload: { request_id: requestId } })) {\n throw new Error(\"SFU signaling is not connected\");\n }\n }\n\n async rejectJoinRequest(requestId: string, reason?: string) {\n if (!requestId) throw new Error(\"requestId is required\");\n if (!this.send({ type: \"reject_join\", payload: { request_id: requestId, reason } })) {\n throw new Error(\"SFU signaling is not connected\");\n }\n }\n\n private isSocketOpen() {\n return this.ws?.readyState === WebSocket.OPEN;\n }\n\n private send(message: any) {\n if (!this.isSocketOpen()) return false;\n this.ws!.send(\n JSON.stringify({\n request_id: this.nextRequestId(),\n ...message,\n }),\n );\n return true;\n }\n\n private removeRemoteParticipant(participantId: string) {\n const stream = this.remoteStreams.get(participantId);\n if (stream) {\n stream.getTracks().forEach((track) => track.stop());\n this.remoteStreams.delete(participantId);\n }\n\n for (const [trackId, metadata] of this.trackMetadata) {\n if (metadata.participant_id === participantId) {\n this.trackMetadata.delete(trackId);\n this.subscribedTracks.delete(trackId);\n this.trackToParticipant.delete(trackId);\n this.trackToSource.delete(trackId);\n }\n }\n }\n\n async leave() {\n this.intentionalClose = true;\n this.setState(\"leaving\");\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n const roomCode = this.room;\n const ws = this.ws;\n this.leaveAcknowledged = false;\n\n if (ws?.readyState === WebSocket.OPEN) {\n await new Promise<void>((resolve) => {\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n resolve();\n };\n\n // The normal onmessage path remains authoritative. We only wait for\n // the server's `left` acknowledgement through a short polling window.\n const timeout = setTimeout(finish, 1200);\n\n const check = () => {\n if (this.leaveAcknowledged || this.ws !== ws) {\n clearTimeout(timeout);\n finish();\n return;\n }\n if (ws.readyState !== WebSocket.OPEN) {\n clearTimeout(timeout);\n finish();\n return;\n }\n setTimeout(check, 25);\n };\n\n ws.addEventListener(\"close\", () => {\n clearTimeout(timeout);\n finish();\n }, { once: true });\n\n this.send({ type: \"leave\" });\n check();\n });\n\n try {\n ws.close(1000, \"client_leave\");\n } catch {\n // ignore\n }\n }\n\n this.clearResumeToken(roomCode);\n this.cleanupAll();\n this.setState(\"disconnected\");\n }\n\n private closePeerConnectionsOnly() {\n if (this.publisher) {\n try { this.publisher.close(); } catch { /* ignore */ }\n this.publisher = null;\n }\n if (this.subscriber) {\n try { this.subscriber.close(); } catch { /* ignore */ }\n this.subscriber = null;\n }\n this.videoSender = null;\n this.audioSender = null;\n this.screenSender = null;\n this.pendingIce = { publisher: [], subscriber: [] };\n this.offerQueue = [];\n this.subscriberNegotiating = false;\n this.subscriptionQueue = [];\n this.subscriptionRunning = false;\n this.subscriptionWaiters.splice(0).forEach((w) => w.reject(new Error(\"PeerConnection recreated\")));\n this.subscribedTracks.clear();\n }\n\n private cleanupAll() {\n if (this.subscriberStatsTimer) {\n clearInterval(this.subscriberStatsTimer);\n this.subscriberStatsTimer = null;\n }\n\n this.closePeerConnectionsOnly();\n\n this.localStream?.getTracks().forEach((track) => track.stop());\n this.screenStream?.getTracks().forEach((track) => track.stop());\n this.localStream = null;\n this.screenStream = null;\n\n for (const stream of this.remoteStreams.values()) {\n stream.getTracks().forEach((track) => track.stop());\n }\n this.remoteStreams.clear();\n\n this.trackMetadata.clear();\n this.trackToParticipant.clear();\n this.trackToSource.clear();\n this.localTrackIds.clear();\n this.participants.clear();\n this.currentParticipantId = null;\n this.resumeToken = null;\n this.pendingJoinRequestId = null;\n this.token = null;\n this.room = null;\n\n if (this.ws) {\n try { this.ws.close(); } catch { /* ignore */ }\n this.ws = null;\n }\n }\n\n private async logSubscriberVideoStats() {\n if (!this.subscriber || this.subscriber.connectionState === \"closed\") return;\n try {\n const stats = await this.subscriber.getStats();\n stats.forEach((report: any) => {\n if (\n report.type === \"inbound-rtp\" &&\n (report.kind === \"video\" || report.mediaType === \"video\")\n ) {\n console.debug(\"[SFU] subscriber video\", {\n packetsReceived: report.packetsReceived,\n packetsLost: report.packetsLost,\n framesDecoded: report.framesDecoded,\n frameWidth: report.frameWidth,\n frameHeight: report.frameHeight,\n });\n }\n });\n } catch {\n // stats are diagnostic only\n }\n }\n}\n","import { SDK_CONFIG } from \"../config/ws\";\nimport {\n ChatInput,\n ChatMessage,\n Events,\n MeetingConfig,\n Participant,\n SDKError,\n RecordingInfo,\n} from \"../types/meeting\";\nimport { ActiveSpeakerDetector } from \"./ActiveSpeakerDetector\";\nimport { MeetingState } from \"./MeetingState\";\nimport { SFUClient, SFUConnectionState, TrackInfo } from \"./SFUClient\";\n\nexport class VideoSDKCore {\n private sfuClient: SFUClient | null = null;\n\n private myId: string;\n\n private room: {\n id: string | null;\n name: string | null;\n } = {\n id: null,\n name: null,\n };\n\n private localStream: MediaStream | null = null;\n private screenStream: MediaStream | null = null;\n private isScreenSharing = false;\n private participantName = \"\";\n\n public readonly state: MeetingState;\n\n private intentionalDisconnect = false;\n\n private remoteStreams = new Map<string, MediaStream>();\n private remoteScreenStreams = new Map<string, MediaStream>();\n\n private activeSpeakerDetector: ActiveSpeakerDetector;\n\n private joinPromise: Promise<void> | null = null;\n private disconnectPromise: Promise<void> | null = null;\n\n private emitError(\n code: string,\n message: string,\n raw?: any,\n recoverable = true,\n ) {\n const err: SDKError = {\n code,\n message,\n raw,\n roomId: this.room.id,\n userId: this.myId,\n recoverable,\n };\n\n this.events.onError?.(err);\n\n console.error(\"[MeetingSDK Error]\", err);\n }\n\n constructor(\n private events: Events = {},\n private apiBase: string = SDK_CONFIG.apiBase,\n private wsBase: string = SDK_CONFIG.wsBase,\n ) {\n this.state = new MeetingState();\n this.events = events;\n this.activeSpeakerDetector = new ActiveSpeakerDetector({\n onActiveSpeakersChanged: (participantIds) => {\n this.state.setActiveSpeakers(participantIds);\n\n this.events.onActiveSpeakersChanged?.(participantIds);\n },\n });\n\n let storedId: string | null = null;\n\n try {\n storedId =\n typeof localStorage !== \"undefined\"\n ? localStorage.getItem(\"defcomm:participant_id\")\n : null;\n } catch {\n // SSR/private browsing may not expose localStorage.\n }\n\n this.myId =\n storedId ||\n (typeof crypto !== \"undefined\" && crypto.randomUUID\n ? crypto.randomUUID()\n : `user_${Date.now()}`);\n\n try {\n if (typeof localStorage !== \"undefined\") {\n localStorage.setItem(\"defcomm:participant_id\", this.myId);\n }\n } catch {\n // ignore\n }\n }\n\n // LOCAL MEDIA\n\n async initLocal(video: HTMLVideoElement, name: string) {\n this.participantName = name;\n\n try {\n this.localStream = await navigator.mediaDevices.getUserMedia({\n video: {\n width: { ideal: 1280 },\n height: { ideal: 720 },\n },\n audio: {\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n },\n });\n\n const localAudioTrack = this.localStream.getAudioTracks()[0];\n\n if (localAudioTrack) {\n this.activeSpeakerDetector.addTrack(this.myId, localAudioTrack);\n }\n\n const hasVideo = this.localStream\n .getVideoTracks()\n .some((t) => t.readyState === \"live\");\n\n const hasAudio = this.localStream\n .getAudioTracks()\n .some((t) => t.readyState === \"live\");\n\n if (!hasVideo || !hasAudio) {\n throw new Error(`Missing tracks: video=${hasVideo}, audio=${hasAudio}`);\n }\n\n video.srcObject = this.localStream;\n\n this.updateLocalMedia();\n } catch (err: any) {\n this.emitError(\"GET_USER_MEDIA_FAILED\", err?.message, err, false);\n\n throw err;\n }\n }\n\n private updateLocalMedia(audioMuted = false, videoMuted = false) {\n if (!this.localStream) return;\n\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n\n media: {\n stream: this.localStream,\n cameraTrack: this.localStream.getVideoTracks()[0],\n audioTrack: this.localStream.getAudioTracks()[0],\n micEnabled:\n this.localStream.getAudioTracks()[0]?.enabled ?? !audioMuted,\n camEnabled:\n this.localStream.getVideoTracks()[0]?.enabled ?? !videoMuted,\n isScreenSharing: this.isScreenSharing,\n screenStream: this.screenStream,\n screenTrack: this.screenStream?.getVideoTracks()[0],\n },\n });\n\n this.state.localStream = this.localStream;\n }\n\n // ROOM MANAGEMENT\n async createRoom(input: {\n name: string;\n description?: string;\n capacity?: number;\n is_private?: boolean;\n }) {\n const client =\n this.sfuClient ??\n new SFUClient({\n apiBase: this.apiBase,\n wsBase: this.wsBase,\n userId: this.myId,\n });\n\n return client.createRoom(input);\n }\n\n async getRoom(roomCode: string) {\n const client =\n this.sfuClient ??\n new SFUClient({\n apiBase: this.apiBase,\n wsBase: this.wsBase,\n userId: this.myId,\n });\n\n return client.getRoom(roomCode);\n }\n\n async deleteRoom(roomCode: string) {\n const client =\n this.sfuClient ??\n new SFUClient({\n apiBase: this.apiBase,\n wsBase: this.wsBase,\n userId: this.myId,\n });\n\n return client.deleteRoom(roomCode);\n }\n\n // JOIN\n async joinMeeting(config: MeetingConfig): Promise<void> {\n const {\n roomId,\n name,\n audioMuted = false,\n videoMuted = false,\n userId,\n } = config;\n\n if (!roomId || !name) {\n throw new Error(\"roomId and name are required to join meeting\");\n }\n\n if (userId) {\n this.myId = userId;\n }\n\n /*Already connected?\n * Calling join() again must NOT cause leave().\n */\n if (\n this.sfuClient &&\n this.room.id === roomId &&\n this.sfuClient.getConnectionState() === \"connected\"\n ) {\n console.info(\"[SDK] Already connected; duplicate join ignored\", {\n roomId,\n userId: this.myId,\n });\n\n return;\n }\n\n if (this.joinPromise) {\n console.info(\n \"[SDK] Join already in progress; waiting for existing join\",\n {\n roomId,\n userId: this.myId,\n },\n );\n\n return this.joinPromise;\n }\n\n if (this.sfuClient && this.room.id && this.room.id !== roomId) {\n throw new Error(\n `Already connected to room ${this.room.id}. Leave the current meeting before joining another room.`,\n );\n }\n\n this.intentionalDisconnect = false;\n this.participantName = name;\n this.room.id = roomId;\n this.room.name = name;\n\n if (!this.localStream) {\n this.localStream = await navigator.mediaDevices.getUserMedia({\n video: true,\n audio: true,\n });\n\n const localAudioTrack = this.localStream.getAudioTracks()[0];\n\n if (localAudioTrack) {\n this.activeSpeakerDetector.addTrack(this.myId, localAudioTrack);\n }\n }\n\n this.localStream.getAudioTracks().forEach((track) => {\n track.enabled = !audioMuted;\n });\n\n this.localStream.getVideoTracks().forEach((track) => {\n track.enabled = !videoMuted;\n });\n\n this.updateLocalMedia(audioMuted, videoMuted);\n\n const promise = this.connect(roomId, name);\n\n this.joinPromise = promise;\n\n try {\n await promise;\n } finally {\n if (this.joinPromise === promise) {\n this.joinPromise = null;\n }\n }\n }\n\n // SFU CONNECTION\n private async connect(roomId: string, name: string): Promise<void> {\n if (this.sfuClient) {\n const state = this.sfuClient.getConnectionState();\n if (\n this.room.id === roomId &&\n (state === \"connecting\" ||\n state === \"connected\" ||\n state === \"reconnecting\")\n ) {\n console.info(\n \"[SDK] Existing SFU connection is active; connect ignored\",\n {\n roomId,\n state,\n },\n );\n\n return;\n }\n\n throw new Error(\n `SFU client already exists in state \"${state}\". Disconnect explicitly before creating another connection.`,\n );\n }\n\n const client = new SFUClient({\n apiBase: this.apiBase,\n wsBase: this.wsBase,\n userId: this.myId,\n autoSubscribe: true,\n // CONNECTION STATE\n\n onStateChange: (state) => {\n this.handleSFUState(state);\n },\n\n onConnected: (payload, resumed) => {\n console.log(`[SFU] ${resumed ? \"Resumed\" : \"Joined\"} room`, payload);\n\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n });\n },\n\n onDisconnected: () => {\n /*\n * Disconnected does NOT necessarily mean\n * the participant left the room.\n * SFUClient should attempt reconnect.\n */\n console.log(\"[SFU] Signaling WebSocket disconnected; reconnecting\");\n },\n\n onReconnecting: (attempt) => {\n console.warn(`[SFU] Reconnecting, attempt ${attempt}`);\n },\n\n // ADMISSION CONTROL\n onJoinPending: (info) => {\n console.log(\"[SFU] Join request pending\", info);\n\n this.events.onEntryRequested?.({\n requestId: info.request_id,\n userId: this.myId,\n name: this.participantName,\n });\n },\n\n onJoinApproved: (requestId) => {\n console.log(\"[SFU] Join approved\", requestId);\n this.events.onJoinApproved?.(requestId);\n this.events.onEntryResponded?.(\n {\n participantId: this.myId,\n decision: \"approved\",\n },\n\n \"approved\",\n );\n },\n\n onJoinRejected: (requestId, reason) => {\n console.warn(\"[SFU] Join rejected\", requestId, reason);\n this.events.onJoinRejected?.(requestId);\n this.events.onEntryResponded?.(\n {\n participantId: this.myId,\n decision: \"rejected\",\n },\n\n \"rejected\",\n );\n\n this.emitError(\n \"JOIN_REJECTED\",\n reason || \"Your request to join was rejected\",\n {\n requestId,\n reason,\n },\n false,\n );\n },\n\n onJoinRequested: (request) => {\n const requestId = request?.request_id || request?.requestId;\n const userId = request?.user_id || request?.userId;\n const nameValue =\n request?.user_metadata?.name ||\n request?.display_name ||\n request?.name ||\n \"Participant\";\n\n if (!requestId || !userId) {\n return;\n }\n\n this.events.onEntryRequested?.({\n requestId,\n userId,\n name: nameValue,\n });\n },\n\n // PARTICIPANTS\n onParticipantJoined: (participant) => {\n const pid = participant.participant_id;\n\n if (!pid || pid === this.myId) {\n return;\n }\n\n const pname =\n participant.user_metadata?.name ||\n participant.display_name ||\n \"Participant\";\n\n this.state.addParticipant({\n id: pid,\n name: pname,\n connectionState: \"connected\",\n media: {\n micEnabled: true,\n camEnabled: true,\n isScreenSharing: false,\n stream: null,\n },\n });\n\n this.events.onUserJoined?.({\n id: pid,\n name: pname,\n });\n },\n\n onParticipantPresence: (participantId, presence) => {\n if (participantId === this.myId) {\n return;\n }\n\n const current = this.state.getParticipant(participantId);\n\n if (!current) {\n return;\n }\n\n const connectionState =\n presence === \"reconnecting\"\n ? \"reconnecting\"\n : presence === \"connected\" || presence === \"online\"\n ? \"connected\"\n : presence === \"disconnected\"\n ? \"disconnected\"\n : current.connectionState;\n\n this.state.updateParticipantMedia(participantId, {\n stream: current.media?.stream ?? null,\n });\n\n const next = new Map(this.state.participants);\n\n next.set(participantId, {\n ...current,\n connectionState,\n });\n\n this.state.participants = next;\n\n this.state.notify(`participant:${participantId}`);\n\n this.state.notify(\"participants\");\n },\n\n onParticipantLeft: (participant) => {\n const pid =\n typeof participant === \"string\"\n ? participant\n : participant.participant_id;\n\n if (!pid) {\n return;\n }\n\n console.log(\"[SFU] Participant permanently left\", pid);\n\n this.cleanupRemoteParticipant(pid);\n this.state.removeParticipant(pid);\n this.events.onUserLeft?.(pid);\n },\n\n // TRACKS\n onTrackPublished: (track) => {\n console.log(\"[SFU] Track published\", track);\n },\n\n onTrackUnpublished: (track) => {\n console.log(\"[SFU] Track unpublished\", track);\n const pid = track.participant_id;\n\n if (!pid) {\n return;\n }\n\n const current = this.state.getParticipant(pid);\n if (track.source === \"screen\") {\n const screen = this.remoteScreenStreams.get(pid);\n\n screen?.getTracks().forEach((t) => t.stop());\n\n this.remoteScreenStreams.delete(pid);\n\n this.state.updateParticipantMedia(pid, {\n isScreenSharing: false,\n screenStream: null,\n screenTrack: undefined,\n });\n\n this.events.onScreenShareStopped?.(pid);\n\n return;\n }\n\n if (!current) {\n return;\n }\n\n this.state.updateParticipantMedia(pid, {\n stream: current.media?.stream ?? null,\n micEnabled:\n track.kind === \"audio\"\n ? false\n : (current.media?.micEnabled ?? true),\n\n camEnabled:\n track.kind === \"video\"\n ? false\n : (current.media?.camEnabled ?? true),\n });\n },\n\n onTrackStateChanged: (track) => {\n const pid = track.participant_id;\n\n if (!pid || pid === this.myId) {\n return;\n }\n\n const current = this.state.getParticipant(pid);\n\n if (!current) {\n return;\n }\n\n if (track.source === \"audio\") {\n this.state.updateParticipantMedia(pid, {\n stream: current.media?.stream ?? null,\n micEnabled: !track.muted,\n });\n\n this.events.onMuteStateChanged?.(pid, \"audio\", track.muted);\n } else if (track.source === \"camera\") {\n this.state.updateParticipantMedia(pid, {\n stream: current.media?.stream ?? null,\n camEnabled: !track.muted,\n });\n\n this.events.onMuteStateChanged?.(pid, \"video\", track.muted);\n }\n\n this.events.onTrackStateChanged?.(track as any);\n },\n\n // RECORDING\n onRecordingStarted: (recording) => {\n this.events.onRecordingStarted?.(recording);\n },\n\n onRecordingStopped: (recording) => {\n this.events.onRecordingStopped?.(recording);\n },\n\n // REMOTE MEDIA\n onRemoteTrack: (track, stream, metadata) => {\n this.handleRemoteTrack(track, stream, metadata);\n },\n\n // SCREEN SHARE\n onScreenShareStarted: (participantId, track) => {\n if (participantId === this.myId) {\n return;\n }\n\n console.log(\"[SFU] Screen share started\", participantId, track);\n const current = this.state.getParticipant(participantId);\n if (current) {\n this.state.updateParticipantMedia(participantId, {\n isScreenSharing: true,\n screenStream: current.media?.screenStream ?? null,\n });\n }\n },\n\n onScreenShareStopped: (participantId) => {\n if (participantId === this.myId) {\n return;\n }\n\n const screen = this.remoteScreenStreams.get(participantId);\n\n screen?.getTracks().forEach((track) => track.stop());\n\n this.remoteScreenStreams.delete(participantId);\n\n this.state.updateParticipantMedia(participantId, {\n isScreenSharing: false,\n screenStream: null,\n screenTrack: undefined,\n });\n\n this.events.onScreenShareStopped?.(participantId);\n },\n\n // ERROR\n onError: (error) => {\n console.error(\"[SFU] Error:\", error);\n this.emitError(\n \"SFU_ERROR\",\n error?.message || String(error),\n error,\n true,\n );\n },\n });\n\n /*Assign the client BEFORE starting the connection.\n * This is important because callbacks may fire during\n * getToken().\n */\n this.sfuClient = client;\n\n client.setLocalStream(this.localStream);\n\n await client.getToken(roomId, {\n displayName: name,\n userId: this.myId,\n });\n }\n\n // SFU STATE\n private handleSFUState(state: SFUConnectionState) {\n this.events.onConnectionStateChanged?.(state);\n\n if (state === \"reconnecting\") {\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n });\n\n return;\n }\n\n /*Do NOT emit CONNECTION_LOST while reconnecting.\n * SFUClient should only eventually transition to\n * \"disconnected\" when reconnect attempts are exhausted.\n */\n if (state === \"disconnected\" && !this.intentionalDisconnect) {\n this.emitError(\n \"CONNECTION_LOST\",\n \"Unable to reconnect to SFU server\",\n null,\n true,\n );\n }\n }\n\n // REMOTE TRACKS\n private handleRemoteTrack(\n track: MediaStreamTrack,\n stream: MediaStream,\n metadata: TrackInfo,\n ) {\n const participantId = metadata?.participant_id;\n\n if (!participantId || participantId === this.myId) {\n return;\n }\n\n const source = metadata.source;\n\n /* SCREEN SHARE\n */\n if (source === \"screen\") {\n let screenStream = this.remoteScreenStreams.get(participantId);\n\n if (!screenStream) {\n screenStream = new MediaStream();\n this.remoteScreenStreams.set(participantId, screenStream);\n }\n\n for (const old of screenStream.getVideoTracks()) {\n if (old.id !== track.id) {\n screenStream.removeTrack(old);\n old.stop();\n }\n }\n\n if (!screenStream.getTracks().some((t) => t.id === track.id)) {\n screenStream.addTrack(track);\n }\n\n this.state.updateParticipantMedia(participantId, {\n screenStream,\n screenTrack: track,\n isScreenSharing: true,\n });\n\n this.events.onScreenShareStarted?.(participantId, screenStream);\n\n return;\n }\n\n let remoteStream = this.remoteStreams.get(participantId);\n\n if (!remoteStream) {\n remoteStream = new MediaStream();\n\n this.remoteStreams.set(participantId, remoteStream);\n }\n\n for (const old of remoteStream.getTracks()) {\n if (old.kind === track.kind && old.id !== track.id) {\n remoteStream.removeTrack(old);\n old.stop();\n }\n }\n\n if (!remoteStream.getTracks().some((t) => t.id === track.id)) {\n remoteStream.addTrack(track);\n }\n\n const current = this.state.getParticipant(participantId);\n\n this.state.updateParticipantMedia(participantId, {\n stream: remoteStream,\n cameraTrack: track.kind === \"video\" ? track : current?.media?.cameraTrack,\n audioTrack: track.kind === \"audio\" ? track : current?.media?.audioTrack,\n });\n\n if (track.kind === \"audio\") {\n this.activeSpeakerDetector.addTrack(participantId, track);\n }\n\n this.events.onTrack?.(remoteStream, participantId);\n\n track.onended = () => {\n if (track.kind === \"video\") {\n this.state.updateParticipantMedia(participantId, {\n camEnabled: false,\n stream: remoteStream,\n });\n\n return;\n }\n\n this.state.updateParticipantMedia(participantId, {\n micEnabled: false,\n stream: remoteStream,\n });\n };\n }\n\n // MEETING\n getMeeting(): {\n id: string | null;\n name: string | null;\n } {\n return this.room;\n }\n\n // ADMISSION CONTROL\n async approveJoinRequest(requestId: string) {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n return this.sfuClient.approveJoinRequest(requestId);\n }\n\n async rejectJoinRequest(requestId: string, reason?: string) {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n return this.sfuClient.rejectJoinRequest(requestId, reason);\n }\n\n // MEDIA CONTROL\n toggleMic() {\n const mediaState = this.state.localParticipant?.media;\n\n if (!mediaState || !this.localStream) {\n return;\n }\n\n const nextEnabled = !mediaState.micEnabled;\n\n this.localStream.getAudioTracks().forEach((track) => {\n track.enabled = nextEnabled;\n });\n\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n media: {\n micEnabled: nextEnabled,\n },\n });\n\n this.sfuClient?.muteAudio(!nextEnabled);\n this.events.onMicToggled?.(this.myId, nextEnabled);\n }\n\n toggleCam() {\n const mediaState = this.state.localParticipant?.media;\n\n if (!mediaState || !this.localStream) {\n return;\n }\n\n const nextEnabled = !mediaState.camEnabled;\n\n this.localStream.getVideoTracks().forEach((track) => {\n track.enabled = nextEnabled;\n });\n\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n media: {\n camEnabled: nextEnabled,\n },\n });\n\n this.sfuClient?.muteVideo(!nextEnabled);\n\n this.events.onCamToggled?.(this.myId, nextEnabled);\n }\n\n // SCREEN SHARING\n async startScreenShare() {\n try {\n if (!navigator.mediaDevices?.getDisplayMedia) {\n throw new Error(\"Screen sharing not supported on this device\");\n }\n\n if (!this.sfuClient) {\n throw new Error(\"Cannot share screen before joining the meeting\");\n }\n\n this.screenStream = await this.sfuClient.shareScreen();\n\n this.isScreenSharing = true;\n\n this.state.updateLocalParticipant({\n media: {\n isScreenSharing: true,\n screenStream: this.screenStream,\n screenTrack: this.screenStream.getVideoTracks()[0],\n },\n });\n\n return this.screenStream;\n } catch (err: any) {\n this.emitError(\n \"SCREEN_SHARE_FAILED\",\n err?.message || \"Failed to start screen sharing\",\n err,\n true,\n );\n\n this.isScreenSharing = false;\n this.screenStream = null;\n\n throw err;\n }\n }\n\n stopScreenShare() {\n if (!this.screenStream) {\n return;\n }\n\n void this.sfuClient?.stopScreenShare();\n this.screenStream.getTracks().forEach((track) => track.stop());\n this.screenStream = null;\n this.isScreenSharing = false;\n\n this.state.updateLocalParticipant({\n media: {\n isScreenSharing: false,\n screenStream: null,\n screenTrack: undefined,\n },\n });\n }\n\n // RECORDING\n async startRecording() {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n await this.sfuClient.startRecording();\n }\n\n async stopRecording() {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n await this.sfuClient.stopRecording();\n }\n\n async getRecordingStatus(): Promise<{\n recording: RecordingInfo | null;\n }> {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n return this.sfuClient.getRecordingStatus();\n }\n\n // CHAT\n\n sendChatMessage(payload: ChatInput) {\n if (!this.sfuClient) {\n console.warn(\"SFU Client not connected\");\n\n return;\n }\n\n const senderName = this.state.localParticipant?.name || \"Anonymous\";\n\n const msg: ChatMessage = {\n id: crypto.randomUUID(),\n sender_id: this.myId,\n sender_name: senderName,\n text: payload.message.trim(),\n timestamp: Date.now(),\n reply_to: payload.reply_to ?? null,\n target: payload.target ?? null,\n };\n\n this.state.addChatMessage(msg);\n this.events.onChatMessage?.(msg);\n }\n\n // CLEANUP\n private cleanupRemoteParticipant(participantId: string) {\n this.activeSpeakerDetector.removeParticipant(participantId);\n\n const stream = this.remoteStreams.get(participantId);\n\n stream?.getTracks().forEach((track) => track.stop());\n\n this.remoteStreams.delete(participantId);\n\n const screen = this.remoteScreenStreams.get(participantId);\n\n screen?.getTracks().forEach((track) => track.stop());\n\n this.remoteScreenStreams.delete(participantId);\n }\n\n // DISCONNECT\n async disconnect(): Promise<void> {\n if (this.disconnectPromise) {\n return this.disconnectPromise;\n }\n\n this.disconnectPromise = this.performDisconnect();\n\n try {\n await this.disconnectPromise;\n } finally {\n this.disconnectPromise = null;\n }\n }\n\n private async performDisconnect() {\n this.intentionalDisconnect = true;\n this.joinPromise = null;\n\n const client = this.sfuClient;\n this.sfuClient = null;\n\n if (client) {\n await client.leave();\n }\n\n // LOCAL MEDIA\n if (this.localStream) {\n this.localStream.getTracks().forEach((track) => track.stop());\n\n this.localStream = null;\n }\n\n if (this.screenStream) {\n this.screenStream.getTracks().forEach((track) => track.stop());\n this.screenStream = null;\n }\n\n this.isScreenSharing = false;\n\n // REMOTE MEDIA\n for (const stream of this.remoteStreams.values()) {\n stream.getTracks().forEach((track) => track.stop());\n }\n\n this.remoteStreams.clear();\n for (const stream of this.remoteScreenStreams.values()) {\n stream.getTracks().forEach((track) => track.stop());\n }\n\n this.remoteScreenStreams.clear();\n this.room.id = null;\n this.room.name = null;\n\n this.state.localParticipant = null;\n\n this.state.notify(\"localParticipant\");\n\n this.state.resetRemoteState();\n this.events.onMeetingLeft?.();\n }\n}\n","import { useEffect, useState } from \"react\";\nimport { StateScope } from \"../types/meeting\";\nimport { MeetingState } from \"../core/MeetingState\";\n\nexport function useMeetingStore<T>(\n stateManager: MeetingState,\n scope: StateScope,\n selector: (state: MeetingState) => T,\n): T {\n const [state, setState] = useState(() => selector(stateManager));\n\n useEffect(() => {\n // Update local react state whenever the SDK notifies this scope\n const unsubscribe = stateManager.subscribe(scope, () => {\n setState(selector(stateManager));\n });\n\n return unsubscribe;\n }, [stateManager, scope, selector]);\n\n return state;\n}\n","import { useEffect } from \"react\";\nimport { useMeetingContext } from \"./MeetingProvider\";\n\nexport const useMeeting = (handlers?: {\n onError?: (err: any) => void;\n onEntryRequested?: (req: any) => void;\n onEntryResponded?: (payload: any, decision?: any) => void;\n onMeetingLeft?: () => void;\n onTrackStateChanged?: (track: any) => void;\n onRecordingStarted?: (recording: any) => void;\n onRecordingStopped?: (recording: any) => void;\n onActiveSpeakersChanged?: (participantIds: string[]) => void;\n}) => {\n const ctx = useMeetingContext();\n\n // Error Handler\n useEffect(() => {\n if (!handlers?.onError) return;\n return ctx.onError(handlers.onError);\n }, [handlers?.onError]);\n\n useEffect(() => {\n if (!handlers?.onActiveSpeakersChanged) return;\n\n return ctx.onActiveSpeakersChanged(handlers.onActiveSpeakersChanged);\n }, [handlers?.onActiveSpeakersChanged]);\n\n // Entry Request Handler\n useEffect(() => {\n if (!handlers?.onEntryRequested) return;\n return ctx.onEntryRequested(handlers.onEntryRequested);\n }, [handlers?.onEntryRequested]);\n\n // Entry Response Handler\n useEffect(() => {\n if (!handlers?.onEntryResponded) return;\n return ctx.onEntryResponded(handlers.onEntryResponded);\n }, [handlers?.onEntryResponded]);\n\n // Meeting Left Handler\n useEffect(() => {\n if (!handlers?.onMeetingLeft) return;\n return ctx.onMeetingLeft(handlers.onMeetingLeft);\n }, [handlers?.onMeetingLeft]);\n\n useEffect(() => {\n if (!handlers?.onTrackStateChanged) return;\n return ctx.onTrackStateChanged(handlers.onTrackStateChanged);\n }, [handlers?.onTrackStateChanged]);\n\n useEffect(() => {\n if (!handlers?.onRecordingStarted) return;\n return ctx.onRecordingStarted(handlers.onRecordingStarted);\n }, [handlers?.onRecordingStarted]);\n\n useEffect(() => {\n if (!handlers?.onRecordingStopped) return;\n return ctx.onRecordingStopped(handlers.onRecordingStopped);\n }, [handlers?.onRecordingStopped]);\n\n const { sdk: _, ...publicApi } = ctx;\n return publicApi;\n};\n","import { useEffect, useState } from \"react\";\nimport { useMeetingContext } from \"./MeetingProvider\";\nimport { Participant } from \"../types/meeting\";\n\nexport const useParticipants = () => {\n const { sdk } = useMeetingContext();\n\n const [participants, setParticipants] = useState<Participant[]>(() =>\n sdk.state.getParticipants(),\n );\n\n useEffect(() => {\n const update = () => {\n setParticipants(sdk.state.getParticipants());\n };\n\n update();\n\n const unsub = sdk.state.subscribe(\"participants\", update);\n\n return unsub;\n }, [sdk]);\n\n return participants;\n};\n","import { useEffect, useRef, useState } from \"react\";\nimport { useMeetingContext } from \"./MeetingProvider\";\nimport { Participant } from \"../types/meeting\";\n\nexport const useRemoteMedia = (participantId: string) => {\n const { sdk } = useMeetingContext();\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const audioRef = useRef<HTMLAudioElement | null>(null);\n\n const [participant, setParticipant] = useState<Participant | null>(\n () => sdk.state.getParticipant(participantId) || null,\n );\n\n useEffect(() => {\n const unsub = sdk.state.subscribe(`participant:${participantId}`, () => {\n const p = sdk.state.getParticipant(participantId);\n setParticipant(p ? { ...p } : null);\n });\n\n return unsub;\n }, [participantId, sdk]);\n\n useEffect(() => {\n const stream = participant?.media?.stream;\n if (!stream) return;\n\n // VIDEO\n if (videoRef.current) {\n videoRef.current.srcObject = stream;\n videoRef.current.muted = true;\n videoRef.current.playsInline = true;\n videoRef.current.play().catch(() => {});\n }\n\n // AUDIO\n if (audioRef.current) {\n audioRef.current.srcObject = stream;\n audioRef.current.play().catch(() => {});\n }\n }, [participant?.media?.stream]);\n\n return {\n videoRef,\n audioRef,\n isCamActive: !!participant?.media?.camEnabled,\n isMicEnabled: !!participant?.media?.micEnabled,\n };\n};\n","import { useEffect, useState } from \"react\";\nimport { SDK_CONFIG } from \"../config/ws\";\n\ntype LiveRoomState = {\n active: boolean;\n count: number;\n canJoin: boolean;\n approved: boolean;\n isHost: boolean;\n hasMoreParticipants: boolean;\n participants: {\n id: string;\n name: string;\n isHost: boolean;\n isPresenter: boolean;\n micEnabled: boolean;\n camEnabled: boolean;\n }[];\n room?: {\n id: string;\n name: string;\n room_code: string;\n capacity: number;\n is_private: boolean;\n };\n};\n\n/**\n * Current SFU does not expose the old `/watch/:room` mesh presence socket.\n * Preview therefore uses the authoritative REST room endpoint and polls it.\n * Live participant/media state begins after JOIN over the SFU WebSocket.\n */\nexport function useMeetingPreview(roomId: string, userId: string) {\n const [room, setRoom] = useState<LiveRoomState | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [isConnected, setIsConnected] = useState(false);\n const [isLoading, setIsLoading] = useState(true);\n\n useEffect(() => {\n if (!roomId) {\n setIsLoading(false);\n return;\n }\n\n let stopped = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n const load = async () => {\n try {\n const response = await fetch(\n `${SDK_CONFIG.apiBase}/rooms/${encodeURIComponent(roomId)}`,\n );\n\n if (!response.ok) {\n throw new Error(`Room lookup failed (${response.status})`);\n }\n\n const data = await response.json();\n if (stopped) return;\n\n setRoom({\n active: true,\n // The current REST room model intentionally does not expose a live\n // participant count. Do not fabricate one.\n count: 0,\n canJoin: !data.is_private,\n approved: false,\n isHost: false,\n hasMoreParticipants: false,\n participants: [],\n room: {\n id: data.id,\n name: data.name,\n room_code: data.room_code,\n capacity: data.capacity,\n is_private: data.is_private,\n },\n });\n setError(null);\n setIsConnected(true);\n setIsLoading(false);\n } catch (err: any) {\n if (stopped) return;\n setError(err?.message || \"Failed to load room\");\n setIsConnected(false);\n setIsLoading(false);\n } finally {\n if (!stopped) {\n timer = setTimeout(load, 5000);\n }\n }\n };\n\n void load();\n\n return () => {\n stopped = true;\n if (timer) clearTimeout(timer);\n };\n }, [roomId, userId]);\n\n return {\n room,\n isConnected,\n isLoading,\n error,\n };\n}\n"],"mappings":"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","names":["useEffect","useRef","useState","useState","useEffect","useRef","useEffect","useEffect","useEffect","useState","useState","useEffect","useEffect","useRef","useState","useRef","useState","useEffect","useEffect","useState","useState","useEffect"]}
1
+ {"version":3,"sources":["../src/react/useLocalParticipant.tsx","../src/react/MeetingProvider.tsx","../src/config/ws.ts","../src/core/ActiveSpeakerDetector.ts","../src/core/MeetingState.ts","../src/core/SFUClient.ts","../src/core/VideoCore.ts","../src/react/useMeetingStore.ts","../src/react/useMeeting.ts","../src/react/useParticipants.ts","../src/react/useRemoteMedia.ts","../src/react/useMeetingPreview.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useMeetingContext } from \"./MeetingProvider\";\nimport { Participant } from \"../types/meeting\";\n\nexport const useLocalParticipant = () => {\n const { sdk } = useMeetingContext();\n\n // Guard the initial state to ensure it matches Participant | null\n const [localParticipant, setLocalParticipant] = useState<Participant | null>(\n () => {\n const current = sdk.state.localParticipant;\n return current && current.id ? (current as Participant) : null;\n },\n );\n\n useEffect(() => {\n const unsubscribe = sdk.state.subscribe(\"localParticipant\", () => {\n const current = sdk.state.localParticipant;\n\n // Safe Type-Guard: Only update if the object has a finalized id\n if (current && current.id) {\n setLocalParticipant({ ...current } as Participant);\n } else {\n setLocalParticipant(null);\n }\n });\n\n return unsubscribe;\n }, [sdk]);\n\n const lastStreamRef = useRef<MediaStream | null>(null);\n\n const videoRef = useCallback(\n (video: HTMLVideoElement | null) => {\n if (!video) return;\n\n const stream = localParticipant?.media?.stream;\n if (!stream) return;\n\n if (lastStreamRef.current === stream) return;\n lastStreamRef.current = stream;\n\n video.srcObject = stream;\n video.autoplay = true;\n video.playsInline = true;\n\n video.play().catch((err) => {\n console.warn(`Autoplay failed for local view:`, err);\n });\n },\n [localParticipant?.media?.stream],\n );\n\n return {\n participant: localParticipant,\n videoRef,\n };\n};\n","import React, { createContext, useContext, useMemo, useRef } from \"react\";\nimport { VideoSDKCore } from \"../core/VideoCore\";\nimport {\n ChatInput,\n ChatMessage,\n MeetingConfig,\n Participant,\n PubSubTopic,\n Recording,\n} from \"../types/meeting\";\nimport { useMeetingStore } from \"./useMeetingStore\";\n\ntype PubSubHandle = {\n messages: ChatMessage[];\n publish: (input: ChatInput) => void;\n};\n\ntype MeetingContextValue = {\n sdk: VideoSDKCore;\n join: (config?: MeetingConfig) => Promise<void>;\n leave: () => void;\n createRoom: (input: {\n name: string;\n description?: string;\n capacity?: number;\n is_private?: boolean;\n }) => Promise<any>;\n getRoom: (roomCode: string) => Promise<any>;\n deleteRoom: (roomCode: string) => Promise<any>;\n\n toggleMic: () => void;\n toggleCam: () => void;\n\n startScreenShare: () => Promise<MediaStream>;\n stopScreenShare: () => void;\n\n sendMessage: (input: ChatInput) => void;\n\n room: { id: string | null; name: string | null };\n localParticipant: Participant | null;\n participants: Map<string, Participant>;\n messages: ChatMessage[];\n presenterId: string | null;\n activeSpeakerIds: string[];\n usePubSub: (topic: PubSubTopic) => PubSubHandle;\n approveJoinRequest: (requestId: string) => void;\n rejectJoinRequest: (requestId: string) => void;\n startRecording: () => Promise<void>;\n stopRecording: () => Promise<void>;\n getRecordingStatus: () => Promise<any>;\n onError: (cb: (err: any) => void) => () => void;\n onEntryRequested: (cb: (req: any) => void) => () => void;\n onEntryResponded: (cb: (payload: any, decision?: any) => void) => () => void;\n onMeetingLeft: (cb: () => void) => () => void;\n onTrackStateChanged: (cb: (track: any) => void) => () => void;\n onRecordingStarted: (cb: (recording: Recording) => void) => () => void;\n onRecordingStopped: (cb: (recording: any) => void) => () => void;\n onActiveSpeakersChanged: (\n cb: (participantIds: string[]) => void,\n ) => () => void;\n};\n\nconst MeetingContext = createContext<MeetingContextValue | null>(null);\n\nexport const MeetingProvider = ({\n config,\n children,\n}: {\n config: MeetingConfig;\n children: React.ReactNode;\n}) => {\n const sdkRef = useRef<VideoSDKCore | null>(null);\n const errorListeners = useRef(new Set<(err: any) => void>());\n const entryRequestListeners = useRef(new Set<(req: any) => void>());\n const entryResponseListeners = useRef(\n new Set<(payload: any, decision?: any) => void>(),\n );\n const meetingLeftListeners = useRef(new Set<() => void>());\n const trackStateListeners = useRef(new Set<(track: any) => void>());\n const recordingStartedListeners = useRef(new Set<(recording: any) => void>());\n const recordingStoppedListeners = useRef(new Set<(recording: any) => void>());\n const activeSpeakerListeners = useRef(\n new Set<(participantIds: string[]) => void>(),\n );\n\n if (!sdkRef.current) {\n sdkRef.current = new VideoSDKCore({\n onError: (err) => errorListeners.current.forEach((fn) => fn(err)),\n onEntryRequested: (req) =>\n entryRequestListeners.current.forEach((fn) => fn(req)),\n onEntryResponded: (p, d) =>\n entryResponseListeners.current.forEach((fn) => fn(p, d)),\n onMeetingLeft: () => meetingLeftListeners.current.forEach((fn) => fn()),\n onTrackStateChanged: (track) =>\n trackStateListeners.current.forEach((fn) => fn(track)),\n onRecordingStarted: (recording: {\n recording_id: string;\n started_at: string;\n }) => recordingStartedListeners.current.forEach((fn) => fn(recording)),\n onRecordingStopped: (recording: {\n recording_id: string;\n stopped_at: string;\n }) => recordingStoppedListeners.current.forEach((fn) => fn(recording)),\n });\n }\n\n const sdk = sdkRef.current;\n const activeSpeakerIds = useMeetingStore(sdk.state, \"activeSpeakers\", (s) =>\n Array.from(s.activeSpeakerIds),\n );\n const presenterId = useMeetingStore(\n sdk.state,\n \"presenter\",\n (s) => s.presenterId,\n );\n const participants = useMeetingStore(\n sdk.state,\n \"participants\",\n (s) => s.participants,\n );\n const localParticipant = useMeetingStore(\n sdk.state,\n \"localParticipant\",\n (s) => s.localParticipant,\n );\n const messages = useMeetingStore(sdk.state, \"chat\", (s) =>\n s.getChatMessages(),\n );\n\n const value = useMemo<MeetingContextValue>(() => {\n if (!sdkRef.current) {\n sdkRef.current = new VideoSDKCore({\n onError: (err) => {\n errorListeners.current.forEach((fn) => fn(err));\n },\n });\n }\n\n return {\n sdk,\n\n join: (joinConfig?: MeetingConfig) =>\n sdk.joinMeeting({\n ...config,\n ...joinConfig,\n }),\n leave: () => sdk.disconnect(),\n createRoom: sdk.createRoom.bind(sdk),\n getRoom: sdk.getRoom.bind(sdk),\n deleteRoom: sdk.deleteRoom.bind(sdk),\n toggleMic: sdk.toggleMic.bind(sdk),\n toggleCam: sdk.toggleCam.bind(sdk),\n startScreenShare: sdk.startScreenShare.bind(sdk),\n stopScreenShare: sdk.stopScreenShare.bind(sdk),\n sendMessage: sdk.sendChatMessage.bind(sdk),\n\n room: sdk.getMeeting(),\n localParticipant,\n participants,\n messages,\n presenterId,\n activeSpeakerIds,\n usePubSub: (topic: PubSubTopic) => {\n if (topic !== \"SECURE_CHAT\") {\n throw new Error(`Unsupported PubSub argument: \"${topic}\"`);\n }\n return {\n messages: sdk.state.getChatMessages(),\n publish: sdk.sendChatMessage.bind(sdk),\n };\n },\n approveJoinRequest: sdk.approveJoinRequest.bind(sdk),\n rejectJoinRequest: sdk.rejectJoinRequest.bind(sdk),\n startRecording: sdk.startRecording.bind(sdk),\n stopRecording: sdk.stopRecording.bind(sdk),\n getRecordingStatus: sdk.getRecordingStatus.bind(sdk),\n\n onError: (cb: (err: any) => void) => {\n errorListeners.current.add(cb);\n\n return () => {\n errorListeners.current.delete(cb);\n };\n },\n\n onEntryRequested: (cb: (err: any) => void) => {\n entryRequestListeners.current.add(cb);\n\n return () => {\n entryRequestListeners.current.delete(cb);\n };\n },\n onEntryResponded: (cb: (err: any) => void) => {\n entryResponseListeners.current.add(cb);\n\n return () => {\n entryResponseListeners.current.delete(cb);\n };\n },\n onMeetingLeft: (cb: () => void) => {\n meetingLeftListeners.current.add(cb);\n return () => {\n meetingLeftListeners.current.delete(cb);\n };\n },\n onTrackStateChanged: (cb: (track: any) => void) => {\n trackStateListeners.current.add(cb);\n return () => trackStateListeners.current.delete(cb);\n },\n onRecordingStarted: (cb: (recording: any) => void) => {\n recordingStartedListeners.current.add(cb);\n return () => recordingStartedListeners.current.delete(cb);\n },\n onRecordingStopped: (cb: (recording: any) => void) => {\n recordingStoppedListeners.current.add(cb);\n return () => recordingStoppedListeners.current.delete(cb);\n },\n onActiveSpeakersChanged: (cb) => {\n activeSpeakerListeners.current.add(cb);\n\n return () => {\n activeSpeakerListeners.current.delete(cb);\n };\n },\n };\n }, [config, sdk, localParticipant, participants, messages, presenterId]);\n\n return (\n <MeetingContext.Provider value={value}>{children}</MeetingContext.Provider>\n );\n};\n\nexport const useMeetingContext = () => {\n const ctx = useContext(MeetingContext);\n if (!ctx)\n throw new Error(\"useMeetingContext must be used inside <MeetingProvider>\");\n return ctx;\n};\n","/**\n * SDK Configuration for WebSocket and SFU connections\n * Updated to support the new Selective Forwarding Unit (SFU) architecture\n */\n\nexport interface SDKConfig {\n apiBase: string;\n wsBase: string;\n iceServers?: RTCIceServer[];\n connectionTimeout?: number;\n maxReconnectAttempts?: number;\n}\n\nexport const SDK_CONFIG: SDKConfig = {\n apiBase: \"https://sfu-server.duckdns.org/api\",\n wsBase: \"wss://sfu-server.duckdns.org/ws\",\n // Public STUN/TURN servers (fallback)\n iceServers: [\n { urls: [\"stun:stun.l.google.com:19302\"] },\n { urls: [\"stun:stun1.l.google.com:19302\"] },\n ],\n // Connection and reconnection settings\n connectionTimeout: 10000,\n maxReconnectAttempts: 5,\n};\n","type SpeakerState = {\n participantId: string;\n track: MediaStreamTrack;\n stream: MediaStream;\n source: MediaStreamAudioSourceNode;\n analyser: AnalyserNode;\n data: Float32Array<ArrayBuffer>;\n active: boolean;\n lastActiveAt: number;\n};\n\nexport interface ActiveSpeakerDetectorOptions {\n intervalMs?: number;\n threshold?: number;\n releaseThreshold?: number;\n releaseMs?: number;\n onActiveSpeakersChanged?: (participantIds: string[]) => void;\n}\n\nexport class ActiveSpeakerDetector {\n private audioContext: AudioContext | null = null;\n\n private speakers = new Map<string, SpeakerState>();\n\n private timer: ReturnType<typeof setInterval> | null = null;\n\n private readonly intervalMs: number;\n private readonly threshold: number;\n private readonly releaseThreshold: number;\n private readonly releaseMs: number;\n\n private onActiveSpeakersChanged: (participantIds: string[]) => void;\n\n private lastEmitted = \"\";\n\n constructor(options: ActiveSpeakerDetectorOptions = {}) {\n this.intervalMs = options.intervalMs ?? 100;\n this.threshold = options.threshold ?? 0.025;\n this.releaseThreshold = options.releaseThreshold ?? 0.015;\n this.releaseMs = options.releaseMs ?? 600;\n\n this.onActiveSpeakersChanged =\n options.onActiveSpeakersChanged ?? (() => {});\n }\n\n private ensureAudioContext(): AudioContext {\n if (!this.audioContext) {\n const AudioContextClass =\n window.AudioContext ||\n (\n window as typeof window & {\n webkitAudioContext?: typeof AudioContext;\n }\n ).webkitAudioContext;\n\n if (!AudioContextClass) {\n throw new Error(\"Web Audio API is not supported by this browser\");\n }\n\n this.audioContext = new AudioContextClass();\n }\n\n return this.audioContext;\n }\n\n async resume() {\n if (!this.audioContext) return;\n\n if (this.audioContext.state === \"suspended\") {\n try {\n await this.audioContext.resume();\n } catch {\n // Browser may require a user gesture.\n }\n }\n }\n\n addTrack(participantId: string, track: MediaStreamTrack) {\n if (!participantId) return;\n\n if (track.kind !== \"audio\") return;\n\n this.removeParticipant(participantId);\n const context = this.ensureAudioContext();\n const stream = new MediaStream([track]);\n const source = context.createMediaStreamSource(stream);\n const analyser = context.createAnalyser();\n\n analyser.fftSize = 512;\n analyser.smoothingTimeConstant = 0.65;\n analyser.minDecibels = -90;\n analyser.maxDecibels = -10;\n\n source.connect(analyser);\n\n const data = new Float32Array(analyser.fftSize);\n\n const state: SpeakerState = {\n participantId,\n track,\n stream,\n source,\n analyser,\n data,\n active: false,\n lastActiveAt: 0,\n };\n\n this.speakers.set(participantId, state);\n\n track.addEventListener(\n \"ended\",\n () => {\n this.removeParticipant(participantId);\n },\n { once: true },\n );\n\n this.start();\n\n void this.resume();\n }\n\n removeParticipant(participantId: string) {\n const state = this.speakers.get(participantId);\n\n if (!state) return;\n\n state.active = false;\n\n try {\n state.source.disconnect();\n } catch {\n // Already disconnected.\n }\n\n state.stream.getTracks().forEach((track) => {\n if (track !== state.track) {\n track.stop();\n }\n });\n\n this.speakers.delete(participantId);\n\n this.emitIfChanged();\n }\n\n removeTrack(track: MediaStreamTrack) {\n for (const [participantId, state] of this.speakers) {\n if (state.track === track) {\n this.removeParticipant(participantId);\n }\n }\n }\n\n clear() {\n for (const participantId of this.speakers.keys()) {\n this.removeParticipant(participantId);\n }\n\n this.speakers.clear();\n\n this.stop();\n\n this.emitIfChanged(true);\n }\n\n start() {\n if (this.timer) return;\n\n this.timer = setInterval(() => this.sample(), this.intervalMs);\n }\n\n stop() {\n if (!this.timer) return;\n\n clearInterval(this.timer);\n this.timer = null;\n }\n\n private sample() {\n const now = performance.now();\n\n for (const state of this.speakers.values()) {\n if (\n state.track.readyState !== \"live\" ||\n state.track.muted ||\n !state.track.enabled\n ) {\n if (state.active) {\n state.active = false;\n }\n\n continue;\n }\n\n state.analyser.getFloatTimeDomainData(state.data);\n\n let sumSquares = 0;\n\n for (let i = 0; i < state.data.length; i++) {\n const sample = state.data[i];\n sumSquares += sample * sample;\n }\n\n const rms = Math.sqrt(sumSquares / state.data.length);\n\n if (!state.active) {\n if (rms >= this.threshold) {\n state.active = true;\n state.lastActiveAt = now;\n }\n } else {\n if (rms >= this.releaseThreshold) {\n state.lastActiveAt = now;\n } else if (now - state.lastActiveAt >= this.releaseMs) {\n state.active = false;\n }\n }\n }\n\n this.emitIfChanged();\n }\n\n private getActiveSpeakerIds(): string[] {\n return Array.from(this.speakers.values())\n .filter((speaker) => speaker.active)\n .map((speaker) => speaker.participantId);\n }\n\n private emitIfChanged(force = false) {\n const ids = this.getActiveSpeakerIds().sort();\n\n const key = ids.join(\"|\");\n\n if (!force && key === this.lastEmitted) {\n return;\n }\n\n this.lastEmitted = key;\n\n this.onActiveSpeakersChanged(ids);\n }\n\n async destroy() {\n this.clear();\n\n if (this.audioContext) {\n try {\n await this.audioContext.close();\n } catch {\n // Ignore already closed context.\n }\n\n this.audioContext = null;\n }\n }\n}\n","import {\n ChatMessage,\n Listener,\n Participant,\n ParticipantMedia,\n StateScope,\n} from \"../types/meeting\";\n\ntype LocalParticipantPatch = {\n id?: string;\n name?: string;\n media?: Partial<ParticipantMedia>;\n};\n\nexport class MeetingState {\n participants = new Map<string, Participant>();\n localParticipant: Participant | null = null;\n localStream: MediaStream | null = null;\n chatMessages = new Map<string, ChatMessage>();\n presenterId: string | null = null;\n activeSpeakerIds = new Set<string>();\n\n private listeners = new Map<StateScope, Set<Listener>>();\n\n // ---- reactive system ----\n\n subscribe(scope: StateScope, fn: Listener): () => void {\n if (!this.listeners.has(scope)) {\n this.listeners.set(scope, new Set());\n }\n this.listeners.get(scope)!.add(fn);\n\n return () => {\n this.listeners.get(scope)?.delete(fn);\n };\n }\n\n notify(scope: StateScope) {\n this.listeners.get(scope)?.forEach((fn) => fn());\n }\n\n setPresenterId(id: string | null) {\n if (this.presenterId === id) return;\n this.presenterId = id;\n this.notify(\"presenter\");\n this.notify(\"participants\");\n }\n\n setActiveSpeakers(ids: string[]) {\n const next = new Set(ids);\n\n if (\n next.size === this.activeSpeakerIds.size &&\n [...next].every((id) => this.activeSpeakerIds.has(id))\n ) {\n return;\n }\n\n this.activeSpeakerIds = next;\n\n this.notify(\"activeSpeakers\");\n }\n\n // ---- participants ----\n\n addParticipant(p: Participant) {\n if (this.participants.has(p.id)) return false;\n // Fix: Immutable Map update\n const next = new Map(this.participants);\n next.set(p.id, p);\n this.participants = next;\n\n this.notify(\"participants\");\n return true;\n }\n\n removeParticipant(id: string) {\n // Fix: Immutable Map update\n const next = new Map(this.participants);\n next.delete(id);\n this.participants = next;\n\n this.notify(\"participants\");\n }\n\n updateParticipantMedia(\n id: string,\n patch: Partial<NonNullable<Participant[\"media\"]>>,\n ) {\n const p = this.participants.get(id);\n if (!p) return;\n\n const updated: Participant = {\n ...p,\n media: {\n stream: null,\n screenStream: undefined,\n cameraTrack: undefined,\n screenTrack: undefined,\n audioTrack: undefined,\n micEnabled: true,\n camEnabled: true,\n isScreenSharing: false,\n ...p.media,\n ...patch,\n },\n };\n\n // Keep your clean immutable map update\n const next = new Map(this.participants);\n next.set(id, updated);\n this.participants = next;\n\n this.notify(`participant:${id}`);\n this.notify(\"participants\");\n }\n\n updateLocalParticipant(patch: LocalParticipantPatch) {\n const prev = this.localParticipant;\n\n if (!prev) {\n this.localParticipant = {\n id: patch.id ?? \"\",\n name: patch.name ?? \"\",\n media: {\n stream: patch.media?.stream ?? null, // ◄ FIX: Capture the stream from the patch here\n screenStream: patch.media?.screenStream,\n cameraTrack: patch.media?.cameraTrack,\n screenTrack: patch.media?.screenTrack,\n audioTrack: patch.media?.audioTrack,\n micEnabled: patch.media?.micEnabled ?? true,\n camEnabled: patch.media?.camEnabled ?? true,\n isScreenSharing: patch.media?.isScreenSharing ?? false,\n },\n };\n\n this.notify(\"localParticipant\");\n return;\n }\n\n const prevMedia = prev.media ?? {\n stream: null,\n screenStream: undefined,\n cameraTrack: undefined,\n screenTrack: undefined,\n audioTrack: undefined,\n micEnabled: true,\n camEnabled: true,\n isScreenSharing: false,\n };\n\n const nextMedia: ParticipantMedia = {\n stream: patch.media?.stream ?? prevMedia.stream,\n screenStream: patch.media?.screenStream ?? prevMedia.screenStream,\n cameraTrack: patch.media?.cameraTrack ?? prevMedia.cameraTrack,\n screenTrack: patch.media?.screenTrack ?? prevMedia.screenTrack,\n audioTrack: patch.media?.audioTrack ?? prevMedia.audioTrack,\n micEnabled: patch.media?.micEnabled ?? prevMedia.micEnabled,\n camEnabled: patch.media?.camEnabled ?? prevMedia.camEnabled,\n isScreenSharing:\n patch.media?.isScreenSharing ?? prevMedia.isScreenSharing,\n };\n\n this.localParticipant = {\n ...prev,\n id: patch.id ?? prev.id,\n name: patch.name ?? prev.name,\n media: nextMedia,\n };\n\n this.notify(\"localParticipant\");\n }\n\n // ---- chat ----\n\n addChatMessage(msg: ChatMessage) {\n this.chatMessages.set(msg.id, msg);\n this.notify(\"chat\");\n }\n\n getChatMessages() {\n return Array.from(this.chatMessages.values()).sort(\n (a, b) => a.timestamp - b.timestamp,\n );\n }\n\n clearChat() {\n this.chatMessages.clear();\n this.notify(\"chat\");\n }\n\n // ---- helpers ----\n\n getParticipants() {\n return Array.from(this.participants.values());\n }\n\n getParticipant(id: string) {\n return this.participants.get(id) ?? null;\n }\n\n resetRemoteState() {\n this.participants.clear();\n this.chatMessages.clear();\n this.presenterId = null;\n this.activeSpeakerIds = new Set();\n this.notify(\"participants\");\n this.notify(\"chat\");\n this.notify(\"presenter\");\n this.notify(\"activeSpeakers\");\n }\n}\n","/**\n * DefComm SFU client.\n *\n * Signaling is authoritative for admission/session state.\n * WebRTC peer connections are transport state and are recreated only after a\n * successful join/resume. A transient WebSocket close therefore does NOT\n * destroy the local MediaStream or immediately declare the participant gone.\n */\n\nexport type SFUConnectionState =\n | \"idle\"\n | \"connecting\"\n | \"joining\"\n | \"waiting_approval\"\n | \"connected\"\n | \"reconnecting\"\n | \"leaving\"\n | \"disconnected\";\n\nexport interface TrackInfo {\n track_id: string;\n participant_id: string;\n kind: \"audio\" | \"video\";\n source?: \"camera\" | \"screen\" | \"audio\" | string;\n [key: string]: any;\n}\n\nexport interface ParticipantInfo {\n participant_id: string;\n user_metadata?: { name?: string; [key: string]: any };\n display_name?: string;\n [key: string]: any;\n}\n\nexport interface JoinPendingInfo {\n request_id: string;\n room_code?: string;\n message?: string;\n}\n\ninterface SFUClientOptions {\n apiBase?: string;\n wsBase?: string;\n userId?: string;\n onStateChange?: (state: SFUConnectionState) => void;\n onParticipantJoined?: (participant: ParticipantInfo) => void;\n onParticipantLeft?: (participant: string | ParticipantInfo) => void;\n onParticipantPresence?: (participantId: string, presence: string) => void;\n onTrackPublished?: (track: TrackInfo) => void;\n onTrackUnpublished?: (track: TrackInfo) => void;\n onRemoteTrack?: (\n track: MediaStreamTrack,\n stream: MediaStream,\n metadata: TrackInfo,\n ) => void;\n onConnected?: (payload: any, resumed: boolean) => void;\n onDisconnected?: () => void;\n onReconnecting?: (attempt: number) => void;\n onJoinPending?: (info: JoinPendingInfo) => void;\n onJoinApproved?: (requestId: string) => void;\n onJoinRejected?: (requestId: string, reason?: string) => void;\n onJoinRequested?: (request: any) => void;\n onScreenShareStarted?: (participantId: string, track?: TrackInfo) => void;\n onScreenShareStopped?: (participantId: string, trackId?: string) => void;\n onTrackStateChanged?: (track: TrackInfo) => void;\n onRecordingStarted?: (recording: { recording_id: string; started_at: string }) => void;\n onRecordingStopped?: (recording: { recording_id: string; stopped_at: string }) => void;\n onError?: (error: any) => void;\n autoSubscribe?: boolean;\n}\n\ntype PeerName = \"publisher\" | \"subscriber\";\ntype JoinWaiter = {\n resolve: (value: any) => void;\n reject: (error: any) => void;\n};\n\nexport class SFUClient {\n private apiBase: string;\n private wsBase: string;\n private userId: string;\n\n private ws: WebSocket | null = null;\n private publisher: RTCPeerConnection | null = null;\n private subscriber: RTCPeerConnection | null = null;\n\n private localStream: MediaStream | null = null;\n private screenStream: MediaStream | null = null;\n private videoSender: RTCRtpSender | null = null;\n private audioSender: RTCRtpSender | null = null;\n private screenSender: RTCRtpSender | null = null;\n private audioTransceiver: RTCRtpTransceiver | null = null;\n private cameraTransceiver: RTCRtpTransceiver | null = null;\n private screenTransceiver: RTCRtpTransceiver | null = null;\n\n private iceServers: RTCIceServer[] = [];\n private requestId = 0;\n private publisherRevision = 0;\n private currentParticipantId: string | null = null;\n private token: string | null = null;\n private room: string | null = null;\n private resumeToken: string | null = null;\n private pendingJoinRequestId: string | null = null;\n private joinOptions: {\n displayName?: string;\n avatarUrl?: string;\n } = {};\n\n private state: SFUConnectionState = \"idle\";\n private intentionalClose = false;\n private leaveAcknowledged = false;\n private joiningWithResume = false;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private reconnectAttempt = 0;\n private maxReconnectAttempts = 8;\n private reconnectBaseMs = 750;\n private joinWaiter: JoinWaiter | null = null;\n\n private pendingIce: Record<PeerName, RTCIceCandidateInit[]> = {\n publisher: [],\n subscriber: [],\n };\n\n private subscriberNegotiating = false;\n private offerQueue: any[] = [];\n private subscriptionQueue: string[] = [];\n private subscriptionRunning = false;\n private subscriptionWaiters: Array<{\n resolve: () => void;\n reject: (error: any) => void;\n }> = [];\n\n private subscribedTracks = new Set<string>();\n private trackMetadata = new Map<string, TrackInfo>();\n private participants = new Map<string, ParticipantInfo>();\n private remoteStreams = new Map<string, MediaStream>();\n private remoteScreenStreams = new Map<string, MediaStream>();\n private trackToParticipant = new Map<string, string>();\n private trackToSource = new Map<string, string>();\n private localTrackIds = new Map<\"audio\" | \"camera\" | \"screen\", string>();\n\n private subscriberStatsTimer: ReturnType<typeof setInterval> | null = null;\n\n private onStateChange: (state: SFUConnectionState) => void;\n private onParticipantJoined: (p: ParticipantInfo) => void;\n private onParticipantLeft: (p: string | ParticipantInfo) => void;\n private onParticipantPresence: (id: string, presence: string) => void;\n private onTrackPublished: (t: TrackInfo) => void;\n private onTrackUnpublished: (t: TrackInfo) => void;\n private onRemoteTrack: (\n t: MediaStreamTrack,\n s: MediaStream,\n m: TrackInfo,\n ) => void;\n private onConnected: (p: any, resumed: boolean) => void;\n private onDisconnected: () => void;\n private onReconnecting: (attempt: number) => void;\n private onJoinPending: (info: JoinPendingInfo) => void;\n private onJoinApproved: (requestId: string) => void;\n private onJoinRejected: (requestId: string, reason?: string) => void;\n private onJoinRequested: (request: any) => void;\n private onScreenShareStarted: (participantId: string, track?: TrackInfo) => void;\n private onScreenShareStopped: (participantId: string, trackId?: string) => void;\n private onTrackStateChanged: (track: TrackInfo) => void;\n private onRecordingStarted: (recording: { recording_id: string; started_at: string }) => void;\n private onRecordingStopped: (recording: { recording_id: string; stopped_at: string }) => void;\n private onError: (e: any) => void;\n private autoSubscribe: boolean;\n\n constructor(options: SFUClientOptions = {}) {\n this.apiBase = options.apiBase || \"https://api.example.com/api\";\n this.wsBase = options.wsBase || \"wss://api.example.com/ws\";\n this.userId = options.userId || this.createId();\n\n this.onStateChange = options.onStateChange || (() => {});\n this.onParticipantJoined = options.onParticipantJoined || (() => {});\n this.onParticipantLeft = options.onParticipantLeft || (() => {});\n this.onParticipantPresence = options.onParticipantPresence || (() => {});\n this.onTrackPublished = options.onTrackPublished || (() => {});\n this.onTrackUnpublished = options.onTrackUnpublished || (() => {});\n this.onRemoteTrack = options.onRemoteTrack || (() => {});\n this.onConnected = options.onConnected || (() => {});\n this.onDisconnected = options.onDisconnected || (() => {});\n this.onReconnecting = options.onReconnecting || (() => {});\n this.onJoinPending = options.onJoinPending || (() => {});\n this.onJoinApproved = options.onJoinApproved || (() => {});\n this.onJoinRejected = options.onJoinRejected || (() => {});\n this.onJoinRequested = options.onJoinRequested || (() => {});\n this.onScreenShareStarted = options.onScreenShareStarted || (() => {});\n this.onScreenShareStopped = options.onScreenShareStopped || (() => {});\n this.onTrackStateChanged = options.onTrackStateChanged || (() => {});\n this.onRecordingStarted = options.onRecordingStarted || (() => {});\n this.onRecordingStopped = options.onRecordingStopped || (() => {});\n this.onError = options.onError || console.error;\n this.autoSubscribe = options.autoSubscribe !== false;\n }\n\n private createId(): string {\n return typeof crypto !== \"undefined\" && crypto.randomUUID\n ? crypto.randomUUID()\n : `id_${Math.random().toString(36).slice(2)}_${Date.now()}`;\n }\n\n private resumeStorageKey(roomCode: string) {\n return `defcomm:sfu:resume:${roomCode}`;\n }\n\n private loadResumeToken(roomCode: string): string | null {\n try {\n return localStorage.getItem(this.resumeStorageKey(roomCode));\n } catch {\n return null;\n }\n }\n\n private saveResumeToken(roomCode: string, token: string) {\n try {\n localStorage.setItem(this.resumeStorageKey(roomCode), token);\n } catch {\n // Storage can be unavailable in private/SSR environments.\n }\n }\n\n private clearResumeToken(roomCode: string | null) {\n if (!roomCode) return;\n try {\n localStorage.removeItem(this.resumeStorageKey(roomCode));\n } catch {\n // ignore\n }\n }\n\n private setState(next: SFUConnectionState) {\n if (this.state === next) return;\n this.state = next;\n this.onStateChange(next);\n }\n\n getConnectionState(): SFUConnectionState {\n return this.state;\n }\n\n getParticipantId(): string | null {\n return this.currentParticipantId;\n }\n\n getResumeToken(): string | null {\n return this.resumeToken;\n }\n\n getLocalStream(): MediaStream | null {\n return this.localStream;\n }\n\n getScreenStream(): MediaStream | null {\n return this.screenStream;\n }\n\n setLocalStream(stream: MediaStream | null) {\n this.localStream = stream;\n }\n\n private nextRequestId(): string {\n return (++this.requestId).toString();\n }\n\n private async request(url: string, options: RequestInit = {}) {\n const res = await fetch(url, {\n headers: { \"Content-Type\": \"application/json\" },\n ...options,\n });\n\n if (!res.ok) {\n let body: any = {};\n try {\n body = await res.json();\n } catch {\n // ignore non-json error bodies\n }\n throw new Error(body.message || res.statusText);\n }\n\n return res.json();\n }\n\n async createRoom(input: {\n name: string;\n description?: string;\n capacity?: number;\n is_private?: boolean;\n }) {\n return this.request(`${this.apiBase}/rooms`, {\n method: \"POST\",\n body: JSON.stringify({\n name: input.name,\n description: input.description ?? \"\",\n capacity: input.capacity ?? 20,\n is_private: input.is_private ?? false,\n }),\n });\n }\n\n async getRoom(roomCode: string) {\n return this.request(`${this.apiBase}/rooms/${encodeURIComponent(roomCode)}`);\n }\n\n async deleteRoom(roomCode: string) {\n return this.request(`${this.apiBase}/rooms/${encodeURIComponent(roomCode)}`, {\n method: \"DELETE\",\n });\n }\n\n async getToken(\n roomCode: string,\n options: {\n displayName?: string;\n avatarUrl?: string;\n userId?: string;\n } = {},\n ) {\n const nextRoom = roomCode.trim();\n if (this.room && this.room !== nextRoom) {\n this.resumeToken = null;\n }\n\n this.room = nextRoom;\n this.joinOptions = {\n displayName: options.displayName,\n avatarUrl: options.avatarUrl,\n };\n if (options.userId) this.userId = options.userId;\n if (!this.resumeToken) {\n this.resumeToken = this.loadResumeToken(this.room);\n }\n\n const data = await this.request(`${this.apiBase}/token`, {\n method: \"POST\",\n body: JSON.stringify({\n room_code: this.room,\n user_id: this.userId,\n display_name: options.displayName,\n avatar_url: options.avatarUrl,\n }),\n });\n\n this.token = data?.token;\n if (!this.token) throw new Error(\"Token endpoint returned no token\");\n\n return this.connect(this.token, this.joinOptions);\n }\n\n private async refreshAccessToken() {\n if (!this.room) throw new Error(\"Cannot refresh token without a room\");\n\n const data = await this.request(`${this.apiBase}/token`, {\n method: \"POST\",\n body: JSON.stringify({\n room_code: this.room,\n user_id: this.userId,\n display_name: this.joinOptions.displayName,\n avatar_url: this.joinOptions.avatarUrl,\n }),\n });\n\n if (!data?.token) throw new Error(\"Token refresh returned no token\");\n this.token = data.token;\n return this.token;\n }\n\n private connect(token: string, options: any = {}) {\n this.token = token;\n this.intentionalClose = false;\n this.setState(this.reconnectAttempt > 0 ? \"reconnecting\" : \"connecting\");\n\n return new Promise<void>((resolve, reject) => {\n this.joinWaiter = { resolve, reject };\n this.openWebSocket(options);\n });\n }\n\n private openWebSocket(options: any = {}) {\n if (!this.token || !this.room) {\n const error = new Error(\"Cannot connect without token and room\");\n this.failJoin(error);\n return;\n }\n\n if (this.ws) {\n try {\n this.ws.onclose = null;\n this.ws.close();\n } catch {\n // ignore\n }\n }\n\n const ws = new WebSocket(\n `${this.wsBase}?access_token=${encodeURIComponent(this.token)}`,\n );\n this.ws = ws;\n\n ws.onopen = () => {\n this.setState(\"joining\");\n this.joiningWithResume = Boolean(this.resumeToken);\n\n const joinPayload: any = {\n token: this.token,\n room_code: this.room,\n resume_token: this.resumeToken,\n display_name: options.displayName,\n avatar_url: options.avatarUrl,\n };\n\n // After approval the Rust server requires the original pending request id.\n if (this.pendingJoinRequestId) {\n this.send({\n type: \"join\",\n request_id: this.pendingJoinRequestId,\n payload: joinPayload,\n });\n } else {\n this.send({ type: \"join\", payload: joinPayload });\n }\n };\n\n ws.onerror = (event) => {\n this.onError(event);\n };\n\n ws.onclose = () => {\n if (this.ws !== ws) return;\n this.ws = null;\n\n if (this.intentionalClose || this.state === \"leaving\") {\n this.setState(\"disconnected\");\n this.onDisconnected();\n return;\n }\n\n // Keep MediaStreams and logical participant state alive.\n this.setState(\"reconnecting\");\n this.onDisconnected();\n this.scheduleReconnect();\n };\n\n ws.onmessage = async (event) => {\n if (this.ws !== ws) return;\n try {\n const message = JSON.parse(event.data);\n await this.handleServerMessage(message);\n } catch (error) {\n this.onError(error);\n }\n };\n }\n\n private scheduleReconnect() {\n if (this.reconnectTimer || this.intentionalClose) return;\n if (this.reconnectAttempt >= this.maxReconnectAttempts) {\n this.setState(\"disconnected\");\n this.failJoin(new Error(\"SFU reconnect attempts exhausted\"));\n return;\n }\n\n this.reconnectAttempt += 1;\n const delay = Math.min(\n 15000,\n this.reconnectBaseMs * Math.pow(2, this.reconnectAttempt - 1),\n );\n\n this.onReconnecting(this.reconnectAttempt);\n\n this.reconnectTimer = setTimeout(async () => {\n this.reconnectTimer = null;\n try {\n await this.refreshAccessToken();\n this.openWebSocket(this.joinOptions);\n } catch (error) {\n this.onError(error);\n this.scheduleReconnect();\n }\n }, delay);\n }\n\n private failJoin(error: any) {\n if (this.joinWaiter) {\n const waiter = this.joinWaiter;\n this.joinWaiter = null;\n waiter.reject(error);\n }\n }\n\n private resolveJoin(value: any) {\n if (!this.joinWaiter) return;\n const waiter = this.joinWaiter;\n this.joinWaiter = null;\n waiter.resolve(value);\n }\n\n private async handleServerMessage(message: any) {\n const type = message?.type;\n const payload = message?.payload || {};\n\n switch (type) {\n case \"joined\": {\n await this.handleJoined(payload);\n break;\n }\n\n case \"left\": {\n this.leaveAcknowledged = true;\n break;\n }\n\n case \"join_pending\": {\n const requestId = payload.request_id || message.request_id;\n if (!requestId) throw new Error(\"join_pending has no request_id\");\n\n this.pendingJoinRequestId = requestId;\n this.setState(\"waiting_approval\");\n this.onJoinPending({\n request_id: requestId,\n room_code: payload.room_code || this.room || undefined,\n message: payload.message,\n });\n break;\n }\n\n case \"join_approved\": {\n const requestId = payload.request_id || message.request_id;\n if (!requestId) break;\n this.pendingJoinRequestId = requestId;\n this.onJoinApproved(requestId);\n\n // Approval is a direct signal to the waiting session. Continue the join\n // with the same request id; the Rust Room layer performs the admission.\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.setState(\"joining\");\n this.send({\n type: \"join\",\n request_id: requestId,\n payload: {\n token: this.token,\n room_code: this.room,\n resume_token: this.resumeToken,\n display_name: this.joinOptions.displayName,\n avatar_url: this.joinOptions.avatarUrl,\n },\n });\n }\n break;\n }\n\n case \"join_rejected\": {\n const requestId = payload.request_id || message.request_id;\n const reason = payload.reason;\n this.onJoinRejected(requestId, reason);\n this.pendingJoinRequestId = null;\n this.intentionalClose = true;\n this.failJoin(new Error(reason || \"Join request rejected\"));\n break;\n }\n\n case \"join_requested\":\n case \"join_request\": {\n this.onJoinRequested(payload.request || payload);\n break;\n }\n\n case \"publish_answer\": {\n if (!this.publisher) break;\n await this.publisher.setRemoteDescription({\n type: \"answer\",\n sdp: payload.sdp,\n });\n await this.flushPendingIce(\"publisher\");\n break;\n }\n\n case \"subscribe_offer\": {\n this.offerQueue.push(payload);\n if (!this.subscriberNegotiating) await this.processOfferQueue();\n break;\n }\n\n case \"ice_candidate\":\n case \"publisher_ice_candidate\":\n case \"subscriber_ice_candidate\": {\n const candidatePayload = {\n ...payload,\n peer:\n payload.peer ||\n (type === \"publisher_ice_candidate\" ? \"publisher\" : \"subscriber\"),\n };\n await this.handleIce(candidatePayload);\n break;\n }\n\n case \"participant_joined\": {\n const participant = payload.participant || payload;\n const participantId =\n participant?.participant_id || payload.participant_id;\n if (!participantId || participantId === this.currentParticipantId) break;\n\n if (participant) this.participants.set(participantId, participant);\n this.onParticipantJoined(participant);\n break;\n }\n\n case \"participant_left\": {\n const participantId = payload.participant_id;\n if (!participantId) break;\n this.participants.delete(participantId);\n this.removeRemoteParticipant(participantId);\n this.onParticipantLeft(participantId);\n break;\n }\n\n case \"participant_presence\":\n case \"participant_presence_changed\": {\n const participantId = payload.participant_id;\n const presence = payload.presence;\n if (participantId && presence) {\n this.onParticipantPresence(participantId, String(presence));\n }\n break;\n }\n\n case \"track_published\": {\n const track: TrackInfo = payload.track || payload;\n if (!track?.track_id) break;\n this.rememberTrack(track);\n\n if (track.participant_id === this.currentParticipantId) {\n if (track.source === \"audio\") {\n this.localTrackIds.set(\"audio\", track.track_id);\n const muted = !(this.localStream?.getAudioTracks()[0]?.enabled ?? true);\n this.send({ type: \"track_state\", payload: { track_id: track.track_id, muted } });\n }\n if (track.source === \"camera\") {\n this.localTrackIds.set(\"camera\", track.track_id);\n const muted = !(this.localStream?.getVideoTracks()[0]?.enabled ?? true);\n this.send({ type: \"track_state\", payload: { track_id: track.track_id, muted } });\n }\n if (track.source === \"screen\") this.localTrackIds.set(\"screen\", track.track_id);\n break;\n }\n\n this.onTrackPublished(track);\n if (this.autoSubscribe) await this.subscribe(track.track_id);\n break;\n }\n\n case \"track_unpublished\": {\n const trackId = payload.track_id || payload.track?.track_id;\n if (!trackId) break;\n const track =\n this.trackMetadata.get(trackId) ||\n ({\n track_id: trackId,\n participant_id: this.trackToParticipant.get(trackId) || \"\",\n source: this.trackToSource.get(trackId),\n kind: \"video\",\n } as TrackInfo);\n\n this.trackMetadata.delete(trackId);\n this.subscribedTracks.delete(trackId);\n this.trackToParticipant.delete(trackId);\n this.trackToSource.delete(trackId);\n\n for (const [source, localId] of this.localTrackIds) {\n if (localId === trackId) this.localTrackIds.delete(source);\n }\n\n if (track.participant_id === this.currentParticipantId) break;\n this.onTrackUnpublished(track);\n break;\n }\n\n case \"track_state_changed\": {\n const trackId = payload.track_id || payload.track?.track_id;\n if (!trackId) break;\n\n const existing = this.trackMetadata.get(trackId);\n const track: TrackInfo = {\n ...(existing || {}),\n ...(payload.track || {}),\n track_id: trackId,\n participant_id:\n payload.participant_id ||\n existing?.participant_id ||\n payload.track?.participant_id,\n kind:\n payload.kind ||\n payload.track?.kind ||\n existing?.kind ||\n \"video\",\n source:\n payload.source ||\n payload.track?.source ||\n existing?.source,\n muted: Boolean(payload.muted),\n };\n\n if (!track.participant_id) break;\n this.rememberTrack(track);\n this.onTrackStateChanged(track);\n break;\n }\n\n case \"subscription_updated\": {\n // Authoritative acknowledgement of the current subscriber set.\n break;\n }\n\n case \"recording_started\": {\n this.onRecordingStarted({\n recording_id: payload.recording_id,\n started_at: payload.started_at,\n });\n break;\n }\n\n case \"recording_stopped\": {\n this.onRecordingStopped({\n recording_id: payload.recording_id,\n stopped_at: payload.stopped_at,\n });\n break;\n }\n\n case \"reconnecting\": {\n this.setState(\"reconnecting\");\n break;\n }\n\n case \"screen_share_started\": {\n const participantId = payload.participant_id;\n const track = payload.track as TrackInfo | undefined;\n if (track) this.rememberTrack(track);\n if (participantId) this.onScreenShareStarted(participantId, track);\n break;\n }\n\n case \"screen_share_stopped\": {\n const participantId = payload.participant_id;\n const screenStream = participantId\n ? this.remoteScreenStreams.get(participantId)\n : null;\n const trackId = payload.track_id;\n\n if (screenStream) {\n for (const track of screenStream.getVideoTracks()) {\n if (\n !trackId ||\n this.normalizeRemoteTrackId(track.id) === String(trackId)\n ) {\n screenStream.removeTrack(track);\n track.stop();\n }\n }\n\n if (screenStream.getTracks().length === 0 && participantId) {\n this.remoteScreenStreams.delete(participantId);\n }\n }\n\n this.onScreenShareStopped(participantId, trackId);\n break;\n }\n\n case \"error\": {\n const error = new Error(payload.message || \"SFU signaling error\");\n this.onError(error);\n if (this.state === \"joining\" || this.state === \"waiting_approval\") {\n this.failJoin(error);\n }\n break;\n }\n\n default:\n // Unknown messages must not tear down the signaling state machine.\n console.debug(\"[SFU] Ignoring unknown server message\", message);\n }\n }\n\n private rememberTrack(track: TrackInfo) {\n this.trackMetadata.set(track.track_id, track);\n this.trackToParticipant.set(track.track_id, track.participant_id);\n if (track.source) this.trackToSource.set(track.track_id, track.source);\n }\n\n private async handleJoined(payload: any) {\n const resumed = this.joiningWithResume;\n this.joiningWithResume = false;\n\n this.iceServers = payload.ice_servers || this.iceServers || [];\n this.currentParticipantId = payload.participant_id;\n this.resumeToken = payload.resume_token || payload.resumeToken || this.resumeToken;\n if (this.room && this.resumeToken) {\n this.saveResumeToken(this.room, this.resumeToken);\n }\n this.pendingJoinRequestId = null;\n this.reconnectAttempt = 0;\n\n this.participants.clear();\n this.trackMetadata.clear();\n this.trackToParticipant.clear();\n this.trackToSource.clear();\n this.localTrackIds.clear();\n\n for (const participant of payload.participants || []) {\n if (participant?.participant_id) {\n this.participants.set(participant.participant_id, participant);\n }\n }\n\n for (const track of payload.tracks || []) {\n if (track?.track_id) this.rememberTrack(track);\n }\n\n await this.initializePeerConnections();\n this.setState(\"connected\");\n this.onConnected(payload, resumed);\n\n for (const participant of this.participants.values()) {\n if (participant.participant_id !== this.currentParticipantId) {\n this.onParticipantJoined(participant);\n }\n }\n\n // A reconnect/resume needs a fresh publisher negotiation and subscription\n // reconciliation because the WebSocket transport was replaced.\n if (this.localStream) {\n await this.publishExistingTracks();\n }\n\n if (this.autoSubscribe) {\n const trackIds = [...this.trackMetadata.values()]\n .filter((track) => track.participant_id !== this.currentParticipantId)\n .map((track) => track.track_id);\n if (trackIds.length) await this.subscribeMultiple(trackIds);\n }\n\n this.resolveJoin(payload);\n }\n\n private async initializePeerConnections() {\n this.closePeerConnectionsOnly();\n this.publisherRevision = 0;\n\n const config: RTCConfiguration = { iceServers: this.iceServers };\n this.publisher = new RTCPeerConnection(config);\n this.subscriber = new RTCPeerConnection(config);\n\n // Keep audio, camera, and screen on three permanent publisher m-lines.\n // This mirrors the working client: screen sharing must never reuse the\n // camera sender/transceiver.\n this.audioTransceiver = this.publisher.addTransceiver(\"audio\", {\n direction: \"sendonly\",\n });\n this.cameraTransceiver = this.publisher.addTransceiver(\"video\", {\n direction: \"sendonly\",\n });\n this.screenTransceiver = this.publisher.addTransceiver(\"video\", {\n direction: \"inactive\",\n });\n\n this.audioSender = this.audioTransceiver.sender;\n this.videoSender = this.cameraTransceiver.sender;\n this.screenSender = this.screenTransceiver.sender;\n\n this.publisher.onicecandidate = (event) => {\n if (event.candidate) this.sendCandidate(\"publisher\", event.candidate);\n };\n\n this.subscriber.onicecandidate = (event) => {\n if (event.candidate) this.sendCandidate(\"subscriber\", event.candidate);\n };\n\n this.publisher.onconnectionstatechange = () => {\n const state = this.publisher?.connectionState;\n if (state === \"failed\") {\n this.onError(new Error(\"Publisher PeerConnection failed\"));\n }\n };\n\n this.subscriber.onconnectionstatechange = () => {\n const state = this.subscriber?.connectionState;\n if (state === \"failed\") {\n this.onError(new Error(\"Subscriber PeerConnection failed\"));\n }\n };\n\n this.subscriber.ontrack = (event) => {\n void this.handleRemoteTrack(event);\n };\n\n if (!this.subscriberStatsTimer) {\n this.subscriberStatsTimer = setInterval(() => {\n void this.logSubscriberVideoStats();\n }, 3000);\n }\n }\n\n private async handleRemoteTrack(event: RTCTrackEvent) {\n const stream = event.streams?.[0] || null;\n const metadata = this.resolveRemoteTrackMetadata(event.track, stream);\n\n if (!metadata?.participant_id) {\n this.onError(\n new Error(\n `Remote ${event.track.kind} track ${event.track.id} has no SFU participant mapping`,\n ),\n );\n return;\n }\n\n const participantId = metadata.participant_id;\n const source = String(\n metadata.source || this.trackToSource.get(metadata.track_id) || \"\",\n ).trim().toLowerCase();\n\n // Screen is a completely separate media path. Never put it in the\n // participant's normal camera/audio MediaStream.\n if (source === \"screen\" || source === \"screen_share\") {\n let screenStream = this.remoteScreenStreams.get(participantId);\n\n if (!screenStream) {\n screenStream = new MediaStream();\n this.remoteScreenStreams.set(participantId, screenStream);\n }\n\n for (const existing of screenStream.getVideoTracks()) {\n if (existing.id !== event.track.id) {\n screenStream.removeTrack(existing);\n existing.stop();\n }\n }\n\n if (!screenStream.getTracks().some((track) => track.id === event.track.id)) {\n screenStream.addTrack(event.track);\n }\n\n event.track.onended = () => {\n try {\n screenStream?.removeTrack(event.track);\n } catch {}\n\n if (screenStream?.getTracks().length === 0) {\n this.remoteScreenStreams.delete(participantId);\n this.onScreenShareStopped(\n participantId,\n metadata.track_id,\n );\n }\n };\n\n this.onScreenShareStarted(participantId, metadata);\n this.onRemoteTrack(event.track, screenStream, {\n ...metadata,\n source: \"screen\",\n });\n return;\n }\n\n // Only audio and camera video belong to the normal participant stream.\n if (event.track.kind === \"video\" && source !== \"camera\") {\n this.onError(\n new Error(\n `Refusing to route unknown remote video source to camera: ${metadata.track_id}`,\n ),\n );\n return;\n }\n\n let remoteStream = this.remoteStreams.get(participantId);\n if (!remoteStream) {\n remoteStream = new MediaStream();\n this.remoteStreams.set(participantId, remoteStream);\n }\n\n for (const existing of remoteStream.getTracks()) {\n if (existing.kind === event.track.kind && existing.id !== event.track.id) {\n remoteStream.removeTrack(existing);\n existing.stop();\n }\n }\n\n if (!remoteStream.getTracks().some((track) => track.id === event.track.id)) {\n remoteStream.addTrack(event.track);\n }\n\n event.track.onended = () => {\n try {\n remoteStream?.removeTrack(event.track);\n } catch {}\n };\n\n this.onRemoteTrack(event.track, remoteStream, {\n ...metadata,\n source: event.track.kind === \"audio\" ? \"audio\" : \"camera\",\n });\n }\n\n private normalizeRemoteTrackId(browserTrackId: string): string {\n return browserTrackId?.startsWith(\"track-\")\n ? browserTrackId.slice(\"track-\".length)\n : browserTrackId;\n }\n\n private resolveRemoteTrackMetadata(\n track: MediaStreamTrack,\n stream: MediaStream | null,\n ): TrackInfo | null {\n const candidates = [\n this.normalizeRemoteTrackId(track.id),\n track.id,\n stream?.id ? this.normalizeRemoteTrackId(stream.id) : null,\n stream?.id || null,\n ].filter(Boolean) as string[];\n\n for (const id of candidates) {\n const metadata = this.trackMetadata.get(id);\n if (metadata) return metadata;\n }\n\n // Never guess by participant + kind. A participant can publish camera\n // and screen simultaneously; guessing is exactly how a screen track can\n // end up in the camera tile.\n return null;\n }\n\n private sendCandidate(peer: PeerName, candidate: RTCIceCandidate) {\n this.send({\n type: \"ice_candidate\",\n payload: {\n peer,\n candidate: candidate.candidate,\n sdp_mid: candidate.sdpMid,\n sdp_mline_index: candidate.sdpMLineIndex,\n username_fragment: candidate.usernameFragment,\n },\n });\n }\n\n private async handleIce(payload: any) {\n const peer: PeerName = payload.peer === \"publisher\" ? \"publisher\" : \"subscriber\";\n const pc = peer === \"publisher\" ? this.publisher : this.subscriber;\n\n const candidate: RTCIceCandidateInit = {\n candidate: payload.candidate,\n sdpMid: payload.sdp_mid ?? payload.sdpMid ?? null,\n sdpMLineIndex: payload.sdp_mline_index ?? payload.sdpMLineIndex ?? null,\n usernameFragment: payload.username_fragment ?? payload.usernameFragment ?? null,\n };\n\n if (!pc || !pc.remoteDescription) {\n this.pendingIce[peer].push(candidate);\n return;\n }\n\n try {\n await pc.addIceCandidate(candidate);\n } catch (error) {\n this.onError(new Error(`Failed to add ${peer} ICE candidate: ${String(error)}`));\n }\n }\n\n private async flushPendingIce(peer: PeerName) {\n const pc = peer === \"publisher\" ? this.publisher : this.subscriber;\n if (!pc || !pc.remoteDescription) return;\n\n const queue = this.pendingIce[peer];\n while (queue.length) {\n const candidate = queue.shift()!;\n try {\n await pc.addIceCandidate(candidate);\n } catch (error) {\n this.onError(new Error(`Failed to add queued ${peer} ICE candidate: ${String(error)}`));\n }\n }\n }\n\n private async processOfferQueue() {\n if (!this.subscriber) return;\n\n while (this.offerQueue.length) {\n if (this.subscriberNegotiating) return;\n this.subscriberNegotiating = true;\n const offer = this.offerQueue.shift();\n\n try {\n await this.subscriber.setRemoteDescription({\n type: \"offer\",\n sdp: offer.sdp,\n });\n await this.flushPendingIce(\"subscriber\");\n\n const answer = await this.subscriber.createAnswer();\n await this.subscriber.setLocalDescription(answer);\n\n this.send({\n type: \"subscribe_answer\",\n payload: {\n revision: offer.revision,\n sdp: answer.sdp,\n },\n });\n\n const waiters = this.subscriptionWaiters.splice(0);\n waiters.forEach((w) => w.resolve());\n } catch (error) {\n const waiters = this.subscriptionWaiters.splice(0);\n waiters.forEach((w) => w.reject(error));\n this.onError(new Error(`Failed to process subscriber offer: ${String(error)}`));\n } finally {\n this.subscriberNegotiating = false;\n }\n }\n }\n\n private async subscribe(trackId: string) {\n if (!trackId || this.subscribedTracks.has(trackId)) return;\n this.subscribedTracks.add(trackId);\n this.subscriptionQueue.push(trackId);\n if (!this.subscriptionRunning) await this.processSubscriptionQueue();\n }\n\n private async subscribeMultiple(trackIds: string[]) {\n const uniqueIds = [...new Set(trackIds.filter(Boolean))].filter(\n (id) => !this.subscribedTracks.has(id),\n );\n if (!uniqueIds.length || !this.isSocketOpen()) return;\n\n uniqueIds.forEach((id) => this.subscribedTracks.add(id));\n return new Promise<void>((resolve, reject) => {\n this.subscriptionWaiters.push({ resolve, reject });\n this.send({\n type: \"subscribe\",\n payload: { track_ids: uniqueIds },\n });\n });\n }\n\n private async processSubscriptionQueue() {\n this.subscriptionRunning = true;\n try {\n while (this.subscriptionQueue.length) {\n const trackId = this.subscriptionQueue.shift()!;\n if (!this.isSocketOpen()) {\n this.subscribedTracks.delete(trackId);\n continue;\n }\n\n await new Promise<void>((resolve, reject) => {\n this.subscriptionWaiters.push({ resolve, reject });\n this.send({\n type: \"subscribe\",\n payload: { track_ids: [trackId] },\n });\n });\n }\n } finally {\n this.subscriptionRunning = false;\n }\n }\n\n async publish({ audio = true, video = true } = {}) {\n if (!this.publisher) throw new Error(\"Publisher PeerConnection is not initialized\");\n\n if (!this.localStream) {\n this.localStream = await navigator.mediaDevices.getUserMedia({ audio, video });\n }\n\n await this.publishExistingTracks(audio, video);\n return this.localStream;\n }\n\n private async publishExistingTracks(audio = true, video = true) {\n if (!this.publisher || !this.localStream) return;\n\n if (!this.audioTransceiver || !this.cameraTransceiver || !this.screenTransceiver) {\n throw new Error(\"Publisher transceivers are not initialized\");\n }\n\n const audioTrack = this.localStream\n .getAudioTracks()\n .find((track) => track.readyState === \"live\");\n const cameraTrack = this.localStream\n .getVideoTracks()\n .find((track) => track.readyState === \"live\");\n const screenTrack = this.screenStream\n ?.getVideoTracks()\n .find((track) => track.readyState === \"live\");\n\n await this.audioSender?.replaceTrack(audio && audioTrack ? audioTrack : null);\n this.audioTransceiver.direction = audio && audioTrack ? \"sendonly\" : \"inactive\";\n\n await this.videoSender?.replaceTrack(video && cameraTrack ? cameraTrack : null);\n this.cameraTransceiver.direction = video && cameraTrack ? \"sendonly\" : \"inactive\";\n\n await this.screenSender?.replaceTrack(screenTrack || null);\n this.screenTransceiver.direction = screenTrack ? \"sendonly\" : \"inactive\";\n\n if (!audioTrack && !cameraTrack && !screenTrack) return;\n\n const offer = await this.publisher.createOffer();\n await this.publisher.setLocalDescription(offer);\n\n this.send({\n type: \"publish_offer\",\n payload: {\n revision: ++this.publisherRevision,\n sdp: offer.sdp,\n },\n });\n\n if (screenTrack) {\n this.send({ type: \"start_screen_share\" });\n }\n }\n\n async shareScreen() {\n if (!this.publisher) {\n throw new Error(\"Publisher PeerConnection is not initialized\");\n }\n if (!this.screenTransceiver || !this.screenSender) {\n throw new Error(\"Screen transceiver is not initialized\");\n }\n if (this.screenStream) {\n return this.screenStream;\n }\n\n const screenStream = await navigator.mediaDevices.getDisplayMedia({\n video: true,\n audio: false,\n });\n\n const screenTrack = screenStream.getVideoTracks()[0];\n if (!screenTrack) {\n screenStream.getTracks().forEach((track) => track.stop());\n throw new Error(\"Screen share returned no video track\");\n }\n\n this.screenStream = screenStream;\n\n try {\n // Signal the semantic state before negotiation, matching the working\n // client. The SFU can therefore classify the next video publication as\n // screen rather than camera.\n if (!this.send({ type: \"start_screen_share\" })) {\n throw new Error(\"Failed to signal start_screen_share\");\n }\n\n // IMPORTANT: never addTrack() here. The screen has its own permanent\n // video transceiver. replaceTrack() attaches the display track without\n // touching the camera sender.\n await this.screenSender.replaceTrack(screenTrack);\n this.screenTransceiver.direction = \"sendonly\";\n\n const offer = await this.publisher.createOffer();\n await this.publisher.setLocalDescription(offer);\n\n this.send({\n type: \"publish_offer\",\n payload: {\n revision: ++this.publisherRevision,\n sdp: offer.sdp,\n },\n });\n\n screenTrack.onended = () => {\n void this.stopScreenShare();\n };\n\n console.info(\"[publisher] Screen track attached\", {\n screenTrackId: screenTrack.id,\n cameraTrackId: this.videoSender?.track?.id,\n screenMid: this.screenTransceiver.mid,\n cameraMid: this.cameraTransceiver?.mid,\n });\n\n return this.screenStream;\n } catch (error) {\n try {\n await this.screenSender.replaceTrack(null);\n } catch {}\n\n this.screenTransceiver.direction = \"inactive\";\n screenStream.getTracks().forEach((track) => track.stop());\n this.screenStream = null;\n\n try {\n this.send({ type: \"stop_screen_share\" });\n } catch {}\n\n throw error;\n }\n }\n\n async stopScreenShare() {\n if (!this.screenStream && !this.screenSender?.track) return;\n\n const screenTrack = this.screenSender?.track || null;\n if (screenTrack) screenTrack.onended = null;\n\n try {\n await this.screenSender?.replaceTrack(null);\n } catch (error) {\n this.onError(error);\n }\n\n if (this.screenTransceiver) {\n this.screenTransceiver.direction = \"inactive\";\n }\n\n this.send({ type: \"stop_screen_share\" });\n\n try {\n const offer = await this.publisher?.createOffer();\n if (offer && this.publisher) {\n await this.publisher.setLocalDescription(offer);\n this.send({\n type: \"publish_offer\",\n payload: {\n revision: ++this.publisherRevision,\n sdp: offer.sdp,\n },\n });\n }\n } catch (error) {\n this.onError(error);\n }\n\n this.screenStream?.getTracks().forEach((track) => track.stop());\n this.screenStream = null;\n\n if (this.currentParticipantId) {\n this.onScreenShareStopped(this.currentParticipantId);\n }\n }\n\n muteAudio(muted: boolean) {\n this.localStream?.getAudioTracks().forEach((track) => {\n track.enabled = !muted;\n });\n\n const trackId = this.localTrackIds.get(\"audio\");\n if (trackId) {\n this.send({\n type: \"track_state\",\n payload: {\n track_id: trackId,\n muted,\n },\n });\n }\n }\n\n muteVideo(muted: boolean) {\n this.localStream?.getVideoTracks().forEach((track) => {\n track.enabled = !muted;\n });\n\n const trackId = this.localTrackIds.get(\"camera\");\n if (trackId) {\n this.send({\n type: \"track_state\",\n payload: {\n track_id: trackId,\n muted,\n },\n });\n }\n }\n\n async startRecording() {\n if (!this.send({ type: \"start_recording\" })) {\n throw new Error(\"SFU signaling is not connected\");\n }\n }\n\n async stopRecording() {\n if (!this.send({ type: \"stop_recording\" })) {\n throw new Error(\"SFU signaling is not connected\");\n }\n }\n\n async getRecordingStatus() {\n if (!this.room || !this.token) {\n throw new Error(\"SFU client is not connected\");\n }\n\n return this.request(\n `${this.apiBase}/rooms/${encodeURIComponent(this.room)}/recording`,\n {\n headers: {\n Authorization: `Bearer ${this.token}`,\n },\n },\n );\n }\n\n async approveJoinRequest(requestId: string) {\n if (!requestId) throw new Error(\"requestId is required\");\n if (!this.send({ type: \"approve_join\", payload: { request_id: requestId } })) {\n throw new Error(\"SFU signaling is not connected\");\n }\n }\n\n async rejectJoinRequest(requestId: string, reason?: string) {\n if (!requestId) throw new Error(\"requestId is required\");\n if (!this.send({ type: \"reject_join\", payload: { request_id: requestId, reason } })) {\n throw new Error(\"SFU signaling is not connected\");\n }\n }\n\n private isSocketOpen() {\n return this.ws?.readyState === WebSocket.OPEN;\n }\n\n private send(message: any) {\n if (!this.isSocketOpen()) return false;\n this.ws!.send(\n JSON.stringify({\n request_id: this.nextRequestId(),\n ...message,\n }),\n );\n return true;\n }\n\n private removeRemoteParticipant(participantId: string) {\n const stream = this.remoteStreams.get(participantId);\n if (stream) {\n stream.getTracks().forEach((track) => track.stop());\n this.remoteStreams.delete(participantId);\n }\n\n const screenStream = this.remoteScreenStreams.get(participantId);\n if (screenStream) {\n screenStream.getTracks().forEach((track) => track.stop());\n this.remoteScreenStreams.delete(participantId);\n }\n\n for (const [trackId, metadata] of this.trackMetadata) {\n if (metadata.participant_id === participantId) {\n this.trackMetadata.delete(trackId);\n this.subscribedTracks.delete(trackId);\n this.trackToParticipant.delete(trackId);\n this.trackToSource.delete(trackId);\n }\n }\n }\n\n async leave() {\n this.intentionalClose = true;\n this.setState(\"leaving\");\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n const roomCode = this.room;\n const ws = this.ws;\n this.leaveAcknowledged = false;\n\n if (ws?.readyState === WebSocket.OPEN) {\n await new Promise<void>((resolve) => {\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n resolve();\n };\n\n // The normal onmessage path remains authoritative. We only wait for\n // the server's `left` acknowledgement through a short polling window.\n const timeout = setTimeout(finish, 1200);\n\n const check = () => {\n if (this.leaveAcknowledged || this.ws !== ws) {\n clearTimeout(timeout);\n finish();\n return;\n }\n if (ws.readyState !== WebSocket.OPEN) {\n clearTimeout(timeout);\n finish();\n return;\n }\n setTimeout(check, 25);\n };\n\n ws.addEventListener(\"close\", () => {\n clearTimeout(timeout);\n finish();\n }, { once: true });\n\n this.send({ type: \"leave\" });\n check();\n });\n\n try {\n ws.close(1000, \"client_leave\");\n } catch {\n // ignore\n }\n }\n\n this.clearResumeToken(roomCode);\n this.cleanupAll();\n this.setState(\"disconnected\");\n }\n\n private closePeerConnectionsOnly() {\n if (this.publisher) {\n try { this.publisher.close(); } catch { /* ignore */ }\n this.publisher = null;\n }\n if (this.subscriber) {\n try { this.subscriber.close(); } catch { /* ignore */ }\n this.subscriber = null;\n }\n this.videoSender = null;\n this.audioSender = null;\n this.screenSender = null;\n this.audioTransceiver = null;\n this.cameraTransceiver = null;\n this.screenTransceiver = null;\n this.pendingIce = { publisher: [], subscriber: [] };\n this.offerQueue = [];\n this.subscriberNegotiating = false;\n this.subscriptionQueue = [];\n this.subscriptionRunning = false;\n this.subscriptionWaiters.splice(0).forEach((w) => w.reject(new Error(\"PeerConnection recreated\")));\n this.subscribedTracks.clear();\n }\n\n private cleanupAll() {\n if (this.subscriberStatsTimer) {\n clearInterval(this.subscriberStatsTimer);\n this.subscriberStatsTimer = null;\n }\n\n this.closePeerConnectionsOnly();\n\n this.localStream?.getTracks().forEach((track) => track.stop());\n this.screenStream?.getTracks().forEach((track) => track.stop());\n this.localStream = null;\n this.screenStream = null;\n\n for (const stream of this.remoteStreams.values()) {\n stream.getTracks().forEach((track) => track.stop());\n }\n this.remoteStreams.clear();\n\n for (const stream of this.remoteScreenStreams.values()) {\n stream.getTracks().forEach((track) => track.stop());\n }\n this.remoteScreenStreams.clear();\n\n this.trackMetadata.clear();\n this.trackToParticipant.clear();\n this.trackToSource.clear();\n this.localTrackIds.clear();\n this.participants.clear();\n this.currentParticipantId = null;\n this.resumeToken = null;\n this.pendingJoinRequestId = null;\n this.token = null;\n this.room = null;\n\n if (this.ws) {\n try { this.ws.close(); } catch { /* ignore */ }\n this.ws = null;\n }\n }\n\n private async logSubscriberVideoStats() {\n if (!this.subscriber || this.subscriber.connectionState === \"closed\") return;\n try {\n const stats = await this.subscriber.getStats();\n stats.forEach((report: any) => {\n if (\n report.type === \"inbound-rtp\" &&\n (report.kind === \"video\" || report.mediaType === \"video\")\n ) {\n console.debug(\"[SFU] subscriber video\", {\n packetsReceived: report.packetsReceived,\n packetsLost: report.packetsLost,\n framesDecoded: report.framesDecoded,\n frameWidth: report.frameWidth,\n frameHeight: report.frameHeight,\n });\n }\n });\n } catch {\n // stats are diagnostic only\n }\n }\n}\n","import { SDK_CONFIG } from \"../config/ws\";\nimport {\n ChatInput,\n ChatMessage,\n Events,\n MeetingConfig,\n Participant,\n SDKError,\n RecordingInfo,\n} from \"../types/meeting\";\nimport { ActiveSpeakerDetector } from \"./ActiveSpeakerDetector\";\nimport { MeetingState } from \"./MeetingState\";\nimport { SFUClient, SFUConnectionState, TrackInfo } from \"./SFUClient\";\n\nexport class VideoSDKCore {\n private sfuClient: SFUClient | null = null;\n\n private myId: string;\n\n private room: {\n id: string | null;\n name: string | null;\n } = {\n id: null,\n name: null,\n };\n\n private localStream: MediaStream | null = null;\n private screenStream: MediaStream | null = null;\n private isScreenSharing = false;\n private participantName = \"\";\n\n public readonly state: MeetingState;\n\n private intentionalDisconnect = false;\n\n private remoteStreams = new Map<string, MediaStream>();\n private remoteScreenStreams = new Map<string, MediaStream>();\n\n private activeSpeakerDetector: ActiveSpeakerDetector;\n\n private joinPromise: Promise<void> | null = null;\n private disconnectPromise: Promise<void> | null = null;\n\n private emitError(\n code: string,\n message: string,\n raw?: any,\n recoverable = true,\n ) {\n const err: SDKError = {\n code,\n message,\n raw,\n roomId: this.room.id,\n userId: this.myId,\n recoverable,\n };\n\n this.events.onError?.(err);\n\n console.error(\"[MeetingSDK Error]\", err);\n }\n\n constructor(\n private events: Events = {},\n private apiBase: string = SDK_CONFIG.apiBase,\n private wsBase: string = SDK_CONFIG.wsBase,\n ) {\n this.state = new MeetingState();\n this.events = events;\n this.activeSpeakerDetector = new ActiveSpeakerDetector({\n onActiveSpeakersChanged: (participantIds) => {\n this.state.setActiveSpeakers(participantIds);\n\n this.events.onActiveSpeakersChanged?.(participantIds);\n },\n });\n\n let storedId: string | null = null;\n\n try {\n storedId =\n typeof localStorage !== \"undefined\"\n ? localStorage.getItem(\"defcomm:participant_id\")\n : null;\n } catch {\n // SSR/private browsing may not expose localStorage.\n }\n\n this.myId =\n storedId ||\n (typeof crypto !== \"undefined\" && crypto.randomUUID\n ? crypto.randomUUID()\n : `user_${Date.now()}`);\n\n try {\n if (typeof localStorage !== \"undefined\") {\n localStorage.setItem(\"defcomm:participant_id\", this.myId);\n }\n } catch {\n // ignore\n }\n }\n\n // LOCAL MEDIA\n\n async initLocal(video: HTMLVideoElement, name: string) {\n this.participantName = name;\n\n try {\n this.localStream = await navigator.mediaDevices.getUserMedia({\n video: {\n width: { ideal: 1280 },\n height: { ideal: 720 },\n },\n audio: {\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n },\n });\n\n const localAudioTrack = this.localStream.getAudioTracks()[0];\n\n if (localAudioTrack) {\n this.activeSpeakerDetector.addTrack(this.myId, localAudioTrack);\n }\n\n const hasVideo = this.localStream\n .getVideoTracks()\n .some((t) => t.readyState === \"live\");\n\n const hasAudio = this.localStream\n .getAudioTracks()\n .some((t) => t.readyState === \"live\");\n\n if (!hasVideo || !hasAudio) {\n throw new Error(`Missing tracks: video=${hasVideo}, audio=${hasAudio}`);\n }\n\n video.srcObject = this.localStream;\n\n this.updateLocalMedia();\n } catch (err: any) {\n this.emitError(\"GET_USER_MEDIA_FAILED\", err?.message, err, false);\n\n throw err;\n }\n }\n\n private updateLocalMedia(audioMuted = false, videoMuted = false) {\n if (!this.localStream) return;\n\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n\n media: {\n stream: this.localStream,\n cameraTrack: this.localStream.getVideoTracks()[0],\n audioTrack: this.localStream.getAudioTracks()[0],\n micEnabled:\n this.localStream.getAudioTracks()[0]?.enabled ?? !audioMuted,\n camEnabled:\n this.localStream.getVideoTracks()[0]?.enabled ?? !videoMuted,\n isScreenSharing: this.isScreenSharing,\n screenStream: this.screenStream,\n screenTrack: this.screenStream?.getVideoTracks()[0],\n },\n });\n\n this.state.localStream = this.localStream;\n }\n\n // ROOM MANAGEMENT\n async createRoom(input: {\n name: string;\n description?: string;\n capacity?: number;\n is_private?: boolean;\n }) {\n const client =\n this.sfuClient ??\n new SFUClient({\n apiBase: this.apiBase,\n wsBase: this.wsBase,\n userId: this.myId,\n });\n\n return client.createRoom(input);\n }\n\n async getRoom(roomCode: string) {\n const client =\n this.sfuClient ??\n new SFUClient({\n apiBase: this.apiBase,\n wsBase: this.wsBase,\n userId: this.myId,\n });\n\n return client.getRoom(roomCode);\n }\n\n async deleteRoom(roomCode: string) {\n const client =\n this.sfuClient ??\n new SFUClient({\n apiBase: this.apiBase,\n wsBase: this.wsBase,\n userId: this.myId,\n });\n\n return client.deleteRoom(roomCode);\n }\n\n // JOIN\n async joinMeeting(config: MeetingConfig): Promise<void> {\n const {\n roomId,\n name,\n audioMuted = false,\n videoMuted = false,\n userId,\n } = config;\n\n if (!roomId || !name) {\n throw new Error(\"roomId and name are required to join meeting\");\n }\n\n if (userId) {\n this.myId = userId;\n }\n\n /*Already connected?\n * Calling join() again must NOT cause leave().\n */\n if (\n this.sfuClient &&\n this.room.id === roomId &&\n this.sfuClient.getConnectionState() === \"connected\"\n ) {\n console.info(\"[SDK] Already connected; duplicate join ignored\", {\n roomId,\n userId: this.myId,\n });\n\n return;\n }\n\n if (this.joinPromise) {\n console.info(\n \"[SDK] Join already in progress; waiting for existing join\",\n {\n roomId,\n userId: this.myId,\n },\n );\n\n return this.joinPromise;\n }\n\n if (this.sfuClient && this.room.id && this.room.id !== roomId) {\n throw new Error(\n `Already connected to room ${this.room.id}. Leave the current meeting before joining another room.`,\n );\n }\n\n this.intentionalDisconnect = false;\n this.participantName = name;\n this.room.id = roomId;\n this.room.name = name;\n\n if (!this.localStream) {\n this.localStream = await navigator.mediaDevices.getUserMedia({\n video: true,\n audio: true,\n });\n\n const localAudioTrack = this.localStream.getAudioTracks()[0];\n\n if (localAudioTrack) {\n this.activeSpeakerDetector.addTrack(this.myId, localAudioTrack);\n }\n }\n\n this.localStream.getAudioTracks().forEach((track) => {\n track.enabled = !audioMuted;\n });\n\n this.localStream.getVideoTracks().forEach((track) => {\n track.enabled = !videoMuted;\n });\n\n this.updateLocalMedia(audioMuted, videoMuted);\n\n const promise = this.connect(roomId, name);\n\n this.joinPromise = promise;\n\n try {\n await promise;\n } finally {\n if (this.joinPromise === promise) {\n this.joinPromise = null;\n }\n }\n }\n\n // SFU CONNECTION\n private async connect(roomId: string, name: string): Promise<void> {\n if (this.sfuClient) {\n const state = this.sfuClient.getConnectionState();\n if (\n this.room.id === roomId &&\n (state === \"connecting\" ||\n state === \"connected\" ||\n state === \"reconnecting\")\n ) {\n console.info(\n \"[SDK] Existing SFU connection is active; connect ignored\",\n {\n roomId,\n state,\n },\n );\n\n return;\n }\n\n throw new Error(\n `SFU client already exists in state \"${state}\". Disconnect explicitly before creating another connection.`,\n );\n }\n\n const client = new SFUClient({\n apiBase: this.apiBase,\n wsBase: this.wsBase,\n userId: this.myId,\n autoSubscribe: true,\n // CONNECTION STATE\n\n onStateChange: (state) => {\n this.handleSFUState(state);\n },\n\n onConnected: (payload, resumed) => {\n console.log(`[SFU] ${resumed ? \"Resumed\" : \"Joined\"} room`, payload);\n\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n });\n },\n\n onDisconnected: () => {\n /*\n * Disconnected does NOT necessarily mean\n * the participant left the room.\n * SFUClient should attempt reconnect.\n */\n console.log(\"[SFU] Signaling WebSocket disconnected; reconnecting\");\n },\n\n onReconnecting: (attempt) => {\n console.warn(`[SFU] Reconnecting, attempt ${attempt}`);\n },\n\n // ADMISSION CONTROL\n onJoinPending: (info) => {\n console.log(\"[SFU] Join request pending\", info);\n\n this.events.onEntryRequested?.({\n requestId: info.request_id,\n userId: this.myId,\n name: this.participantName,\n });\n },\n\n onJoinApproved: (requestId) => {\n console.log(\"[SFU] Join approved\", requestId);\n this.events.onJoinApproved?.(requestId);\n this.events.onEntryResponded?.(\n {\n participantId: this.myId,\n decision: \"approved\",\n },\n\n \"approved\",\n );\n },\n\n onJoinRejected: (requestId, reason) => {\n console.warn(\"[SFU] Join rejected\", requestId, reason);\n this.events.onJoinRejected?.(requestId);\n this.events.onEntryResponded?.(\n {\n participantId: this.myId,\n decision: \"rejected\",\n },\n\n \"rejected\",\n );\n\n this.emitError(\n \"JOIN_REJECTED\",\n reason || \"Your request to join was rejected\",\n {\n requestId,\n reason,\n },\n false,\n );\n },\n\n onJoinRequested: (request) => {\n const requestId = request?.request_id || request?.requestId;\n const userId = request?.user_id || request?.userId;\n const nameValue =\n request?.user_metadata?.name ||\n request?.display_name ||\n request?.name ||\n \"Participant\";\n\n if (!requestId || !userId) {\n return;\n }\n\n this.events.onEntryRequested?.({\n requestId,\n userId,\n name: nameValue,\n });\n },\n\n // PARTICIPANTS\n onParticipantJoined: (participant) => {\n const pid = participant.participant_id;\n\n if (!pid || pid === this.myId) {\n return;\n }\n\n const pname =\n participant.user_metadata?.name ||\n participant.display_name ||\n \"Participant\";\n\n this.state.addParticipant({\n id: pid,\n name: pname,\n connectionState: \"connected\",\n media: {\n micEnabled: true,\n camEnabled: true,\n isScreenSharing: false,\n stream: null,\n },\n });\n\n this.events.onUserJoined?.({\n id: pid,\n name: pname,\n });\n },\n\n onParticipantPresence: (participantId, presence) => {\n if (participantId === this.myId) {\n return;\n }\n\n const current = this.state.getParticipant(participantId);\n\n if (!current) {\n return;\n }\n\n const connectionState =\n presence === \"reconnecting\"\n ? \"reconnecting\"\n : presence === \"connected\" || presence === \"online\"\n ? \"connected\"\n : presence === \"disconnected\"\n ? \"disconnected\"\n : current.connectionState;\n\n this.state.updateParticipantMedia(participantId, {\n stream: current.media?.stream ?? null,\n });\n\n const next = new Map(this.state.participants);\n\n next.set(participantId, {\n ...current,\n connectionState,\n });\n\n this.state.participants = next;\n\n this.state.notify(`participant:${participantId}`);\n\n this.state.notify(\"participants\");\n },\n\n onParticipantLeft: (participant) => {\n const pid =\n typeof participant === \"string\"\n ? participant\n : participant.participant_id;\n\n if (!pid) {\n return;\n }\n\n console.log(\"[SFU] Participant permanently left\", pid);\n\n this.cleanupRemoteParticipant(pid);\n this.state.removeParticipant(pid);\n this.events.onUserLeft?.(pid);\n },\n\n // TRACKS\n onTrackPublished: (track) => {\n console.log(\"[SFU] Track published\", track);\n },\n\n onTrackUnpublished: (track) => {\n console.log(\"[SFU] Track unpublished\", track);\n const pid = track.participant_id;\n\n if (!pid) {\n return;\n }\n\n const current = this.state.getParticipant(pid);\n if (track.source === \"screen\") {\n const screen = this.remoteScreenStreams.get(pid);\n\n screen?.getTracks().forEach((t) => t.stop());\n\n this.remoteScreenStreams.delete(pid);\n\n this.state.updateParticipantMedia(pid, {\n isScreenSharing: false,\n screenStream: null,\n screenTrack: undefined,\n });\n\n this.events.onScreenShareStopped?.(pid);\n\n return;\n }\n\n if (!current) {\n return;\n }\n\n this.state.updateParticipantMedia(pid, {\n stream: current.media?.stream ?? null,\n micEnabled:\n track.kind === \"audio\"\n ? false\n : (current.media?.micEnabled ?? true),\n\n camEnabled:\n track.kind === \"video\"\n ? false\n : (current.media?.camEnabled ?? true),\n });\n },\n\n onTrackStateChanged: (track) => {\n const pid = track.participant_id;\n\n if (!pid || pid === this.myId) {\n return;\n }\n\n const current = this.state.getParticipant(pid);\n\n if (!current) {\n return;\n }\n\n if (track.source === \"audio\") {\n this.state.updateParticipantMedia(pid, {\n stream: current.media?.stream ?? null,\n micEnabled: !track.muted,\n });\n\n this.events.onMuteStateChanged?.(pid, \"audio\", track.muted);\n } else if (track.source === \"camera\") {\n this.state.updateParticipantMedia(pid, {\n stream: current.media?.stream ?? null,\n camEnabled: !track.muted,\n });\n\n this.events.onMuteStateChanged?.(pid, \"video\", track.muted);\n }\n\n this.events.onTrackStateChanged?.(track as any);\n },\n\n // RECORDING\n onRecordingStarted: (recording) => {\n this.events.onRecordingStarted?.(recording);\n },\n\n onRecordingStopped: (recording) => {\n this.events.onRecordingStopped?.(recording);\n },\n\n // REMOTE MEDIA\n onRemoteTrack: (track, stream, metadata) => {\n this.handleRemoteTrack(track, stream, metadata);\n },\n\n // SCREEN SHARE\n onScreenShareStarted: (participantId, _track) => {\n if (participantId === this.myId) {\n return;\n }\n\n console.log(\"[SFU] Screen share started\", participantId);\n this.state.setPresenterId(participantId);\n const current = this.state.getParticipant(participantId);\n if (current) {\n this.state.updateParticipantMedia(participantId, {\n isScreenSharing: true,\n screenStream: current.media?.screenStream ?? null,\n });\n }\n },\n\n onScreenShareStopped: (participantId) => {\n if (participantId === this.myId) {\n return;\n }\n\n const screen = this.remoteScreenStreams.get(participantId);\n\n screen?.getTracks().forEach((track) => track.stop());\n\n this.remoteScreenStreams.delete(participantId);\n\n this.state.updateParticipantMedia(participantId, {\n isScreenSharing: false,\n screenStream: null,\n screenTrack: undefined,\n });\n\n this.events.onScreenShareStopped?.(participantId);\n },\n\n // ERROR\n onError: (error) => {\n console.error(\"[SFU] Error:\", error);\n this.emitError(\n \"SFU_ERROR\",\n error?.message || String(error),\n error,\n true,\n );\n },\n });\n\n /*Assign the client BEFORE starting the connection.\n * This is important because callbacks may fire during\n * getToken().\n */\n this.sfuClient = client;\n\n client.setLocalStream(this.localStream);\n\n await client.getToken(roomId, {\n displayName: name,\n userId: this.myId,\n });\n }\n\n // SFU STATE\n private handleSFUState(state: SFUConnectionState) {\n this.events.onConnectionStateChanged?.(state);\n\n if (state === \"reconnecting\") {\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n });\n\n return;\n }\n\n /*Do NOT emit CONNECTION_LOST while reconnecting.\n * SFUClient should only eventually transition to\n * \"disconnected\" when reconnect attempts are exhausted.\n */\n if (state === \"disconnected\" && !this.intentionalDisconnect) {\n this.emitError(\n \"CONNECTION_LOST\",\n \"Unable to reconnect to SFU server\",\n null,\n true,\n );\n }\n }\n\n // REMOTE TRACKS\n private handleRemoteTrack(\n track: MediaStreamTrack,\n stream: MediaStream,\n metadata: TrackInfo,\n ) {\n const participantId = metadata?.participant_id;\n\n if (!participantId || participantId === this.myId) {\n return;\n }\n\n const source = metadata.source;\n\n /* SCREEN SHARE\n */\n if (source === \"screen\") {\n let screenStream = this.remoteScreenStreams.get(participantId);\n\n if (!screenStream) {\n screenStream = new MediaStream();\n this.remoteScreenStreams.set(participantId, screenStream);\n }\n\n for (const old of screenStream.getVideoTracks()) {\n if (old.id !== track.id) {\n screenStream.removeTrack(old);\n old.stop();\n }\n }\n\n if (!screenStream.getTracks().some((t) => t.id === track.id)) {\n screenStream.addTrack(track);\n }\n\n this.state.updateParticipantMedia(participantId, {\n screenStream,\n screenTrack: track,\n isScreenSharing: true,\n });\n\n this.events.onScreenShareStarted?.(participantId, screenStream);\n\n return;\n }\n\n let remoteStream = this.remoteStreams.get(participantId);\n\n if (!remoteStream) {\n remoteStream = new MediaStream();\n\n this.remoteStreams.set(participantId, remoteStream);\n }\n\n for (const old of remoteStream.getTracks()) {\n if (old.kind === track.kind && old.id !== track.id) {\n remoteStream.removeTrack(old);\n old.stop();\n }\n }\n\n if (!remoteStream.getTracks().some((t) => t.id === track.id)) {\n remoteStream.addTrack(track);\n }\n\n const current = this.state.getParticipant(participantId);\n\n this.state.updateParticipantMedia(participantId, {\n stream: remoteStream,\n cameraTrack: track.kind === \"video\" ? track : current?.media?.cameraTrack,\n audioTrack: track.kind === \"audio\" ? track : current?.media?.audioTrack,\n });\n\n if (track.kind === \"audio\") {\n this.activeSpeakerDetector.addTrack(participantId, track);\n }\n\n this.events.onTrack?.(remoteStream, participantId);\n\n track.onended = () => {\n if (track.kind === \"video\") {\n this.state.updateParticipantMedia(participantId, {\n camEnabled: false,\n stream: remoteStream,\n });\n\n return;\n }\n\n this.state.updateParticipantMedia(participantId, {\n micEnabled: false,\n stream: remoteStream,\n });\n };\n }\n\n // MEETING\n getMeeting(): {\n id: string | null;\n name: string | null;\n } {\n return this.room;\n }\n\n // ADMISSION CONTROL\n async approveJoinRequest(requestId: string) {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n return this.sfuClient.approveJoinRequest(requestId);\n }\n\n async rejectJoinRequest(requestId: string, reason?: string) {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n return this.sfuClient.rejectJoinRequest(requestId, reason);\n }\n\n // MEDIA CONTROL\n toggleMic() {\n const mediaState = this.state.localParticipant?.media;\n\n if (!mediaState || !this.localStream) {\n return;\n }\n\n const nextEnabled = !mediaState.micEnabled;\n\n this.localStream.getAudioTracks().forEach((track) => {\n track.enabled = nextEnabled;\n });\n\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n media: {\n micEnabled: nextEnabled,\n },\n });\n\n this.sfuClient?.muteAudio(!nextEnabled);\n this.events.onMicToggled?.(this.myId, nextEnabled);\n }\n\n toggleCam() {\n const mediaState = this.state.localParticipant?.media;\n\n if (!mediaState || !this.localStream) {\n return;\n }\n\n const nextEnabled = !mediaState.camEnabled;\n\n this.localStream.getVideoTracks().forEach((track) => {\n track.enabled = nextEnabled;\n });\n\n this.state.updateLocalParticipant({\n id: this.myId,\n name: this.participantName,\n media: {\n camEnabled: nextEnabled,\n },\n });\n\n this.sfuClient?.muteVideo(!nextEnabled);\n\n this.events.onCamToggled?.(this.myId, nextEnabled);\n }\n\n // SCREEN SHARING\n async startScreenShare() {\n try {\n if (!navigator.mediaDevices?.getDisplayMedia) {\n throw new Error(\"Screen sharing not supported on this device\");\n }\n\n if (!this.sfuClient) {\n throw new Error(\"Cannot share screen before joining the meeting\");\n }\n\n this.screenStream = await this.sfuClient.shareScreen();\n\n this.isScreenSharing = true;\n\n this.state.updateLocalParticipant({\n media: {\n isScreenSharing: true,\n screenStream: this.screenStream,\n screenTrack: this.screenStream.getVideoTracks()[0],\n },\n });\n\n return this.screenStream;\n } catch (err: any) {\n this.emitError(\n \"SCREEN_SHARE_FAILED\",\n err?.message || \"Failed to start screen sharing\",\n err,\n true,\n );\n\n this.isScreenSharing = false;\n this.screenStream = null;\n\n throw err;\n }\n }\n\n stopScreenShare() {\n if (!this.screenStream) {\n return;\n }\n\n void this.sfuClient?.stopScreenShare();\n this.screenStream.getTracks().forEach((track) => track.stop());\n this.screenStream = null;\n this.isScreenSharing = false;\n\n this.state.updateLocalParticipant({\n media: {\n isScreenSharing: false,\n screenStream: null,\n screenTrack: undefined,\n },\n });\n }\n\n // RECORDING\n async startRecording() {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n await this.sfuClient.startRecording();\n }\n\n async stopRecording() {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n await this.sfuClient.stopRecording();\n }\n\n async getRecordingStatus(): Promise<{\n recording: RecordingInfo | null;\n }> {\n if (!this.sfuClient) {\n throw new Error(\"SFU client is not connected\");\n }\n\n return this.sfuClient.getRecordingStatus();\n }\n\n // CHAT\n\n sendChatMessage(payload: ChatInput) {\n if (!this.sfuClient) {\n console.warn(\"SFU Client not connected\");\n\n return;\n }\n\n const senderName = this.state.localParticipant?.name || \"Anonymous\";\n\n const msg: ChatMessage = {\n id: crypto.randomUUID(),\n sender_id: this.myId,\n sender_name: senderName,\n text: payload.message.trim(),\n timestamp: Date.now(),\n reply_to: payload.reply_to ?? null,\n target: payload.target ?? null,\n };\n\n this.state.addChatMessage(msg);\n this.events.onChatMessage?.(msg);\n }\n\n // CLEANUP\n private cleanupRemoteParticipant(participantId: string) {\n this.activeSpeakerDetector.removeParticipant(participantId);\n\n const stream = this.remoteStreams.get(participantId);\n\n stream?.getTracks().forEach((track) => track.stop());\n\n this.remoteStreams.delete(participantId);\n\n const screen = this.remoteScreenStreams.get(participantId);\n\n screen?.getTracks().forEach((track) => track.stop());\n\n this.remoteScreenStreams.delete(participantId);\n }\n\n // DISCONNECT\n async disconnect(): Promise<void> {\n if (this.disconnectPromise) {\n return this.disconnectPromise;\n }\n\n this.disconnectPromise = this.performDisconnect();\n\n try {\n await this.disconnectPromise;\n } finally {\n this.disconnectPromise = null;\n }\n }\n\n private async performDisconnect() {\n this.intentionalDisconnect = true;\n this.joinPromise = null;\n\n const client = this.sfuClient;\n this.sfuClient = null;\n\n if (client) {\n await client.leave();\n }\n\n // LOCAL MEDIA\n if (this.localStream) {\n this.localStream.getTracks().forEach((track) => track.stop());\n\n this.localStream = null;\n }\n\n if (this.screenStream) {\n this.screenStream.getTracks().forEach((track) => track.stop());\n this.screenStream = null;\n }\n\n this.isScreenSharing = false;\n\n // REMOTE MEDIA\n for (const stream of this.remoteStreams.values()) {\n stream.getTracks().forEach((track) => track.stop());\n }\n\n this.remoteStreams.clear();\n for (const stream of this.remoteScreenStreams.values()) {\n stream.getTracks().forEach((track) => track.stop());\n }\n\n this.remoteScreenStreams.clear();\n this.room.id = null;\n this.room.name = null;\n\n this.state.localParticipant = null;\n\n this.state.notify(\"localParticipant\");\n\n this.state.resetRemoteState();\n this.events.onMeetingLeft?.();\n }\n}\n","import { useEffect, useState } from \"react\";\nimport { StateScope } from \"../types/meeting\";\nimport { MeetingState } from \"../core/MeetingState\";\n\nexport function useMeetingStore<T>(\n stateManager: MeetingState,\n scope: StateScope,\n selector: (state: MeetingState) => T,\n): T {\n const [state, setState] = useState(() => selector(stateManager));\n\n useEffect(() => {\n // Update local react state whenever the SDK notifies this scope\n const unsubscribe = stateManager.subscribe(scope, () => {\n setState(selector(stateManager));\n });\n\n return unsubscribe;\n }, [stateManager, scope, selector]);\n\n return state;\n}\n","import { useEffect } from \"react\";\nimport { useMeetingContext } from \"./MeetingProvider\";\n\nexport const useMeeting = (handlers?: {\n onError?: (err: any) => void;\n onEntryRequested?: (req: any) => void;\n onEntryResponded?: (payload: any, decision?: any) => void;\n onMeetingLeft?: () => void;\n onTrackStateChanged?: (track: any) => void;\n onRecordingStarted?: (recording: any) => void;\n onRecordingStopped?: (recording: any) => void;\n onActiveSpeakersChanged?: (participantIds: string[]) => void;\n}) => {\n const ctx = useMeetingContext();\n\n // Error Handler\n useEffect(() => {\n if (!handlers?.onError) return;\n return ctx.onError(handlers.onError);\n }, [handlers?.onError]);\n\n useEffect(() => {\n if (!handlers?.onActiveSpeakersChanged) return;\n\n return ctx.onActiveSpeakersChanged(handlers.onActiveSpeakersChanged);\n }, [handlers?.onActiveSpeakersChanged]);\n\n // Entry Request Handler\n useEffect(() => {\n if (!handlers?.onEntryRequested) return;\n return ctx.onEntryRequested(handlers.onEntryRequested);\n }, [handlers?.onEntryRequested]);\n\n // Entry Response Handler\n useEffect(() => {\n if (!handlers?.onEntryResponded) return;\n return ctx.onEntryResponded(handlers.onEntryResponded);\n }, [handlers?.onEntryResponded]);\n\n // Meeting Left Handler\n useEffect(() => {\n if (!handlers?.onMeetingLeft) return;\n return ctx.onMeetingLeft(handlers.onMeetingLeft);\n }, [handlers?.onMeetingLeft]);\n\n useEffect(() => {\n if (!handlers?.onTrackStateChanged) return;\n return ctx.onTrackStateChanged(handlers.onTrackStateChanged);\n }, [handlers?.onTrackStateChanged]);\n\n useEffect(() => {\n if (!handlers?.onRecordingStarted) return;\n return ctx.onRecordingStarted(handlers.onRecordingStarted);\n }, [handlers?.onRecordingStarted]);\n\n useEffect(() => {\n if (!handlers?.onRecordingStopped) return;\n return ctx.onRecordingStopped(handlers.onRecordingStopped);\n }, [handlers?.onRecordingStopped]);\n\n const { sdk: _, ...publicApi } = ctx;\n return publicApi;\n};\n","import { useEffect, useState } from \"react\";\nimport { useMeetingContext } from \"./MeetingProvider\";\nimport { Participant } from \"../types/meeting\";\n\nexport const useParticipants = () => {\n const { sdk } = useMeetingContext();\n\n const [participants, setParticipants] = useState<Participant[]>(() =>\n sdk.state.getParticipants(),\n );\n\n useEffect(() => {\n const update = () => {\n setParticipants(sdk.state.getParticipants());\n };\n\n update();\n\n const unsub = sdk.state.subscribe(\"participants\", update);\n\n return unsub;\n }, [sdk]);\n\n return participants;\n};\n","import { useEffect, useRef, useState } from \"react\";\nimport { useMeetingContext } from \"./MeetingProvider\";\nimport { Participant } from \"../types/meeting\";\n\nexport const useRemoteMedia = (participantId: string) => {\n const { sdk } = useMeetingContext();\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const audioRef = useRef<HTMLAudioElement | null>(null);\n\n const [participant, setParticipant] = useState<Participant | null>(\n () => sdk.state.getParticipant(participantId) || null,\n );\n\n useEffect(() => {\n const unsub = sdk.state.subscribe(`participant:${participantId}`, () => {\n const p = sdk.state.getParticipant(participantId);\n setParticipant(p ? { ...p } : null);\n });\n\n return unsub;\n }, [participantId, sdk]);\n\n useEffect(() => {\n const stream = participant?.media?.stream;\n if (!stream) return;\n\n // VIDEO\n if (videoRef.current) {\n videoRef.current.srcObject = stream;\n videoRef.current.muted = true;\n videoRef.current.playsInline = true;\n videoRef.current.play().catch(() => {});\n }\n\n // AUDIO\n if (audioRef.current) {\n audioRef.current.srcObject = stream;\n audioRef.current.play().catch(() => {});\n }\n }, [participant?.media?.stream]);\n\n return {\n videoRef,\n audioRef,\n isCamActive: !!participant?.media?.camEnabled,\n isMicEnabled: !!participant?.media?.micEnabled,\n };\n};\n","import { useEffect, useState } from \"react\";\nimport { SDK_CONFIG } from \"../config/ws\";\n\ntype LiveRoomState = {\n active: boolean;\n count: number;\n canJoin: boolean;\n approved: boolean;\n isHost: boolean;\n hasMoreParticipants: boolean;\n participants: {\n id: string;\n name: string;\n isHost: boolean;\n isPresenter: boolean;\n micEnabled: boolean;\n camEnabled: boolean;\n }[];\n room?: {\n id: string;\n name: string;\n room_code: string;\n capacity: number;\n is_private: boolean;\n };\n};\n\n/**\n * Current SFU does not expose the old `/watch/:room` mesh presence socket.\n * Preview therefore uses the authoritative REST room endpoint and polls it.\n * Live participant/media state begins after JOIN over the SFU WebSocket.\n */\nexport function useMeetingPreview(roomId: string, userId: string) {\n const [room, setRoom] = useState<LiveRoomState | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [isConnected, setIsConnected] = useState(false);\n const [isLoading, setIsLoading] = useState(true);\n\n useEffect(() => {\n if (!roomId) {\n setIsLoading(false);\n return;\n }\n\n let stopped = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n const load = async () => {\n try {\n const response = await fetch(\n `${SDK_CONFIG.apiBase}/rooms/${encodeURIComponent(roomId)}`,\n );\n\n if (!response.ok) {\n throw new Error(`Room lookup failed (${response.status})`);\n }\n\n const data = await response.json();\n if (stopped) return;\n\n setRoom({\n active: true,\n // The current REST room model intentionally does not expose a live\n // participant count. Do not fabricate one.\n count: 0,\n canJoin: !data.is_private,\n approved: false,\n isHost: false,\n hasMoreParticipants: false,\n participants: [],\n room: {\n id: data.id,\n name: data.name,\n room_code: data.room_code,\n capacity: data.capacity,\n is_private: data.is_private,\n },\n });\n setError(null);\n setIsConnected(true);\n setIsLoading(false);\n } catch (err: any) {\n if (stopped) return;\n setError(err?.message || \"Failed to load room\");\n setIsConnected(false);\n setIsLoading(false);\n } finally {\n if (!stopped) {\n timer = setTimeout(load, 5000);\n }\n }\n };\n\n void load();\n\n return () => {\n stopped = true;\n if (timer) clearTimeout(timer);\n };\n }, [roomId, userId]);\n\n return {\n room,\n isConnected,\n isLoading,\n error,\n };\n}\n"],"mappings":"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","names":["useEffect","useRef","useState","useState","useEffect","useRef","useEffect","useEffect","useEffect","useState","useState","useEffect","useEffect","useRef","useState","useRef","useState","useEffect","useEffect","useState","useState","useEffect"]}