@daydreamlive/browser 0.1.0 → 0.1.1
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 +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
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"],"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 BroadcastOptions,\n PlayerOptions,\n BroadcastState,\n PlayerState,\n ReconnectConfig,\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\";\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 onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n onResponse?: (response: Response) => WHIPResponseResult | void;\n}\n\nexport interface PlayerOptions {\n reconnect?: ReconnectConfig;\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 VideoConfig {\n bitrate?: number;\n maxFramerate?: number;\n}\n\nexport interface BroadcastEventMap {\n stateChange: (state: BroadcastState) => void;\n error: (error: DaydreamError) => void;\n}\n\nexport interface PlayerEventMap {\n stateChange: (state: PlayerState) => void;\n error: (error: DaydreamError) => 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 = 2_000_000;\nexport const DEFAULT_AUDIO_BITRATE = 64_000;\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 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\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 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.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 await this.applyBitrateConstraints();\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 10000,\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 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 return this.pc !== null && this.pc.connectionState === \"connected\";\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 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 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 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.onconnectionstatechange = () => {\n if (this.state === \"ended\") return;\n\n const connState = pc.connectionState;\n\n if (connState === \"connected\") {\n this.clearGraceTimeout();\n if (this.state === \"reconnecting\") {\n this.stateMachine.transition(\"live\");\n this.reconnectAttempts = 0;\n }\n return;\n }\n\n if (connState === \"disconnected\") {\n this.clearGraceTimeout();\n this.whipClient.restartIce();\n\n this.disconnectedGraceTimeout = setTimeout(() => {\n if (this.state === \"ended\") return;\n const currentState = pc.connectionState;\n if (currentState === \"disconnected\") {\n this.scheduleReconnect();\n }\n }, 2000);\n return;\n }\n\n if (connState === \"failed\" || connState === \"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.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 onStats,\n statsIntervalMs,\n onResponse,\n } = options;\n\n return new Broadcast({\n whipUrl,\n stream,\n reconnect,\n whipConfig: {\n videoBitrate: video?.bitrate,\n maxFramerate: video?.maxFramerate,\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 onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n peerConnectionFactory?: PeerConnectionFactory;\n fetch?: FetchFn;\n timers?: TimerProvider;\n mediaStreamFactory?: MediaStreamFactory;\n}\n\nexport class WHEPClient {\n private readonly url: string;\n private readonly iceServers: RTCIceServer[];\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.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 await this.waitForIceGathering();\n\n this.abortController = new AbortController();\n const timeoutId = this.timers.setTimeout(\n () => this.abortController?.abort(),\n 10000,\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 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 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 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 (this.reconnectConfig.enabled && this.reconnectAttempts < (this.reconnectConfig.maxAttempts ?? 30)) {\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 ?? 10;\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 ?? 300;\n const delay = this.calculateReconnectDelay(\n this.reconnectAttempts,\n baseDelay,\n );\n this.reconnectAttempts++;\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 onStats: options?.onStats,\n statsIntervalMs: options?.statsIntervalMs,\n },\n });\n}\n"],"mappings":"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","names":["createBroadcast","createPlayer","createBroadcast","createPlayer"]}
|
|
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"],"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 BroadcastOptions,\n PlayerOptions,\n BroadcastState,\n PlayerState,\n ReconnectConfig,\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\";\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 onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n onResponse?: (response: Response) => WHIPResponseResult | void;\n}\n\nexport interface PlayerOptions {\n reconnect?: ReconnectConfig;\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 VideoConfig {\n bitrate?: number;\n maxFramerate?: number;\n}\n\nexport interface BroadcastEventMap {\n stateChange: (state: BroadcastState) => void;\n error: (error: DaydreamError) => void;\n}\n\nexport interface PlayerEventMap {\n stateChange: (state: PlayerState) => void;\n error: (error: DaydreamError) => 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","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 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\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 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.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 await this.applyBitrateConstraints();\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 10000,\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 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 return this.pc !== null && this.pc.connectionState === \"connected\";\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 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 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 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.onconnectionstatechange = () => {\n if (this.state === \"ended\") return;\n\n const connState = pc.connectionState;\n\n if (connState === \"connected\") {\n this.clearGraceTimeout();\n if (this.state === \"reconnecting\") {\n this.stateMachine.transition(\"live\");\n this.reconnectAttempts = 0;\n }\n return;\n }\n\n if (connState === \"disconnected\") {\n this.clearGraceTimeout();\n this.whipClient.restartIce();\n\n this.disconnectedGraceTimeout = setTimeout(() => {\n if (this.state === \"ended\") return;\n const currentState = pc.connectionState;\n if (currentState === \"disconnected\") {\n this.scheduleReconnect();\n }\n }, 2000);\n return;\n }\n\n if (connState === \"failed\" || connState === \"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.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 onStats,\n statsIntervalMs,\n onResponse,\n } = options;\n\n return new Broadcast({\n whipUrl,\n stream,\n reconnect,\n whipConfig: {\n videoBitrate: video?.bitrate,\n maxFramerate: video?.maxFramerate,\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 onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n peerConnectionFactory?: PeerConnectionFactory;\n fetch?: FetchFn;\n timers?: TimerProvider;\n mediaStreamFactory?: MediaStreamFactory;\n}\n\nexport class WHEPClient {\n private readonly url: string;\n private readonly iceServers: RTCIceServer[];\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.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 await this.waitForIceGathering();\n\n this.abortController = new AbortController();\n const timeoutId = this.timers.setTimeout(\n () => this.abortController?.abort(),\n 10000,\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 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 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 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 (this.reconnectConfig.enabled && this.reconnectAttempts < (this.reconnectConfig.maxAttempts ?? 30)) {\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 ?? 10;\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 ?? 300;\n const delay = this.calculateReconnectDelay(\n this.reconnectAttempts,\n baseDelay,\n );\n this.reconnectAttempts++;\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 onStats: options?.onStats,\n statsIntervalMs: options?.statsIntervalMs,\n },\n });\n}\n"],"mappings":"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","names":["createBroadcast","createPlayer","createBroadcast","createPlayer"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -40,7 +40,7 @@ interface DaydreamError extends Error {
|
|
|
40
40
|
}
|
|
41
41
|
type DaydreamErrorCode = "NETWORK_ERROR" | "CONNECTION_FAILED" | "STREAM_NOT_FOUND" | "UNAUTHORIZED" | "UNKNOWN";
|
|
42
42
|
declare const DEFAULT_ICE_SERVERS: RTCIceServer[];
|
|
43
|
-
declare const DEFAULT_VIDEO_BITRATE =
|
|
43
|
+
declare const DEFAULT_VIDEO_BITRATE = 300000;
|
|
44
44
|
declare const DEFAULT_AUDIO_BITRATE = 64000;
|
|
45
45
|
|
|
46
46
|
interface PeerConnectionFactory {
|
package/dist/index.d.ts
CHANGED
|
@@ -40,7 +40,7 @@ interface DaydreamError extends Error {
|
|
|
40
40
|
}
|
|
41
41
|
type DaydreamErrorCode = "NETWORK_ERROR" | "CONNECTION_FAILED" | "STREAM_NOT_FOUND" | "UNAUTHORIZED" | "UNKNOWN";
|
|
42
42
|
declare const DEFAULT_ICE_SERVERS: RTCIceServer[];
|
|
43
|
-
declare const DEFAULT_VIDEO_BITRATE =
|
|
43
|
+
declare const DEFAULT_VIDEO_BITRATE = 300000;
|
|
44
44
|
declare const DEFAULT_AUDIO_BITRATE = 64000;
|
|
45
45
|
|
|
46
46
|
interface PeerConnectionFactory {
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../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/index.ts"],"sourcesContent":["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 onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n onResponse?: (response: Response) => WHIPResponseResult | void;\n}\n\nexport interface PlayerOptions {\n reconnect?: ReconnectConfig;\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 VideoConfig {\n bitrate?: number;\n maxFramerate?: number;\n}\n\nexport interface BroadcastEventMap {\n stateChange: (state: BroadcastState) => void;\n error: (error: DaydreamError) => void;\n}\n\nexport interface PlayerEventMap {\n stateChange: (state: PlayerState) => void;\n error: (error: DaydreamError) => 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 = 2_000_000;\nexport const DEFAULT_AUDIO_BITRATE = 64_000;\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 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\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 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.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 await this.applyBitrateConstraints();\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 10000,\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 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 return this.pc !== null && this.pc.connectionState === \"connected\";\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 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 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 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.onconnectionstatechange = () => {\n if (this.state === \"ended\") return;\n\n const connState = pc.connectionState;\n\n if (connState === \"connected\") {\n this.clearGraceTimeout();\n if (this.state === \"reconnecting\") {\n this.stateMachine.transition(\"live\");\n this.reconnectAttempts = 0;\n }\n return;\n }\n\n if (connState === \"disconnected\") {\n this.clearGraceTimeout();\n this.whipClient.restartIce();\n\n this.disconnectedGraceTimeout = setTimeout(() => {\n if (this.state === \"ended\") return;\n const currentState = pc.connectionState;\n if (currentState === \"disconnected\") {\n this.scheduleReconnect();\n }\n }, 2000);\n return;\n }\n\n if (connState === \"failed\" || connState === \"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.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 onStats,\n statsIntervalMs,\n onResponse,\n } = options;\n\n return new Broadcast({\n whipUrl,\n stream,\n reconnect,\n whipConfig: {\n videoBitrate: video?.bitrate,\n maxFramerate: video?.maxFramerate,\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 onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n peerConnectionFactory?: PeerConnectionFactory;\n fetch?: FetchFn;\n timers?: TimerProvider;\n mediaStreamFactory?: MediaStreamFactory;\n}\n\nexport class WHEPClient {\n private readonly url: string;\n private readonly iceServers: RTCIceServer[];\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.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 await this.waitForIceGathering();\n\n this.abortController = new AbortController();\n const timeoutId = this.timers.setTimeout(\n () => this.abortController?.abort(),\n 10000,\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 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 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 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 (this.reconnectConfig.enabled && this.reconnectAttempts < (this.reconnectConfig.maxAttempts ?? 30)) {\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 ?? 10;\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 ?? 300;\n const delay = this.calculateReconnectDelay(\n this.reconnectAttempts,\n baseDelay,\n );\n this.reconnectAttempts++;\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 onStats: options?.onStats,\n statsIntervalMs: options?.statsIntervalMs,\n },\n });\n}\n","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 BroadcastOptions,\n PlayerOptions,\n BroadcastState,\n PlayerState,\n ReconnectConfig,\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\";\n"],"mappings":"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","names":["createBroadcast","createPlayer"]}
|
|
1
|
+
{"version":3,"sources":["../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/index.ts"],"sourcesContent":["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 onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n onResponse?: (response: Response) => WHIPResponseResult | void;\n}\n\nexport interface PlayerOptions {\n reconnect?: ReconnectConfig;\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 VideoConfig {\n bitrate?: number;\n maxFramerate?: number;\n}\n\nexport interface BroadcastEventMap {\n stateChange: (state: BroadcastState) => void;\n error: (error: DaydreamError) => void;\n}\n\nexport interface PlayerEventMap {\n stateChange: (state: PlayerState) => void;\n error: (error: DaydreamError) => 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","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 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\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 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.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 await this.applyBitrateConstraints();\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 10000,\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 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 return this.pc !== null && this.pc.connectionState === \"connected\";\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 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 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 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.onconnectionstatechange = () => {\n if (this.state === \"ended\") return;\n\n const connState = pc.connectionState;\n\n if (connState === \"connected\") {\n this.clearGraceTimeout();\n if (this.state === \"reconnecting\") {\n this.stateMachine.transition(\"live\");\n this.reconnectAttempts = 0;\n }\n return;\n }\n\n if (connState === \"disconnected\") {\n this.clearGraceTimeout();\n this.whipClient.restartIce();\n\n this.disconnectedGraceTimeout = setTimeout(() => {\n if (this.state === \"ended\") return;\n const currentState = pc.connectionState;\n if (currentState === \"disconnected\") {\n this.scheduleReconnect();\n }\n }, 2000);\n return;\n }\n\n if (connState === \"failed\" || connState === \"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.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 onStats,\n statsIntervalMs,\n onResponse,\n } = options;\n\n return new Broadcast({\n whipUrl,\n stream,\n reconnect,\n whipConfig: {\n videoBitrate: video?.bitrate,\n maxFramerate: video?.maxFramerate,\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 onStats?: (report: RTCStatsReport) => void;\n statsIntervalMs?: number;\n peerConnectionFactory?: PeerConnectionFactory;\n fetch?: FetchFn;\n timers?: TimerProvider;\n mediaStreamFactory?: MediaStreamFactory;\n}\n\nexport class WHEPClient {\n private readonly url: string;\n private readonly iceServers: RTCIceServer[];\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.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 await this.waitForIceGathering();\n\n this.abortController = new AbortController();\n const timeoutId = this.timers.setTimeout(\n () => this.abortController?.abort(),\n 10000,\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 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 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 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 (this.reconnectConfig.enabled && this.reconnectAttempts < (this.reconnectConfig.maxAttempts ?? 30)) {\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 ?? 10;\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 ?? 300;\n const delay = this.calculateReconnectDelay(\n this.reconnectAttempts,\n baseDelay,\n );\n this.reconnectAttempts++;\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 onStats: options?.onStats,\n statsIntervalMs: options?.statsIntervalMs,\n },\n });\n}\n","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 BroadcastOptions,\n PlayerOptions,\n BroadcastState,\n PlayerState,\n ReconnectConfig,\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\";\n"],"mappings":"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","names":["createBroadcast","createPlayer"]}
|