@daydreamlive/browser 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +126 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +593 -103
- package/dist/index.d.ts +593 -103
- package/dist/index.js +126 -26
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/errors.ts","../src/internal/dependencies.ts","../src/internal/WHIPClient.ts","../src/internal/TypedEventEmitter.ts","../src/internal/StateMachine.ts","../src/Broadcast.ts","../src/internal/WHEPClient.ts","../src/Player.ts","../src/internal/compositor/Registry.ts","../src/internal/compositor/Renderer.ts","../src/internal/compositor/Scheduler.ts","../src/internal/compositor/AudioManager.ts","../src/internal/compositor/VisibilityHandler.ts","../src/Compositor.ts"],"sourcesContent":["import type { BroadcastOptions, WHIPResponseResult } from \"./types\";\nimport { Broadcast, createBroadcast as baseCreateBroadcast } from \"./Broadcast\";\nimport { Player, createPlayer as baseCreatePlayer } from \"./Player\";\nimport type { PlayerOptions } from \"./types\";\n\nexport const livepeerResponseHandler = (\n response: Response,\n): WHIPResponseResult => ({\n whepUrl: response.headers.get(\"livepeer-playback-url\") ?? undefined,\n});\n\nexport type LivepeerBroadcastOptions = Omit<BroadcastOptions, \"onResponse\">;\n\nexport function createBroadcast(options: LivepeerBroadcastOptions): Broadcast {\n return baseCreateBroadcast({\n ...options,\n onResponse: livepeerResponseHandler,\n });\n}\n\nexport function createPlayer(whepUrl: string, options?: PlayerOptions): Player {\n return baseCreatePlayer(whepUrl, options);\n}\n\nexport {\n BaseDaydreamError,\n NetworkError,\n ConnectionError,\n StreamNotFoundError,\n UnauthorizedError,\n} from \"./errors\";\n\nexport type {\n AudioConfig,\n BroadcastOptions,\n PlayerOptions,\n BroadcastState,\n PlayerState,\n ReconnectConfig,\n ReconnectInfo,\n VideoConfig,\n BroadcastEventMap,\n PlayerEventMap,\n DaydreamError,\n DaydreamErrorCode,\n WHIPResponseResult,\n} from \"./types\";\n\nexport {\n DEFAULT_ICE_SERVERS,\n DEFAULT_VIDEO_BITRATE,\n DEFAULT_AUDIO_BITRATE,\n} from \"./types\";\n\nexport { Broadcast, type BroadcastConfig } from \"./Broadcast\";\nexport { Player, type PlayerConfig } from \"./Player\";\nexport { createCompositor } from \"./Compositor\";\n\nexport type {\n Compositor,\n CompositorOptions,\n CompositorEvent,\n CompositorEventMap,\n Source,\n VideoSource,\n CanvasSource,\n Size,\n FitMode,\n ContentHint,\n Ctx2D,\n} from \"./types\";\n","export type BroadcastState =\n | \"connecting\"\n | \"live\"\n | \"reconnecting\"\n | \"ended\"\n | \"error\";\n\nexport type PlayerState =\n | \"connecting\"\n | \"playing\"\n | \"buffering\"\n | \"ended\"\n | \"error\";\n\nexport interface WHIPResponseResult {\n whepUrl?: string;\n}\n\nexport interface BroadcastOptions {\n whipUrl: string;\n stream: MediaStream;\n reconnect?: ReconnectConfig;\n video?: VideoConfig;\n audio?: AudioConfig;\n iceServers?: RTCIceServer[];\n connectionTimeout?: number;\n onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n onResponse?: (response: Response) => WHIPResponseResult | void;\n}\n\nexport interface PlayerOptions {\n reconnect?: ReconnectConfig;\n iceServers?: RTCIceServer[];\n connectionTimeout?: number;\n skipIceGathering?: boolean;\n onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n}\n\nexport interface ReconnectConfig {\n enabled?: boolean;\n maxAttempts?: number;\n baseDelayMs?: number;\n}\n\nexport interface ReconnectInfo {\n attempt: number;\n maxAttempts: number;\n delayMs: number;\n}\n\nexport interface VideoConfig {\n bitrate?: number;\n maxFramerate?: number;\n}\n\nexport interface AudioConfig {\n bitrate?: number;\n}\n\nexport interface BroadcastEventMap {\n stateChange: (state: BroadcastState) => void;\n error: (error: DaydreamError) => void;\n reconnect: (info: ReconnectInfo) => void;\n}\n\nexport interface PlayerEventMap {\n stateChange: (state: PlayerState) => void;\n error: (error: DaydreamError) => void;\n reconnect: (info: ReconnectInfo) => void;\n}\n\nexport interface DaydreamError extends Error {\n code: DaydreamErrorCode;\n cause?: unknown;\n}\n\nexport type DaydreamErrorCode =\n | \"NETWORK_ERROR\"\n | \"CONNECTION_FAILED\"\n | \"STREAM_NOT_FOUND\"\n | \"UNAUTHORIZED\"\n | \"UNKNOWN\";\n\nexport const DEFAULT_ICE_SERVERS: RTCIceServer[] = [\n { urls: \"stun:stun.l.google.com:19302\" },\n { urls: \"stun:stun1.l.google.com:19302\" },\n { urls: \"stun:stun.cloudflare.com:3478\" },\n];\n\nexport const DEFAULT_VIDEO_BITRATE = 300_000;\nexport const DEFAULT_AUDIO_BITRATE = 64_000;\n\n// ============================================================================\n// Compositor Types\n// ============================================================================\n\nexport type Ctx2D =\n | CanvasRenderingContext2D\n | OffscreenCanvasRenderingContext2D;\n\nexport type FitMode = \"contain\" | \"cover\";\n\nexport type ContentHint = \"detail\" | \"motion\" | \"\";\n\nexport type VideoSource = {\n kind: \"video\";\n element: HTMLVideoElement;\n fit?: FitMode;\n contentHint?: ContentHint;\n};\n\nexport type CanvasSource = {\n kind: \"canvas\";\n element: HTMLCanvasElement;\n fit?: FitMode;\n contentHint?: ContentHint;\n};\n\nexport type Source = VideoSource | CanvasSource;\n\nexport type Size = {\n width: number;\n height: number;\n dpr: number;\n};\n\nexport interface CompositorOptions {\n width?: number;\n height?: number;\n fps?: number;\n dpr?: number;\n sendFps?: number;\n keepalive?: boolean;\n autoUnlockAudio?: boolean;\n unlockEvents?: string[];\n disableSilentAudio?: boolean;\n onSendFpsChange?: (fps: number) => void;\n}\n\nexport type CompositorEvent = \"activated\" | \"registered\" | \"unregistered\";\n\nexport interface CompositorEventMap {\n activated: (id: string | null, source: Source | undefined) => void;\n registered: (id: string, source: Source) => void;\n unregistered: (id: string) => void;\n}\n\nexport interface Compositor {\n // Source Registry\n register(id: string, source: Source): void;\n unregister(id: string): void;\n get(id: string): Source | undefined;\n has(id: string): boolean;\n list(): Array<{ id: string; source: Source }>;\n\n // Active source management\n activate(id: string): void;\n deactivate(): void;\n readonly activeId: string | null;\n\n // Output stream\n readonly stream: MediaStream;\n\n // Settings\n resize(width: number, height: number, dpr?: number): void;\n readonly size: Size;\n setFps(fps: number): void;\n readonly fps: number;\n setSendFps(fps: number): void;\n readonly sendFps: number;\n\n // Audio\n addAudioTrack(track: MediaStreamTrack): void;\n removeAudioTrack(trackId: string): void;\n unlockAudio(): Promise<boolean>;\n\n // Lifecycle\n destroy(): void;\n\n // Events\n on<E extends CompositorEvent>(\n event: E,\n cb: CompositorEventMap[E],\n ): () => void;\n}\n","import type { DaydreamError, DaydreamErrorCode } from \"./types\";\n\nexport class BaseDaydreamError extends Error implements DaydreamError {\n readonly code: DaydreamErrorCode;\n readonly cause?: unknown;\n\n constructor(code: DaydreamErrorCode, message: string, cause?: unknown) {\n super(message);\n this.name = \"DaydreamError\";\n this.code = code;\n this.cause = cause;\n }\n}\n\nexport class NetworkError extends BaseDaydreamError {\n constructor(message: string, cause?: unknown) {\n super(\"NETWORK_ERROR\", message, cause);\n this.name = \"NetworkError\";\n }\n}\n\nexport class ConnectionError extends BaseDaydreamError {\n constructor(message: string, cause?: unknown) {\n super(\"CONNECTION_FAILED\", message, cause);\n this.name = \"ConnectionError\";\n }\n}\n\nexport class StreamNotFoundError extends BaseDaydreamError {\n constructor(message: string, cause?: unknown) {\n super(\"STREAM_NOT_FOUND\", message, cause);\n this.name = \"StreamNotFoundError\";\n }\n}\n\nexport class UnauthorizedError extends BaseDaydreamError {\n constructor(message: string, cause?: unknown) {\n super(\"UNAUTHORIZED\", message, cause);\n this.name = \"UnauthorizedError\";\n }\n}\n","export interface PeerConnectionFactory {\n create(config: RTCConfiguration): RTCPeerConnection;\n}\n\nexport interface FetchFn {\n (input: RequestInfo | URL, init?: RequestInit): Promise<Response>;\n}\n\nexport interface TimerProvider {\n setTimeout(callback: () => void, ms: number): number;\n clearTimeout(id: number): void;\n setInterval(callback: () => void, ms: number): number;\n clearInterval(id: number): void;\n}\n\nexport interface MediaStreamFactory {\n create(): MediaStream;\n}\n\nexport const defaultMediaStreamFactory: MediaStreamFactory = {\n create: () => new MediaStream(),\n};\n\nexport const defaultPeerConnectionFactory: PeerConnectionFactory = {\n create: (config) => new RTCPeerConnection(config),\n};\n\nexport const defaultFetch: FetchFn = globalThis.fetch.bind(globalThis);\n\nexport const defaultTimerProvider: TimerProvider = {\n setTimeout: (cb, ms) => globalThis.setTimeout(cb, ms) as unknown as number,\n clearTimeout: (id) => globalThis.clearTimeout(id),\n setInterval: (cb, ms) => globalThis.setInterval(cb, ms) as unknown as number,\n clearInterval: (id) => globalThis.clearInterval(id),\n};\n\n","import {\n DEFAULT_ICE_SERVERS,\n DEFAULT_VIDEO_BITRATE,\n DEFAULT_AUDIO_BITRATE,\n type WHIPResponseResult,\n} from \"../types\";\nimport { ConnectionError, NetworkError } from \"../errors\";\nimport {\n type PeerConnectionFactory,\n type FetchFn,\n type TimerProvider,\n defaultPeerConnectionFactory,\n defaultFetch,\n defaultTimerProvider,\n} from \"./dependencies\";\n\nconst PLAYBACK_ID_PATTERN = /([/+])([^/+?]+)$/;\nconst PLAYBACK_ID_PLACEHOLDER = \"__PLAYBACK_ID__\";\n\nexport interface RedirectCache {\n get(key: string): URL | undefined;\n set(key: string, value: URL): void;\n}\n\nclass LRURedirectCache implements RedirectCache {\n private cache = new Map<string, URL>();\n private readonly maxSize: number;\n\n constructor(maxSize = 10) {\n this.maxSize = maxSize;\n }\n\n get(key: string): URL | undefined {\n const cached = this.cache.get(key);\n if (cached) {\n this.cache.delete(key);\n this.cache.set(key, cached);\n }\n return cached;\n }\n\n set(key: string, value: URL): void {\n if (this.cache.has(key)) {\n this.cache.delete(key);\n } else if (this.cache.size >= this.maxSize) {\n const oldestKey = this.cache.keys().next().value;\n if (oldestKey) this.cache.delete(oldestKey);\n }\n this.cache.set(key, value);\n }\n}\n\nexport interface WHIPClientConfig {\n url: string;\n iceServers?: RTCIceServer[];\n videoBitrate?: number;\n audioBitrate?: number;\n maxFramerate?: number;\n connectionTimeout?: number;\n skipIceGathering?: boolean;\n onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n onResponse?: (response: Response) => WHIPResponseResult | void;\n peerConnectionFactory?: PeerConnectionFactory;\n fetch?: FetchFn;\n timers?: TimerProvider;\n redirectCache?: RedirectCache;\n}\n\nfunction preferH264(sdp: string): string {\n const lines = sdp.split(\"\\r\\n\");\n const mLineIndex = lines.findIndex((line) => line.startsWith(\"m=video\"));\n if (mLineIndex === -1) return sdp;\n\n const codecRegex = /a=rtpmap:(\\d+) H264(\\/\\d+)+/;\n const codecLine = lines.find((line) => codecRegex.test(line));\n if (!codecLine) return sdp;\n\n const match = codecRegex.exec(codecLine);\n const codecPayload = match?.[1];\n if (!codecPayload) return sdp;\n\n const mLine = lines[mLineIndex];\n if (!mLine) return sdp;\n\n const mLineElements = mLine.split(\" \");\n const reorderedMLine = [\n ...mLineElements.slice(0, 3),\n codecPayload,\n ...mLineElements.slice(3).filter((payload) => payload !== codecPayload),\n ];\n lines[mLineIndex] = reorderedMLine.join(\" \");\n return lines.join(\"\\r\\n\");\n}\n\nconst sharedRedirectCache = new LRURedirectCache();\n\nconst DEFAULT_CONNECTION_TIMEOUT = 10000;\n\nexport class WHIPClient {\n private readonly url: string;\n private readonly iceServers: RTCIceServer[];\n private readonly videoBitrate: number;\n private readonly audioBitrate: number;\n private readonly connectionTimeout: number;\n private readonly onStats?: (report: RTCStatsReport) => void;\n private readonly statsIntervalMs: number;\n private readonly onResponse?: (\n response: Response,\n ) => WHIPResponseResult | void;\n private readonly pcFactory: PeerConnectionFactory;\n private readonly fetch: FetchFn;\n private readonly timers: TimerProvider;\n private readonly redirectCache: RedirectCache;\n private readonly skipIceGathering: boolean;\n\n private maxFramerate?: number;\n private pc: RTCPeerConnection | null = null;\n private resourceUrl: string | null = null;\n private abortController: AbortController | null = null;\n private statsTimer: number | null = null;\n private videoSender: RTCRtpSender | null = null;\n private audioSender: RTCRtpSender | null = null;\n private videoTransceiver: RTCRtpTransceiver | null = null;\n private audioTransceiver: RTCRtpTransceiver | null = null;\n private iceGatheringTimer: number | null = null;\n\n constructor(config: WHIPClientConfig) {\n this.url = config.url;\n this.iceServers = config.iceServers ?? DEFAULT_ICE_SERVERS;\n this.videoBitrate = config.videoBitrate ?? DEFAULT_VIDEO_BITRATE;\n this.audioBitrate = config.audioBitrate ?? DEFAULT_AUDIO_BITRATE;\n this.connectionTimeout =\n config.connectionTimeout ?? DEFAULT_CONNECTION_TIMEOUT;\n this.maxFramerate = config.maxFramerate;\n this.onStats = config.onStats;\n this.statsIntervalMs = config.statsIntervalMs ?? 5000;\n this.onResponse = config.onResponse;\n this.pcFactory =\n config.peerConnectionFactory ?? defaultPeerConnectionFactory;\n this.fetch = config.fetch ?? defaultFetch;\n this.timers = config.timers ?? defaultTimerProvider;\n this.redirectCache = config.redirectCache ?? sharedRedirectCache;\n this.skipIceGathering = config.skipIceGathering ?? true;\n }\n\n async connect(stream: MediaStream): Promise<{ whepUrl: string | null }> {\n this.cleanup();\n\n this.pc = this.pcFactory.create({\n iceServers: this.iceServers,\n iceCandidatePoolSize: 10,\n });\n\n this.videoTransceiver = this.pc.addTransceiver(\"video\", {\n direction: \"sendonly\",\n });\n this.audioTransceiver = this.pc.addTransceiver(\"audio\", {\n direction: \"sendonly\",\n });\n this.videoSender = this.videoTransceiver.sender;\n this.audioSender = this.audioTransceiver.sender;\n\n const videoTrack = stream.getVideoTracks()[0];\n const audioTrack = stream.getAudioTracks()[0];\n\n if (videoTrack) {\n if (videoTrack.contentHint === \"\") {\n videoTrack.contentHint = \"motion\";\n }\n await this.videoSender.replaceTrack(videoTrack);\n }\n\n if (audioTrack) {\n await this.audioSender.replaceTrack(audioTrack);\n }\n\n this.setCodecPreferences();\n\n const offer = await this.pc.createOffer({\n offerToReceiveAudio: false,\n offerToReceiveVideo: false,\n });\n const enhancedSdp = preferH264(offer.sdp ?? \"\");\n await this.pc.setLocalDescription({ type: \"offer\", sdp: enhancedSdp });\n\n if (!this.skipIceGathering) {\n await this.waitForIceGathering();\n }\n\n this.abortController = new AbortController();\n const timeoutId = this.timers.setTimeout(\n () => this.abortController?.abort(),\n this.connectionTimeout,\n );\n\n try {\n const fetchUrl = this.getUrlWithCachedRedirect();\n\n const response = await this.fetch(fetchUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/sdp\" },\n body: this.pc.localDescription!.sdp,\n signal: this.abortController.signal,\n });\n\n this.timers.clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"\");\n throw new ConnectionError(\n `WHIP connection failed: ${response.status} ${response.statusText} ${errorText}`,\n );\n }\n\n this.cacheRedirectIfNeeded(fetchUrl, response.url);\n\n const location = response.headers.get(\"location\");\n if (location) {\n this.resourceUrl = new URL(location, this.url).toString();\n }\n\n const responseResult = this.onResponse?.(response);\n\n const answerSdp = await response.text();\n await this.pc.setRemoteDescription({ type: \"answer\", sdp: answerSdp });\n\n await this.applyBitrateConstraints();\n this.startStatsTimer();\n\n return { whepUrl: responseResult?.whepUrl ?? null };\n } catch (error) {\n this.timers.clearTimeout(timeoutId);\n if (error instanceof ConnectionError) {\n throw error;\n }\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new NetworkError(\"Connection timeout\");\n }\n throw new NetworkError(\"Failed to establish connection\", error);\n }\n }\n\n private setCodecPreferences(): void {\n if (!this.videoTransceiver?.setCodecPreferences) return;\n\n try {\n const caps = RTCRtpSender.getCapabilities(\"video\");\n if (!caps?.codecs?.length) return;\n\n const h264Codecs = caps.codecs.filter((c) =>\n c.mimeType.toLowerCase().includes(\"h264\"),\n );\n if (h264Codecs.length) {\n this.videoTransceiver.setCodecPreferences(h264Codecs);\n }\n } catch {\n // Codec preferences not supported\n }\n }\n\n private async applyBitrateConstraints(): Promise<void> {\n if (!this.pc) return;\n\n const senders = this.pc.getSenders();\n for (const sender of senders) {\n if (!sender.track) continue;\n\n const params = sender.getParameters();\n if (!params.encodings) params.encodings = [{}];\n\n const encoding = params.encodings[0];\n if (!encoding) continue;\n\n if (sender.track.kind === \"video\") {\n encoding.maxBitrate = this.videoBitrate;\n if (this.maxFramerate && this.maxFramerate > 0) {\n encoding.maxFramerate = this.maxFramerate;\n }\n encoding.scaleResolutionDownBy = 1.0;\n encoding.priority = \"high\";\n encoding.networkPriority = \"high\";\n params.degradationPreference = \"maintain-resolution\";\n } else if (sender.track.kind === \"audio\") {\n encoding.maxBitrate = this.audioBitrate;\n encoding.priority = \"medium\";\n encoding.networkPriority = \"medium\";\n }\n\n try {\n await sender.setParameters(params);\n } catch {\n // Parameters not supported\n }\n }\n }\n\n private waitForIceGathering(): Promise<void> {\n return new Promise((resolve) => {\n if (!this.pc) {\n resolve();\n return;\n }\n\n if (this.pc.iceGatheringState === \"complete\") {\n resolve();\n return;\n }\n\n const onStateChange = () => {\n if (this.pc?.iceGatheringState === \"complete\") {\n this.pc.removeEventListener(\"icegatheringstatechange\", onStateChange);\n if (this.iceGatheringTimer !== null) {\n this.timers.clearTimeout(this.iceGatheringTimer);\n this.iceGatheringTimer = null;\n }\n resolve();\n }\n };\n\n this.pc.addEventListener(\"icegatheringstatechange\", onStateChange);\n\n this.iceGatheringTimer = this.timers.setTimeout(() => {\n this.pc?.removeEventListener(\"icegatheringstatechange\", onStateChange);\n this.iceGatheringTimer = null;\n resolve();\n }, 1000);\n });\n }\n\n private startStatsTimer(): void {\n if (!this.onStats || !this.pc) return;\n\n this.stopStatsTimer();\n\n this.statsTimer = this.timers.setInterval(async () => {\n if (!this.pc) return;\n try {\n const report = await this.pc.getStats();\n this.onStats?.(report);\n } catch {\n // Stats collection failed\n }\n }, this.statsIntervalMs);\n }\n\n private stopStatsTimer(): void {\n if (this.statsTimer !== null) {\n this.timers.clearInterval(this.statsTimer);\n this.statsTimer = null;\n }\n }\n\n async replaceTrack(track: MediaStreamTrack): Promise<void> {\n if (!this.pc) {\n throw new ConnectionError(\"Not connected\");\n }\n\n const sender = track.kind === \"video\" ? this.videoSender : this.audioSender;\n if (!sender) {\n throw new ConnectionError(\n `No sender found for track kind: ${track.kind}`,\n );\n }\n\n await sender.replaceTrack(track);\n await this.applyBitrateConstraints();\n }\n\n setMaxFramerate(fps?: number): void {\n this.maxFramerate = fps;\n void this.applyBitrateConstraints();\n }\n\n private cleanup(): void {\n this.stopStatsTimer();\n\n if (this.iceGatheringTimer !== null) {\n this.timers.clearTimeout(this.iceGatheringTimer);\n this.iceGatheringTimer = null;\n }\n\n if (this.abortController) {\n try {\n this.abortController.abort();\n } catch {\n // Ignore abort errors\n }\n this.abortController = null;\n }\n\n if (this.pc) {\n // Clear event handlers\n this.pc.oniceconnectionstatechange = null;\n this.pc.onconnectionstatechange = null;\n this.pc.ontrack = null;\n\n try {\n this.pc.getTransceivers().forEach((t) => {\n try {\n t.stop();\n } catch {\n // Ignore stop errors\n }\n });\n } catch {\n // Ignore transceiver errors\n }\n\n try {\n this.pc.close();\n } catch {\n // Ignore close errors\n }\n this.pc = null;\n }\n\n this.videoSender = null;\n this.audioSender = null;\n this.videoTransceiver = null;\n this.audioTransceiver = null;\n }\n\n async disconnect(): Promise<void> {\n if (this.resourceUrl) {\n try {\n await this.fetch(this.resourceUrl, { method: \"DELETE\" });\n } catch {\n // Ignore delete errors\n }\n }\n\n this.cleanup();\n this.resourceUrl = null;\n }\n\n getPeerConnection(): RTCPeerConnection | null {\n return this.pc;\n }\n\n restartIce(): void {\n if (this.pc) {\n try {\n this.pc.restartIce();\n } catch {\n // ICE restart not supported\n }\n }\n }\n\n isConnected(): boolean {\n if (!this.pc) return false;\n const iceState = this.pc.iceConnectionState;\n return iceState === \"connected\" || iceState === \"completed\";\n }\n\n private getUrlWithCachedRedirect(): string {\n const originalUrl = new URL(this.url);\n const playbackIdMatch = originalUrl.pathname.match(PLAYBACK_ID_PATTERN);\n const playbackId = playbackIdMatch?.[2];\n\n const cachedTemplate = this.redirectCache.get(this.url);\n if (!cachedTemplate || !playbackId) {\n return this.url;\n }\n\n const redirectedUrl = new URL(cachedTemplate);\n redirectedUrl.pathname = cachedTemplate.pathname.replace(\n PLAYBACK_ID_PLACEHOLDER,\n playbackId,\n );\n return redirectedUrl.toString();\n }\n\n private cacheRedirectIfNeeded(requestUrl: string, responseUrl: string): void {\n if (requestUrl === responseUrl) return;\n\n try {\n const actualRedirect = new URL(responseUrl);\n const template = new URL(actualRedirect);\n template.pathname = template.pathname.replace(\n PLAYBACK_ID_PATTERN,\n `$1${PLAYBACK_ID_PLACEHOLDER}`,\n );\n this.redirectCache.set(this.url, template);\n } catch {\n // Invalid URL, skip caching\n }\n }\n}\n","export class TypedEventEmitter<EventMap extends { [K in keyof EventMap]: (...args: any[]) => void }> {\n private listeners = new Map<keyof EventMap, Set<(...args: any[]) => void>>();\n\n on<E extends keyof EventMap>(event: E, handler: EventMap[E]): this {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(handler);\n return this;\n }\n\n off<E extends keyof EventMap>(event: E, handler: EventMap[E]): this {\n this.listeners.get(event)?.delete(handler);\n return this;\n }\n\n protected emit<E extends keyof EventMap>(\n event: E,\n ...args: Parameters<EventMap[E]>\n ): void {\n this.listeners.get(event)?.forEach((handler) => {\n (handler as (...args: Parameters<EventMap[E]>) => void)(...args);\n });\n }\n\n protected clearListeners(): void {\n this.listeners.clear();\n }\n}\n\n","type TransitionMap<S extends string> = Record<S, S[]>;\n\nexport interface StateMachine<S extends string> {\n readonly current: S;\n can(next: S): boolean;\n transition(next: S): boolean;\n force(next: S): void;\n}\n\nexport function createStateMachine<S extends string>(\n initial: S,\n transitions: TransitionMap<S>,\n onChange?: (from: S, to: S) => void,\n): StateMachine<S> {\n let current = initial;\n\n return {\n get current() {\n return current;\n },\n can(next: S) {\n return transitions[current].includes(next);\n },\n transition(next: S): boolean {\n if (!transitions[current].includes(next)) return false;\n const prev = current;\n current = next;\n onChange?.(prev, next);\n return true;\n },\n force(next: S) {\n const prev = current;\n current = next;\n onChange?.(prev, next);\n },\n };\n}\n","import type {\n BroadcastState,\n BroadcastEventMap,\n BroadcastOptions,\n ReconnectConfig,\n ReconnectInfo,\n DaydreamError,\n} from \"./types\";\nimport { WHIPClient, type WHIPClientConfig } from \"./internal/WHIPClient\";\nimport { ConnectionError } from \"./errors\";\nimport { TypedEventEmitter } from \"./internal/TypedEventEmitter\";\nimport { createStateMachine, type StateMachine } from \"./internal/StateMachine\";\n\nconst BROADCAST_TRANSITIONS: Record<BroadcastState, BroadcastState[]> = {\n connecting: [\"live\", \"error\"],\n live: [\"reconnecting\", \"ended\"],\n reconnecting: [\"live\", \"ended\"],\n ended: [],\n error: [\"connecting\"],\n};\n\nexport interface BroadcastConfig {\n whipUrl: string;\n stream: MediaStream;\n reconnect?: ReconnectConfig;\n whipConfig?: Partial<WHIPClientConfig>;\n}\n\nexport class Broadcast extends TypedEventEmitter<BroadcastEventMap> {\n private _whepUrl: string | null = null;\n private readonly stateMachine: StateMachine<BroadcastState>;\n private currentStream: MediaStream;\n private readonly reconnectConfig: ReconnectConfig;\n private readonly whipClient: WHIPClient;\n\n private reconnectAttempts = 0;\n private reconnectTimeout: ReturnType<typeof setTimeout> | null = null;\n private disconnectedGraceTimeout: ReturnType<typeof setTimeout> | null = null;\n\n constructor(config: BroadcastConfig) {\n super();\n this.currentStream = config.stream;\n this.reconnectConfig = {\n enabled: config.reconnect?.enabled ?? true,\n maxAttempts: config.reconnect?.maxAttempts ?? 5,\n baseDelayMs: config.reconnect?.baseDelayMs ?? 1000,\n };\n\n this.whipClient = new WHIPClient({\n url: config.whipUrl,\n ...config.whipConfig,\n });\n\n this.stateMachine = createStateMachine<BroadcastState>(\n \"connecting\",\n BROADCAST_TRANSITIONS,\n (_from, to) => this.emit(\"stateChange\", to),\n );\n }\n\n get state(): BroadcastState {\n return this.stateMachine.current;\n }\n\n get whepUrl(): string | null {\n return this._whepUrl;\n }\n\n get stream(): MediaStream {\n return this.currentStream;\n }\n\n get reconnectInfo(): ReconnectInfo | null {\n if (this.state !== \"reconnecting\") return null;\n const baseDelay = this.reconnectConfig.baseDelayMs ?? 1000;\n const delay = baseDelay * Math.pow(2, this.reconnectAttempts - 1);\n return {\n attempt: this.reconnectAttempts,\n maxAttempts: this.reconnectConfig.maxAttempts ?? 5,\n delayMs: delay,\n };\n }\n\n async connect(): Promise<void> {\n try {\n const result = await this.whipClient.connect(this.currentStream);\n if (result.whepUrl) {\n this._whepUrl = result.whepUrl;\n }\n this.setupConnectionMonitoring();\n this.stateMachine.transition(\"live\");\n } catch (error) {\n this.stateMachine.transition(\"error\");\n const daydreamError =\n error instanceof Error\n ? error\n : new ConnectionError(\"Failed to connect\", error);\n this.emit(\"error\", daydreamError as DaydreamError);\n throw daydreamError;\n }\n }\n\n async stop(): Promise<void> {\n this.stateMachine.force(\"ended\");\n this.clearTimeouts();\n\n await this.whipClient.disconnect();\n this.clearListeners();\n }\n\n setMaxFramerate(fps?: number): void {\n this.whipClient.setMaxFramerate(fps);\n }\n\n async replaceStream(newStream: MediaStream): Promise<void> {\n if (!this.whipClient.isConnected()) {\n this.currentStream = newStream;\n return;\n }\n\n const videoTrack = newStream.getVideoTracks()[0];\n const audioTrack = newStream.getAudioTracks()[0];\n\n try {\n if (videoTrack) {\n await this.whipClient.replaceTrack(videoTrack);\n }\n if (audioTrack) {\n await this.whipClient.replaceTrack(audioTrack);\n }\n this.currentStream = newStream;\n } catch {\n this.currentStream = newStream;\n this.scheduleReconnect();\n }\n }\n\n private setupConnectionMonitoring(): void {\n const pc = this.whipClient.getPeerConnection();\n if (!pc) return;\n\n pc.oniceconnectionstatechange = () => {\n if (this.state === \"ended\") return;\n\n const iceState = pc.iceConnectionState;\n\n if (iceState === \"connected\" || iceState === \"completed\") {\n this.clearGraceTimeout();\n if (this.state === \"reconnecting\") {\n this.stateMachine.transition(\"live\");\n this.reconnectAttempts = 0;\n }\n return;\n }\n\n if (iceState === \"disconnected\") {\n this.clearGraceTimeout();\n this.whipClient.restartIce();\n\n this.disconnectedGraceTimeout = setTimeout(() => {\n if (this.state === \"ended\") return;\n const currentState = pc.iceConnectionState;\n if (currentState === \"disconnected\") {\n this.scheduleReconnect();\n }\n }, 2000);\n return;\n }\n\n if (iceState === \"failed\" || iceState === \"closed\") {\n this.clearGraceTimeout();\n this.scheduleReconnect();\n }\n };\n }\n\n private clearGraceTimeout(): void {\n if (this.disconnectedGraceTimeout) {\n clearTimeout(this.disconnectedGraceTimeout);\n this.disconnectedGraceTimeout = null;\n }\n }\n\n private clearReconnectTimeout(): void {\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = null;\n }\n }\n\n private clearTimeouts(): void {\n this.clearGraceTimeout();\n this.clearReconnectTimeout();\n }\n\n private scheduleReconnect(): void {\n if (this.state === \"ended\") return;\n\n if (!this.reconnectConfig.enabled) {\n this.stateMachine.transition(\"ended\");\n return;\n }\n\n const maxAttempts = this.reconnectConfig.maxAttempts ?? 5;\n\n if (this.reconnectAttempts >= maxAttempts) {\n this.stateMachine.transition(\"ended\");\n return;\n }\n\n this.clearReconnectTimeout();\n this.stateMachine.transition(\"reconnecting\");\n\n const baseDelay = this.reconnectConfig.baseDelayMs ?? 1000;\n const delay = baseDelay * Math.pow(2, this.reconnectAttempts);\n this.reconnectAttempts++;\n\n this.emit(\"reconnect\", {\n attempt: this.reconnectAttempts,\n maxAttempts: this.reconnectConfig.maxAttempts ?? 5,\n delayMs: delay,\n });\n\n this.reconnectTimeout = setTimeout(async () => {\n if (this.state === \"ended\") return;\n\n try {\n await this.whipClient.disconnect();\n const result = await this.whipClient.connect(this.currentStream);\n if (result.whepUrl) {\n this._whepUrl = result.whepUrl;\n }\n this.setupConnectionMonitoring();\n this.stateMachine.transition(\"live\");\n this.reconnectAttempts = 0;\n } catch {\n this.scheduleReconnect();\n }\n }, delay);\n }\n}\n\nexport function createBroadcast(options: BroadcastOptions): Broadcast {\n const {\n whipUrl,\n stream,\n reconnect,\n video,\n audio,\n iceServers,\n connectionTimeout,\n onStats,\n statsIntervalMs,\n onResponse,\n } = options;\n\n return new Broadcast({\n whipUrl,\n stream,\n reconnect,\n whipConfig: {\n iceServers,\n videoBitrate: video?.bitrate,\n audioBitrate: audio?.bitrate,\n maxFramerate: video?.maxFramerate,\n connectionTimeout,\n onStats,\n statsIntervalMs,\n onResponse,\n },\n });\n}\n","import { DEFAULT_ICE_SERVERS } from \"../types\";\nimport { ConnectionError, NetworkError } from \"../errors\";\nimport {\n type PeerConnectionFactory,\n type FetchFn,\n type TimerProvider,\n type MediaStreamFactory,\n defaultPeerConnectionFactory,\n defaultFetch,\n defaultTimerProvider,\n defaultMediaStreamFactory,\n} from \"./dependencies\";\n\nexport interface WHEPClientConfig {\n url: string;\n iceServers?: RTCIceServer[];\n connectionTimeout?: number;\n skipIceGathering?: boolean;\n onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n peerConnectionFactory?: PeerConnectionFactory;\n fetch?: FetchFn;\n timers?: TimerProvider;\n mediaStreamFactory?: MediaStreamFactory;\n}\n\nconst DEFAULT_CONNECTION_TIMEOUT = 10000;\n\nexport class WHEPClient {\n private readonly url: string;\n private readonly iceServers: RTCIceServer[];\n private readonly connectionTimeout: number;\n private readonly skipIceGathering: boolean;\n private readonly onStats?: (report: RTCStatsReport) => void;\n private readonly statsIntervalMs: number;\n private readonly pcFactory: PeerConnectionFactory;\n private readonly fetch: FetchFn;\n private readonly timers: TimerProvider;\n private readonly mediaStreamFactory: MediaStreamFactory;\n\n private pc: RTCPeerConnection | null = null;\n private resourceUrl: string | null = null;\n private stream: MediaStream | null = null;\n private abortController: AbortController | null = null;\n private statsTimer: number | null = null;\n private iceGatheringTimer: number | null = null;\n\n constructor(config: WHEPClientConfig) {\n this.url = config.url;\n this.iceServers = config.iceServers ?? DEFAULT_ICE_SERVERS;\n this.connectionTimeout =\n config.connectionTimeout ?? DEFAULT_CONNECTION_TIMEOUT;\n this.skipIceGathering = config.skipIceGathering ?? true;\n this.onStats = config.onStats;\n this.statsIntervalMs = config.statsIntervalMs ?? 5000;\n this.pcFactory =\n config.peerConnectionFactory ?? defaultPeerConnectionFactory;\n this.fetch = config.fetch ?? defaultFetch;\n this.timers = config.timers ?? defaultTimerProvider;\n this.mediaStreamFactory =\n config.mediaStreamFactory ?? defaultMediaStreamFactory;\n }\n\n async connect(): Promise<MediaStream> {\n this.cleanup();\n\n this.pc = this.pcFactory.create({\n iceServers: this.iceServers,\n });\n\n this.pc.addTransceiver(\"video\", { direction: \"recvonly\" });\n this.pc.addTransceiver(\"audio\", { direction: \"recvonly\" });\n\n this.stream = this.mediaStreamFactory.create();\n\n this.pc.ontrack = (event) => {\n const [remoteStream] = event.streams;\n if (remoteStream) {\n this.stream = remoteStream;\n } else if (this.stream) {\n this.stream.addTrack(event.track);\n }\n };\n\n const offer = await this.pc.createOffer();\n await this.pc.setLocalDescription(offer);\n\n if (!this.skipIceGathering) {\n await this.waitForIceGathering();\n }\n\n this.abortController = new AbortController();\n const timeoutId = this.timers.setTimeout(\n () => this.abortController?.abort(),\n this.connectionTimeout,\n );\n\n try {\n const response = await this.fetch(this.url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/sdp\" },\n body: this.pc.localDescription!.sdp,\n signal: this.abortController.signal,\n });\n\n this.timers.clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"\");\n throw new ConnectionError(\n `WHEP connection failed: ${response.status} ${response.statusText} ${errorText}`,\n );\n }\n\n const location = response.headers.get(\"location\");\n if (location) {\n this.resourceUrl = new URL(location, this.url).toString();\n }\n\n const answerSdp = await response.text();\n await this.pc.setRemoteDescription({ type: \"answer\", sdp: answerSdp });\n\n this.startStatsTimer();\n\n return this.stream;\n } catch (error) {\n this.timers.clearTimeout(timeoutId);\n if (error instanceof ConnectionError) {\n throw error;\n }\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new NetworkError(\"Connection timeout\");\n }\n throw new NetworkError(\"Failed to establish connection\", error);\n }\n }\n\n private waitForIceGathering(): Promise<void> {\n return new Promise((resolve) => {\n if (!this.pc) {\n resolve();\n return;\n }\n\n if (this.pc.iceGatheringState === \"complete\") {\n resolve();\n return;\n }\n\n const onStateChange = () => {\n if (this.pc?.iceGatheringState === \"complete\") {\n this.pc.removeEventListener(\"icegatheringstatechange\", onStateChange);\n if (this.iceGatheringTimer !== null) {\n this.timers.clearTimeout(this.iceGatheringTimer);\n this.iceGatheringTimer = null;\n }\n resolve();\n }\n };\n\n this.pc.addEventListener(\"icegatheringstatechange\", onStateChange);\n\n this.iceGatheringTimer = this.timers.setTimeout(() => {\n this.pc?.removeEventListener(\"icegatheringstatechange\", onStateChange);\n this.iceGatheringTimer = null;\n resolve();\n }, 1000);\n });\n }\n\n private startStatsTimer(): void {\n if (!this.onStats || !this.pc) return;\n\n this.stopStatsTimer();\n\n this.statsTimer = this.timers.setInterval(async () => {\n if (!this.pc) return;\n try {\n const report = await this.pc.getStats();\n this.onStats?.(report);\n } catch {\n // Stats collection failed\n }\n }, this.statsIntervalMs);\n }\n\n private stopStatsTimer(): void {\n if (this.statsTimer !== null) {\n this.timers.clearInterval(this.statsTimer);\n this.statsTimer = null;\n }\n }\n\n private cleanup(): void {\n this.stopStatsTimer();\n\n if (this.iceGatheringTimer !== null) {\n this.timers.clearTimeout(this.iceGatheringTimer);\n this.iceGatheringTimer = null;\n }\n\n if (this.abortController) {\n try {\n this.abortController.abort();\n } catch {\n // Ignore abort errors\n }\n this.abortController = null;\n }\n\n if (this.pc) {\n // Clear event handlers\n this.pc.oniceconnectionstatechange = null;\n this.pc.onconnectionstatechange = null;\n this.pc.ontrack = null;\n\n try {\n this.pc.getTransceivers().forEach((t) => {\n try {\n t.stop();\n } catch {\n // Ignore stop errors\n }\n });\n } catch {\n // Ignore transceiver errors\n }\n\n try {\n this.pc.close();\n } catch {\n // Ignore close errors\n }\n this.pc = null;\n }\n }\n\n async disconnect(): Promise<void> {\n if (this.resourceUrl) {\n try {\n await this.fetch(this.resourceUrl, { method: \"DELETE\" });\n } catch {\n // Ignore delete errors\n }\n }\n\n this.cleanup();\n this.stream = null;\n this.resourceUrl = null;\n }\n\n getStream(): MediaStream | null {\n return this.stream;\n }\n\n getPeerConnection(): RTCPeerConnection | null {\n return this.pc;\n }\n\n restartIce(): void {\n if (this.pc) {\n try {\n this.pc.restartIce();\n } catch {\n // ICE restart not supported\n }\n }\n }\n}\n","import type {\n PlayerState,\n PlayerEventMap,\n PlayerOptions,\n ReconnectConfig,\n ReconnectInfo,\n DaydreamError,\n} from \"./types\";\nimport { WHEPClient, type WHEPClientConfig } from \"./internal/WHEPClient\";\nimport { ConnectionError } from \"./errors\";\nimport { TypedEventEmitter } from \"./internal/TypedEventEmitter\";\nimport { createStateMachine, type StateMachine } from \"./internal/StateMachine\";\n\nconst PLAYER_TRANSITIONS: Record<PlayerState, PlayerState[]> = {\n connecting: [\"playing\", \"buffering\", \"error\"],\n playing: [\"buffering\", \"ended\"],\n buffering: [\"playing\", \"ended\"],\n ended: [],\n error: [\"connecting\"],\n};\n\nexport interface PlayerConfig {\n whepUrl: string;\n reconnect?: ReconnectConfig;\n whepConfig?: Partial<WHEPClientConfig>;\n}\n\nexport class Player extends TypedEventEmitter<PlayerEventMap> {\n private readonly stateMachine: StateMachine<PlayerState>;\n private _stream: MediaStream | null = null;\n private readonly whepUrl: string;\n private readonly reconnectConfig: ReconnectConfig;\n private readonly whepConfig: Partial<WHEPClientConfig> | undefined;\n private whepClient: WHEPClient;\n\n private reconnectAttempts = 0;\n private reconnectTimeout: ReturnType<typeof setTimeout> | null = null;\n private disconnectedGraceTimeout: ReturnType<typeof setTimeout> | null = null;\n\n constructor(config: PlayerConfig) {\n super();\n this.whepUrl = config.whepUrl;\n this.whepConfig = config.whepConfig;\n this.reconnectConfig = {\n enabled: config.reconnect?.enabled ?? true,\n maxAttempts: config.reconnect?.maxAttempts ?? 30,\n baseDelayMs: config.reconnect?.baseDelayMs ?? 200,\n };\n\n this.whepClient = new WHEPClient({\n url: config.whepUrl,\n ...this.whepConfig,\n });\n\n this.stateMachine = createStateMachine<PlayerState>(\n \"connecting\",\n PLAYER_TRANSITIONS,\n (_from, to) => this.emit(\"stateChange\", to),\n );\n }\n\n get state(): PlayerState {\n return this.stateMachine.current;\n }\n\n get stream(): MediaStream | null {\n return this._stream;\n }\n\n get reconnectInfo(): ReconnectInfo | null {\n if (this.state !== \"buffering\") return null;\n const baseDelay = this.reconnectConfig.baseDelayMs ?? 200;\n const delay = this.calculateReconnectDelay(\n this.reconnectAttempts - 1,\n baseDelay,\n );\n return {\n attempt: this.reconnectAttempts,\n maxAttempts: this.reconnectConfig.maxAttempts ?? 30,\n delayMs: delay,\n };\n }\n\n async connect(): Promise<void> {\n try {\n this._stream = await this.whepClient.connect();\n this.setupConnectionMonitoring();\n this.stateMachine.transition(\"playing\");\n this.reconnectAttempts = 0;\n } catch (error) {\n if (\n this.reconnectConfig.enabled &&\n this.reconnectAttempts < (this.reconnectConfig.maxAttempts ?? 30)\n ) {\n this.scheduleReconnect();\n return;\n }\n this.stateMachine.transition(\"error\");\n const daydreamError =\n error instanceof Error\n ? error\n : new ConnectionError(\"Failed to connect\", error);\n this.emit(\"error\", daydreamError as DaydreamError);\n throw daydreamError;\n }\n }\n\n attachTo(video: HTMLVideoElement): void {\n if (this._stream) {\n video.srcObject = this._stream;\n }\n }\n\n async stop(): Promise<void> {\n this.stateMachine.force(\"ended\");\n this.clearTimeouts();\n\n await this.whepClient.disconnect();\n this._stream = null;\n this.clearListeners();\n }\n\n private setupConnectionMonitoring(): void {\n const pc = this.whepClient.getPeerConnection();\n if (!pc) return;\n\n pc.oniceconnectionstatechange = () => {\n if (this.state === \"ended\") return;\n\n const iceState = pc.iceConnectionState;\n\n if (iceState === \"connected\" || iceState === \"completed\") {\n this.clearGraceTimeout();\n if (this.state === \"buffering\") {\n this.stateMachine.transition(\"playing\");\n this.reconnectAttempts = 0;\n }\n return;\n }\n\n if (iceState === \"disconnected\") {\n this.clearGraceTimeout();\n this.whepClient.restartIce();\n\n this.disconnectedGraceTimeout = setTimeout(() => {\n if (this.state === \"ended\") return;\n const currentState = pc.iceConnectionState;\n if (currentState === \"disconnected\") {\n this.scheduleReconnect();\n }\n }, 2000);\n return;\n }\n\n if (iceState === \"failed\" || iceState === \"closed\") {\n this.clearGraceTimeout();\n this.scheduleReconnect();\n }\n };\n }\n\n private clearGraceTimeout(): void {\n if (this.disconnectedGraceTimeout) {\n clearTimeout(this.disconnectedGraceTimeout);\n this.disconnectedGraceTimeout = null;\n }\n }\n\n private clearReconnectTimeout(): void {\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = null;\n }\n }\n\n private clearTimeouts(): void {\n this.clearGraceTimeout();\n this.clearReconnectTimeout();\n }\n\n private scheduleReconnect(): void {\n if (this.state === \"ended\") return;\n\n if (!this.reconnectConfig.enabled) {\n this.stateMachine.transition(\"ended\");\n return;\n }\n\n const maxAttempts = this.reconnectConfig.maxAttempts ?? 30;\n\n if (this.reconnectAttempts >= maxAttempts) {\n this.stateMachine.transition(\"ended\");\n return;\n }\n\n this.clearReconnectTimeout();\n this.stateMachine.transition(\"buffering\");\n\n const baseDelay = this.reconnectConfig.baseDelayMs ?? 200;\n const delay = this.calculateReconnectDelay(\n this.reconnectAttempts,\n baseDelay,\n );\n this.reconnectAttempts++;\n\n this.emit(\"reconnect\", {\n attempt: this.reconnectAttempts,\n maxAttempts: this.reconnectConfig.maxAttempts ?? 30,\n delayMs: delay,\n });\n\n this.reconnectTimeout = setTimeout(async () => {\n if (this.state === \"ended\") return;\n\n try {\n await this.whepClient.disconnect();\n this.whepClient = new WHEPClient({\n url: this.whepUrl,\n ...this.whepConfig,\n });\n this._stream = await this.whepClient.connect();\n this.setupConnectionMonitoring();\n this.stateMachine.transition(\"playing\");\n this.reconnectAttempts = 0;\n } catch {\n this.scheduleReconnect();\n }\n }, delay);\n }\n\n private calculateReconnectDelay(attempt: number, baseDelay: number): number {\n const linearPhaseEndCount = 10;\n const maxDelay = 60000;\n\n if (attempt === 0) return 0;\n if (attempt <= linearPhaseEndCount) return baseDelay;\n\n const exponentialAttempt = attempt - linearPhaseEndCount;\n const delay = 500 * Math.pow(2, exponentialAttempt - 1);\n return Math.min(delay, maxDelay);\n }\n}\n\nexport function createPlayer(whepUrl: string, options?: PlayerOptions): Player {\n return new Player({\n whepUrl,\n reconnect: options?.reconnect,\n whepConfig: {\n iceServers: options?.iceServers,\n connectionTimeout: options?.connectionTimeout,\n skipIceGathering: options?.skipIceGathering,\n onStats: options?.onStats,\n statsIntervalMs: options?.statsIntervalMs,\n },\n });\n}\n","import type { Source } from \"../../types\";\n\nexport type RegistryEntry = {\n id: string;\n source: Source;\n registeredAt: number;\n};\n\nexport type RegistryEvents = {\n onRegister?: (id: string, source: Source) => void;\n onUnregister?: (id: string) => void;\n};\n\nexport interface SourceRegistry {\n register(id: string, source: Source): void;\n unregister(id: string): Source | undefined;\n get(id: string): Source | undefined;\n has(id: string): boolean;\n list(): Array<{ id: string; source: Source }>;\n clear(): void;\n}\n\nexport function createRegistry(events?: RegistryEvents): SourceRegistry {\n const sources = new Map<string, RegistryEntry>();\n\n return {\n register(id: string, source: Source): void {\n if (!id) throw new Error(\"Source id is required\");\n if (!source) throw new Error(\"Source is required\");\n\n sources.set(id, {\n id,\n source,\n registeredAt: Date.now(),\n });\n\n events?.onRegister?.(id, source);\n },\n\n unregister(id: string): Source | undefined {\n const entry = sources.get(id);\n if (!entry) return undefined;\n\n sources.delete(id);\n events?.onUnregister?.(id);\n\n return entry.source;\n },\n\n get(id: string): Source | undefined {\n return sources.get(id)?.source;\n },\n\n has(id: string): boolean {\n return sources.has(id);\n },\n\n list(): Array<{ id: string; source: Source }> {\n return Array.from(sources.values()).map((entry) => ({\n id: entry.id,\n source: entry.source,\n }));\n },\n\n clear(): void {\n const ids = Array.from(sources.keys());\n sources.clear();\n ids.forEach((id) => events?.onUnregister?.(id));\n },\n };\n}\n","import type { Ctx2D, FitMode, Size, Source } from \"../../types\";\n\nexport interface RendererOptions {\n width: number;\n height: number;\n dpr: number;\n keepalive: boolean;\n}\n\nexport interface Renderer {\n readonly captureCanvas: HTMLCanvasElement;\n readonly offscreenCtx: Ctx2D;\n readonly size: Size;\n\n setActiveSource(source: Source | null): void;\n renderFrame(timestamp: number): void;\n resize(width: number, height: number, dpr: number): void;\n setKeepalive(enabled: boolean): void;\n isSourceReady(source: Source): boolean;\n destroy(): void;\n}\n\ntype RectCache = {\n canvasW: number;\n canvasH: number;\n sourceW: number;\n sourceH: number;\n dx: number;\n dy: number;\n dw: number;\n dh: number;\n fit: FitMode;\n};\n\nexport function createRenderer(options: RendererOptions): Renderer {\n let size: Size = {\n width: options.width,\n height: options.height,\n dpr: Math.min(2, options.dpr),\n };\n let keepalive = options.keepalive;\n\n // Canvases\n let captureCanvas: HTMLCanvasElement | null = null;\n let captureCtx: Ctx2D | null = null;\n let offscreen: OffscreenCanvas | HTMLCanvasElement | null = null;\n let offscreenCtx: Ctx2D | null = null;\n\n // Source state\n let currentSource: Source | null = null;\n\n // Rendering state\n let frameIndex = 0;\n let rectCache = new WeakMap<\n HTMLCanvasElement | HTMLVideoElement,\n RectCache\n >();\n\n function initCanvas(): void {\n const canvas = document.createElement(\"canvas\");\n canvas.style.display = \"none\";\n\n const pxW = Math.round(size.width * size.dpr);\n const pxH = Math.round(size.height * size.dpr);\n const outW = Math.round(size.width);\n const outH = Math.round(size.height);\n\n canvas.width = outW;\n canvas.height = outH;\n\n const ctx = canvas.getContext(\"2d\", {\n alpha: false,\n desynchronized: true,\n }) as Ctx2D | null;\n\n if (!ctx) throw new Error(\"2D context not available\");\n\n captureCanvas = canvas;\n captureCtx = ctx;\n\n // Create offscreen canvas for DPR scaling\n try {\n const off = new OffscreenCanvas(pxW, pxH);\n offscreen = off;\n const offCtx = off.getContext(\"2d\", { alpha: false }) as Ctx2D | null;\n if (!offCtx) throw new Error(\"2D context not available for Offscreen\");\n offCtx.imageSmoothingEnabled = true;\n offscreenCtx = offCtx;\n } catch {\n // Fallback to HTMLCanvasElement\n const off = document.createElement(\"canvas\");\n off.width = pxW;\n off.height = pxH;\n const offCtx = off.getContext(\"2d\", { alpha: false }) as Ctx2D | null;\n if (!offCtx)\n throw new Error(\"2D context not available for Offscreen fallback\");\n offCtx.imageSmoothingEnabled = true;\n offscreen = off;\n offscreenCtx = offCtx;\n }\n\n // Initial fill\n offscreenCtx!.fillStyle = \"#111\";\n offscreenCtx!.fillRect(0, 0, pxW, pxH);\n captureCtx!.drawImage(\n offscreen as CanvasImageSource,\n 0,\n 0,\n pxW,\n pxH,\n 0,\n 0,\n outW,\n outH,\n );\n }\n\n function isSourceReady(source: Source): boolean {\n if (source.kind === \"video\") {\n const v = source.element;\n return (\n typeof v.readyState === \"number\" &&\n v.readyState >= 2 &&\n (v.videoWidth || 0) > 0 &&\n (v.videoHeight || 0) > 0\n );\n }\n // canvas\n const c = source.element;\n return (c.width || 0) > 0 && (c.height || 0) > 0;\n }\n\n function getDrawRect(\n el: HTMLCanvasElement | HTMLVideoElement,\n fit: FitMode,\n ): { dx: number; dy: number; dw: number; dh: number } | null {\n const canvas = offscreenCtx?.canvas;\n if (!canvas) return null;\n\n const canvasW = canvas.width;\n const canvasH = canvas.height;\n const sourceW = (el as HTMLVideoElement).videoWidth ?? el.width;\n const sourceH = (el as HTMLVideoElement).videoHeight ?? el.height;\n\n if (!sourceW || !sourceH) return null;\n\n const cached = rectCache.get(el);\n if (\n cached &&\n cached.canvasW === canvasW &&\n cached.canvasH === canvasH &&\n cached.sourceW === sourceW &&\n cached.sourceH === sourceH &&\n cached.fit === fit\n ) {\n return { dx: cached.dx, dy: cached.dy, dw: cached.dw, dh: cached.dh };\n }\n\n const scale =\n fit === \"cover\"\n ? Math.max(canvasW / sourceW, canvasH / sourceH)\n : Math.min(canvasW / sourceW, canvasH / sourceH);\n\n const dw = Math.floor(sourceW * scale);\n const dh = Math.floor(sourceH * scale);\n const dx = Math.floor((canvasW - dw) / 2);\n const dy = Math.floor((canvasH - dh) / 2);\n\n rectCache.set(el, {\n canvasW,\n canvasH,\n sourceW,\n sourceH,\n dx,\n dy,\n dw,\n dh,\n fit,\n });\n\n return { dx, dy, dw, dh };\n }\n\n function blitSource(source: Source): void {\n if (!offscreenCtx) return;\n const ctx = offscreenCtx;\n\n const el = source.element;\n const rect = getDrawRect(el, source.fit ?? \"contain\");\n if (!rect) return;\n\n ctx.drawImage(\n el as CanvasImageSource,\n rect.dx,\n rect.dy,\n rect.dw,\n rect.dh,\n );\n }\n\n // Initialize canvas on creation\n initCanvas();\n\n return {\n get captureCanvas(): HTMLCanvasElement {\n return captureCanvas!;\n },\n\n get offscreenCtx(): Ctx2D {\n return offscreenCtx!;\n },\n\n get size(): Size {\n return { ...size };\n },\n\n isSourceReady,\n\n setActiveSource(source: Source | null): void {\n currentSource = source;\n },\n\n renderFrame(_timestamp: number): void {\n const off = offscreenCtx;\n const cap = captureCtx;\n const capCanvas = captureCanvas;\n if (!off || !cap || !capCanvas) return;\n\n off.globalCompositeOperation = \"source-over\";\n\n if (currentSource && isSourceReady(currentSource)) {\n off.fillStyle = \"#000\";\n off.fillRect(0, 0, off.canvas.width, off.canvas.height);\n blitSource(currentSource);\n }\n\n // Keepalive pixel flicker\n if (keepalive) {\n const w = off.canvas.width;\n const h = off.canvas.height;\n const prevAlpha = off.globalAlpha;\n const prevFill = off.fillStyle;\n try {\n off.globalAlpha = 0.08;\n off.fillStyle = frameIndex % 2 ? \"#101010\" : \"#0e0e0e\";\n off.fillRect(w - 16, h - 16, 16, 16);\n } finally {\n off.globalAlpha = prevAlpha;\n off.fillStyle = prevFill;\n }\n }\n\n frameIndex++;\n\n // Blit offscreen to capture canvas\n cap.drawImage(\n off.canvas,\n 0,\n 0,\n off.canvas.width,\n off.canvas.height,\n 0,\n 0,\n capCanvas.width,\n capCanvas.height,\n );\n },\n\n resize(width: number, height: number, dpr: number): void {\n const nextDpr = Math.min(2, dpr);\n if (\n size.width === width &&\n size.height === height &&\n size.dpr === nextDpr\n ) {\n return;\n }\n\n size = { width, height, dpr: nextDpr };\n\n const pxW = Math.round(width * nextDpr);\n const pxH = Math.round(height * nextDpr);\n const outW = Math.round(width);\n const outH = Math.round(height);\n\n if (captureCanvas) {\n captureCanvas.width = outW;\n captureCanvas.height = outH;\n }\n\n if (offscreen instanceof HTMLCanvasElement) {\n offscreen.width = pxW;\n offscreen.height = pxH;\n } else if (offscreen instanceof OffscreenCanvas) {\n offscreen.width = pxW;\n offscreen.height = pxH;\n }\n\n rectCache = new WeakMap();\n },\n\n setKeepalive(enabled: boolean): void {\n keepalive = enabled;\n },\n\n destroy(): void {\n currentSource = null;\n captureCanvas = null;\n captureCtx = null;\n offscreen = null;\n offscreenCtx = null;\n },\n };\n}\n","export interface SchedulerOptions {\n fps: number;\n sendFps: number;\n onFrame: (timestamp: number) => void;\n onSendFpsChange?: (fps: number) => void;\n}\n\nexport interface Scheduler {\n start(videoElement?: HTMLVideoElement): void;\n stop(): void;\n setFps(fps: number): void;\n setSendFps(fps: number): void;\n readonly isRunning: boolean;\n readonly fps: number;\n readonly sendFps: number;\n}\n\nexport function createScheduler(options: SchedulerOptions): Scheduler {\n let fps = Math.max(1, options.fps);\n let sendFps = Math.max(1, options.sendFps);\n const onFrame = options.onFrame;\n const onSendFpsChange = options.onSendFpsChange;\n\n let isRunning = false;\n let lastFrameAt = 0;\n\n // RAF scheduling\n let rafId: number | null = null;\n let rafFallbackActive = false;\n\n // Video frame callback scheduling\n let videoFrameRequestId: number | null = null;\n let videoFrameSource: HTMLVideoElement | null = null;\n\n function getTimestamp(): number {\n return typeof performance !== \"undefined\" ? performance.now() : Date.now();\n }\n\n function shouldRenderFrame(): boolean {\n const now = getTimestamp();\n const minIntervalMs = 1000 / Math.max(1, sendFps);\n if (lastFrameAt !== 0 && now - lastFrameAt < minIntervalMs) {\n return false;\n }\n return true;\n }\n\n function renderIfNeeded(): void {\n if (!shouldRenderFrame()) return;\n const timestamp = getTimestamp();\n onFrame(timestamp);\n lastFrameAt = timestamp;\n }\n\n function scheduleWithRaf(isFallback: boolean): void {\n if (isFallback) {\n if (rafFallbackActive) return;\n rafFallbackActive = true;\n }\n\n const loop = (): void => {\n renderIfNeeded();\n rafId = requestAnimationFrame(loop);\n };\n\n rafId = requestAnimationFrame(loop);\n }\n\n function scheduleWithVideoFrame(videoEl: HTMLVideoElement): void {\n if (typeof videoEl.requestVideoFrameCallback !== \"function\") {\n scheduleWithRaf(false);\n return;\n }\n\n videoFrameSource = videoEl;\n\n const cb = (): void => {\n renderIfNeeded();\n if (videoFrameSource === videoEl) {\n try {\n videoFrameRequestId = videoEl.requestVideoFrameCallback(cb);\n } catch {\n // Failed to request video frame callback\n }\n }\n };\n\n try {\n videoFrameRequestId = videoEl.requestVideoFrameCallback(cb);\n } catch {\n // Failed to start video frame callback\n }\n\n // Also schedule RAF as fallback for non-video frames\n scheduleWithRaf(true);\n }\n\n function cancelSchedulers(): void {\n if (rafId != null) {\n cancelAnimationFrame(rafId);\n rafId = null;\n }\n rafFallbackActive = false;\n\n if (videoFrameRequestId && videoFrameSource) {\n try {\n if (typeof videoFrameSource.cancelVideoFrameCallback === \"function\") {\n videoFrameSource.cancelVideoFrameCallback(videoFrameRequestId);\n }\n } catch {\n // Failed to cancel video frame callback\n }\n }\n videoFrameRequestId = null;\n videoFrameSource = null;\n }\n\n return {\n get isRunning(): boolean {\n return isRunning;\n },\n\n get fps(): number {\n return fps;\n },\n\n get sendFps(): number {\n return sendFps;\n },\n\n start(videoElement?: HTMLVideoElement): void {\n if (isRunning) {\n cancelSchedulers();\n }\n\n isRunning = true;\n lastFrameAt = 0;\n\n if (\n videoElement &&\n typeof videoElement.requestVideoFrameCallback === \"function\"\n ) {\n scheduleWithVideoFrame(videoElement);\n } else {\n scheduleWithRaf(false);\n }\n },\n\n stop(): void {\n isRunning = false;\n cancelSchedulers();\n },\n\n setFps(newFps: number): void {\n fps = Math.max(1, newFps);\n },\n\n setSendFps(newSendFps: number): void {\n const next = Math.max(1, newSendFps);\n if (sendFps === next) return;\n sendFps = next;\n onSendFpsChange?.(sendFps);\n },\n };\n}\n","export interface AudioManagerOptions {\n autoUnlock: boolean;\n unlockEvents: string[];\n disableSilentAudio: boolean;\n}\n\nexport interface AudioManager {\n setOutputStream(stream: MediaStream): void;\n addTrack(track: MediaStreamTrack): void;\n removeTrack(trackId: string): void;\n unlock(): Promise<boolean>;\n destroy(): void;\n}\n\ndeclare global {\n interface Window {\n webkitAudioContext?: typeof AudioContext;\n }\n}\n\nexport function createAudioManager(options: AudioManagerOptions): AudioManager {\n let outputStream: MediaStream | null = null;\n\n // Audio context and silent track\n let audioCtx: AudioContext | null = null;\n let silentOsc: OscillatorNode | null = null;\n let silentGain: GainNode | null = null;\n let audioDst: MediaStreamAudioDestinationNode | null = null;\n let silentAudioTrack: MediaStreamTrack | null = null;\n\n // External tracks\n const externalAudioTrackIds = new Set<string>();\n const externalAudioEndHandlers = new Map<string, (ev: Event) => void>();\n\n // Auto unlock\n let audioUnlockHandler: ((ev: Event) => void) | null = null;\n let audioUnlockAttached = false;\n let audioStateListenerAttached = false;\n\n function ensureSilentAudioTrack(): void {\n if (options.disableSilentAudio) return;\n if (!outputStream) return;\n\n const alreadyHasAudio = outputStream.getAudioTracks().length > 0;\n if (alreadyHasAudio) return;\n\n if (silentAudioTrack && silentAudioTrack.readyState === \"live\") {\n try {\n outputStream.addTrack(silentAudioTrack);\n } catch {\n // Failed to add silent track\n }\n return;\n }\n\n if (!audioCtx) {\n const AudioContextClass = window.AudioContext || window.webkitAudioContext;\n if (!AudioContextClass) return;\n\n audioCtx = new AudioContextClass({\n sampleRate: 48000,\n });\n try {\n audioCtx.resume().catch(() => {\n // Failed to resume AudioContext\n });\n } catch {\n // Error calling resume\n }\n attachAudioCtxStateListener();\n }\n\n const ac = audioCtx;\n if (!ac) return;\n\n silentOsc = ac.createOscillator();\n silentGain = ac.createGain();\n audioDst = ac.createMediaStreamDestination();\n\n silentGain.gain.setValueAtTime(0.0001, ac.currentTime);\n silentOsc.frequency.setValueAtTime(440, ac.currentTime);\n silentOsc.type = \"sine\";\n silentOsc.connect(silentGain);\n silentGain.connect(audioDst);\n silentOsc.start();\n\n const track = audioDst.stream.getAudioTracks()[0];\n if (track) {\n silentAudioTrack = track;\n try {\n outputStream.addTrack(track);\n } catch {\n // Failed to add track to stream\n }\n }\n }\n\n function removeSilentAudioTrack(): void {\n try {\n if (outputStream && silentAudioTrack) {\n try {\n outputStream.removeTrack(silentAudioTrack);\n } catch {\n // Failed to remove silent track\n }\n }\n if (silentOsc) {\n try {\n silentOsc.stop();\n } catch {\n // Failed to stop oscillator\n }\n try {\n silentOsc.disconnect();\n } catch {\n // Failed to disconnect oscillator\n }\n }\n if (silentGain) {\n try {\n silentGain.disconnect();\n } catch {\n // Failed to disconnect gain\n }\n }\n silentOsc = null;\n silentGain = null;\n audioDst = null;\n silentAudioTrack = null;\n if (audioCtx) {\n try {\n audioCtx.close();\n } catch {\n // Failed to close AudioContext\n }\n }\n audioCtx = null;\n } catch {\n // Error in removeSilentAudioTrack\n }\n }\n\n function rebuildSilentAudioTrack(): void {\n if (options.disableSilentAudio) return;\n if (!outputStream) return;\n if (externalAudioTrackIds.size > 0) return;\n\n if (silentAudioTrack) {\n try {\n outputStream.removeTrack(silentAudioTrack);\n } catch {\n // Failed to remove silent track\n }\n }\n\n if (silentOsc) {\n try {\n silentOsc.stop();\n } catch {\n // Failed to stop oscillator\n }\n try {\n silentOsc.disconnect();\n } catch {\n // Failed to disconnect oscillator\n }\n }\n if (silentGain) {\n try {\n silentGain.disconnect();\n } catch {\n // Failed to disconnect gain\n }\n }\n silentOsc = null;\n silentGain = null;\n audioDst = null;\n silentAudioTrack = null;\n\n const ac = audioCtx;\n if (!ac || ac.state !== \"running\") return;\n\n attachAudioCtxStateListener();\n\n silentOsc = ac.createOscillator();\n silentGain = ac.createGain();\n audioDst = ac.createMediaStreamDestination();\n\n silentGain.gain.setValueAtTime(0.0001, ac.currentTime);\n silentOsc.frequency.setValueAtTime(440, ac.currentTime);\n silentOsc.type = \"sine\";\n silentOsc.connect(silentGain);\n silentGain.connect(audioDst);\n silentOsc.start();\n\n const track = audioDst.stream.getAudioTracks()[0];\n if (track) {\n silentAudioTrack = track;\n try {\n outputStream.addTrack(track);\n } catch {\n // Failed to add track to stream\n }\n }\n }\n\n function attachAudioCtxStateListener(): void {\n const ac = audioCtx;\n if (!ac || audioStateListenerAttached) return;\n\n const onStateChange = (): void => {\n try {\n if (audioCtx && audioCtx.state === \"running\") {\n rebuildSilentAudioTrack();\n cleanupAudioAutoUnlock();\n }\n } catch {\n // Error in state change handler\n }\n };\n\n try {\n (ac as AudioContext & { onstatechange: (() => void) | null }).onstatechange = onStateChange;\n audioStateListenerAttached = true;\n } catch {\n // Failed to attach state listener\n }\n }\n\n function setupAudioAutoUnlock(): void {\n if (!options.autoUnlock) return;\n if (typeof document === \"undefined\") return;\n if (audioUnlockAttached) return;\n\n const handler = (): void => {\n unlock();\n };\n\n audioUnlockHandler = handler;\n options.unlockEvents.forEach((evt) => {\n try {\n document.addEventListener(evt, handler, { capture: true });\n } catch {\n // Failed to add unlock listener\n }\n });\n audioUnlockAttached = true;\n }\n\n function cleanupAudioAutoUnlock(): void {\n if (!audioUnlockAttached) return;\n if (typeof document !== \"undefined\" && audioUnlockHandler) {\n options.unlockEvents.forEach((evt) => {\n try {\n document.removeEventListener(evt, audioUnlockHandler!, {\n capture: true,\n });\n } catch {\n // Failed to remove unlock listener\n }\n });\n }\n audioUnlockAttached = false;\n audioUnlockHandler = null;\n }\n\n async function unlock(): Promise<boolean> {\n try {\n if (typeof window === \"undefined\") return false;\n\n if (!audioCtx || audioCtx.state === \"closed\") {\n const AudioContextClass = window.AudioContext || window.webkitAudioContext;\n if (!AudioContextClass) return false;\n\n audioCtx = new AudioContextClass({\n sampleRate: 48000,\n });\n }\n\n const ac = audioCtx;\n if (!ac) return false;\n\n try {\n await ac.resume();\n } catch {\n // Failed to resume AudioContext\n }\n\n attachAudioCtxStateListener();\n\n if (ac.state === \"running\") {\n rebuildSilentAudioTrack();\n cleanupAudioAutoUnlock();\n return true;\n }\n\n return false;\n } catch {\n // Error in unlock\n return false;\n }\n }\n\n // Setup auto unlock on creation\n setupAudioAutoUnlock();\n\n return {\n setOutputStream(stream: MediaStream): void {\n outputStream = stream;\n ensureSilentAudioTrack();\n },\n\n addTrack(track: MediaStreamTrack): void {\n if (!outputStream) return;\n\n try {\n // Remove silent track when adding external audio\n if (silentAudioTrack) {\n try {\n outputStream.removeTrack(silentAudioTrack);\n } catch {\n // Failed to remove silent track\n }\n }\n\n const exists = outputStream\n .getAudioTracks()\n .some((t) => t.id === track.id);\n if (!exists) {\n outputStream.addTrack(track);\n }\n externalAudioTrackIds.add(track.id);\n\n // Setup ended handler\n const onEnded = (): void => {\n try {\n if (!outputStream) return;\n outputStream.getAudioTracks().forEach((t) => {\n if (t.id === track.id) {\n try {\n outputStream!.removeTrack(t);\n } catch {\n // Failed to remove ended track\n }\n }\n });\n externalAudioTrackIds.delete(track.id);\n externalAudioEndHandlers.delete(track.id);\n\n if (outputStream.getAudioTracks().length === 0) {\n ensureSilentAudioTrack();\n }\n } catch {\n // Error in track ended handler\n }\n try {\n track.removeEventListener(\"ended\", onEnded);\n } catch {\n // Failed to remove ended listener\n }\n };\n\n track.addEventListener(\"ended\", onEnded);\n externalAudioEndHandlers.set(track.id, onEnded);\n } catch {\n // Error in addTrack\n }\n },\n\n removeTrack(trackId: string): void {\n if (!outputStream) return;\n\n outputStream.getAudioTracks().forEach((t) => {\n if (t.id === trackId) {\n outputStream!.removeTrack(t);\n }\n });\n\n externalAudioTrackIds.delete(trackId);\n\n const handler = externalAudioEndHandlers.get(trackId);\n const tracks = outputStream.getAudioTracks();\n const tr = tracks.find((t) => t.id === trackId);\n if (tr && handler) {\n try {\n tr.removeEventListener(\"ended\", handler);\n } catch {\n // Failed to remove ended listener\n }\n }\n externalAudioEndHandlers.delete(trackId);\n\n if (outputStream.getAudioTracks().length === 0) {\n ensureSilentAudioTrack();\n }\n },\n\n unlock,\n\n destroy(): void {\n cleanupAudioAutoUnlock();\n\n try {\n if (audioCtx && (audioCtx as AudioContext & { onstatechange: (() => void) | null }).onstatechange) {\n (audioCtx as AudioContext & { onstatechange: (() => void) | null }).onstatechange = null;\n }\n } catch {\n // Failed to clear state change handler\n }\n audioStateListenerAttached = false;\n\n // Cleanup external track handlers\n externalAudioEndHandlers.forEach((handler, id) => {\n try {\n const tr = outputStream?.getAudioTracks().find((t) => t.id === id);\n if (tr) tr.removeEventListener(\"ended\", handler);\n } catch {\n // Failed to cleanup track handler\n }\n });\n externalAudioEndHandlers.clear();\n externalAudioTrackIds.clear();\n\n removeSilentAudioTrack();\n outputStream = null;\n },\n };\n}\n","export interface VisibilityHandlerOptions {\n onHidden: () => void;\n onVisible: () => void;\n backgroundRenderFn: () => void;\n}\n\nexport interface VisibilityHandler {\n start(): void;\n stop(): void;\n readonly isHidden: boolean;\n}\n\nexport function createVisibilityHandler(\n options: VisibilityHandlerOptions,\n): VisibilityHandler {\n let isHidden = false;\n let backgroundIntervalId: number | null = null;\n let visibilityListener: (() => void) | null = null;\n let started = false;\n\n function onVisibilityChange(): void {\n if (typeof document === \"undefined\") return;\n\n const hidden = document.visibilityState === \"hidden\";\n\n if (hidden && !isHidden) {\n isHidden = true;\n options.onHidden();\n\n // Start background interval rendering\n if (backgroundIntervalId == null) {\n backgroundIntervalId = setInterval(() => {\n options.backgroundRenderFn();\n }, 1000) as unknown as number;\n }\n } else if (!hidden && isHidden) {\n isHidden = false;\n\n // Stop background interval\n if (backgroundIntervalId != null) {\n clearInterval(backgroundIntervalId);\n backgroundIntervalId = null;\n }\n\n options.onVisible();\n }\n }\n\n return {\n get isHidden(): boolean {\n return isHidden;\n },\n\n start(): void {\n if (started) return;\n if (typeof document === \"undefined\") return;\n\n started = true;\n visibilityListener = onVisibilityChange;\n document.addEventListener(\"visibilitychange\", visibilityListener);\n\n // Check initial state\n onVisibilityChange();\n },\n\n stop(): void {\n if (!started) return;\n started = false;\n\n if (typeof document !== \"undefined\" && visibilityListener) {\n try {\n document.removeEventListener(\"visibilitychange\", visibilityListener);\n } catch {\n // Failed to remove visibility listener\n }\n visibilityListener = null;\n }\n\n if (backgroundIntervalId != null) {\n clearInterval(backgroundIntervalId);\n backgroundIntervalId = null;\n }\n\n isHidden = false;\n },\n };\n}\n","import { createRegistry } from \"./internal/compositor/Registry\";\nimport { createRenderer, type Renderer } from \"./internal/compositor/Renderer\";\nimport { createScheduler, type Scheduler } from \"./internal/compositor/Scheduler\";\nimport { createAudioManager, type AudioManager } from \"./internal/compositor/AudioManager\";\nimport { createVisibilityHandler, type VisibilityHandler } from \"./internal/compositor/VisibilityHandler\";\nimport type {\n Compositor as ICompositor,\n CompositorEvent,\n CompositorEventMap,\n CompositorOptions,\n Size,\n Source,\n} from \"./types\";\nimport type { SourceRegistry } from \"./internal/compositor/Registry\";\n\nclass CompositorEventEmitter {\n private listeners = new Map<CompositorEvent, Set<CompositorEventMap[CompositorEvent]>>();\n\n on<E extends CompositorEvent>(event: E, handler: CompositorEventMap[E]): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(handler as CompositorEventMap[CompositorEvent]);\n return () => this.off(event, handler);\n }\n\n off<E extends CompositorEvent>(event: E, handler: CompositorEventMap[E]): void {\n this.listeners.get(event)?.delete(handler as CompositorEventMap[CompositorEvent]);\n }\n\n protected emit<E extends CompositorEvent>(\n event: E,\n ...args: Parameters<CompositorEventMap[E]>\n ): void {\n this.listeners.get(event)?.forEach((handler) => {\n (handler as (...args: Parameters<CompositorEventMap[E]>) => void)(...args);\n });\n }\n\n protected clearListeners(): void {\n this.listeners.clear();\n }\n}\n\nexport class Compositor extends CompositorEventEmitter implements ICompositor {\n private readonly registry: SourceRegistry;\n private readonly renderer: Renderer;\n private readonly scheduler: Scheduler;\n private readonly audioManager: AudioManager;\n private readonly visibilityHandler: VisibilityHandler;\n\n private _activeId: string | null = null;\n private _fps: number;\n private _sendFps: number;\n private lastVisibleSendFps: number | null = null;\n private outputStream: MediaStream | null = null;\n private destroyed = false;\n\n constructor(options: CompositorOptions = {}) {\n super();\n\n const width = options.width ?? 512;\n const height = options.height ?? 512;\n this._fps = Math.max(1, options.fps ?? 30);\n this._sendFps = Math.max(1, options.sendFps ?? this._fps);\n const dpr = Math.min(\n 2,\n options.dpr ??\n (typeof window !== \"undefined\" ? window.devicePixelRatio || 1 : 1),\n );\n const keepalive = options.keepalive ?? true;\n\n // Create subsystems\n this.registry = createRegistry({\n onRegister: (id, source) => this.emit(\"registered\", id, source),\n onUnregister: (id) => this.emit(\"unregistered\", id),\n });\n\n this.renderer = createRenderer({\n width,\n height,\n dpr,\n keepalive,\n });\n\n this.scheduler = createScheduler({\n fps: this._fps,\n sendFps: this._sendFps,\n onFrame: (timestamp) => this.renderer.renderFrame(timestamp),\n onSendFpsChange: (fps) => {\n this._sendFps = fps;\n options.onSendFpsChange?.(fps);\n this.applyVideoTrackConstraints();\n },\n });\n\n this.audioManager = createAudioManager({\n autoUnlock: options.autoUnlockAudio ?? true,\n unlockEvents:\n options.unlockEvents && options.unlockEvents.length > 0\n ? options.unlockEvents\n : [\"pointerdown\", \"click\", \"touchstart\", \"keydown\"],\n disableSilentAudio: options.disableSilentAudio ?? false,\n });\n\n this.visibilityHandler = createVisibilityHandler({\n onHidden: () => {\n if (this.lastVisibleSendFps == null) this.lastVisibleSendFps = this._sendFps;\n if (this._sendFps !== 5) {\n this.scheduler.setSendFps(5);\n this._sendFps = 5;\n }\n },\n onVisible: () => {\n if (this.lastVisibleSendFps != null && this._sendFps !== this.lastVisibleSendFps) {\n this.scheduler.setSendFps(this.lastVisibleSendFps);\n this._sendFps = this.lastVisibleSendFps;\n }\n this.lastVisibleSendFps = null;\n },\n backgroundRenderFn: () => {\n this.renderer.renderFrame(performance.now());\n this.requestVideoTrackFrame();\n },\n });\n\n // Initialize\n this.outputStream = this.createOutputStream();\n this.audioManager.setOutputStream(this.outputStream);\n this.visibilityHandler.start();\n }\n\n // ============================================================================\n // Source Registry\n // ============================================================================\n\n register(id: string, source: Source): void {\n if (this.destroyed) return;\n this.registry.register(id, source);\n }\n\n unregister(id: string): void {\n if (this.destroyed) return;\n const wasActive = this._activeId === id;\n this.registry.unregister(id);\n\n if (wasActive) {\n this._activeId = null;\n this.renderer.setActiveSource(null);\n this.scheduler.stop();\n this.emit(\"activated\", null, undefined);\n }\n }\n\n get(id: string): Source | undefined {\n return this.registry.get(id);\n }\n\n has(id: string): boolean {\n return this.registry.has(id);\n }\n\n list(): Array<{ id: string; source: Source }> {\n return this.registry.list();\n }\n\n // ============================================================================\n // Active Source Management\n // ============================================================================\n\n activate(id: string): void {\n if (this.destroyed) return;\n\n const source = this.registry.get(id);\n if (!source) {\n throw new Error(`Source \"${id}\" not registered`);\n }\n\n this._activeId = id;\n this.renderer.setActiveSource(source);\n\n // Start scheduler with video element if applicable\n const videoEl = source.kind === \"video\" ? source.element : undefined;\n this.scheduler.start(videoEl);\n\n this.emit(\"activated\", id, source);\n }\n\n deactivate(): void {\n if (this.destroyed) return;\n\n this._activeId = null;\n this.renderer.setActiveSource(null);\n this.scheduler.stop();\n this.emit(\"activated\", null, undefined);\n }\n\n get activeId(): string | null {\n return this._activeId;\n }\n\n // ============================================================================\n // Output Stream\n // ============================================================================\n\n get stream(): MediaStream {\n return this.outputStream!;\n }\n\n // ============================================================================\n // Settings\n // ============================================================================\n\n resize(width: number, height: number, dpr?: number): void {\n if (this.destroyed) return;\n\n const effectiveDpr = Math.min(\n 2,\n dpr ??\n (typeof window !== \"undefined\" ? window.devicePixelRatio || 1 : 1),\n );\n\n this.renderer.resize(width, height, effectiveDpr);\n this.recreateStream();\n }\n\n get size(): Size {\n return this.renderer.size;\n }\n\n setFps(fps: number): void {\n if (this.destroyed) return;\n\n const next = Math.max(1, fps);\n if (this._fps === next) return;\n\n this._fps = next;\n this.scheduler.setFps(next);\n this.recreateStream();\n }\n\n get fps(): number {\n return this._fps;\n }\n\n setSendFps(fps: number): void {\n if (this.destroyed) return;\n\n const next = Math.max(1, fps);\n if (this._sendFps === next) return;\n\n this._sendFps = next;\n this.scheduler.setSendFps(next);\n }\n\n get sendFps(): number {\n return this._sendFps;\n }\n\n // ============================================================================\n // Audio\n // ============================================================================\n\n addAudioTrack(track: MediaStreamTrack): void {\n if (this.destroyed) return;\n this.audioManager.addTrack(track);\n }\n\n removeAudioTrack(trackId: string): void {\n if (this.destroyed) return;\n this.audioManager.removeTrack(trackId);\n }\n\n unlockAudio(): Promise<boolean> {\n if (this.destroyed) return Promise.resolve(false);\n return this.audioManager.unlock();\n }\n\n // ============================================================================\n // Lifecycle\n // ============================================================================\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n\n this.scheduler.stop();\n this.visibilityHandler.stop();\n this.audioManager.destroy();\n this.renderer.destroy();\n this.registry.clear();\n\n // Stop video tracks\n if (this.outputStream) {\n try {\n this.outputStream.getVideoTracks().forEach((t) => {\n try {\n t.stop();\n } catch {\n // Failed to stop video track\n }\n });\n } catch {\n // Failed to get video tracks\n }\n }\n\n this.outputStream = null;\n this.clearListeners();\n }\n\n // ============================================================================\n // Private Helpers\n // ============================================================================\n\n private createOutputStream(): MediaStream {\n const stream = this.renderer.captureCanvas.captureStream(this._fps);\n\n // Set video track content hint\n try {\n const vtrack = stream.getVideoTracks()[0];\n if (vtrack && vtrack.contentHint !== undefined) {\n vtrack.contentHint = \"detail\";\n }\n } catch {\n // Failed to set video track content hint\n }\n\n return stream;\n }\n\n private recreateStream(): void {\n const newStream = this.createOutputStream();\n const prev = this.outputStream;\n\n // Transfer audio tracks\n if (prev && prev !== newStream) {\n try {\n prev.getAudioTracks().forEach((t) => {\n try {\n newStream.addTrack(t);\n } catch {\n // Failed to transfer audio track\n }\n });\n } catch {\n // Failed to get audio tracks\n }\n }\n\n this.outputStream = newStream;\n this.audioManager.setOutputStream(newStream);\n this.applyVideoTrackConstraints();\n\n // Stop old video tracks\n if (prev && prev !== newStream) {\n try {\n prev.getVideoTracks().forEach((t) => {\n try {\n t.stop();\n } catch {\n // Failed to stop video track\n }\n });\n } catch {\n // Failed to get video tracks\n }\n }\n }\n\n private applyVideoTrackConstraints(): void {\n try {\n const track = this.outputStream?.getVideoTracks()[0];\n const canvas = this.renderer.captureCanvas;\n if (!track || !canvas) return;\n\n const constraints: MediaTrackConstraints = {\n width: canvas.width,\n height: canvas.height,\n frameRate: Math.max(1, this._sendFps || this._fps),\n };\n\n try {\n if ((track as MediaStreamTrack & { contentHint?: string }).contentHint !== undefined) {\n (track as MediaStreamTrack & { contentHint?: string }).contentHint = \"detail\";\n }\n } catch {\n // Failed to set content hint\n }\n\n track.applyConstraints(constraints).catch(() => {\n // Failed to apply constraints\n });\n } catch {\n // Error in applyVideoTrackConstraints\n }\n }\n\n private requestVideoTrackFrame(): void {\n const track = this.outputStream?.getVideoTracks()[0];\n if (track && typeof (track as MediaStreamTrack & { requestFrame?: () => void }).requestFrame === \"function\") {\n try {\n (track as MediaStreamTrack & { requestFrame: () => void }).requestFrame();\n } catch {\n // Failed to request video frame\n }\n }\n }\n}\n\nexport function createCompositor(options: CompositorOptions = {}): Compositor {\n return new Compositor(options);\n}\n"],"mappings":"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","names":["createBroadcast","createPlayer","DEFAULT_CONNECTION_TIMEOUT","createBroadcast","createPlayer"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types/common.ts","../src/errors.ts","../src/internal/dependencies.ts","../src/internal/WHIPClient.ts","../src/internal/TypedEventEmitter.ts","../src/internal/StateMachine.ts","../src/Broadcast.ts","../src/internal/WHEPClient.ts","../src/Player.ts","../src/internal/compositor/Registry.ts","../src/internal/compositor/Renderer.ts","../src/internal/compositor/Scheduler.ts","../src/internal/compositor/AudioManager.ts","../src/internal/compositor/VisibilityHandler.ts","../src/Compositor.ts"],"sourcesContent":["import type { BroadcastOptions, WHIPResponseResult } from \"./types/broadcast\";\nimport type { PlayerOptions } from \"./types/player\";\nimport { Broadcast, createBroadcast as baseCreateBroadcast } from \"./Broadcast\";\nimport { Player, createPlayer as baseCreatePlayer } from \"./Player\";\n\n/**\n * Response handler for Livepeer WHIP endpoints.\n * Extracts the playback URL from the `livepeer-playback-url` header.\n *\n * @param response - The WHIP response\n * @returns Object containing the WHEP playback URL\n */\nexport const livepeerResponseHandler = (\n response: Response,\n): WHIPResponseResult => ({\n whepUrl: response.headers.get(\"livepeer-playback-url\") ?? undefined,\n});\n\n/**\n * Broadcast options for Livepeer, with the response handler pre-configured.\n */\nexport type LivepeerBroadcastOptions = Omit<BroadcastOptions, \"onResponse\">;\n\n/**\n * Creates a Broadcast instance configured for Livepeer.\n * Automatically extracts the playback URL from the response.\n *\n * @param options - Broadcast options (without onResponse)\n * @returns A new Broadcast instance\n *\n * @example\n * ```ts\n * const broadcast = createBroadcast({\n * whipUrl: \"https://livepeer.studio/webrtc/...\",\n * stream: mediaStream,\n * });\n *\n * await broadcast.connect();\n * console.log(\"Playback URL:\", broadcast.whepUrl);\n * ```\n */\nexport function createBroadcast(options: LivepeerBroadcastOptions): Broadcast {\n return baseCreateBroadcast({\n ...options,\n onResponse: livepeerResponseHandler,\n });\n}\n\n/**\n * Creates a Player instance for receiving a WebRTC stream.\n *\n * @param whepUrl - WHEP endpoint URL\n * @param options - Optional player configuration\n * @returns A new Player instance\n *\n * @example\n * ```ts\n * const player = createPlayer(\"https://livepeer.studio/webrtc/...\");\n *\n * await player.connect();\n * player.attachTo(videoElement);\n * ```\n */\nexport function createPlayer(whepUrl: string, options?: PlayerOptions): Player {\n return baseCreatePlayer(whepUrl, options);\n}\n\nexport {\n BaseDaydreamError,\n NetworkError,\n ConnectionError,\n StreamNotFoundError,\n UnauthorizedError,\n} from \"./errors\";\n\nexport type {\n AudioConfig,\n DaydreamError,\n DaydreamErrorCode,\n ReconnectConfig,\n ReconnectInfo,\n VideoConfig,\n BroadcastEventMap,\n BroadcastOptions,\n BroadcastState,\n WHIPResponseResult,\n PlayerEventMap,\n PlayerOptions,\n PlayerState,\n CanvasSource,\n Compositor,\n CompositorEvent,\n CompositorEventMap,\n CompositorOptions,\n ContentHint,\n Ctx2D,\n FitMode,\n Size,\n Source,\n VideoSource,\n} from \"./types\";\n\nexport {\n DEFAULT_AUDIO_BITRATE,\n DEFAULT_ICE_SERVERS,\n DEFAULT_VIDEO_BITRATE,\n} from \"./types\";\n\nexport { Broadcast, type BroadcastConfig } from \"./Broadcast\";\nexport { Player, type PlayerConfig } from \"./Player\";\nexport { createCompositor } from \"./Compositor\";\n","/**\n * Configuration for automatic reconnection behavior.\n */\nexport interface ReconnectConfig {\n /** Whether automatic reconnection is enabled. Defaults to `true`. */\n enabled?: boolean;\n /** Maximum number of reconnection attempts before giving up. */\n maxAttempts?: number;\n /** Base delay in milliseconds between reconnection attempts. Used for exponential backoff. */\n baseDelayMs?: number;\n}\n\n/**\n * Information about the current reconnection attempt.\n * Emitted with the `reconnect` event.\n */\nexport interface ReconnectInfo {\n /** Current attempt number (1-indexed). */\n attempt: number;\n /** Maximum number of attempts before giving up. */\n maxAttempts: number;\n /** Delay in milliseconds before this reconnection attempt. */\n delayMs: number;\n}\n\n/**\n * Video encoding configuration.\n */\nexport interface VideoConfig {\n /** Target video bitrate in bits per second. Defaults to 300,000 (300 kbps). */\n bitrate?: number;\n /** Maximum frame rate for the video track. */\n maxFramerate?: number;\n}\n\n/**\n * Audio encoding configuration.\n */\nexport interface AudioConfig {\n /** Target audio bitrate in bits per second. Defaults to 64,000 (64 kbps). */\n bitrate?: number;\n}\n\n/**\n * Error interface for all Daydream SDK errors.\n * Extends the standard Error with a code and optional cause.\n */\nexport interface DaydreamError extends Error {\n /** Error code identifying the type of error. */\n code: DaydreamErrorCode;\n /** The underlying cause of the error, if any. */\n cause?: unknown;\n}\n\n/**\n * Error codes for Daydream SDK errors.\n * - `NETWORK_ERROR`: Network-related failure (e.g., fetch failed)\n * - `CONNECTION_FAILED`: WebRTC connection failed to establish\n * - `STREAM_NOT_FOUND`: The requested stream does not exist\n * - `UNAUTHORIZED`: Authentication or authorization failed\n * - `UNKNOWN`: An unexpected error occurred\n */\nexport type DaydreamErrorCode =\n | \"NETWORK_ERROR\"\n | \"CONNECTION_FAILED\"\n | \"STREAM_NOT_FOUND\"\n | \"UNAUTHORIZED\"\n | \"UNKNOWN\";\n\n/**\n * Default ICE servers used for WebRTC connections.\n * Includes Google and Cloudflare STUN servers.\n */\nexport const DEFAULT_ICE_SERVERS: RTCIceServer[] = [\n { urls: \"stun:stun.l.google.com:19302\" },\n { urls: \"stun:stun1.l.google.com:19302\" },\n { urls: \"stun:stun.cloudflare.com:3478\" },\n];\n\n/** Default video bitrate in bits per second (300 kbps). */\nexport const DEFAULT_VIDEO_BITRATE = 300_000;\n\n/** Default audio bitrate in bits per second (64 kbps). */\nexport const DEFAULT_AUDIO_BITRATE = 64_000;\n","import type { DaydreamError, DaydreamErrorCode } from \"./types/common\";\n\n/**\n * Base class for all Daydream SDK errors.\n * Extends the standard Error with a code and optional cause for error chaining.\n *\n * @example\n * ```ts\n * try {\n * await broadcast.connect();\n * } catch (err) {\n * if (err instanceof BaseDaydreamError) {\n * console.log(\"Error code:\", err.code);\n * console.log(\"Cause:\", err.cause);\n * }\n * }\n * ```\n */\nexport class BaseDaydreamError extends Error implements DaydreamError {\n /** Error code identifying the type of error. */\n readonly code: DaydreamErrorCode;\n /** The underlying cause of the error, if any. */\n readonly cause?: unknown;\n\n /**\n * Creates a new DaydreamError.\n * @param code - Error code\n * @param message - Human-readable error message\n * @param cause - Optional underlying cause\n */\n constructor(code: DaydreamErrorCode, message: string, cause?: unknown) {\n super(message);\n this.name = \"DaydreamError\";\n this.code = code;\n this.cause = cause;\n }\n}\n\n/**\n * Error thrown when a network request fails (e.g., fetch failed, timeout).\n */\nexport class NetworkError extends BaseDaydreamError {\n constructor(message: string, cause?: unknown) {\n super(\"NETWORK_ERROR\", message, cause);\n this.name = \"NetworkError\";\n }\n}\n\n/**\n * Error thrown when a WebRTC connection fails to establish.\n */\nexport class ConnectionError extends BaseDaydreamError {\n constructor(message: string, cause?: unknown) {\n super(\"CONNECTION_FAILED\", message, cause);\n this.name = \"ConnectionError\";\n }\n}\n\n/**\n * Error thrown when the requested stream does not exist (404).\n */\nexport class StreamNotFoundError extends BaseDaydreamError {\n constructor(message: string, cause?: unknown) {\n super(\"STREAM_NOT_FOUND\", message, cause);\n this.name = \"StreamNotFoundError\";\n }\n}\n\n/**\n * Error thrown when authentication or authorization fails (401/403).\n */\nexport class UnauthorizedError extends BaseDaydreamError {\n constructor(message: string, cause?: unknown) {\n super(\"UNAUTHORIZED\", message, cause);\n this.name = \"UnauthorizedError\";\n }\n}\n","export interface PeerConnectionFactory {\n create(config: RTCConfiguration): RTCPeerConnection;\n}\n\nexport interface FetchFn {\n (input: RequestInfo | URL, init?: RequestInit): Promise<Response>;\n}\n\nexport interface TimerProvider {\n setTimeout(callback: () => void, ms: number): number;\n clearTimeout(id: number): void;\n setInterval(callback: () => void, ms: number): number;\n clearInterval(id: number): void;\n}\n\nexport interface MediaStreamFactory {\n create(): MediaStream;\n}\n\nexport const defaultMediaStreamFactory: MediaStreamFactory = {\n create: () => new MediaStream(),\n};\n\nexport const defaultPeerConnectionFactory: PeerConnectionFactory = {\n create: (config) => new RTCPeerConnection(config),\n};\n\nexport const defaultFetch: FetchFn = globalThis.fetch.bind(globalThis);\n\nexport const defaultTimerProvider: TimerProvider = {\n setTimeout: (cb, ms) => globalThis.setTimeout(cb, ms) as unknown as number,\n clearTimeout: (id) => globalThis.clearTimeout(id),\n setInterval: (cb, ms) => globalThis.setInterval(cb, ms) as unknown as number,\n clearInterval: (id) => globalThis.clearInterval(id),\n};\n\n","import {\n DEFAULT_AUDIO_BITRATE,\n DEFAULT_ICE_SERVERS,\n DEFAULT_VIDEO_BITRATE,\n} from \"../types/common\";\nimport type { WHIPResponseResult } from \"../types/broadcast\";\nimport { ConnectionError, NetworkError } from \"../errors\";\nimport {\n type PeerConnectionFactory,\n type FetchFn,\n type TimerProvider,\n defaultPeerConnectionFactory,\n defaultFetch,\n defaultTimerProvider,\n} from \"./dependencies\";\n\nconst PLAYBACK_ID_PATTERN = /([/+])([^/+?]+)$/;\nconst PLAYBACK_ID_PLACEHOLDER = \"__PLAYBACK_ID__\";\n\nexport interface RedirectCache {\n get(key: string): URL | undefined;\n set(key: string, value: URL): void;\n}\n\nclass LRURedirectCache implements RedirectCache {\n private cache = new Map<string, URL>();\n private readonly maxSize: number;\n\n constructor(maxSize = 10) {\n this.maxSize = maxSize;\n }\n\n get(key: string): URL | undefined {\n const cached = this.cache.get(key);\n if (cached) {\n this.cache.delete(key);\n this.cache.set(key, cached);\n }\n return cached;\n }\n\n set(key: string, value: URL): void {\n if (this.cache.has(key)) {\n this.cache.delete(key);\n } else if (this.cache.size >= this.maxSize) {\n const oldestKey = this.cache.keys().next().value;\n if (oldestKey) this.cache.delete(oldestKey);\n }\n this.cache.set(key, value);\n }\n}\n\nexport interface WHIPClientConfig {\n url: string;\n iceServers?: RTCIceServer[];\n videoBitrate?: number;\n audioBitrate?: number;\n maxFramerate?: number;\n connectionTimeout?: number;\n skipIceGathering?: boolean;\n onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n onResponse?: (response: Response) => WHIPResponseResult | void;\n peerConnectionFactory?: PeerConnectionFactory;\n fetch?: FetchFn;\n timers?: TimerProvider;\n redirectCache?: RedirectCache;\n}\n\nfunction preferH264(sdp: string): string {\n const lines = sdp.split(\"\\r\\n\");\n const mLineIndex = lines.findIndex((line) => line.startsWith(\"m=video\"));\n if (mLineIndex === -1) return sdp;\n\n const codecRegex = /a=rtpmap:(\\d+) H264(\\/\\d+)+/;\n const codecLine = lines.find((line) => codecRegex.test(line));\n if (!codecLine) return sdp;\n\n const match = codecRegex.exec(codecLine);\n const codecPayload = match?.[1];\n if (!codecPayload) return sdp;\n\n const mLine = lines[mLineIndex];\n if (!mLine) return sdp;\n\n const mLineElements = mLine.split(\" \");\n const reorderedMLine = [\n ...mLineElements.slice(0, 3),\n codecPayload,\n ...mLineElements.slice(3).filter((payload) => payload !== codecPayload),\n ];\n lines[mLineIndex] = reorderedMLine.join(\" \");\n return lines.join(\"\\r\\n\");\n}\n\nconst sharedRedirectCache = new LRURedirectCache();\n\nconst DEFAULT_CONNECTION_TIMEOUT = 10000;\n\nexport class WHIPClient {\n private readonly url: string;\n private readonly iceServers: RTCIceServer[];\n private readonly videoBitrate: number;\n private readonly audioBitrate: number;\n private readonly connectionTimeout: number;\n private readonly onStats?: (report: RTCStatsReport) => void;\n private readonly statsIntervalMs: number;\n private readonly onResponse?: (\n response: Response,\n ) => WHIPResponseResult | void;\n private readonly pcFactory: PeerConnectionFactory;\n private readonly fetch: FetchFn;\n private readonly timers: TimerProvider;\n private readonly redirectCache: RedirectCache;\n private readonly skipIceGathering: boolean;\n\n private maxFramerate?: number;\n private pc: RTCPeerConnection | null = null;\n private resourceUrl: string | null = null;\n private abortController: AbortController | null = null;\n private statsTimer: number | null = null;\n private videoSender: RTCRtpSender | null = null;\n private audioSender: RTCRtpSender | null = null;\n private videoTransceiver: RTCRtpTransceiver | null = null;\n private audioTransceiver: RTCRtpTransceiver | null = null;\n private iceGatheringTimer: number | null = null;\n\n constructor(config: WHIPClientConfig) {\n this.url = config.url;\n this.iceServers = config.iceServers ?? DEFAULT_ICE_SERVERS;\n this.videoBitrate = config.videoBitrate ?? DEFAULT_VIDEO_BITRATE;\n this.audioBitrate = config.audioBitrate ?? DEFAULT_AUDIO_BITRATE;\n this.connectionTimeout =\n config.connectionTimeout ?? DEFAULT_CONNECTION_TIMEOUT;\n this.maxFramerate = config.maxFramerate;\n this.onStats = config.onStats;\n this.statsIntervalMs = config.statsIntervalMs ?? 5000;\n this.onResponse = config.onResponse;\n this.pcFactory =\n config.peerConnectionFactory ?? defaultPeerConnectionFactory;\n this.fetch = config.fetch ?? defaultFetch;\n this.timers = config.timers ?? defaultTimerProvider;\n this.redirectCache = config.redirectCache ?? sharedRedirectCache;\n this.skipIceGathering = config.skipIceGathering ?? true;\n }\n\n async connect(stream: MediaStream): Promise<{ whepUrl: string | null }> {\n this.cleanup();\n\n this.pc = this.pcFactory.create({\n iceServers: this.iceServers,\n iceCandidatePoolSize: 10,\n });\n\n this.videoTransceiver = this.pc.addTransceiver(\"video\", {\n direction: \"sendonly\",\n });\n this.audioTransceiver = this.pc.addTransceiver(\"audio\", {\n direction: \"sendonly\",\n });\n this.videoSender = this.videoTransceiver.sender;\n this.audioSender = this.audioTransceiver.sender;\n\n const videoTrack = stream.getVideoTracks()[0];\n const audioTrack = stream.getAudioTracks()[0];\n\n if (videoTrack) {\n if (videoTrack.contentHint === \"\") {\n videoTrack.contentHint = \"motion\";\n }\n await this.videoSender.replaceTrack(videoTrack);\n }\n\n if (audioTrack) {\n await this.audioSender.replaceTrack(audioTrack);\n }\n\n this.setCodecPreferences();\n\n const offer = await this.pc.createOffer({\n offerToReceiveAudio: false,\n offerToReceiveVideo: false,\n });\n const enhancedSdp = preferH264(offer.sdp ?? \"\");\n await this.pc.setLocalDescription({ type: \"offer\", sdp: enhancedSdp });\n\n if (!this.skipIceGathering) {\n await this.waitForIceGathering();\n }\n\n this.abortController = new AbortController();\n const timeoutId = this.timers.setTimeout(\n () => this.abortController?.abort(),\n this.connectionTimeout,\n );\n\n try {\n const fetchUrl = this.getUrlWithCachedRedirect();\n\n const response = await this.fetch(fetchUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/sdp\" },\n body: this.pc.localDescription!.sdp,\n signal: this.abortController.signal,\n });\n\n this.timers.clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"\");\n throw new ConnectionError(\n `WHIP connection failed: ${response.status} ${response.statusText} ${errorText}`,\n );\n }\n\n this.cacheRedirectIfNeeded(fetchUrl, response.url);\n\n const location = response.headers.get(\"location\");\n if (location) {\n this.resourceUrl = new URL(location, this.url).toString();\n }\n\n const responseResult = this.onResponse?.(response);\n\n const answerSdp = await response.text();\n await this.pc.setRemoteDescription({ type: \"answer\", sdp: answerSdp });\n\n await this.applyBitrateConstraints();\n this.startStatsTimer();\n\n return { whepUrl: responseResult?.whepUrl ?? null };\n } catch (error) {\n this.timers.clearTimeout(timeoutId);\n if (error instanceof ConnectionError) {\n throw error;\n }\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new NetworkError(\"Connection timeout\");\n }\n throw new NetworkError(\"Failed to establish connection\", error);\n }\n }\n\n private setCodecPreferences(): void {\n if (!this.videoTransceiver?.setCodecPreferences) return;\n\n try {\n const caps = RTCRtpSender.getCapabilities(\"video\");\n if (!caps?.codecs?.length) return;\n\n const h264Codecs = caps.codecs.filter((c) =>\n c.mimeType.toLowerCase().includes(\"h264\"),\n );\n if (h264Codecs.length) {\n this.videoTransceiver.setCodecPreferences(h264Codecs);\n }\n } catch {\n // Codec preferences not supported\n }\n }\n\n private async applyBitrateConstraints(): Promise<void> {\n if (!this.pc) return;\n\n const senders = this.pc.getSenders();\n for (const sender of senders) {\n if (!sender.track) continue;\n\n const params = sender.getParameters();\n if (!params.encodings) params.encodings = [{}];\n\n const encoding = params.encodings[0];\n if (!encoding) continue;\n\n if (sender.track.kind === \"video\") {\n encoding.maxBitrate = this.videoBitrate;\n if (this.maxFramerate && this.maxFramerate > 0) {\n encoding.maxFramerate = this.maxFramerate;\n }\n encoding.scaleResolutionDownBy = 1.0;\n encoding.priority = \"high\";\n encoding.networkPriority = \"high\";\n params.degradationPreference = \"maintain-resolution\";\n } else if (sender.track.kind === \"audio\") {\n encoding.maxBitrate = this.audioBitrate;\n encoding.priority = \"medium\";\n encoding.networkPriority = \"medium\";\n }\n\n try {\n await sender.setParameters(params);\n } catch {\n // Parameters not supported\n }\n }\n }\n\n private waitForIceGathering(): Promise<void> {\n return new Promise((resolve) => {\n if (!this.pc) {\n resolve();\n return;\n }\n\n if (this.pc.iceGatheringState === \"complete\") {\n resolve();\n return;\n }\n\n const onStateChange = () => {\n if (this.pc?.iceGatheringState === \"complete\") {\n this.pc.removeEventListener(\"icegatheringstatechange\", onStateChange);\n if (this.iceGatheringTimer !== null) {\n this.timers.clearTimeout(this.iceGatheringTimer);\n this.iceGatheringTimer = null;\n }\n resolve();\n }\n };\n\n this.pc.addEventListener(\"icegatheringstatechange\", onStateChange);\n\n this.iceGatheringTimer = this.timers.setTimeout(() => {\n this.pc?.removeEventListener(\"icegatheringstatechange\", onStateChange);\n this.iceGatheringTimer = null;\n resolve();\n }, 1000);\n });\n }\n\n private startStatsTimer(): void {\n if (!this.onStats || !this.pc) return;\n\n this.stopStatsTimer();\n\n this.statsTimer = this.timers.setInterval(async () => {\n if (!this.pc) return;\n try {\n const report = await this.pc.getStats();\n this.onStats?.(report);\n } catch {\n // Stats collection failed\n }\n }, this.statsIntervalMs);\n }\n\n private stopStatsTimer(): void {\n if (this.statsTimer !== null) {\n this.timers.clearInterval(this.statsTimer);\n this.statsTimer = null;\n }\n }\n\n async replaceTrack(track: MediaStreamTrack): Promise<void> {\n if (!this.pc) {\n throw new ConnectionError(\"Not connected\");\n }\n\n const sender = track.kind === \"video\" ? this.videoSender : this.audioSender;\n if (!sender) {\n throw new ConnectionError(\n `No sender found for track kind: ${track.kind}`,\n );\n }\n\n await sender.replaceTrack(track);\n await this.applyBitrateConstraints();\n }\n\n setMaxFramerate(fps?: number): void {\n this.maxFramerate = fps;\n void this.applyBitrateConstraints();\n }\n\n private cleanup(): void {\n this.stopStatsTimer();\n\n if (this.iceGatheringTimer !== null) {\n this.timers.clearTimeout(this.iceGatheringTimer);\n this.iceGatheringTimer = null;\n }\n\n if (this.abortController) {\n try {\n this.abortController.abort();\n } catch {\n // Ignore abort errors\n }\n this.abortController = null;\n }\n\n if (this.pc) {\n // Clear event handlers\n this.pc.oniceconnectionstatechange = null;\n this.pc.onconnectionstatechange = null;\n this.pc.ontrack = null;\n\n try {\n this.pc.getTransceivers().forEach((t) => {\n try {\n t.stop();\n } catch {\n // Ignore stop errors\n }\n });\n } catch {\n // Ignore transceiver errors\n }\n\n try {\n this.pc.close();\n } catch {\n // Ignore close errors\n }\n this.pc = null;\n }\n\n this.videoSender = null;\n this.audioSender = null;\n this.videoTransceiver = null;\n this.audioTransceiver = null;\n }\n\n async disconnect(): Promise<void> {\n if (this.resourceUrl) {\n try {\n await this.fetch(this.resourceUrl, { method: \"DELETE\" });\n } catch {\n // Ignore delete errors\n }\n }\n\n this.cleanup();\n this.resourceUrl = null;\n }\n\n getPeerConnection(): RTCPeerConnection | null {\n return this.pc;\n }\n\n restartIce(): void {\n if (this.pc) {\n try {\n this.pc.restartIce();\n } catch {\n // ICE restart not supported\n }\n }\n }\n\n isConnected(): boolean {\n if (!this.pc) return false;\n const iceState = this.pc.iceConnectionState;\n return iceState === \"connected\" || iceState === \"completed\";\n }\n\n private getUrlWithCachedRedirect(): string {\n const originalUrl = new URL(this.url);\n const playbackIdMatch = originalUrl.pathname.match(PLAYBACK_ID_PATTERN);\n const playbackId = playbackIdMatch?.[2];\n\n const cachedTemplate = this.redirectCache.get(this.url);\n if (!cachedTemplate || !playbackId) {\n return this.url;\n }\n\n const redirectedUrl = new URL(cachedTemplate);\n redirectedUrl.pathname = cachedTemplate.pathname.replace(\n PLAYBACK_ID_PLACEHOLDER,\n playbackId,\n );\n return redirectedUrl.toString();\n }\n\n private cacheRedirectIfNeeded(requestUrl: string, responseUrl: string): void {\n if (requestUrl === responseUrl) return;\n\n try {\n const actualRedirect = new URL(responseUrl);\n const template = new URL(actualRedirect);\n template.pathname = template.pathname.replace(\n PLAYBACK_ID_PATTERN,\n `$1${PLAYBACK_ID_PLACEHOLDER}`,\n );\n this.redirectCache.set(this.url, template);\n } catch {\n // Invalid URL, skip caching\n }\n }\n}\n","export class TypedEventEmitter<EventMap extends { [K in keyof EventMap]: (...args: any[]) => void }> {\n private listeners = new Map<keyof EventMap, Set<(...args: any[]) => void>>();\n\n on<E extends keyof EventMap>(event: E, handler: EventMap[E]): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(handler);\n return () => this.off(event, handler);\n }\n\n off<E extends keyof EventMap>(event: E, handler: EventMap[E]): this {\n this.listeners.get(event)?.delete(handler);\n return this;\n }\n\n protected emit<E extends keyof EventMap>(\n event: E,\n ...args: Parameters<EventMap[E]>\n ): void {\n this.listeners.get(event)?.forEach((handler) => {\n (handler as (...args: Parameters<EventMap[E]>) => void)(...args);\n });\n }\n\n protected clearListeners(): void {\n this.listeners.clear();\n }\n}\n\n","type TransitionMap<S extends string> = Record<S, S[]>;\n\nexport interface StateMachine<S extends string> {\n readonly current: S;\n can(next: S): boolean;\n transition(next: S): boolean;\n force(next: S): void;\n}\n\nexport function createStateMachine<S extends string>(\n initial: S,\n transitions: TransitionMap<S>,\n onChange?: (from: S, to: S) => void,\n): StateMachine<S> {\n let current = initial;\n\n return {\n get current() {\n return current;\n },\n can(next: S) {\n return transitions[current].includes(next);\n },\n transition(next: S): boolean {\n if (!transitions[current].includes(next)) return false;\n const prev = current;\n current = next;\n onChange?.(prev, next);\n return true;\n },\n force(next: S) {\n const prev = current;\n current = next;\n onChange?.(prev, next);\n },\n };\n}\n","import type {\n DaydreamError,\n ReconnectConfig,\n ReconnectInfo,\n} from \"./types/common\";\nimport type {\n BroadcastEventMap,\n BroadcastOptions,\n BroadcastState,\n} from \"./types/broadcast\";\nimport { WHIPClient, type WHIPClientConfig } from \"./internal/WHIPClient\";\nimport { ConnectionError } from \"./errors\";\nimport { TypedEventEmitter } from \"./internal/TypedEventEmitter\";\nimport { createStateMachine, type StateMachine } from \"./internal/StateMachine\";\n\nconst BROADCAST_TRANSITIONS: Record<BroadcastState, BroadcastState[]> = {\n connecting: [\"live\", \"error\"],\n live: [\"reconnecting\", \"ended\"],\n reconnecting: [\"live\", \"ended\"],\n ended: [],\n error: [\"connecting\"],\n};\n\n/**\n * Low-level configuration for the Broadcast class.\n * For most use cases, prefer using {@link createBroadcast} with {@link BroadcastOptions}.\n */\nexport interface BroadcastConfig {\n /** WHIP endpoint URL for publishing the stream. */\n whipUrl: string;\n /** MediaStream to broadcast. */\n stream: MediaStream;\n /** Reconnection behavior configuration. */\n reconnect?: ReconnectConfig;\n /** Advanced WHIP client configuration. */\n whipConfig?: Partial<WHIPClientConfig>;\n}\n\n/**\n * Manages a WebRTC broadcast session using WHIP protocol.\n *\n * Handles connection establishment, reconnection logic, and stream management.\n * Emits events for state changes, errors, and reconnection attempts.\n *\n * @example\n * ```ts\n * const broadcast = new Broadcast({\n * whipUrl: \"https://example.com/whip\",\n * stream: mediaStream,\n * });\n *\n * broadcast.on(\"stateChange\", (state) => console.log(\"State:\", state));\n * await broadcast.connect();\n * ```\n *\n * @see {@link createBroadcast} for a simpler factory function\n */\nexport class Broadcast extends TypedEventEmitter<BroadcastEventMap> {\n private _whepUrl: string | null = null;\n private readonly stateMachine: StateMachine<BroadcastState>;\n private currentStream: MediaStream;\n private readonly reconnectConfig: ReconnectConfig;\n private readonly whipClient: WHIPClient;\n\n private reconnectAttempts = 0;\n private reconnectTimeout: ReturnType<typeof setTimeout> | null = null;\n private disconnectedGraceTimeout: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Creates a new Broadcast instance.\n * @param config - Broadcast configuration\n */\n constructor(config: BroadcastConfig) {\n super();\n this.currentStream = config.stream;\n this.reconnectConfig = {\n enabled: config.reconnect?.enabled ?? true,\n maxAttempts: config.reconnect?.maxAttempts ?? 5,\n baseDelayMs: config.reconnect?.baseDelayMs ?? 1000,\n };\n\n this.whipClient = new WHIPClient({\n url: config.whipUrl,\n ...config.whipConfig,\n });\n\n this.stateMachine = createStateMachine<BroadcastState>(\n \"connecting\",\n BROADCAST_TRANSITIONS,\n (_from, to) => this.emit(\"stateChange\", to),\n );\n }\n\n /** Current broadcast state. */\n get state(): BroadcastState {\n return this.stateMachine.current;\n }\n\n /** WHEP playback URL for viewers, available after connecting. */\n get whepUrl(): string | null {\n return this._whepUrl;\n }\n\n /** The MediaStream being broadcast. */\n get stream(): MediaStream {\n return this.currentStream;\n }\n\n /** Information about the current reconnection attempt, or null if not reconnecting. */\n get reconnectInfo(): ReconnectInfo | null {\n if (this.state !== \"reconnecting\") return null;\n const baseDelay = this.reconnectConfig.baseDelayMs ?? 1000;\n const delay = baseDelay * Math.pow(2, this.reconnectAttempts - 1);\n return {\n attempt: this.reconnectAttempts,\n maxAttempts: this.reconnectConfig.maxAttempts ?? 5,\n delayMs: delay,\n };\n }\n\n /**\n * Establishes the WebRTC connection and starts broadcasting.\n * @throws {DaydreamError} If connection fails\n */\n async connect(): Promise<void> {\n try {\n const result = await this.whipClient.connect(this.currentStream);\n if (result.whepUrl) {\n this._whepUrl = result.whepUrl;\n }\n this.setupConnectionMonitoring();\n this.stateMachine.transition(\"live\");\n } catch (error) {\n this.stateMachine.transition(\"error\");\n const daydreamError =\n error instanceof Error\n ? error\n : new ConnectionError(\"Failed to connect\", error);\n this.emit(\"error\", daydreamError as DaydreamError);\n throw daydreamError;\n }\n }\n\n /**\n * Stops the broadcast and disconnects.\n * After calling this, the instance cannot be reused.\n */\n async stop(): Promise<void> {\n this.stateMachine.force(\"ended\");\n this.clearTimeouts();\n\n await this.whipClient.disconnect();\n this.clearListeners();\n }\n\n /**\n * Sets the maximum frame rate for the video track.\n * @param fps - Maximum frame rate, or undefined to remove the limit\n */\n setMaxFramerate(fps?: number): void {\n this.whipClient.setMaxFramerate(fps);\n }\n\n /**\n * Replaces the current MediaStream with a new one.\n * The tracks are replaced in-place if connected, otherwise just stored.\n * @param newStream - The new MediaStream to use\n */\n async replaceStream(newStream: MediaStream): Promise<void> {\n if (!this.whipClient.isConnected()) {\n this.currentStream = newStream;\n return;\n }\n\n const videoTrack = newStream.getVideoTracks()[0];\n const audioTrack = newStream.getAudioTracks()[0];\n\n try {\n if (videoTrack) {\n await this.whipClient.replaceTrack(videoTrack);\n }\n if (audioTrack) {\n await this.whipClient.replaceTrack(audioTrack);\n }\n this.currentStream = newStream;\n } catch {\n this.currentStream = newStream;\n this.scheduleReconnect();\n }\n }\n\n private setupConnectionMonitoring(): void {\n const pc = this.whipClient.getPeerConnection();\n if (!pc) return;\n\n pc.oniceconnectionstatechange = () => {\n if (this.state === \"ended\") return;\n\n const iceState = pc.iceConnectionState;\n\n if (iceState === \"connected\" || iceState === \"completed\") {\n this.clearGraceTimeout();\n if (this.state === \"reconnecting\") {\n this.stateMachine.transition(\"live\");\n this.reconnectAttempts = 0;\n }\n return;\n }\n\n if (iceState === \"disconnected\") {\n this.clearGraceTimeout();\n this.whipClient.restartIce();\n\n this.disconnectedGraceTimeout = setTimeout(() => {\n if (this.state === \"ended\") return;\n const currentState = pc.iceConnectionState;\n if (currentState === \"disconnected\") {\n this.scheduleReconnect();\n }\n }, 2000);\n return;\n }\n\n if (iceState === \"failed\" || iceState === \"closed\") {\n this.clearGraceTimeout();\n this.scheduleReconnect();\n }\n };\n }\n\n private clearGraceTimeout(): void {\n if (this.disconnectedGraceTimeout) {\n clearTimeout(this.disconnectedGraceTimeout);\n this.disconnectedGraceTimeout = null;\n }\n }\n\n private clearReconnectTimeout(): void {\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = null;\n }\n }\n\n private clearTimeouts(): void {\n this.clearGraceTimeout();\n this.clearReconnectTimeout();\n }\n\n private scheduleReconnect(): void {\n if (this.state === \"ended\") return;\n\n if (!this.reconnectConfig.enabled) {\n this.stateMachine.transition(\"ended\");\n return;\n }\n\n const maxAttempts = this.reconnectConfig.maxAttempts ?? 5;\n\n if (this.reconnectAttempts >= maxAttempts) {\n this.stateMachine.transition(\"ended\");\n return;\n }\n\n this.clearReconnectTimeout();\n this.stateMachine.transition(\"reconnecting\");\n\n const baseDelay = this.reconnectConfig.baseDelayMs ?? 1000;\n const delay = baseDelay * Math.pow(2, this.reconnectAttempts);\n this.reconnectAttempts++;\n\n this.emit(\"reconnect\", {\n attempt: this.reconnectAttempts,\n maxAttempts: this.reconnectConfig.maxAttempts ?? 5,\n delayMs: delay,\n });\n\n this.reconnectTimeout = setTimeout(async () => {\n if (this.state === \"ended\") return;\n\n try {\n await this.whipClient.disconnect();\n const result = await this.whipClient.connect(this.currentStream);\n if (result.whepUrl) {\n this._whepUrl = result.whepUrl;\n }\n this.setupConnectionMonitoring();\n this.stateMachine.transition(\"live\");\n this.reconnectAttempts = 0;\n } catch {\n this.scheduleReconnect();\n }\n }, delay);\n }\n}\n\n/**\n * Creates a new Broadcast instance with the given options.\n *\n * This is the recommended way to create a broadcast session.\n * Automatically configures the Livepeer response handler to extract the playback URL.\n *\n * @param options - Broadcast options\n * @returns A new Broadcast instance\n *\n * @example\n * ```ts\n * const broadcast = createBroadcast({\n * whipUrl: \"https://livepeer.studio/webrtc/...\",\n * stream: await navigator.mediaDevices.getUserMedia({ video: true, audio: true }),\n * });\n *\n * broadcast.on(\"stateChange\", (state) => {\n * if (state === \"live\") {\n * console.log(\"Playback URL:\", broadcast.whepUrl);\n * }\n * });\n *\n * await broadcast.connect();\n * ```\n */\nexport function createBroadcast(options: BroadcastOptions): Broadcast {\n const {\n whipUrl,\n stream,\n reconnect,\n video,\n audio,\n iceServers,\n connectionTimeout,\n onStats,\n statsIntervalMs,\n onResponse,\n } = options;\n\n return new Broadcast({\n whipUrl,\n stream,\n reconnect,\n whipConfig: {\n iceServers,\n videoBitrate: video?.bitrate,\n audioBitrate: audio?.bitrate,\n maxFramerate: video?.maxFramerate,\n connectionTimeout,\n onStats,\n statsIntervalMs,\n onResponse,\n },\n });\n}\n","import { DEFAULT_ICE_SERVERS } from \"../types/common\";\nimport { ConnectionError, NetworkError } from \"../errors\";\nimport {\n type PeerConnectionFactory,\n type FetchFn,\n type TimerProvider,\n type MediaStreamFactory,\n defaultPeerConnectionFactory,\n defaultFetch,\n defaultTimerProvider,\n defaultMediaStreamFactory,\n} from \"./dependencies\";\n\nexport interface WHEPClientConfig {\n url: string;\n iceServers?: RTCIceServer[];\n connectionTimeout?: number;\n skipIceGathering?: boolean;\n onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n peerConnectionFactory?: PeerConnectionFactory;\n fetch?: FetchFn;\n timers?: TimerProvider;\n mediaStreamFactory?: MediaStreamFactory;\n}\n\nconst DEFAULT_CONNECTION_TIMEOUT = 10000;\n\nexport class WHEPClient {\n private readonly url: string;\n private readonly iceServers: RTCIceServer[];\n private readonly connectionTimeout: number;\n private readonly skipIceGathering: boolean;\n private readonly onStats?: (report: RTCStatsReport) => void;\n private readonly statsIntervalMs: number;\n private readonly pcFactory: PeerConnectionFactory;\n private readonly fetch: FetchFn;\n private readonly timers: TimerProvider;\n private readonly mediaStreamFactory: MediaStreamFactory;\n\n private pc: RTCPeerConnection | null = null;\n private resourceUrl: string | null = null;\n private stream: MediaStream | null = null;\n private abortController: AbortController | null = null;\n private statsTimer: number | null = null;\n private iceGatheringTimer: number | null = null;\n\n constructor(config: WHEPClientConfig) {\n this.url = config.url;\n this.iceServers = config.iceServers ?? DEFAULT_ICE_SERVERS;\n this.connectionTimeout =\n config.connectionTimeout ?? DEFAULT_CONNECTION_TIMEOUT;\n this.skipIceGathering = config.skipIceGathering ?? true;\n this.onStats = config.onStats;\n this.statsIntervalMs = config.statsIntervalMs ?? 5000;\n this.pcFactory =\n config.peerConnectionFactory ?? defaultPeerConnectionFactory;\n this.fetch = config.fetch ?? defaultFetch;\n this.timers = config.timers ?? defaultTimerProvider;\n this.mediaStreamFactory =\n config.mediaStreamFactory ?? defaultMediaStreamFactory;\n }\n\n async connect(): Promise<MediaStream> {\n this.cleanup();\n\n this.pc = this.pcFactory.create({\n iceServers: this.iceServers,\n });\n\n this.pc.addTransceiver(\"video\", { direction: \"recvonly\" });\n this.pc.addTransceiver(\"audio\", { direction: \"recvonly\" });\n\n this.stream = this.mediaStreamFactory.create();\n\n this.pc.ontrack = (event) => {\n const [remoteStream] = event.streams;\n if (remoteStream) {\n this.stream = remoteStream;\n } else if (this.stream) {\n this.stream.addTrack(event.track);\n }\n };\n\n const offer = await this.pc.createOffer();\n await this.pc.setLocalDescription(offer);\n\n if (!this.skipIceGathering) {\n await this.waitForIceGathering();\n }\n\n this.abortController = new AbortController();\n const timeoutId = this.timers.setTimeout(\n () => this.abortController?.abort(),\n this.connectionTimeout,\n );\n\n try {\n const response = await this.fetch(this.url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/sdp\" },\n body: this.pc.localDescription!.sdp,\n signal: this.abortController.signal,\n });\n\n this.timers.clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"\");\n throw new ConnectionError(\n `WHEP connection failed: ${response.status} ${response.statusText} ${errorText}`,\n );\n }\n\n const location = response.headers.get(\"location\");\n if (location) {\n this.resourceUrl = new URL(location, this.url).toString();\n }\n\n const answerSdp = await response.text();\n await this.pc.setRemoteDescription({ type: \"answer\", sdp: answerSdp });\n\n this.startStatsTimer();\n\n return this.stream;\n } catch (error) {\n this.timers.clearTimeout(timeoutId);\n if (error instanceof ConnectionError) {\n throw error;\n }\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new NetworkError(\"Connection timeout\");\n }\n throw new NetworkError(\"Failed to establish connection\", error);\n }\n }\n\n private waitForIceGathering(): Promise<void> {\n return new Promise((resolve) => {\n if (!this.pc) {\n resolve();\n return;\n }\n\n if (this.pc.iceGatheringState === \"complete\") {\n resolve();\n return;\n }\n\n const onStateChange = () => {\n if (this.pc?.iceGatheringState === \"complete\") {\n this.pc.removeEventListener(\"icegatheringstatechange\", onStateChange);\n if (this.iceGatheringTimer !== null) {\n this.timers.clearTimeout(this.iceGatheringTimer);\n this.iceGatheringTimer = null;\n }\n resolve();\n }\n };\n\n this.pc.addEventListener(\"icegatheringstatechange\", onStateChange);\n\n this.iceGatheringTimer = this.timers.setTimeout(() => {\n this.pc?.removeEventListener(\"icegatheringstatechange\", onStateChange);\n this.iceGatheringTimer = null;\n resolve();\n }, 1000);\n });\n }\n\n private startStatsTimer(): void {\n if (!this.onStats || !this.pc) return;\n\n this.stopStatsTimer();\n\n this.statsTimer = this.timers.setInterval(async () => {\n if (!this.pc) return;\n try {\n const report = await this.pc.getStats();\n this.onStats?.(report);\n } catch {\n // Stats collection failed\n }\n }, this.statsIntervalMs);\n }\n\n private stopStatsTimer(): void {\n if (this.statsTimer !== null) {\n this.timers.clearInterval(this.statsTimer);\n this.statsTimer = null;\n }\n }\n\n private cleanup(): void {\n this.stopStatsTimer();\n\n if (this.iceGatheringTimer !== null) {\n this.timers.clearTimeout(this.iceGatheringTimer);\n this.iceGatheringTimer = null;\n }\n\n if (this.abortController) {\n try {\n this.abortController.abort();\n } catch {\n // Ignore abort errors\n }\n this.abortController = null;\n }\n\n if (this.pc) {\n // Clear event handlers\n this.pc.oniceconnectionstatechange = null;\n this.pc.onconnectionstatechange = null;\n this.pc.ontrack = null;\n\n try {\n this.pc.getTransceivers().forEach((t) => {\n try {\n t.stop();\n } catch {\n // Ignore stop errors\n }\n });\n } catch {\n // Ignore transceiver errors\n }\n\n try {\n this.pc.close();\n } catch {\n // Ignore close errors\n }\n this.pc = null;\n }\n }\n\n async disconnect(): Promise<void> {\n if (this.resourceUrl) {\n try {\n await this.fetch(this.resourceUrl, { method: \"DELETE\" });\n } catch {\n // Ignore delete errors\n }\n }\n\n this.cleanup();\n this.stream = null;\n this.resourceUrl = null;\n }\n\n getStream(): MediaStream | null {\n return this.stream;\n }\n\n getPeerConnection(): RTCPeerConnection | null {\n return this.pc;\n }\n\n restartIce(): void {\n if (this.pc) {\n try {\n this.pc.restartIce();\n } catch {\n // ICE restart not supported\n }\n }\n }\n}\n","import type {\n DaydreamError,\n ReconnectConfig,\n ReconnectInfo,\n} from \"./types/common\";\nimport type {\n PlayerEventMap,\n PlayerOptions,\n PlayerState,\n} from \"./types/player\";\nimport { WHEPClient, type WHEPClientConfig } from \"./internal/WHEPClient\";\nimport { ConnectionError } from \"./errors\";\nimport { TypedEventEmitter } from \"./internal/TypedEventEmitter\";\nimport { createStateMachine, type StateMachine } from \"./internal/StateMachine\";\n\nconst PLAYER_TRANSITIONS: Record<PlayerState, PlayerState[]> = {\n connecting: [\"playing\", \"buffering\", \"error\"],\n playing: [\"buffering\", \"ended\"],\n buffering: [\"playing\", \"ended\"],\n ended: [],\n error: [\"connecting\"],\n};\n\n/**\n * Low-level configuration for the Player class.\n * For most use cases, prefer using {@link createPlayer} with {@link PlayerOptions}.\n */\nexport interface PlayerConfig {\n /** WHEP endpoint URL for receiving the stream. */\n whepUrl: string;\n /** Reconnection behavior configuration. */\n reconnect?: ReconnectConfig;\n /** Advanced WHEP client configuration. */\n whepConfig?: Partial<WHEPClientConfig>;\n}\n\n/**\n * Manages a WebRTC playback session using WHEP protocol.\n *\n * Handles connection establishment, reconnection logic, and stream management.\n * Emits events for state changes, errors, and reconnection attempts.\n *\n * @example\n * ```ts\n * const player = new Player({\n * whepUrl: \"https://example.com/whep/stream-id\",\n * });\n *\n * player.on(\"stateChange\", (state) => console.log(\"State:\", state));\n * await player.connect();\n * player.attachTo(videoElement);\n * ```\n *\n * @see {@link createPlayer} for a simpler factory function\n */\nexport class Player extends TypedEventEmitter<PlayerEventMap> {\n private readonly stateMachine: StateMachine<PlayerState>;\n private _stream: MediaStream | null = null;\n private readonly whepUrl: string;\n private readonly reconnectConfig: ReconnectConfig;\n private readonly whepConfig: Partial<WHEPClientConfig> | undefined;\n private whepClient: WHEPClient;\n\n private reconnectAttempts = 0;\n private reconnectTimeout: ReturnType<typeof setTimeout> | null = null;\n private disconnectedGraceTimeout: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Creates a new Player instance.\n * @param config - Player configuration\n */\n constructor(config: PlayerConfig) {\n super();\n this.whepUrl = config.whepUrl;\n this.whepConfig = config.whepConfig;\n this.reconnectConfig = {\n enabled: config.reconnect?.enabled ?? true,\n maxAttempts: config.reconnect?.maxAttempts ?? 30,\n baseDelayMs: config.reconnect?.baseDelayMs ?? 200,\n };\n\n this.whepClient = new WHEPClient({\n url: config.whepUrl,\n ...this.whepConfig,\n });\n\n this.stateMachine = createStateMachine<PlayerState>(\n \"connecting\",\n PLAYER_TRANSITIONS,\n (_from, to) => this.emit(\"stateChange\", to),\n );\n }\n\n /** Current player state. */\n get state(): PlayerState {\n return this.stateMachine.current;\n }\n\n /** The received MediaStream, or null if not connected. */\n get stream(): MediaStream | null {\n return this._stream;\n }\n\n /** Information about the current reconnection attempt, or null if not buffering. */\n get reconnectInfo(): ReconnectInfo | null {\n if (this.state !== \"buffering\") return null;\n const baseDelay = this.reconnectConfig.baseDelayMs ?? 200;\n const delay = this.calculateReconnectDelay(\n this.reconnectAttempts - 1,\n baseDelay,\n );\n return {\n attempt: this.reconnectAttempts,\n maxAttempts: this.reconnectConfig.maxAttempts ?? 30,\n delayMs: delay,\n };\n }\n\n /**\n * Establishes the WebRTC connection and starts receiving the stream.\n * @throws {DaydreamError} If connection fails after all retry attempts\n */\n async connect(): Promise<void> {\n try {\n this._stream = await this.whepClient.connect();\n this.setupConnectionMonitoring();\n this.stateMachine.transition(\"playing\");\n this.reconnectAttempts = 0;\n } catch (error) {\n if (\n this.reconnectConfig.enabled &&\n this.reconnectAttempts < (this.reconnectConfig.maxAttempts ?? 30)\n ) {\n this.scheduleReconnect();\n return;\n }\n this.stateMachine.transition(\"error\");\n const daydreamError =\n error instanceof Error\n ? error\n : new ConnectionError(\"Failed to connect\", error);\n this.emit(\"error\", daydreamError as DaydreamError);\n throw daydreamError;\n }\n }\n\n /**\n * Attaches the received stream to a video element.\n * @param video - The HTMLVideoElement to display the stream\n */\n attachTo(video: HTMLVideoElement): void {\n if (this._stream) {\n video.srcObject = this._stream;\n }\n }\n\n /**\n * Stops playback and disconnects.\n * After calling this, the instance cannot be reused.\n */\n async stop(): Promise<void> {\n this.stateMachine.force(\"ended\");\n this.clearTimeouts();\n\n await this.whepClient.disconnect();\n this._stream = null;\n this.clearListeners();\n }\n\n private setupConnectionMonitoring(): void {\n const pc = this.whepClient.getPeerConnection();\n if (!pc) return;\n\n pc.oniceconnectionstatechange = () => {\n if (this.state === \"ended\") return;\n\n const iceState = pc.iceConnectionState;\n\n if (iceState === \"connected\" || iceState === \"completed\") {\n this.clearGraceTimeout();\n if (this.state === \"buffering\") {\n this.stateMachine.transition(\"playing\");\n this.reconnectAttempts = 0;\n }\n return;\n }\n\n if (iceState === \"disconnected\") {\n this.clearGraceTimeout();\n this.whepClient.restartIce();\n\n this.disconnectedGraceTimeout = setTimeout(() => {\n if (this.state === \"ended\") return;\n const currentState = pc.iceConnectionState;\n if (currentState === \"disconnected\") {\n this.scheduleReconnect();\n }\n }, 2000);\n return;\n }\n\n if (iceState === \"failed\" || iceState === \"closed\") {\n this.clearGraceTimeout();\n this.scheduleReconnect();\n }\n };\n }\n\n private clearGraceTimeout(): void {\n if (this.disconnectedGraceTimeout) {\n clearTimeout(this.disconnectedGraceTimeout);\n this.disconnectedGraceTimeout = null;\n }\n }\n\n private clearReconnectTimeout(): void {\n if (this.reconnectTimeout) {\n clearTimeout(this.reconnectTimeout);\n this.reconnectTimeout = null;\n }\n }\n\n private clearTimeouts(): void {\n this.clearGraceTimeout();\n this.clearReconnectTimeout();\n }\n\n private scheduleReconnect(): void {\n if (this.state === \"ended\") return;\n\n if (!this.reconnectConfig.enabled) {\n this.stateMachine.transition(\"ended\");\n return;\n }\n\n const maxAttempts = this.reconnectConfig.maxAttempts ?? 30;\n\n if (this.reconnectAttempts >= maxAttempts) {\n this.stateMachine.transition(\"ended\");\n return;\n }\n\n this.clearReconnectTimeout();\n this.stateMachine.transition(\"buffering\");\n\n const baseDelay = this.reconnectConfig.baseDelayMs ?? 200;\n const delay = this.calculateReconnectDelay(\n this.reconnectAttempts,\n baseDelay,\n );\n this.reconnectAttempts++;\n\n this.emit(\"reconnect\", {\n attempt: this.reconnectAttempts,\n maxAttempts: this.reconnectConfig.maxAttempts ?? 30,\n delayMs: delay,\n });\n\n this.reconnectTimeout = setTimeout(async () => {\n if (this.state === \"ended\") return;\n\n try {\n await this.whepClient.disconnect();\n this.whepClient = new WHEPClient({\n url: this.whepUrl,\n ...this.whepConfig,\n });\n this._stream = await this.whepClient.connect();\n this.setupConnectionMonitoring();\n this.stateMachine.transition(\"playing\");\n this.reconnectAttempts = 0;\n } catch {\n this.scheduleReconnect();\n }\n }, delay);\n }\n\n private calculateReconnectDelay(attempt: number, baseDelay: number): number {\n const linearPhaseEndCount = 10;\n const maxDelay = 60000;\n\n if (attempt === 0) return 0;\n if (attempt <= linearPhaseEndCount) return baseDelay;\n\n const exponentialAttempt = attempt - linearPhaseEndCount;\n const delay = 500 * Math.pow(2, exponentialAttempt - 1);\n return Math.min(delay, maxDelay);\n }\n}\n\n/**\n * Creates a new Player instance with the given WHEP URL and options.\n *\n * This is the recommended way to create a player session.\n *\n * @param whepUrl - WHEP endpoint URL for receiving the stream\n * @param options - Optional player configuration\n * @returns A new Player instance\n *\n * @example\n * ```ts\n * const player = createPlayer(\"https://livepeer.studio/webrtc/...\");\n *\n * player.on(\"stateChange\", (state) => {\n * if (state === \"playing\") {\n * player.attachTo(videoElement);\n * }\n * });\n *\n * await player.connect();\n * ```\n */\nexport function createPlayer(whepUrl: string, options?: PlayerOptions): Player {\n return new Player({\n whepUrl,\n reconnect: options?.reconnect,\n whepConfig: {\n iceServers: options?.iceServers,\n connectionTimeout: options?.connectionTimeout,\n skipIceGathering: options?.skipIceGathering,\n onStats: options?.onStats,\n statsIntervalMs: options?.statsIntervalMs,\n },\n });\n}\n","import type { Source } from \"../../types\";\n\nexport type RegistryEntry = {\n id: string;\n source: Source;\n registeredAt: number;\n};\n\nexport type RegistryEvents = {\n onRegister?: (id: string, source: Source) => void;\n onUnregister?: (id: string) => void;\n};\n\nexport interface SourceRegistry {\n register(id: string, source: Source): void;\n unregister(id: string): Source | undefined;\n get(id: string): Source | undefined;\n has(id: string): boolean;\n list(): Array<{ id: string; source: Source }>;\n clear(): void;\n}\n\nexport function createRegistry(events?: RegistryEvents): SourceRegistry {\n const sources = new Map<string, RegistryEntry>();\n\n return {\n register(id: string, source: Source): void {\n if (!id) throw new Error(\"Source id is required\");\n if (!source) throw new Error(\"Source is required\");\n\n sources.set(id, {\n id,\n source,\n registeredAt: Date.now(),\n });\n\n events?.onRegister?.(id, source);\n },\n\n unregister(id: string): Source | undefined {\n const entry = sources.get(id);\n if (!entry) return undefined;\n\n sources.delete(id);\n events?.onUnregister?.(id);\n\n return entry.source;\n },\n\n get(id: string): Source | undefined {\n return sources.get(id)?.source;\n },\n\n has(id: string): boolean {\n return sources.has(id);\n },\n\n list(): Array<{ id: string; source: Source }> {\n return Array.from(sources.values()).map((entry) => ({\n id: entry.id,\n source: entry.source,\n }));\n },\n\n clear(): void {\n const ids = Array.from(sources.keys());\n sources.clear();\n ids.forEach((id) => events?.onUnregister?.(id));\n },\n };\n}\n","import type { Ctx2D, FitMode, Size, Source } from \"../../types\";\n\nexport interface RendererOptions {\n width: number;\n height: number;\n dpr: number;\n keepalive: boolean;\n}\n\nexport interface Renderer {\n readonly captureCanvas: HTMLCanvasElement;\n readonly offscreenCtx: Ctx2D;\n readonly size: Size;\n\n setActiveSource(source: Source | null): void;\n renderFrame(timestamp: number): void;\n resize(width: number, height: number, dpr: number): void;\n setKeepalive(enabled: boolean): void;\n isSourceReady(source: Source): boolean;\n destroy(): void;\n}\n\ntype RectCache = {\n canvasW: number;\n canvasH: number;\n sourceW: number;\n sourceH: number;\n dx: number;\n dy: number;\n dw: number;\n dh: number;\n fit: FitMode;\n};\n\nexport function createRenderer(options: RendererOptions): Renderer {\n let size: Size = {\n width: options.width,\n height: options.height,\n dpr: Math.min(2, options.dpr),\n };\n let keepalive = options.keepalive;\n\n // Canvases\n let captureCanvas: HTMLCanvasElement | null = null;\n let captureCtx: Ctx2D | null = null;\n let offscreen: OffscreenCanvas | HTMLCanvasElement | null = null;\n let offscreenCtx: Ctx2D | null = null;\n\n // Source state\n let currentSource: Source | null = null;\n\n // Rendering state\n let frameIndex = 0;\n let rectCache = new WeakMap<\n HTMLCanvasElement | HTMLVideoElement,\n RectCache\n >();\n\n function initCanvas(): void {\n const canvas = document.createElement(\"canvas\");\n canvas.style.display = \"none\";\n\n const pxW = Math.round(size.width * size.dpr);\n const pxH = Math.round(size.height * size.dpr);\n const outW = Math.round(size.width);\n const outH = Math.round(size.height);\n\n canvas.width = outW;\n canvas.height = outH;\n\n const ctx = canvas.getContext(\"2d\", {\n alpha: false,\n desynchronized: true,\n }) as Ctx2D | null;\n\n if (!ctx) throw new Error(\"2D context not available\");\n\n captureCanvas = canvas;\n captureCtx = ctx;\n\n // Create offscreen canvas for DPR scaling\n try {\n const off = new OffscreenCanvas(pxW, pxH);\n offscreen = off;\n const offCtx = off.getContext(\"2d\", { alpha: false }) as Ctx2D | null;\n if (!offCtx) throw new Error(\"2D context not available for Offscreen\");\n offCtx.imageSmoothingEnabled = true;\n offscreenCtx = offCtx;\n } catch {\n // Fallback to HTMLCanvasElement\n const off = document.createElement(\"canvas\");\n off.width = pxW;\n off.height = pxH;\n const offCtx = off.getContext(\"2d\", { alpha: false }) as Ctx2D | null;\n if (!offCtx)\n throw new Error(\"2D context not available for Offscreen fallback\");\n offCtx.imageSmoothingEnabled = true;\n offscreen = off;\n offscreenCtx = offCtx;\n }\n\n // Initial fill\n offscreenCtx!.fillStyle = \"#111\";\n offscreenCtx!.fillRect(0, 0, pxW, pxH);\n captureCtx!.drawImage(\n offscreen as CanvasImageSource,\n 0,\n 0,\n pxW,\n pxH,\n 0,\n 0,\n outW,\n outH,\n );\n }\n\n function isSourceReady(source: Source): boolean {\n if (source.kind === \"video\") {\n const v = source.element;\n return (\n typeof v.readyState === \"number\" &&\n v.readyState >= 2 &&\n (v.videoWidth || 0) > 0 &&\n (v.videoHeight || 0) > 0\n );\n }\n // canvas\n const c = source.element;\n return (c.width || 0) > 0 && (c.height || 0) > 0;\n }\n\n function getDrawRect(\n el: HTMLCanvasElement | HTMLVideoElement,\n fit: FitMode,\n ): { dx: number; dy: number; dw: number; dh: number } | null {\n const canvas = offscreenCtx?.canvas;\n if (!canvas) return null;\n\n const canvasW = canvas.width;\n const canvasH = canvas.height;\n const sourceW = (el as HTMLVideoElement).videoWidth ?? el.width;\n const sourceH = (el as HTMLVideoElement).videoHeight ?? el.height;\n\n if (!sourceW || !sourceH) return null;\n\n const cached = rectCache.get(el);\n if (\n cached &&\n cached.canvasW === canvasW &&\n cached.canvasH === canvasH &&\n cached.sourceW === sourceW &&\n cached.sourceH === sourceH &&\n cached.fit === fit\n ) {\n return { dx: cached.dx, dy: cached.dy, dw: cached.dw, dh: cached.dh };\n }\n\n const scale =\n fit === \"cover\"\n ? Math.max(canvasW / sourceW, canvasH / sourceH)\n : Math.min(canvasW / sourceW, canvasH / sourceH);\n\n const dw = Math.floor(sourceW * scale);\n const dh = Math.floor(sourceH * scale);\n const dx = Math.floor((canvasW - dw) / 2);\n const dy = Math.floor((canvasH - dh) / 2);\n\n rectCache.set(el, {\n canvasW,\n canvasH,\n sourceW,\n sourceH,\n dx,\n dy,\n dw,\n dh,\n fit,\n });\n\n return { dx, dy, dw, dh };\n }\n\n function blitSource(source: Source): void {\n if (!offscreenCtx) return;\n const ctx = offscreenCtx;\n\n const el = source.element;\n const rect = getDrawRect(el, source.fit ?? \"contain\");\n if (!rect) return;\n\n ctx.drawImage(\n el as CanvasImageSource,\n rect.dx,\n rect.dy,\n rect.dw,\n rect.dh,\n );\n }\n\n // Initialize canvas on creation\n initCanvas();\n\n return {\n get captureCanvas(): HTMLCanvasElement {\n return captureCanvas!;\n },\n\n get offscreenCtx(): Ctx2D {\n return offscreenCtx!;\n },\n\n get size(): Size {\n return { ...size };\n },\n\n isSourceReady,\n\n setActiveSource(source: Source | null): void {\n currentSource = source;\n },\n\n renderFrame(_timestamp: number): void {\n const off = offscreenCtx;\n const cap = captureCtx;\n const capCanvas = captureCanvas;\n if (!off || !cap || !capCanvas) return;\n\n off.globalCompositeOperation = \"source-over\";\n\n if (currentSource && isSourceReady(currentSource)) {\n off.fillStyle = \"#000\";\n off.fillRect(0, 0, off.canvas.width, off.canvas.height);\n blitSource(currentSource);\n }\n\n // Keepalive pixel flicker\n if (keepalive) {\n const w = off.canvas.width;\n const h = off.canvas.height;\n const prevAlpha = off.globalAlpha;\n const prevFill = off.fillStyle;\n try {\n off.globalAlpha = 0.08;\n off.fillStyle = frameIndex % 2 ? \"#101010\" : \"#0e0e0e\";\n off.fillRect(w - 16, h - 16, 16, 16);\n } finally {\n off.globalAlpha = prevAlpha;\n off.fillStyle = prevFill;\n }\n }\n\n frameIndex++;\n\n // Blit offscreen to capture canvas\n cap.drawImage(\n off.canvas,\n 0,\n 0,\n off.canvas.width,\n off.canvas.height,\n 0,\n 0,\n capCanvas.width,\n capCanvas.height,\n );\n },\n\n resize(width: number, height: number, dpr: number): void {\n const nextDpr = Math.min(2, dpr);\n if (\n size.width === width &&\n size.height === height &&\n size.dpr === nextDpr\n ) {\n return;\n }\n\n size = { width, height, dpr: nextDpr };\n\n const pxW = Math.round(width * nextDpr);\n const pxH = Math.round(height * nextDpr);\n const outW = Math.round(width);\n const outH = Math.round(height);\n\n if (captureCanvas) {\n captureCanvas.width = outW;\n captureCanvas.height = outH;\n }\n\n if (offscreen instanceof HTMLCanvasElement) {\n offscreen.width = pxW;\n offscreen.height = pxH;\n } else if (offscreen instanceof OffscreenCanvas) {\n offscreen.width = pxW;\n offscreen.height = pxH;\n }\n\n rectCache = new WeakMap();\n },\n\n setKeepalive(enabled: boolean): void {\n keepalive = enabled;\n },\n\n destroy(): void {\n currentSource = null;\n captureCanvas = null;\n captureCtx = null;\n offscreen = null;\n offscreenCtx = null;\n },\n };\n}\n","export interface SchedulerOptions {\n fps: number;\n sendFps: number;\n onFrame: (timestamp: number) => void;\n onSendFpsChange?: (fps: number) => void;\n}\n\nexport interface Scheduler {\n start(videoElement?: HTMLVideoElement): void;\n stop(): void;\n setFps(fps: number): void;\n setSendFps(fps: number): void;\n readonly isRunning: boolean;\n readonly fps: number;\n readonly sendFps: number;\n}\n\nexport function createScheduler(options: SchedulerOptions): Scheduler {\n let fps = Math.max(1, options.fps);\n let sendFps = Math.max(1, options.sendFps);\n const onFrame = options.onFrame;\n const onSendFpsChange = options.onSendFpsChange;\n\n let isRunning = false;\n let lastFrameAt = 0;\n\n // RAF scheduling\n let rafId: number | null = null;\n let rafFallbackActive = false;\n\n // Video frame callback scheduling\n let videoFrameRequestId: number | null = null;\n let videoFrameSource: HTMLVideoElement | null = null;\n\n function getTimestamp(): number {\n return typeof performance !== \"undefined\" ? performance.now() : Date.now();\n }\n\n function shouldRenderFrame(): boolean {\n const now = getTimestamp();\n const minIntervalMs = 1000 / Math.max(1, sendFps);\n if (lastFrameAt !== 0 && now - lastFrameAt < minIntervalMs) {\n return false;\n }\n return true;\n }\n\n function renderIfNeeded(): void {\n if (!shouldRenderFrame()) return;\n const timestamp = getTimestamp();\n onFrame(timestamp);\n lastFrameAt = timestamp;\n }\n\n function scheduleWithRaf(isFallback: boolean): void {\n if (isFallback) {\n if (rafFallbackActive) return;\n rafFallbackActive = true;\n }\n\n const loop = (): void => {\n renderIfNeeded();\n rafId = requestAnimationFrame(loop);\n };\n\n rafId = requestAnimationFrame(loop);\n }\n\n function scheduleWithVideoFrame(videoEl: HTMLVideoElement): void {\n if (typeof videoEl.requestVideoFrameCallback !== \"function\") {\n scheduleWithRaf(false);\n return;\n }\n\n videoFrameSource = videoEl;\n\n const cb = (): void => {\n renderIfNeeded();\n if (videoFrameSource === videoEl) {\n try {\n videoFrameRequestId = videoEl.requestVideoFrameCallback(cb);\n } catch {\n // Failed to request video frame callback\n }\n }\n };\n\n try {\n videoFrameRequestId = videoEl.requestVideoFrameCallback(cb);\n } catch {\n // Failed to start video frame callback\n }\n\n // Also schedule RAF as fallback for non-video frames\n scheduleWithRaf(true);\n }\n\n function cancelSchedulers(): void {\n if (rafId != null) {\n cancelAnimationFrame(rafId);\n rafId = null;\n }\n rafFallbackActive = false;\n\n if (videoFrameRequestId && videoFrameSource) {\n try {\n if (typeof videoFrameSource.cancelVideoFrameCallback === \"function\") {\n videoFrameSource.cancelVideoFrameCallback(videoFrameRequestId);\n }\n } catch {\n // Failed to cancel video frame callback\n }\n }\n videoFrameRequestId = null;\n videoFrameSource = null;\n }\n\n return {\n get isRunning(): boolean {\n return isRunning;\n },\n\n get fps(): number {\n return fps;\n },\n\n get sendFps(): number {\n return sendFps;\n },\n\n start(videoElement?: HTMLVideoElement): void {\n if (isRunning) {\n cancelSchedulers();\n }\n\n isRunning = true;\n lastFrameAt = 0;\n\n if (\n videoElement &&\n typeof videoElement.requestVideoFrameCallback === \"function\"\n ) {\n scheduleWithVideoFrame(videoElement);\n } else {\n scheduleWithRaf(false);\n }\n },\n\n stop(): void {\n isRunning = false;\n cancelSchedulers();\n },\n\n setFps(newFps: number): void {\n fps = Math.max(1, newFps);\n },\n\n setSendFps(newSendFps: number): void {\n const next = Math.max(1, newSendFps);\n if (sendFps === next) return;\n sendFps = next;\n onSendFpsChange?.(sendFps);\n },\n };\n}\n","export interface AudioManagerOptions {\n autoUnlock: boolean;\n unlockEvents: string[];\n disableSilentAudio: boolean;\n}\n\nexport interface AudioManager {\n setOutputStream(stream: MediaStream): void;\n addTrack(track: MediaStreamTrack): void;\n removeTrack(trackId: string): void;\n unlock(): Promise<boolean>;\n destroy(): void;\n}\n\ndeclare global {\n interface Window {\n webkitAudioContext?: typeof AudioContext;\n }\n}\n\nexport function createAudioManager(options: AudioManagerOptions): AudioManager {\n let outputStream: MediaStream | null = null;\n\n // Audio context and silent track\n let audioCtx: AudioContext | null = null;\n let silentOsc: OscillatorNode | null = null;\n let silentGain: GainNode | null = null;\n let audioDst: MediaStreamAudioDestinationNode | null = null;\n let silentAudioTrack: MediaStreamTrack | null = null;\n\n // External tracks\n const externalAudioTrackIds = new Set<string>();\n const externalAudioEndHandlers = new Map<string, (ev: Event) => void>();\n\n // Auto unlock\n let audioUnlockHandler: ((ev: Event) => void) | null = null;\n let audioUnlockAttached = false;\n let audioStateListenerAttached = false;\n\n function ensureSilentAudioTrack(): void {\n if (options.disableSilentAudio) return;\n if (!outputStream) return;\n\n const alreadyHasAudio = outputStream.getAudioTracks().length > 0;\n if (alreadyHasAudio) return;\n\n if (silentAudioTrack && silentAudioTrack.readyState === \"live\") {\n try {\n outputStream.addTrack(silentAudioTrack);\n } catch {\n // Failed to add silent track\n }\n return;\n }\n\n if (!audioCtx) {\n const AudioContextClass = window.AudioContext || window.webkitAudioContext;\n if (!AudioContextClass) return;\n\n audioCtx = new AudioContextClass({\n sampleRate: 48000,\n });\n try {\n audioCtx.resume().catch(() => {\n // Failed to resume AudioContext\n });\n } catch {\n // Error calling resume\n }\n attachAudioCtxStateListener();\n }\n\n const ac = audioCtx;\n if (!ac) return;\n\n silentOsc = ac.createOscillator();\n silentGain = ac.createGain();\n audioDst = ac.createMediaStreamDestination();\n\n silentGain.gain.setValueAtTime(0.0001, ac.currentTime);\n silentOsc.frequency.setValueAtTime(440, ac.currentTime);\n silentOsc.type = \"sine\";\n silentOsc.connect(silentGain);\n silentGain.connect(audioDst);\n silentOsc.start();\n\n const track = audioDst.stream.getAudioTracks()[0];\n if (track) {\n silentAudioTrack = track;\n try {\n outputStream.addTrack(track);\n } catch {\n // Failed to add track to stream\n }\n }\n }\n\n function removeSilentAudioTrack(): void {\n try {\n if (outputStream && silentAudioTrack) {\n try {\n outputStream.removeTrack(silentAudioTrack);\n } catch {\n // Failed to remove silent track\n }\n }\n if (silentOsc) {\n try {\n silentOsc.stop();\n } catch {\n // Failed to stop oscillator\n }\n try {\n silentOsc.disconnect();\n } catch {\n // Failed to disconnect oscillator\n }\n }\n if (silentGain) {\n try {\n silentGain.disconnect();\n } catch {\n // Failed to disconnect gain\n }\n }\n silentOsc = null;\n silentGain = null;\n audioDst = null;\n silentAudioTrack = null;\n if (audioCtx) {\n try {\n audioCtx.close();\n } catch {\n // Failed to close AudioContext\n }\n }\n audioCtx = null;\n } catch {\n // Error in removeSilentAudioTrack\n }\n }\n\n function rebuildSilentAudioTrack(): void {\n if (options.disableSilentAudio) return;\n if (!outputStream) return;\n if (externalAudioTrackIds.size > 0) return;\n\n if (silentAudioTrack) {\n try {\n outputStream.removeTrack(silentAudioTrack);\n } catch {\n // Failed to remove silent track\n }\n }\n\n if (silentOsc) {\n try {\n silentOsc.stop();\n } catch {\n // Failed to stop oscillator\n }\n try {\n silentOsc.disconnect();\n } catch {\n // Failed to disconnect oscillator\n }\n }\n if (silentGain) {\n try {\n silentGain.disconnect();\n } catch {\n // Failed to disconnect gain\n }\n }\n silentOsc = null;\n silentGain = null;\n audioDst = null;\n silentAudioTrack = null;\n\n const ac = audioCtx;\n if (!ac || ac.state !== \"running\") return;\n\n attachAudioCtxStateListener();\n\n silentOsc = ac.createOscillator();\n silentGain = ac.createGain();\n audioDst = ac.createMediaStreamDestination();\n\n silentGain.gain.setValueAtTime(0.0001, ac.currentTime);\n silentOsc.frequency.setValueAtTime(440, ac.currentTime);\n silentOsc.type = \"sine\";\n silentOsc.connect(silentGain);\n silentGain.connect(audioDst);\n silentOsc.start();\n\n const track = audioDst.stream.getAudioTracks()[0];\n if (track) {\n silentAudioTrack = track;\n try {\n outputStream.addTrack(track);\n } catch {\n // Failed to add track to stream\n }\n }\n }\n\n function attachAudioCtxStateListener(): void {\n const ac = audioCtx;\n if (!ac || audioStateListenerAttached) return;\n\n const onStateChange = (): void => {\n try {\n if (audioCtx && audioCtx.state === \"running\") {\n rebuildSilentAudioTrack();\n cleanupAudioAutoUnlock();\n }\n } catch {\n // Error in state change handler\n }\n };\n\n try {\n (ac as AudioContext & { onstatechange: (() => void) | null }).onstatechange = onStateChange;\n audioStateListenerAttached = true;\n } catch {\n // Failed to attach state listener\n }\n }\n\n function setupAudioAutoUnlock(): void {\n if (!options.autoUnlock) return;\n if (typeof document === \"undefined\") return;\n if (audioUnlockAttached) return;\n\n const handler = (): void => {\n unlock();\n };\n\n audioUnlockHandler = handler;\n options.unlockEvents.forEach((evt) => {\n try {\n document.addEventListener(evt, handler, { capture: true });\n } catch {\n // Failed to add unlock listener\n }\n });\n audioUnlockAttached = true;\n }\n\n function cleanupAudioAutoUnlock(): void {\n if (!audioUnlockAttached) return;\n if (typeof document !== \"undefined\" && audioUnlockHandler) {\n options.unlockEvents.forEach((evt) => {\n try {\n document.removeEventListener(evt, audioUnlockHandler!, {\n capture: true,\n });\n } catch {\n // Failed to remove unlock listener\n }\n });\n }\n audioUnlockAttached = false;\n audioUnlockHandler = null;\n }\n\n async function unlock(): Promise<boolean> {\n try {\n if (typeof window === \"undefined\") return false;\n\n if (!audioCtx || audioCtx.state === \"closed\") {\n const AudioContextClass = window.AudioContext || window.webkitAudioContext;\n if (!AudioContextClass) return false;\n\n audioCtx = new AudioContextClass({\n sampleRate: 48000,\n });\n }\n\n const ac = audioCtx;\n if (!ac) return false;\n\n try {\n await ac.resume();\n } catch {\n // Failed to resume AudioContext\n }\n\n attachAudioCtxStateListener();\n\n if (ac.state === \"running\") {\n rebuildSilentAudioTrack();\n cleanupAudioAutoUnlock();\n return true;\n }\n\n return false;\n } catch {\n // Error in unlock\n return false;\n }\n }\n\n // Setup auto unlock on creation\n setupAudioAutoUnlock();\n\n return {\n setOutputStream(stream: MediaStream): void {\n outputStream = stream;\n ensureSilentAudioTrack();\n },\n\n addTrack(track: MediaStreamTrack): void {\n if (!outputStream) return;\n\n try {\n // Remove silent track when adding external audio\n if (silentAudioTrack) {\n try {\n outputStream.removeTrack(silentAudioTrack);\n } catch {\n // Failed to remove silent track\n }\n }\n\n const exists = outputStream\n .getAudioTracks()\n .some((t) => t.id === track.id);\n if (!exists) {\n outputStream.addTrack(track);\n }\n externalAudioTrackIds.add(track.id);\n\n // Setup ended handler\n const onEnded = (): void => {\n try {\n if (!outputStream) return;\n outputStream.getAudioTracks().forEach((t) => {\n if (t.id === track.id) {\n try {\n outputStream!.removeTrack(t);\n } catch {\n // Failed to remove ended track\n }\n }\n });\n externalAudioTrackIds.delete(track.id);\n externalAudioEndHandlers.delete(track.id);\n\n if (outputStream.getAudioTracks().length === 0) {\n ensureSilentAudioTrack();\n }\n } catch {\n // Error in track ended handler\n }\n try {\n track.removeEventListener(\"ended\", onEnded);\n } catch {\n // Failed to remove ended listener\n }\n };\n\n track.addEventListener(\"ended\", onEnded);\n externalAudioEndHandlers.set(track.id, onEnded);\n } catch {\n // Error in addTrack\n }\n },\n\n removeTrack(trackId: string): void {\n if (!outputStream) return;\n\n outputStream.getAudioTracks().forEach((t) => {\n if (t.id === trackId) {\n outputStream!.removeTrack(t);\n }\n });\n\n externalAudioTrackIds.delete(trackId);\n\n const handler = externalAudioEndHandlers.get(trackId);\n const tracks = outputStream.getAudioTracks();\n const tr = tracks.find((t) => t.id === trackId);\n if (tr && handler) {\n try {\n tr.removeEventListener(\"ended\", handler);\n } catch {\n // Failed to remove ended listener\n }\n }\n externalAudioEndHandlers.delete(trackId);\n\n if (outputStream.getAudioTracks().length === 0) {\n ensureSilentAudioTrack();\n }\n },\n\n unlock,\n\n destroy(): void {\n cleanupAudioAutoUnlock();\n\n try {\n if (audioCtx && (audioCtx as AudioContext & { onstatechange: (() => void) | null }).onstatechange) {\n (audioCtx as AudioContext & { onstatechange: (() => void) | null }).onstatechange = null;\n }\n } catch {\n // Failed to clear state change handler\n }\n audioStateListenerAttached = false;\n\n // Cleanup external track handlers\n externalAudioEndHandlers.forEach((handler, id) => {\n try {\n const tr = outputStream?.getAudioTracks().find((t) => t.id === id);\n if (tr) tr.removeEventListener(\"ended\", handler);\n } catch {\n // Failed to cleanup track handler\n }\n });\n externalAudioEndHandlers.clear();\n externalAudioTrackIds.clear();\n\n removeSilentAudioTrack();\n outputStream = null;\n },\n };\n}\n","export interface VisibilityHandlerOptions {\n onHidden: () => void;\n onVisible: () => void;\n backgroundRenderFn: () => void;\n}\n\nexport interface VisibilityHandler {\n start(): void;\n stop(): void;\n readonly isHidden: boolean;\n}\n\nexport function createVisibilityHandler(\n options: VisibilityHandlerOptions,\n): VisibilityHandler {\n let isHidden = false;\n let backgroundIntervalId: number | null = null;\n let visibilityListener: (() => void) | null = null;\n let started = false;\n\n function onVisibilityChange(): void {\n if (typeof document === \"undefined\") return;\n\n const hidden = document.visibilityState === \"hidden\";\n\n if (hidden && !isHidden) {\n isHidden = true;\n options.onHidden();\n\n // Start background interval rendering\n if (backgroundIntervalId == null) {\n backgroundIntervalId = setInterval(() => {\n options.backgroundRenderFn();\n }, 1000) as unknown as number;\n }\n } else if (!hidden && isHidden) {\n isHidden = false;\n\n // Stop background interval\n if (backgroundIntervalId != null) {\n clearInterval(backgroundIntervalId);\n backgroundIntervalId = null;\n }\n\n options.onVisible();\n }\n }\n\n return {\n get isHidden(): boolean {\n return isHidden;\n },\n\n start(): void {\n if (started) return;\n if (typeof document === \"undefined\") return;\n\n started = true;\n visibilityListener = onVisibilityChange;\n document.addEventListener(\"visibilitychange\", visibilityListener);\n\n // Check initial state\n onVisibilityChange();\n },\n\n stop(): void {\n if (!started) return;\n started = false;\n\n if (typeof document !== \"undefined\" && visibilityListener) {\n try {\n document.removeEventListener(\"visibilitychange\", visibilityListener);\n } catch {\n // Failed to remove visibility listener\n }\n visibilityListener = null;\n }\n\n if (backgroundIntervalId != null) {\n clearInterval(backgroundIntervalId);\n backgroundIntervalId = null;\n }\n\n isHidden = false;\n },\n };\n}\n","import { createRegistry } from \"./internal/compositor/Registry\";\nimport { createRenderer, type Renderer } from \"./internal/compositor/Renderer\";\nimport { createScheduler, type Scheduler } from \"./internal/compositor/Scheduler\";\nimport { createAudioManager, type AudioManager } from \"./internal/compositor/AudioManager\";\nimport { createVisibilityHandler, type VisibilityHandler } from \"./internal/compositor/VisibilityHandler\";\nimport { TypedEventEmitter } from \"./internal/TypedEventEmitter\";\nimport type {\n Compositor as ICompositor,\n CompositorEventMap,\n CompositorOptions,\n Size,\n Source,\n} from \"./types/compositor\";\nimport type { SourceRegistry } from \"./internal/compositor/Registry\";\n\n/**\n * Composites multiple video/canvas sources into a single output MediaStream.\n *\n * The Compositor manages a registry of sources, renders the active source to an internal\n * canvas, and provides the output as a capturable MediaStream. It handles frame scheduling,\n * visibility changes (reducing FPS when the page is hidden), and audio track management.\n *\n * @example\n * ```ts\n * const compositor = createCompositor({ width: 1280, height: 720, fps: 30 });\n *\n * // Register and activate a video source\n * compositor.register(\"camera\", { kind: \"video\", element: videoElement, fit: \"cover\" });\n * compositor.activate(\"camera\");\n *\n * // Use the output stream for broadcasting\n * const broadcast = createBroadcast({ whipUrl, stream: compositor.stream });\n * ```\n */\nexport class Compositor extends TypedEventEmitter<CompositorEventMap> implements ICompositor {\n private readonly registry: SourceRegistry;\n private readonly renderer: Renderer;\n private readonly scheduler: Scheduler;\n private readonly audioManager: AudioManager;\n private readonly visibilityHandler: VisibilityHandler;\n\n private _activeId: string | null = null;\n private _fps: number;\n private _sendFps: number;\n private lastVisibleSendFps: number | null = null;\n private outputStream: MediaStream | null = null;\n private destroyed = false;\n\n constructor(options: CompositorOptions = {}) {\n super();\n\n const width = options.width ?? 512;\n const height = options.height ?? 512;\n this._fps = Math.max(1, options.fps ?? 30);\n this._sendFps = Math.max(1, options.sendFps ?? this._fps);\n const dpr = Math.min(\n 2,\n options.dpr ??\n (typeof window !== \"undefined\" ? window.devicePixelRatio || 1 : 1),\n );\n const keepalive = options.keepalive ?? true;\n\n // Create subsystems\n this.registry = createRegistry({\n onRegister: (id, source) => this.emit(\"registered\", id, source),\n onUnregister: (id) => this.emit(\"unregistered\", id),\n });\n\n this.renderer = createRenderer({\n width,\n height,\n dpr,\n keepalive,\n });\n\n this.scheduler = createScheduler({\n fps: this._fps,\n sendFps: this._sendFps,\n onFrame: (timestamp) => this.renderer.renderFrame(timestamp),\n onSendFpsChange: (fps) => {\n this._sendFps = fps;\n options.onSendFpsChange?.(fps);\n this.applyVideoTrackConstraints();\n },\n });\n\n this.audioManager = createAudioManager({\n autoUnlock: options.autoUnlockAudio ?? true,\n unlockEvents:\n options.unlockEvents && options.unlockEvents.length > 0\n ? options.unlockEvents\n : [\"pointerdown\", \"click\", \"touchstart\", \"keydown\"],\n disableSilentAudio: options.disableSilentAudio ?? false,\n });\n\n this.visibilityHandler = createVisibilityHandler({\n onHidden: () => {\n if (this.lastVisibleSendFps == null) this.lastVisibleSendFps = this._sendFps;\n if (this._sendFps !== 5) {\n this.scheduler.setSendFps(5);\n this._sendFps = 5;\n }\n },\n onVisible: () => {\n if (this.lastVisibleSendFps != null && this._sendFps !== this.lastVisibleSendFps) {\n this.scheduler.setSendFps(this.lastVisibleSendFps);\n this._sendFps = this.lastVisibleSendFps;\n }\n this.lastVisibleSendFps = null;\n },\n backgroundRenderFn: () => {\n this.renderer.renderFrame(performance.now());\n this.requestVideoTrackFrame();\n },\n });\n\n // Initialize\n this.outputStream = this.createOutputStream();\n this.audioManager.setOutputStream(this.outputStream);\n this.visibilityHandler.start();\n }\n\n // ============================================================================\n // Source Registry\n // ============================================================================\n\n /**\n * Registers a source with a unique ID.\n * @param id - Unique identifier for the source\n * @param source - The source configuration (video or canvas element)\n */\n register(id: string, source: Source): void {\n if (this.destroyed) return;\n this.registry.register(id, source);\n }\n\n /**\n * Unregisters a source by ID.\n * If the source is currently active, it will be deactivated first.\n * @param id - The source ID to unregister\n */\n unregister(id: string): void {\n if (this.destroyed) return;\n const wasActive = this._activeId === id;\n this.registry.unregister(id);\n\n if (wasActive) {\n this._activeId = null;\n this.renderer.setActiveSource(null);\n this.scheduler.stop();\n this.emit(\"activated\", null, undefined);\n }\n }\n\n /**\n * Gets a registered source by ID.\n * @param id - The source ID\n * @returns The source, or undefined if not found\n */\n get(id: string): Source | undefined {\n return this.registry.get(id);\n }\n\n /**\n * Checks if a source is registered.\n * @param id - The source ID to check\n * @returns True if the source is registered\n */\n has(id: string): boolean {\n return this.registry.has(id);\n }\n\n /**\n * Lists all registered sources.\n * @returns Array of source entries with id and source\n */\n list(): Array<{ id: string; source: Source }> {\n return this.registry.list();\n }\n\n // ============================================================================\n // Active Source Management\n // ============================================================================\n\n /**\n * Activates a registered source for rendering.\n * Only one source can be active at a time.\n * @param id - The source ID to activate\n * @throws {Error} If the source is not registered\n */\n activate(id: string): void {\n if (this.destroyed) return;\n\n const source = this.registry.get(id);\n if (!source) {\n throw new Error(`Source \"${id}\" not registered`);\n }\n\n this._activeId = id;\n this.renderer.setActiveSource(source);\n\n // Start scheduler with video element if applicable\n const videoEl = source.kind === \"video\" ? source.element : undefined;\n this.scheduler.start(videoEl);\n\n this.emit(\"activated\", id, source);\n }\n\n /**\n * Deactivates the current source.\n * The compositor will stop rendering until another source is activated.\n */\n deactivate(): void {\n if (this.destroyed) return;\n\n this._activeId = null;\n this.renderer.setActiveSource(null);\n this.scheduler.stop();\n this.emit(\"activated\", null, undefined);\n }\n\n /** ID of the currently active source, or null if none. */\n get activeId(): string | null {\n return this._activeId;\n }\n\n // ============================================================================\n // Output Stream\n // ============================================================================\n\n /** The composited output MediaStream. Can be used with Broadcast or other consumers. */\n get stream(): MediaStream {\n return this.outputStream!;\n }\n\n // ============================================================================\n // Settings\n // ============================================================================\n\n /**\n * Resizes the output canvas.\n * This recreates the output stream, so consumers may need to be updated.\n * @param width - New width in logical pixels\n * @param height - New height in logical pixels\n * @param dpr - Optional device pixel ratio (defaults to window.devicePixelRatio, capped at 2)\n */\n resize(width: number, height: number, dpr?: number): void {\n if (this.destroyed) return;\n\n const effectiveDpr = Math.min(\n 2,\n dpr ??\n (typeof window !== \"undefined\" ? window.devicePixelRatio || 1 : 1),\n );\n\n this.renderer.resize(width, height, effectiveDpr);\n this.recreateStream();\n }\n\n /** Current output size configuration. */\n get size(): Size {\n return this.renderer.size;\n }\n\n /**\n * Sets the rendering frame rate.\n * This recreates the output stream, so consumers may need to be updated.\n * @param fps - Frame rate (minimum 1)\n */\n setFps(fps: number): void {\n if (this.destroyed) return;\n\n const next = Math.max(1, fps);\n if (this._fps === next) return;\n\n this._fps = next;\n this.scheduler.setFps(next);\n this.recreateStream();\n }\n\n /** Current rendering frame rate. */\n get fps(): number {\n return this._fps;\n }\n\n /**\n * Sets the frame rate for sending to the stream.\n * Can be different from the rendering FPS (e.g., render at 60fps, send at 30fps).\n * @param fps - Frame rate (minimum 1)\n */\n setSendFps(fps: number): void {\n if (this.destroyed) return;\n\n const next = Math.max(1, fps);\n if (this._sendFps === next) return;\n\n this._sendFps = next;\n this.scheduler.setSendFps(next);\n }\n\n /** Current send frame rate. */\n get sendFps(): number {\n return this._sendFps;\n }\n\n // ============================================================================\n // Audio\n // ============================================================================\n\n /**\n * Adds an audio track to the output stream.\n * @param track - The MediaStreamTrack to add (must be an audio track)\n */\n addAudioTrack(track: MediaStreamTrack): void {\n if (this.destroyed) return;\n this.audioManager.addTrack(track);\n }\n\n /**\n * Removes an audio track from the output stream.\n * @param trackId - The track ID to remove\n */\n removeAudioTrack(trackId: string): void {\n if (this.destroyed) return;\n this.audioManager.removeTrack(trackId);\n }\n\n /**\n * Manually unlocks the audio context.\n * Usually not needed as audio is auto-unlocked on user interaction.\n * @returns True if the audio context was successfully unlocked\n */\n unlockAudio(): Promise<boolean> {\n if (this.destroyed) return Promise.resolve(false);\n return this.audioManager.unlock();\n }\n\n // ============================================================================\n // Lifecycle\n // ============================================================================\n\n /**\n * Destroys the compositor and releases all resources.\n * After calling this, the instance cannot be reused.\n */\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n\n this.scheduler.stop();\n this.visibilityHandler.stop();\n this.audioManager.destroy();\n this.renderer.destroy();\n this.registry.clear();\n\n // Stop video tracks\n if (this.outputStream) {\n try {\n this.outputStream.getVideoTracks().forEach((t) => {\n try {\n t.stop();\n } catch {\n // Failed to stop video track\n }\n });\n } catch {\n // Failed to get video tracks\n }\n }\n\n this.outputStream = null;\n this.clearListeners();\n }\n\n // ============================================================================\n // Private Helpers\n // ============================================================================\n\n private createOutputStream(): MediaStream {\n const stream = this.renderer.captureCanvas.captureStream(this._fps);\n\n // Set video track content hint\n try {\n const vtrack = stream.getVideoTracks()[0];\n if (vtrack && vtrack.contentHint !== undefined) {\n vtrack.contentHint = \"detail\";\n }\n } catch {\n // Failed to set video track content hint\n }\n\n return stream;\n }\n\n private recreateStream(): void {\n const newStream = this.createOutputStream();\n const prev = this.outputStream;\n\n // Transfer audio tracks\n if (prev && prev !== newStream) {\n try {\n prev.getAudioTracks().forEach((t) => {\n try {\n newStream.addTrack(t);\n } catch {\n // Failed to transfer audio track\n }\n });\n } catch {\n // Failed to get audio tracks\n }\n }\n\n this.outputStream = newStream;\n this.audioManager.setOutputStream(newStream);\n this.applyVideoTrackConstraints();\n\n // Stop old video tracks\n if (prev && prev !== newStream) {\n try {\n prev.getVideoTracks().forEach((t) => {\n try {\n t.stop();\n } catch {\n // Failed to stop video track\n }\n });\n } catch {\n // Failed to get video tracks\n }\n }\n }\n\n private applyVideoTrackConstraints(): void {\n try {\n const track = this.outputStream?.getVideoTracks()[0];\n const canvas = this.renderer.captureCanvas;\n if (!track || !canvas) return;\n\n const constraints: MediaTrackConstraints = {\n width: canvas.width,\n height: canvas.height,\n frameRate: Math.max(1, this._sendFps || this._fps),\n };\n\n try {\n if ((track as MediaStreamTrack & { contentHint?: string }).contentHint !== undefined) {\n (track as MediaStreamTrack & { contentHint?: string }).contentHint = \"detail\";\n }\n } catch {\n // Failed to set content hint\n }\n\n track.applyConstraints(constraints).catch(() => {\n // Failed to apply constraints\n });\n } catch {\n // Error in applyVideoTrackConstraints\n }\n }\n\n private requestVideoTrackFrame(): void {\n const track = this.outputStream?.getVideoTracks()[0];\n if (track && typeof (track as MediaStreamTrack & { requestFrame?: () => void }).requestFrame === \"function\") {\n try {\n (track as MediaStreamTrack & { requestFrame: () => void }).requestFrame();\n } catch {\n // Failed to request video frame\n }\n }\n }\n}\n\n/**\n * Creates a new Compositor instance with the given options.\n *\n * @param options - Compositor configuration\n * @returns A new Compositor instance\n *\n * @example\n * ```ts\n * const compositor = createCompositor({\n * width: 1280,\n * height: 720,\n * fps: 30,\n * });\n *\n * compositor.register(\"camera\", { kind: \"video\", element: videoEl, fit: \"cover\" });\n * compositor.activate(\"camera\");\n *\n * // Use compositor.stream for broadcasting\n * ```\n */\nexport function createCompositor(options: CompositorOptions = {}): Compositor {\n return new Compositor(options);\n}\n"],"mappings":"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","names":["createBroadcast","createPlayer","DEFAULT_CONNECTION_TIMEOUT","createBroadcast","createPlayer"]}
|