@qencode/calls 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/call.ts", "../src/errors.ts", "../src/events.ts", "../src/credential.ts", "../src/profiles.ts", "../src/latency.ts", "../src/regions.ts", "../src/stats.ts", "../src/telemetry.ts", "../src/devices.ts", "../src/render.ts", "../src/version.ts", "../src/index.ts"],
4
- "sourcesContent": ["import {\n Room, RoomEvent, ConnectionState, DisconnectReason, Track, setLogLevel,\n type RemoteParticipant, type RemoteTrack, type Participant, type TrackPublication,\n type RoomConnectOptions, type TrackPublishOptions, type VideoCaptureOptions, type AudioCaptureOptions,\n type LocalVideoTrack, DataPacket_Kind, ConnectionError, ConnectionErrorReason } from 'livekit-client';\nimport { CallError, mapEngineError } from './errors';\nimport { Emitter } from './events';\nimport { parseCredential, isExpired, msUntilExpiryWarning, type CallCredential, type ParsedCredential } from './credential';\nimport { resolveProfile, DEFAULT_PROFILE, AUDIO_BITRATE, type VideoProfileName, type VideoProfile } from './profiles';\nimport { latencySettings, applyJitterBufferTarget, applyDegradationPreference, DEFAULT_LATENCY_MODE, type LatencyMode } from './latency';\nimport { chooseRegion, type RegionChoice } from './regions';\nimport { DeltaTracker, QualityTracker, collectRecv, collectSend, estimateLatency, absCaptureLatency, type CallStats, type Quality, type Direction, type AudioRoute } from './stats';\nimport { Telemetry, type TelemetryFields } from './telemetry';\nimport { Devices, type DeviceList } from './devices';\nimport { wrapTrack, type VideoHandle } from './render';\nimport { SDK_VERSION } from './version';\n\nexport type CallState = 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'ended';\nexport type EndReason = 'left' | 'peerLeft' | 'roomClosed' | 'network' | 'credential' | 'error' | 'roomFull';\nexport type LogLevelName = 'debug' | 'info' | 'warn' | 'error' | 'silent';\n\nexport interface Peer {\n identity: string;\n name: string | null;\n audioMuted: boolean;\n videoMuted: boolean;\n}\n\n/** A data message from the peer. Strings and JSON objects arrive as sent; bytes arrive as Uint8Array. */\nexport type MessagePayload = string | Uint8Array | Record<string, unknown> | unknown[];\n\nexport interface ModerationEvent { level: 'warn' | 'mute' | 'end'; classes: string[]; at: number }\n\n/** Video codecs an app may ask for. H.264 is the default; the engine negotiates VP8 when a peer cannot decode the choice. */\nexport type VideoCodec = 'h264' | 'vp8' | 'vp9' | 'av1';\nexport const VIDEO_CODECS: readonly VideoCodec[] = Object.freeze(['h264', 'vp8', 'vp9', 'av1']);\n\n/**\n * Builds the video track to publish for a profile: size a canvas, open a screen, wrap a processed\n * camera. Called on every publish and republish, so a profile switch reaches it with the new size.\n */\nexport type VideoSourceFactory = (profile: VideoProfile) => MediaStreamTrack | Promise<MediaStreamTrack>;\nexport type VideoSource = MediaStreamTrack | VideoSourceFactory;\n\n/** Which receiver property took the jitter buffer target; null before the first remote video track. */\nexport type JitterBufferSupport = 'jitterBufferTarget' | 'playoutDelayHint' | 'unsupported' | null;\n\n/**\n * App fields for every telemetry row, called once per row with its direction. `g2g_p50`, `g2g_p95`\n * and `g2g_samples` (the app's own measured glass-to-glass latency, ms) are stored as columns;\n * every other key lands in the row's `extra` object.\n */\nexport type TelemetryExtra = (direction: Direction) => TelemetryFields | null | undefined;\n\nexport interface CallOptions {\n /** Publish the microphone on connect. Default true. */\n audio?: boolean;\n /** Publish the camera on connect. Default true. */\n video?: boolean;\n /** Named media tier. Default p540_60. */\n videoProfile?: VideoProfileName;\n /** `lowest` (default) or `smooth`. */\n latencyMode?: LatencyMode;\n /** Pin a region name from the credential; default picks the fastest by probe. */\n region?: string | null;\n /** Post quality stats to Qencode every 5 s. Default true. */\n telemetry?: boolean;\n /** Resume after network changes for up to 60 s. Default true. */\n autoReconnect?: boolean;\n /** Default 'warn'. Never logs media or credentials. */\n logLevel?: LogLevelName;\n /** API base used only by telemetry. Default https://api.qencode.com, or the credential's api_base. */\n apiBase?: string;\n /** Initial camera and microphone device ids. */\n cameraId?: string;\n microphoneId?: string;\n /** End the call when the peer leaves. Default true: a 1:1 call is over when one side is gone. */\n endOnPeerLeft?: boolean;\n /**\n * Let the engine adapt what it sends and receives to how the video is displayed (default true).\n * The receiver asks for the layer matching the rendered size, and a video element that is\n * hidden or in a background tab pauses that track on the server. Set false to always\n * receive and send the full profile regardless of visibility, as a measurement bench does.\n */\n adaptiveStream?: boolean;\n /**\n * Publish this track instead of opening the camera: a canvas, a screen, a processed camera. A\n * factory is called with the profile on every publish and republish. The SDK stops a track a\n * factory returned when it is replaced or the call ends; a track passed directly stays yours to\n * stop. `devices.setCamera` does not apply while a custom source is published.\n */\n videoSource?: VideoSource;\n /** Video codec to publish. Default `h264`. */\n codec?: VideoCodec;\n /** Override the profile's simulcast setting. Default follows the profile. */\n simulcast?: boolean;\n /** Jitter buffer target in ms, overriding the latency mode's. `setLatencyMode` clears it. */\n jitterBufferTargetMs?: number;\n /** Fields appended to every telemetry row. */\n telemetryExtra?: TelemetryExtra;\n /** Forces TURN relay, for measuring the relay path. */\n forceRelay?: boolean;\n}\n\ntype OptionalKey = 'cameraId' | 'microphoneId' | 'region' | 'forceRelay' | 'videoSource' | 'simulcast' | 'jitterBufferTargetMs' | 'telemetryExtra';\n\nexport type CallEvents = {\n stateChanged: [CallState, EndReason | null];\n peerJoined: [Peer];\n peerLeft: [Peer];\n remoteVideo: [VideoHandle | null];\n remoteAudio: [VideoHandle | null];\n peerMuted: ['audio' | 'video', boolean];\n stats: [CallStats];\n qualityChanged: [Quality, Direction];\n message: [MessagePayload, boolean];\n credentialExpiring: [number];\n devicesChanged: [DeviceList];\n moderation: [ModerationEvent];\n error: [CallError];\n};\n\nconst DEFAULT_API_BASE = 'https://api.qencode.com';\nconst MSG_TOPIC = 'qencode:msg';\nconst STATS_TOPIC = 'qencode:stats';\nconst MSG_MAX_BYTES = 15 * 1024;\nconst MSG_MAX_PER_SECOND = 30;\nconst STATS_INTERVAL_MS = 1000;\nconst RECONNECT_WINDOW_MS = 60_000;\n\nconst enc = new TextEncoder();\nconst dec = new TextDecoder();\n\n/**\n * One 1:1 call. Create it from a credential minted by your backend, attach the video handles to\n * your views, and call `connect()`. The engine underneath is not part of this API.\n */\nexport class Call {\n static create(credential: CallCredential, options: CallOptions = {}): Call {\n return new Call(parseCredential(credential), options);\n }\n\n readonly devices = new Devices();\n readonly options: Readonly<Required<Omit<CallOptions, OptionalKey>> & Pick<CallOptions, OptionalKey>>;\n\n private readonly emitter = new Emitter<CallEvents>();\n private cred: ParsedCredential;\n private _state: CallState = 'idle';\n private _endReason: EndReason | null = null;\n private room: Room | null = null;\n private profile: VideoProfile;\n private latency: LatencyMode;\n private _codec: VideoCodec;\n private simulcastOverride: boolean | null;\n private jbOverride: number | null;\n private jbSupport: JitterBufferSupport = null;\n private videoSource: VideoSource | null;\n /** The MediaStreamTrack currently published from `videoSource`, and whether a factory made it (then the SDK stops it). */\n private sourceTrack: MediaStreamTrack | null = null;\n private sourceOwned = false;\n private regionChoice: RegionChoice | null = null;\n private _peer: Peer | null = null;\n private agentPresent = false;\n private remoteVideoTrack: RemoteTrack | null = null;\n private remoteAudioTrack: RemoteTrack | null = null;\n private _localVideo: VideoHandle | null = null;\n private _remoteVideo: VideoHandle | null = null;\n private _remoteAudio: VideoHandle | null = null;\n private audioEl: HTMLMediaElement | null = null;\n private statsTimer: ReturnType<typeof setInterval> | null = null;\n private expiryTimer: ReturnType<typeof setTimeout> | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private telemetry: Telemetry | null = null;\n private readonly recvTracker = new DeltaTracker();\n private readonly sendTracker = new DeltaTracker();\n private readonly recvQuality = new QualityTracker();\n private readonly sendQuality = new QualityTracker();\n private peerRttMs: number | null = null;\n private joinMs: number | null = null;\n private _stats: CallStats | null = null;\n private msgTimes: number[] = [];\n private leaving = false;\n private pendingEnd: EndReason | null = null;\n\n private constructor(cred: ParsedCredential, options: CallOptions) {\n this.cred = cred;\n this.options = Object.freeze({\n audio: options.audio ?? true,\n video: options.video ?? true,\n videoProfile: options.videoProfile ?? DEFAULT_PROFILE,\n latencyMode: options.latencyMode ?? DEFAULT_LATENCY_MODE,\n telemetry: options.telemetry ?? true,\n autoReconnect: options.autoReconnect ?? true,\n logLevel: options.logLevel ?? 'warn',\n apiBase: options.apiBase ?? cred.apiBase ?? DEFAULT_API_BASE,\n endOnPeerLeft: options.endOnPeerLeft ?? true,\n adaptiveStream: options.adaptiveStream ?? true,\n codec: options.codec ?? 'h264',\n cameraId: options.cameraId, microphoneId: options.microphoneId, region: options.region ?? null, forceRelay: options.forceRelay,\n videoSource: options.videoSource, simulcast: options.simulcast, jitterBufferTargetMs: options.jitterBufferTargetMs, telemetryExtra: options.telemetryExtra,\n });\n this.profile = resolveProfile(this.options.videoProfile);\n this.latency = this.options.latencyMode;\n latencySettings(this.latency); // validates\n this._codec = checkCodec(this.options.codec);\n this.simulcastOverride = typeof options.simulcast === 'boolean' ? options.simulcast : null;\n this.jbOverride = options.jitterBufferTargetMs === undefined ? null : checkJitterTarget(options.jitterBufferTargetMs);\n this.videoSource = options.videoSource ?? null;\n this.devices._setCustomVideo(this.videoSource !== null);\n try { setLogLevel(this.options.logLevel); } catch { /* logger unavailable in this build */ }\n }\n\n // ------------------------------------------------------------------ public state\n\n get state(): CallState { return this._state; }\n get endReason(): EndReason | null { return this._endReason; }\n get peer(): Peer | null { return this._peer ? { ...this._peer } : null; }\n get localVideo(): VideoHandle | null { return this._localVideo; }\n get remoteVideo(): VideoHandle | null { return this._remoteVideo; }\n get remoteAudio(): VideoHandle | null { return this._remoteAudio; }\n get stats(): CallStats | null { return this._stats; }\n get videoProfile(): VideoProfileName { return this.profile.name; }\n get latencyMode(): LatencyMode { return this.latency; }\n get videoCodec(): VideoCodec { return this._codec; }\n /** Whether video is published with simulcast layers: the override when set, else the profile's setting. */\n get simulcast(): boolean { return this.simulcastOverride ?? this.profile.simulcast; }\n /** The jitter buffer target in force: the override when set, else the latency mode's. */\n get jitterBufferTargetMs(): number { return this.jbOverride ?? latencySettings(this.latency).jitterBufferTargetMs; }\n get jitterBufferSupport(): JitterBufferSupport { return this.jbSupport; }\n /** Region probe results in ms by name, or null when no probe ran (one region, or a pinned one). */\n get regionProbe(): Record<string, number> | null { const p = this.regionChoice?.probe; return p && Object.keys(p).length ? { ...p } : null; }\n get identity(): string { return this.cred.identity; }\n get callId(): string | null { return this.cred.callId; }\n get region(): string | null { return this.regionChoice?.region.name ?? null; }\n get credentialExpiresAt(): number | null { return this.cred.expiresAt; }\n get agentJoined(): boolean { return this.agentPresent; }\n\n on<K extends keyof CallEvents>(event: K, handler: (...args: CallEvents[K]) => void): () => void { return this.emitter.on(event, handler); }\n once<K extends keyof CallEvents>(event: K, handler: (...args: CallEvents[K]) => void): () => void { return this.emitter.once(event, handler); }\n off<K extends keyof CallEvents>(event: K, handler: (...args: CallEvents[K]) => void): void { this.emitter.off(event, handler); }\n\n // ------------------------------------------------------------------ lifecycle\n\n async connect(): Promise<void> {\n if (this._state !== 'idle') throw new CallError('internal', `connect() called in state \"${this._state}\"; create a new Call to connect again.`, { retryable: false });\n if (typeof navigator === 'undefined' || !navigator.mediaDevices) throw new CallError('unsupported', 'WebRTC media devices are not available here; a secure context (HTTPS or localhost) is required.');\n if (isExpired(this.cred)) {\n this.emitter.emit('credentialExpiring', this.cred.expiresAt ?? Date.now());\n throw new CallError('credentialExpired', 'The credential has expired; fetch a new one from your backend.');\n }\n this.setState('connecting', null);\n const t0 = now();\n try {\n this.regionChoice = await chooseRegion(this.cred.regions, this.options.region);\n const room = this.buildRoom();\n this.room = room;\n this.devices._attachRoom(room);\n this.devices._start();\n const connectOpts: RoomConnectOptions = { autoSubscribe: true };\n if (this.options.forceRelay) connectOpts.rtcConfig = { iceTransportPolicy: 'relay' };\n await room.connect(this.regionChoice.region.url, this.cred.token, connectOpts);\n if (this.leaving) throw new CallError('internal', 'Left during connect.', { retryable: false });\n this.adoptExistingParticipants(room);\n if (this.countHumans(room) >= 2) {\n this.pendingEnd = 'roomFull';\n await this.teardown();\n throw new CallError('roomFull', 'The call already has two participants.');\n }\n if (this.options.audio) await this.publishAudio();\n if (this.options.video && this.profile.video) await this.publishVideo();\n this.joinMs = Math.round(now() - t0);\n this.setState('connected', null);\n // A peer already in the room never triggers ParticipantConnected; report it the same way.\n if (this._peer) this.emitter.emit('peerJoined', { ...this._peer });\n this.scheduleExpiryWarning();\n this.startStats();\n this.telemetry = new Telemetry({ apiBase: this.options.apiBase, callId: this.cred.callId, token: this.cred.token, enabled: this.options.telemetry, sdkVersion: SDK_VERSION });\n this.telemetry.start(this.joinMs);\n this.sendHello();\n } catch (e) {\n let err = mapEngineError(e);\n if (err.code === 'network' && await this.joinRefusedByServer(e)) err = new CallError('roomFull', 'The call already has two participants.', { cause: e });\n this.pendingEnd = this.pendingEnd ?? reasonForError(err);\n // End first so the error reaches listeners; the engine's Disconnected during teardown then finds the call already ended.\n this.finish(this.pendingEnd, err);\n await this.teardown();\n throw err;\n }\n }\n\n async leave(): Promise<void> {\n if (this._state === 'ended') return;\n this.leaving = true;\n this.pendingEnd = this.pendingEnd ?? 'left';\n await this.teardown();\n this.finish(this.pendingEnd, null);\n }\n\n /** Replace the credential (same call, same identity) so the next reconnect uses a fresh token. */\n updateCredential(credential: CallCredential): void {\n const next = parseCredential(credential);\n if (next.roomName !== this.cred.roomName || next.identity !== this.cred.identity) {\n throw new CallError('credentialInvalid', 'The new credential is for a different call or identity.', { retryable: false });\n }\n this.cred = next;\n if (this._state === 'connected' || this._state === 'reconnecting') this.scheduleExpiryWarning();\n }\n\n /**\n * A media server refuses a join with a bare websocket close, and a browser never sees the\n * reason. When the server's validate endpoint still accepts the very same credential, the\n * refusal was not the token, the room or the network; on a two-person room it is capacity.\n * One short request on the failure path only.\n */\n private async joinRefusedByServer(e: unknown): Promise<boolean> {\n if (!(e instanceof ConnectionError)) return false;\n if (e.reason !== ConnectionErrorReason.WebSocket && e.reason !== ConnectionErrorReason.InternalError) return false;\n const region = this.regionChoice?.region;\n if (!region || typeof fetch !== 'function') return false;\n try {\n const url = new URL(region.url);\n url.protocol = url.protocol === 'ws:' || url.protocol === 'http:' ? 'http:' : 'https:';\n url.pathname = `${url.pathname.replace(/\\/+$/, '')}/rtc/validate`;\n url.search = `access_token=${encodeURIComponent(this.cred.token)}`;\n const ctl = typeof AbortController === 'function' ? new AbortController() : undefined;\n const timer = setTimeout(() => ctl?.abort(), 3000);\n try {\n const r = await fetch(url.toString(), { cache: 'no-store', credentials: 'omit', signal: ctl?.signal });\n return r.status === 200;\n } finally { clearTimeout(timer); }\n } catch { return false; }\n }\n\n // ------------------------------------------------------------------ media controls\n\n async setMicrophoneEnabled(enabled: boolean): Promise<void> {\n const room = this.requireRoom();\n try {\n if (enabled && !room.localParticipant.getTrackPublication(Track.Source.Microphone)) await this.publishAudio();\n else await room.localParticipant.setMicrophoneEnabled(enabled);\n } catch (e) { throw mapEngineError(e); }\n }\n\n async setCameraEnabled(enabled: boolean): Promise<void> {\n const room = this.requireRoom();\n try {\n if (enabled) {\n if (!this.profile.video) this.profile = resolveProfile(DEFAULT_PROFILE);\n if (!room.localParticipant.getTrackPublication(Track.Source.Camera)) await this.publishVideo();\n else await room.localParticipant.setCameraEnabled(true);\n } else {\n await room.localParticipant.setCameraEnabled(false);\n }\n } catch (e) { throw mapEngineError(e); }\n }\n\n /**\n * Switch resolution, frame rate and bitrate cap mid-call. A simulcast change or a factory video\n * source republishes the track; a camera restarts capture in place; a fixed custom track only\n * gets the new encoding parameters.\n */\n async setVideoProfile(name: VideoProfileName): Promise<void> {\n const next = resolveProfile(name);\n const prev = this.profile;\n this.profile = next;\n const room = this.room;\n if (!room || this._state === 'ended') return;\n try {\n const pub = room.localParticipant.getTrackPublication(Track.Source.Camera);\n if (!next.video) { await this.unpublishVideo(); return; }\n if (!pub?.track) { await this.publishVideo(); return; }\n const simulcastChanged = (this.simulcastOverride ?? prev.simulcast) !== (this.simulcastOverride ?? next.simulcast);\n if (simulcastChanged || typeof this.videoSource === 'function') { await this.republishVideo(); return; }\n const track = pub.track as LocalVideoTrack;\n if (!this.videoSource) await track.restartTrack(this.captureOptions());\n await this.applyEncoding(track.sender, next);\n } catch (e) { throw mapEngineError(e); }\n }\n\n async setLatencyMode(mode: LatencyMode): Promise<void> {\n const s = latencySettings(mode);\n this.latency = mode;\n this.jbOverride = null;\n this.applyJitterTarget();\n const pub = this.room?.localParticipant.getTrackPublication(Track.Source.Camera);\n const sender = (pub?.track as LocalVideoTrack | undefined)?.sender;\n if (sender) await applyDegradationPreference(sender, s.degradationPreference);\n }\n\n /**\n * Pin the receiver's jitter buffer target in ms regardless of the latency mode (0 asks the\n * browser for its floor). Returns which receiver property took it; `unsupported` on Firefox.\n * `setLatencyMode` clears the pin.\n */\n setJitterBufferTarget(ms: number): JitterBufferSupport {\n this.jbOverride = checkJitterTarget(ms);\n return this.applyJitterTarget();\n }\n\n /** Change the codec or the simulcast setting mid-call; the video track is republished. */\n async setVideoEncoding(opts: { codec?: VideoCodec; simulcast?: boolean | null }): Promise<void> {\n if (opts.codec !== undefined) this._codec = checkCodec(opts.codec);\n if (opts.simulcast !== undefined) this.simulcastOverride = opts.simulcast;\n if (!this.room || this._state === 'ended') return;\n try { await this.republishVideo(); } catch (e) { throw mapEngineError(e); }\n }\n\n /** Replace the video source mid-call; `null` returns to the camera. Republishes when video is published. */\n async setVideoSource(source: VideoSource | null): Promise<void> {\n this.videoSource = source;\n this.devices._setCustomVideo(source !== null);\n if (!this.room || this._state === 'ended') return;\n try { await this.republishVideo(); } catch (e) { throw mapEngineError(e); }\n }\n\n /** Send up to 15 KB to the peer. Strings and JSON-able objects arrive as sent; Uint8Array arrives as bytes. */\n async sendMessage(payload: MessagePayload, reliable = true): Promise<void> {\n const room = this.requireRoom();\n const bytes = encodeMessage(payload);\n if (bytes.byteLength > MSG_MAX_BYTES) throw new CallError('internal', `Message is ${bytes.byteLength} bytes; the limit is ${MSG_MAX_BYTES}.`, { retryable: false });\n const t = Date.now();\n this.msgTimes = this.msgTimes.filter((x) => t - x < 1000);\n if (this.msgTimes.length >= MSG_MAX_PER_SECOND) throw new CallError('internal', `Message rate limit: at most ${MSG_MAX_PER_SECOND} messages per second.`, { retryable: true });\n this.msgTimes.push(t);\n try { await room.localParticipant.publishData(toNonShared(bytes), { reliable, topic: MSG_TOPIC }); }\n catch (e) { throw mapEngineError(e); }\n }\n\n // ------------------------------------------------------------------ engine wiring\n\n private buildRoom(): Room {\n const s = latencySettings(this.latency);\n const adaptive = this.options.adaptiveStream !== false;\n const room = new Room({\n adaptiveStream: adaptive,\n dynacast: adaptive,\n publishDefaults: this.publishOptions(s.degradationPreference),\n videoCaptureDefaults: this.captureOptions(),\n audioCaptureDefaults: this.audioCaptureOptions(),\n });\n room.on(RoomEvent.ParticipantConnected, (p) => this.onParticipantConnected(p));\n room.on(RoomEvent.ParticipantDisconnected, (p) => this.onParticipantDisconnected(p));\n room.on(RoomEvent.TrackSubscribed, (track, _pub, p) => this.onTrackSubscribed(track, p));\n room.on(RoomEvent.TrackUnsubscribed, (track) => this.onTrackUnsubscribed(track));\n room.on(RoomEvent.TrackMuted, (pub, p) => this.onMuteChange(pub, p, true));\n room.on(RoomEvent.TrackUnmuted, (pub, p) => this.onMuteChange(pub, p, false));\n room.on(RoomEvent.DataReceived, (payload, p, kind, topic) => this.onData(payload, p, topic, kind !== DataPacket_Kind.LOSSY));\n room.on(RoomEvent.Reconnecting, () => this.onReconnecting());\n room.on(RoomEvent.Reconnected, () => this.onReconnected());\n room.on(RoomEvent.Disconnected, (reason) => this.onDisconnected(reason));\n room.on(RoomEvent.MediaDevicesError, (e) => this.emitter.emit('error', mapEngineError(e)));\n room.on(RoomEvent.MediaDevicesChanged, () => { void this.devices.list().then((l) => this.emitter.emit('devicesChanged', l)); });\n return room;\n }\n\n private publishOptions(degradation: RTCDegradationPreference): TrackPublishOptions {\n return {\n videoCodec: this._codec,\n simulcast: this.simulcast,\n videoEncoding: this.profile.video ? { maxBitrate: this.profile.maxBitrate, maxFramerate: this.profile.fps } : undefined,\n degradationPreference: degradation,\n dtx: false,\n audioPreset: { maxBitrate: AUDIO_BITRATE },\n };\n }\n\n private captureOptions(): VideoCaptureOptions {\n const p = this.profile.video ? this.profile : resolveProfile(DEFAULT_PROFILE);\n return { resolution: { width: p.width, height: p.height, frameRate: p.fps, aspectRatio: p.width / p.height }, deviceId: this.options.cameraId };\n }\n\n private audioCaptureOptions(): AudioCaptureOptions {\n return { echoCancellation: true, noiseSuppression: true, autoGainControl: true, deviceId: this.options.microphoneId };\n }\n\n private async publishAudio(): Promise<void> {\n const room = this.requireRoom();\n try { await room.localParticipant.setMicrophoneEnabled(true, this.audioCaptureOptions(), this.publishOptions(latencySettings(this.latency).degradationPreference)); }\n catch (e) { throw mapEngineError(e); }\n }\n\n private async publishVideo(): Promise<void> {\n const room = this.requireRoom();\n try {\n const opts = this.publishOptions(latencySettings(this.latency).degradationPreference);\n let track: unknown;\n if (this.videoSource) {\n const source = await this.resolveSource();\n const pub = await room.localParticipant.publishTrack(source, { ...opts, source: Track.Source.Camera, name: 'camera' });\n track = pub?.track;\n } else {\n const pub = await room.localParticipant.setCameraEnabled(true, this.captureOptions(), opts);\n track = pub?.track;\n }\n this._localVideo = track ? wrapTrack(track as Parameters<typeof wrapTrack>[0]) : null;\n } catch (e) { this.releaseSource(); throw mapEngineError(e); }\n }\n\n /** Takes the track from `videoSource`; a factory's result is owned by the SDK, a passed track is not. */\n private async resolveSource(): Promise<MediaStreamTrack> {\n const src = this.videoSource as VideoSource;\n const track = typeof src === 'function' ? await src(this.profile.video ? this.profile : resolveProfile(DEFAULT_PROFILE)) : src;\n if (!track || typeof track !== 'object' || (track as MediaStreamTrack).kind !== 'video') {\n throw new CallError('internal', 'videoSource must be, or return, a video MediaStreamTrack.', { retryable: false });\n }\n this.sourceTrack = track;\n this.sourceOwned = typeof src === 'function';\n return track;\n }\n\n private releaseSource(): void {\n if (this.sourceTrack && this.sourceOwned) { try { this.sourceTrack.stop(); } catch { /* already ended */ } }\n this.sourceTrack = null;\n this.sourceOwned = false;\n }\n\n private async unpublishVideo(): Promise<void> {\n const room = this.room;\n const pub = room?.localParticipant.getTrackPublication(Track.Source.Camera);\n // A track the app handed us is never stopped by the SDK; everything else is.\n if (room && pub?.track) await room.localParticipant.unpublishTrack(pub.track, this.sourceTrack ? this.sourceOwned : true);\n this.releaseSource();\n this._localVideo = null;\n this.sendTracker.reset();\n }\n\n /** Unpublish and publish again with the current source, codec, simulcast and profile. A muted camera stays off. */\n private async republishVideo(): Promise<void> {\n const room = this.room;\n if (!room) return;\n const pub = room.localParticipant.getTrackPublication(Track.Source.Camera);\n if (!pub?.track) return; // video off or audio-only: the next enable publishes fresh\n const wasMuted = !!pub.isMuted;\n await this.unpublishVideo();\n if (!wasMuted && this.profile.video) await this.publishVideo();\n }\n\n private async applyEncoding(sender: RTCRtpSender | undefined, p: VideoProfile): Promise<void> {\n if (!sender) return;\n const params = sender.getParameters();\n params.encodings = (params.encodings && params.encodings.length ? params.encodings : [{}]).map((e) => ({ ...e, maxBitrate: p.maxBitrate, maxFramerate: p.fps }));\n await sender.setParameters(params);\n }\n\n private applyJitterTarget(): JitterBufferSupport {\n const receiver = this.remoteVideoTrack?.receiver;\n if (!receiver) return this.jbSupport;\n const took = applyJitterBufferTarget(receiver, this.jitterBufferTargetMs);\n this.jbSupport = took ?? 'unsupported';\n return this.jbSupport;\n }\n\n private adoptExistingParticipants(room: Room): void {\n room.remoteParticipants.forEach((p) => {\n if (isAgent(p)) { this.agentPresent = true; return; }\n if (!this._peer) this._peer = peerOf(p);\n });\n }\n\n private countHumans(room: Room): number {\n let n = 0;\n room.remoteParticipants.forEach((p) => { if (!isAgent(p)) n += 1; });\n return n;\n }\n\n private onParticipantConnected(p: RemoteParticipant): void {\n if (isAgent(p)) { this.agentPresent = true; return; }\n if (this._peer && this._peer.identity !== p.identity) return; // a third human; the room cap should have rejected it\n this._peer = peerOf(p);\n this.emitter.emit('peerJoined', { ...this._peer });\n this.sendHello();\n }\n\n private onParticipantDisconnected(p: RemoteParticipant): void {\n if (isAgent(p)) { this.agentPresent = false; return; }\n if (!this._peer || this._peer.identity !== p.identity) return;\n const left = { ...this._peer };\n this._peer = null;\n this.peerRttMs = null;\n this.emitter.emit('peerLeft', left);\n if (this.options.endOnPeerLeft) void this.endWith('peerLeft');\n }\n\n private onTrackSubscribed(track: RemoteTrack, p: RemoteParticipant): void {\n if (isAgent(p)) return;\n if (track.kind === Track.Kind.Video) {\n this.remoteVideoTrack = track;\n this.recvTracker.reset();\n this.applyJitterTarget();\n this._remoteVideo = wrapTrack(track as unknown as Parameters<typeof wrapTrack>[0]);\n this.emitter.emit('remoteVideo', this._remoteVideo);\n } else if (track.kind === Track.Kind.Audio) {\n this.remoteAudioTrack = track;\n const el = this.ensureAudioElement();\n if (el) track.attach(el);\n this._remoteAudio = wrapTrack(track as unknown as Parameters<typeof wrapTrack>[0]);\n this.emitter.emit('remoteAudio', this._remoteAudio);\n }\n }\n\n private onTrackUnsubscribed(track: RemoteTrack): void {\n if (track === this.remoteVideoTrack) { this.remoteVideoTrack = null; this._remoteVideo = null; this.emitter.emit('remoteVideo', null); }\n if (track === this.remoteAudioTrack) { this.remoteAudioTrack = null; this._remoteAudio = null; this.emitter.emit('remoteAudio', null); }\n try { track.detach(); } catch { /* already detached */ }\n }\n\n private onMuteChange(pub: TrackPublication, p: Participant, muted: boolean): void {\n if (!this._peer || p.identity !== this._peer.identity) return;\n const kind = pub.kind === Track.Kind.Audio ? 'audio' : 'video';\n if (kind === 'audio') this._peer.audioMuted = muted; else this._peer.videoMuted = muted;\n this.emitter.emit('peerMuted', kind, muted);\n }\n\n private onData(payload: Uint8Array, p: RemoteParticipant | undefined, topic: string | undefined, reliable = true): void {\n if (p && isAgent(p)) return;\n if (topic === STATS_TOPIC) {\n try { const m = JSON.parse(dec.decode(payload)); if (typeof m.rtt === 'number') this.peerRttMs = m.rtt; } catch { /* ignore */ }\n return;\n }\n if (topic === MSG_TOPIC) {\n try { this.emitter.emit('message', decodeMessage(payload), reliable); } catch { /* malformed */ }\n }\n }\n\n private onReconnecting(): void {\n if (this._state !== 'connected') return;\n this.setState('reconnecting', null);\n if (this.cred.expiresAt !== null && isExpired(this.cred)) this.emitter.emit('credentialExpiring', this.cred.expiresAt);\n if (!this.options.autoReconnect) { void this.endWith('network'); return; }\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n this.reconnectTimer = setTimeout(() => { if (this._state === 'reconnecting') void this.endWith('network'); }, RECONNECT_WINDOW_MS);\n }\n\n private onReconnected(): void {\n if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); this.reconnectTimer = null; }\n if (this._state === 'reconnecting') this.setState('connected', null);\n this.recvTracker.reset(); this.sendTracker.reset();\n }\n\n private onDisconnected(reason?: DisconnectReason): void {\n if (this._state === 'ended') return;\n void this.endWith(this.pendingEnd ?? endReasonOf(reason, this.leaving));\n }\n\n // ------------------------------------------------------------------ stats loop\n\n private startStats(): void {\n if (this.statsTimer) return;\n this.statsTimer = setInterval(() => { void this.pollStats(); }, STATS_INTERVAL_MS);\n }\n\n private async pollStats(): Promise<void> {\n const room = this.room;\n if (!room || (this._state !== 'connected' && this._state !== 'reconnecting')) return;\n const t = Date.now();\n try {\n const recvReport = await (this.remoteVideoTrack ?? this.remoteAudioTrack)?.receiver?.getStats?.();\n const lp = room.localParticipant;\n const localTrack = (lp.getTrackPublication(Track.Source.Camera)?.track ?? lp.getTrackPublication(Track.Source.Microphone)?.track) as LocalVideoTrack | undefined;\n const sendReport = await localTrack?.sender?.getStats?.();\n const recv = recvReport ? collectRecv(recvReport, this.recvTracker, t) : emptyRecv();\n const send = sendReport ? collectSend(sendReport, this.sendTracker, t) : emptySend();\n try {\n const rx = this.remoteVideoTrack?.receiver as (RTCRtpReceiver & { getSynchronizationSources?: () => RTCRtpSynchronizationSource[] }) | undefined;\n if (rx?.getSynchronizationSources) recv.absCaptureLatencyMs = absCaptureLatency(rx.getSynchronizationSources(), t, now());\n } catch { /* not exposed here */ }\n const estimatedLatencyMs = estimateLatency({ rttMs: recv.rttMs ?? send.rttMs, peerRttMs: this.peerRttMs, jitterBufferMs: recv.jitterBufferMs, decodeMs: recv.decodeMs, fps: recv.fps });\n const qr = this.recvQuality.update({ lossPct: recv.lossPct, jitterBufferMs: recv.jitterBufferMs, freezes: recv.freezes, rttMs: recv.rttMs });\n const qs = this.sendQuality.update({ lossPct: send.lossPct, jitterBufferMs: null, freezes: null, rttMs: send.rttMs });\n const prev = this._stats;\n const snap: CallStats = {\n ts: t, recv, send, peerRttMs: this.peerRttMs, estimatedLatencyMs,\n quality: { recv: qr, send: qs },\n region: room.serverInfo?.region ?? this.regionChoice?.region.name ?? null,\n nodeId: room.serverInfo?.nodeId ?? null,\n serverVersion: room.serverInfo?.version ?? null,\n joinMs: this.joinMs,\n audioRoute: this.audioRoute(),\n };\n this._stats = snap;\n this.emitter.emit('stats', snap);\n if (!prev || prev.quality.recv !== qr) this.emitter.emit('qualityChanged', qr, 'recv');\n if (!prev || prev.quality.send !== qs) this.emitter.emit('qualityChanged', qs, 'send');\n if (this.telemetry?.enabled) this.telemetry.push(snap, this._peer?.identity ?? null, this.extraFields());\n const rtt = recv.rttMs ?? send.rttMs;\n if (rtt !== null && room.state === ConnectionState.Connected) {\n try { await lp.publishData(enc.encode(JSON.stringify({ t: 'rtt', rtt })), { reliable: false, topic: STATS_TOPIC }); } catch { /* channel not ready */ }\n }\n } catch (e) {\n this.emitter.emit('error', new CallError('internal', `Stats collection failed: ${(e as Error)?.message ?? e}`, { cause: e }));\n }\n }\n\n private extraFields(): { recv: TelemetryFields | null; send: TelemetryFields | null } | undefined {\n const fn = this.options.telemetryExtra;\n if (!fn) return undefined;\n const one = (d: Direction): TelemetryFields | null => {\n try { const v = fn(d); return v && typeof v === 'object' ? v : null; }\n catch (e) { this.emitter.emit('error', new CallError('internal', `telemetryExtra threw: ${(e as Error)?.message ?? e}`, { cause: e })); return null; }\n };\n return { recv: one('recv'), send: one('send') };\n }\n\n private audioRoute(): AudioRoute {\n if (typeof navigator === 'undefined') return 'unknown';\n const label = (this.audioEl as { sinkId?: string } | null)?.sinkId ?? '';\n if (!label) return 'unknown';\n return 'unknown';\n }\n\n private sendHello(): void {\n const room = this.room;\n if (!room || room.state !== ConnectionState.Connected) return;\n void room.localParticipant.publishData(enc.encode(JSON.stringify({ t: 'hello', sdk: SDK_VERSION })), { reliable: true, topic: STATS_TOPIC }).catch(() => undefined);\n }\n\n // ------------------------------------------------------------------ housekeeping\n\n private scheduleExpiryWarning(): void {\n if (this.expiryTimer) { clearTimeout(this.expiryTimer); this.expiryTimer = null; }\n const ms = msUntilExpiryWarning(this.cred);\n if (ms === null) return;\n const at = this.cred.expiresAt as number;\n this.expiryTimer = setTimeout(() => { this.expiryTimer = null; if (this._state === 'connected' || this._state === 'reconnecting') this.emitter.emit('credentialExpiring', at); }, ms);\n }\n\n private ensureAudioElement(): HTMLMediaElement | null {\n if (this.audioEl) return this.audioEl;\n if (typeof document === 'undefined') return null;\n const el = document.createElement('audio');\n el.autoplay = true;\n el.setAttribute('playsinline', '');\n el.style.display = 'none';\n document.body?.appendChild(el);\n this.audioEl = el;\n this.devices._registerAudioElement(el);\n return el;\n }\n\n private requireRoom(): Room {\n if (!this.room || this._state === 'ended' || this._state === 'idle') throw new CallError('internal', `Not connected (state \"${this._state}\").`, { retryable: false });\n return this.room;\n }\n\n private setState(state: CallState, reason: EndReason | null): void {\n if (this._state === state && state !== 'ended') return;\n this._state = state;\n if (state === 'ended') this._endReason = reason;\n this.emitter.emit('stateChanged', state, state === 'ended' ? reason : null);\n }\n\n private async endWith(reason: EndReason): Promise<void> {\n if (this._state === 'ended') return;\n // teardown() disconnects the engine, which emits Disconnected(CLIENT_INITIATED) before we\n // get back here; remember why we are ending so that handler does not relabel it as 'left'.\n this.pendingEnd = this.pendingEnd ?? reason;\n await this.teardown();\n this.finish(this.pendingEnd, null);\n }\n\n private finish(reason: EndReason, err: CallError | null): void {\n if (this._state === 'ended') return;\n if (err) this.emitter.emit('error', err);\n this.setState('ended', reason);\n }\n\n private async teardown(): Promise<void> {\n if (this.statsTimer) { clearInterval(this.statsTimer); this.statsTimer = null; }\n if (this.expiryTimer) { clearTimeout(this.expiryTimer); this.expiryTimer = null; }\n if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); this.reconnectTimer = null; }\n if (this.telemetry) { await this.telemetry.stop(); this.telemetry = null; }\n this.devices._stop();\n this.devices._attachRoom(null);\n const room = this.room;\n this.room = null;\n if (room) {\n // The engine's disconnect stops every published track; a track the app handed us must survive it.\n if (this.sourceTrack && !this.sourceOwned) {\n const pub = room.localParticipant.getTrackPublication(Track.Source.Camera);\n if (pub?.track) { try { await room.localParticipant.unpublishTrack(pub.track, false); } catch { /* already gone */ } }\n }\n try { await room.disconnect(true); } catch { /* already closed */ }\n }\n this.releaseSource();\n this.jbSupport = null;\n if (this.audioEl) { try { this.audioEl.srcObject = null; this.audioEl.remove(); } catch { /* detached */ } this.audioEl = null; }\n this.remoteVideoTrack = null; this.remoteAudioTrack = null;\n this._remoteVideo = null; this._remoteAudio = null; this._localVideo = null;\n }\n}\n\n// ------------------------------------------------------------------ helpers\n\nfunction now(): number { return typeof performance !== 'undefined' ? performance.now() : Date.now(); }\n\n/** The engine requires a Uint8Array over a plain ArrayBuffer (never a SharedArrayBuffer). */\nfunction toNonShared(bytes: Uint8Array): Uint8Array<ArrayBuffer> {\n const out = new Uint8Array(new ArrayBuffer(bytes.byteLength));\n out.set(bytes);\n return out;\n}\n\nfunction isAgent(p: Participant): boolean {\n const asAny = p as { isAgent?: boolean; kind?: unknown };\n if (typeof asAny.isAgent === 'boolean') return asAny.isAgent;\n return asAny.kind === 4; // ParticipantKind.AGENT\n}\n\nfunction peerOf(p: RemoteParticipant): Peer {\n return {\n identity: p.identity,\n name: p.name || null,\n audioMuted: p.getTrackPublication(Track.Source.Microphone)?.isMuted ?? false,\n videoMuted: p.getTrackPublication(Track.Source.Camera)?.isMuted ?? false,\n };\n}\n\nfunction reasonForError(err: CallError): EndReason {\n switch (err.code) {\n case 'roomFull': return 'roomFull';\n case 'roomClosed': return 'roomClosed';\n case 'credentialInvalid': case 'credentialExpired': return 'credential';\n case 'network': return 'network';\n default: return 'error';\n }\n}\n\n/** Engine disconnect reasons to the SDK's end reasons. */\nfunction endReasonOf(reason: DisconnectReason | undefined, leaving: boolean): EndReason {\n if (leaving) return 'left';\n switch (reason) {\n case DisconnectReason.CLIENT_INITIATED: return 'left';\n case DisconnectReason.ROOM_DELETED:\n case DisconnectReason.ROOM_CLOSED:\n case DisconnectReason.SERVER_SHUTDOWN:\n case DisconnectReason.PARTICIPANT_REMOVED: return 'roomClosed';\n case DisconnectReason.DUPLICATE_IDENTITY:\n case DisconnectReason.USER_REJECTED: return 'credential';\n case DisconnectReason.JOIN_FAILURE: return 'error';\n default: return 'network';\n }\n}\n\nfunction emptyRecv(): CallStats['recv'] {\n return { rttMs: null, jitterBufferMs: null, decodeMs: null, fps: null, width: null, height: null, kbps: null, lossPct: null, jitterMs: null, freezes: null, freezeMs: null, processingMs: null, absCaptureLatencyMs: null, codec: null, transport: null, candidateType: null };\n}\nfunction emptySend(): CallStats['send'] {\n return { rttMs: null, encodeMs: null, fps: null, width: null, height: null, kbps: null, targetKbps: null, qualityLimitation: null, lossPct: null, codec: null, transport: null, candidateType: null };\n}\n\nfunction checkCodec(c: unknown): VideoCodec {\n if (typeof c === 'string' && (VIDEO_CODECS as readonly string[]).includes(c)) return c as VideoCodec;\n throw new RangeError(`Unknown video codec \"${String(c)}\". Known: ${VIDEO_CODECS.join(', ')}`);\n}\n\nfunction checkJitterTarget(ms: unknown): number {\n if (typeof ms !== 'number' || !Number.isFinite(ms) || ms < 0 || ms > 4000) throw new RangeError('jitterBufferTargetMs must be a number between 0 and 4000.');\n return ms;\n}\n\n/** Envelope: 1 tag byte (1 string, 2 json, 3 bytes) followed by the payload. */\nexport function encodeMessage(payload: MessagePayload): Uint8Array {\n let tag: number, body: Uint8Array;\n if (typeof payload === 'string') { tag = 1; body = enc.encode(payload); }\n else if (payload instanceof Uint8Array) { tag = 3; body = payload; }\n else { tag = 2; body = enc.encode(JSON.stringify(payload)); }\n const out = new Uint8Array(body.byteLength + 1);\n out[0] = tag; out.set(body, 1);\n return out;\n}\n\nexport function decodeMessage(bytes: Uint8Array): MessagePayload {\n const tag = bytes[0], body = bytes.subarray(1);\n if (tag === 1) return dec.decode(body);\n if (tag === 2) return JSON.parse(dec.decode(body)) as MessagePayload;\n if (tag === 3) return body.slice();\n throw new Error('unknown message envelope');\n}\n", "import { ConnectionError, ConnectionErrorReason } from 'livekit-client';\n\n/** Stable error codes, identical on every platform (web, iOS, Android). */\nexport type CallErrorCode =\n | 'credentialInvalid'\n | 'credentialExpired'\n | 'roomFull'\n | 'roomClosed'\n | 'permissionDenied'\n | 'deviceUnavailable'\n | 'network'\n | 'unsupported'\n | 'internal';\n\nexport class CallError extends Error {\n readonly code: CallErrorCode;\n /** Whether trying again, possibly after user action, can succeed. */\n readonly retryable: boolean;\n readonly cause?: unknown;\n\n constructor(code: CallErrorCode, message: string, opts: { retryable?: boolean; cause?: unknown } = {}) {\n super(message);\n this.name = 'CallError';\n this.code = code;\n this.retryable = opts.retryable ?? DEFAULT_RETRYABLE[code];\n this.cause = opts.cause;\n }\n}\n\nconst DEFAULT_RETRYABLE: Record<CallErrorCode, boolean> = {\n credentialInvalid: false,\n credentialExpired: true, // after the app fetches a new credential\n roomFull: false,\n roomClosed: false,\n permissionDenied: true, // after the user grants access\n deviceUnavailable: true,\n network: true,\n unsupported: false,\n internal: true,\n};\n\nexport function isCallError(e: unknown): e is CallError {\n return e instanceof CallError;\n}\n\n/**\n * Map an engine or browser error to a CallError. Engine mapping (livekit-client 2.22):\n *\n * - message matches \"room is full\" / \"max participants\" -> roomFull\n * - ConnectionError NotAllowed (HTTP 401/403 on join) -> credentialInvalid\n * - ConnectionError ServerUnreachable / WebSocket / Timeout -> network\n * (Call.connect() turns a WebSocket refusal into roomFull when the server's validate\n * endpoint still accepts the credential; the server sends no reason a browser can read)\n * - ConnectionError ServiceNotFound (wrong URL path) -> credentialInvalid (the url in the credential is wrong)\n * - ConnectionError Cancelled / LeaveRequest -> internal, not retryable (connect() was abandoned by leave())\n * - ConnectionError InternalError -> internal\n * - DOMException NotAllowedError / PermissionDeniedError -> permissionDenied\n * - DOMException NotFoundError / NotReadableError / OverconstrainedError / AbortError -> deviceUnavailable\n * - anything else -> internal, with the original message attached\n */\nexport function mapEngineError(e: unknown): CallError {\n if (isCallError(e)) return e;\n const msg = messageOf(e);\n if (/room is full|max(imum)? participants|participant limit/i.test(msg)) {\n return new CallError('roomFull', 'The call already has two participants.', { cause: e });\n }\n if (e instanceof ConnectionError) {\n switch (e.reason) {\n case ConnectionErrorReason.NotAllowed:\n return new CallError('credentialInvalid', `The credential was rejected by the media server (${e.status ?? 'no status'}): ${msg}`, { cause: e });\n case ConnectionErrorReason.ServerUnreachable:\n case ConnectionErrorReason.WebSocket:\n case ConnectionErrorReason.Timeout:\n return new CallError('network', `Could not reach the media server: ${msg}`, { cause: e });\n case ConnectionErrorReason.ServiceNotFound:\n return new CallError('credentialInvalid', `The credential's url does not point at a media server: ${msg}`, { cause: e });\n case ConnectionErrorReason.Cancelled:\n case ConnectionErrorReason.LeaveRequest:\n return new CallError('internal', `Connection was cancelled: ${msg}`, { retryable: false, cause: e });\n default:\n return new CallError('internal', `Media server error: ${msg}`, { cause: e });\n }\n }\n const name = (e as { name?: string } | null)?.name ?? '';\n if (name === 'NotAllowedError' || name === 'PermissionDeniedError' || name === 'SecurityError') {\n return new CallError('permissionDenied', 'Camera or microphone permission was not granted.', { cause: e });\n }\n if (name === 'NotFoundError' || name === 'NotReadableError' || name === 'OverconstrainedError' || name === 'AbortError' || name === 'TrackInvalidError') {\n return new CallError('deviceUnavailable', `The requested device is unavailable: ${msg}`, { cause: e });\n }\n return new CallError('internal', msg || 'Unknown error', { cause: e });\n}\n\nfunction messageOf(e: unknown): string {\n if (typeof e === 'string') return e;\n if (e && typeof e === 'object' && 'message' in e && typeof (e as { message: unknown }).message === 'string') {\n return (e as { message: string }).message;\n }\n return String(e);\n}\n", "/** Minimal typed event emitter. Handlers run synchronously on the calling thread; a throwing\n * handler is reported through console.error and never breaks the emitter or the SDK. */\nexport type Listener<T extends unknown[]> = (...args: T) => void;\n\nexport class Emitter<M extends Record<string, unknown[]>> {\n private readonly handlers = new Map<keyof M, Set<Listener<any>>>();\n\n on<K extends keyof M>(event: K, handler: Listener<M[K]>): () => void {\n let set = this.handlers.get(event);\n if (!set) { set = new Set(); this.handlers.set(event, set); }\n set.add(handler);\n return () => this.off(event, handler);\n }\n\n once<K extends keyof M>(event: K, handler: Listener<M[K]>): () => void {\n const off = this.on(event, ((...args: M[K]) => { off(); handler(...args); }) as Listener<M[K]>);\n return off;\n }\n\n off<K extends keyof M>(event: K, handler: Listener<M[K]>): void {\n this.handlers.get(event)?.delete(handler);\n }\n\n emit<K extends keyof M>(event: K, ...args: M[K]): void {\n const set = this.handlers.get(event);\n if (!set) return;\n for (const h of Array.from(set)) {\n try { h(...args); } catch (err) { console.error(`[qencode-calls] handler for \"${String(event)}\" threw`, err); }\n }\n }\n\n removeAll(): void { this.handlers.clear(); }\n}\n", "import { CallError } from './errors';\n\n/** One region a credential may connect through. */\nexport interface Region { name: string; url: string }\n\n/**\n * The token response from `POST /v1/calls/{id}/tokens`, passed to the app unchanged by the\n * customer's backend. Only `token` and `url` are required; the rest is read from the JWT\n * payload when missing.\n */\nexport interface CallCredential {\n token: string;\n url: string;\n regions?: Region[];\n identity?: string;\n room_name?: string;\n /** ISO 8601 string, epoch seconds, or epoch milliseconds. */\n expires_at?: string | number;\n call_id?: string;\n /** Optional API base for telemetry; overrides the SDK default. */\n api_base?: string;\n}\n\nexport interface ParsedCredential {\n token: string;\n url: string;\n regions: Region[];\n identity: string;\n roomName: string;\n /** Epoch milliseconds, or null when unknown. */\n expiresAt: number | null;\n callId: string | null;\n apiBase: string | null;\n}\n\n/** Fires `credentialExpiring` this long before `expiresAt`. */\nexport const EXPIRY_WARNING_MS = 2 * 60 * 1000;\n\nexport function parseCredential(input: CallCredential): ParsedCredential {\n if (!input || typeof input !== 'object') throw new CallError('credentialInvalid', 'Credential must be an object.');\n const token = typeof input.token === 'string' ? input.token.trim() : '';\n if (!token || token.split('.').length !== 3) throw new CallError('credentialInvalid', 'Credential token is missing or not a JWT.');\n const url = typeof input.url === 'string' ? input.url.trim() : '';\n if (!/^(wss?|https?):\\/\\/\\S+$/i.test(url)) throw new CallError('credentialInvalid', 'Credential url must be a ws(s) or http(s) URL.');\n\n const payload = decodeJwtPayload(token);\n const video = (payload.video ?? {}) as { room?: unknown };\n const identity = firstString(input.identity, payload.sub);\n const roomName = firstString(input.room_name, video.room);\n if (!identity) throw new CallError('credentialInvalid', 'Credential has no identity (neither identity nor the JWT sub claim).');\n if (!roomName) throw new CallError('credentialInvalid', 'Credential has no room (neither room_name nor the JWT video.room grant).');\n\n let expiresAt = parseExpiry(input.expires_at);\n if (expiresAt === null && typeof payload.exp === 'number') expiresAt = payload.exp * 1000;\n\n const regions = Array.isArray(input.regions)\n ? input.regions.filter((r): r is Region => !!r && typeof r.name === 'string' && typeof r.url === 'string')\n : [];\n if (regions.length === 0) regions.push({ name: 'default', url });\n\n return {\n token, url, regions, identity, roomName, expiresAt,\n callId: firstString(input.call_id) || null,\n apiBase: firstString(input.api_base) || null,\n };\n}\n\nexport function isExpired(c: ParsedCredential, now: number = Date.now()): boolean {\n return c.expiresAt !== null && now >= c.expiresAt;\n}\n\n/** Milliseconds until the expiry warning should fire; 0 when already due; null when unknown. */\nexport function msUntilExpiryWarning(c: ParsedCredential, now: number = Date.now()): number | null {\n if (c.expiresAt === null) return null;\n return Math.max(0, c.expiresAt - EXPIRY_WARNING_MS - now);\n}\n\nexport function parseExpiry(v: string | number | undefined): number | null {\n if (v === undefined || v === null || v === '') return null;\n if (typeof v === 'number' && Number.isFinite(v)) return v < 1e12 ? v * 1000 : v;\n if (typeof v === 'string') {\n const asNum = Number(v);\n if (v.trim() !== '' && Number.isFinite(asNum)) return asNum < 1e12 ? asNum * 1000 : asNum;\n // The API returns 'YYYY-MM-DD HH:MM:SS' in UTC without a zone; make that explicit.\n const iso = /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$/.test(v) ? v.replace(' ', 'T') + 'Z' : v;\n const t = Date.parse(iso);\n return Number.isFinite(t) ? t : null;\n }\n return null;\n}\n\n/** Decodes the JWT payload without verifying the signature; the media server verifies it. */\nexport function decodeJwtPayload(token: string): Record<string, unknown> {\n try {\n const part = token.split('.')[1] ?? '';\n const b64 = part.replace(/-/g, '+').replace(/_/g, '/').padEnd(Math.ceil(part.length / 4) * 4, '=');\n if (typeof atob !== 'function') return {};\n const json = atob(b64);\n const bytes = new Uint8Array(json.length);\n for (let i = 0; i < json.length; i++) bytes[i] = json.charCodeAt(i);\n const parsed = JSON.parse(new TextDecoder().decode(bytes));\n return parsed && typeof parsed === 'object' ? (parsed as Record<string, unknown>) : {};\n } catch {\n return {};\n }\n}\n\nfunction firstString(...vals: unknown[]): string {\n for (const v of vals) if (typeof v === 'string' && v.trim()) return v.trim();\n return '';\n}\n", "/** Named media tiers. Quality, cost and the pricing tier line up on these; apps pick a name, never raw constraints. */\nexport type VideoProfileName = 'audioOnly' | 'p360_30' | 'p540_30' | 'p540_60' | 'p720_30' | 'p720_60' | 'p1080_30';\n\nexport interface VideoProfile {\n name: VideoProfileName;\n width: number;\n height: number;\n fps: number;\n /** Encoder bitrate cap in bits per second. */\n maxBitrate: number;\n /** Simulcast layers are published at 720p and above; below, the single layer is cheaper to encode. */\n simulcast: boolean;\n video: boolean;\n}\n\nexport const PROFILES: Readonly<Record<VideoProfileName, VideoProfile>> = Object.freeze({\n audioOnly: { name: 'audioOnly', width: 0, height: 0, fps: 0, maxBitrate: 0, simulcast: false, video: false },\n p360_30: { name: 'p360_30', width: 640, height: 360, fps: 30, maxBitrate: 450_000, simulcast: false, video: true },\n p540_30: { name: 'p540_30', width: 960, height: 540, fps: 30, maxBitrate: 800_000, simulcast: false, video: true },\n p540_60: { name: 'p540_60', width: 960, height: 540, fps: 60, maxBitrate: 1_200_000, simulcast: false, video: true },\n p720_30: { name: 'p720_30', width: 1280, height: 720, fps: 30, maxBitrate: 1_200_000, simulcast: true, video: true },\n p720_60: { name: 'p720_60', width: 1280, height: 720, fps: 60, maxBitrate: 1_800_000, simulcast: true, video: true },\n p1080_30: { name: 'p1080_30', width: 1920, height: 1080, fps: 30, maxBitrate: 2_200_000, simulcast: true, video: true },\n});\n\nexport const DEFAULT_PROFILE: VideoProfileName = 'p540_60';\n\n/** Opus bitrate for the microphone track, bits per second. */\nexport const AUDIO_BITRATE = 48_000;\n\nexport function resolveProfile(name: VideoProfileName | undefined): VideoProfile {\n const p = PROFILES[name ?? DEFAULT_PROFILE];\n if (!p) throw new RangeError(`Unknown video profile \"${String(name)}\". Known: ${Object.keys(PROFILES).join(', ')}`);\n return p;\n}\n", "/**\n * Latency modes move several engine knobs together.\n *\n * - `lowest`: jitter buffer target at the platform minimum (0 ms asks the browser for its floor),\n * degradation drops resolution before frame rate, 10 ms Opus frames where the platform lets us.\n * - `smooth`: jitter buffer target 150 ms, degradation drops frame rate before resolution,\n * 20 ms Opus frames.\n */\nexport type LatencyMode = 'lowest' | 'smooth';\n\nexport interface LatencySettings {\n jitterBufferTargetMs: number;\n degradationPreference: RTCDegradationPreference;\n audioFrameMs: 10 | 20;\n}\n\nexport const LATENCY_SETTINGS: Readonly<Record<LatencyMode, LatencySettings>> = Object.freeze({\n lowest: { jitterBufferTargetMs: 0, degradationPreference: 'maintain-framerate', audioFrameMs: 10 },\n smooth: { jitterBufferTargetMs: 150, degradationPreference: 'maintain-resolution', audioFrameMs: 20 },\n});\n\nexport const DEFAULT_LATENCY_MODE: LatencyMode = 'lowest';\n\nexport function latencySettings(mode: LatencyMode | undefined): LatencySettings {\n const s = LATENCY_SETTINGS[mode ?? DEFAULT_LATENCY_MODE];\n if (!s) throw new RangeError(`Unknown latency mode \"${String(mode)}\". Known: lowest, smooth`);\n return s;\n}\n\ntype ReceiverWithTarget = RTCRtpReceiver & { jitterBufferTarget?: number | null; playoutDelayHint?: number | null };\n\n/**\n * Applies a jitter buffer target to a receiver. Returns which property took it:\n * `jitterBufferTarget` (Chromium 108+, Safari 17.4+), `playoutDelayHint` (older Chromium), or\n * `null` when the browser exposes neither (Firefox). Never throws.\n */\nexport function applyJitterBufferTarget(receiver: RTCRtpReceiver | undefined | null, ms: number): 'jitterBufferTarget' | 'playoutDelayHint' | null {\n if (!receiver) return null;\n const r = receiver as unknown as Record<string, unknown>;\n try {\n if ('jitterBufferTarget' in r) { (receiver as ReceiverWithTarget).jitterBufferTarget = ms; return 'jitterBufferTarget'; }\n if ('playoutDelayHint' in r) { (receiver as ReceiverWithTarget).playoutDelayHint = ms / 1000; return 'playoutDelayHint'; }\n } catch { /* unsupported value range or read-only implementation */ }\n return null;\n}\n\n/** Applies a degradation preference to a live sender without republishing. Returns false when unsupported. */\nexport async function applyDegradationPreference(sender: RTCRtpSender | undefined | null, pref: RTCDegradationPreference): Promise<boolean> {\n if (!sender || typeof sender.getParameters !== 'function') return false;\n try {\n const params = sender.getParameters();\n (params as RTCRtpSendParameters & { degradationPreference?: RTCDegradationPreference }).degradationPreference = pref;\n await sender.setParameters(params);\n return true;\n } catch {\n return false;\n }\n}\n", "import type { Region } from './credential';\n\nexport interface RegionChoice {\n region: Region;\n /** Probe result per region name in milliseconds; Infinity when unreachable. Empty when no probe ran. */\n probe: Record<string, number>;\n /** How the choice was made. */\n how: 'single' | 'pinned' | 'probe' | 'fallback';\n}\n\nexport interface ProbeOptions {\n timeoutMs?: number;\n fetchFn?: typeof fetch;\n now?: () => number;\n}\n\n/** Turns a signaling URL into the media node's HTTPS root, which LiveKit answers with \"OK\". */\nexport function probeUrl(signalingUrl: string): string {\n const u = new URL(signalingUrl);\n const proto = u.protocol === 'ws:' || u.protocol === 'http:' ? 'http:' : 'https:';\n return `${proto}//${u.host}/`;\n}\n\n/**\n * Times one request to a region after one warm-up request. `no-cors` so the timing works even\n * when the node sends no CORS headers; the body is not readable and does not need to be.\n */\nexport async function probeRegion(region: Region, opts: ProbeOptions = {}): Promise<number> {\n const timeoutMs = opts.timeoutMs ?? 3000;\n const f = opts.fetchFn ?? (typeof fetch === 'function' ? fetch : undefined);\n const now = opts.now ?? (() => (typeof performance !== 'undefined' ? performance.now() : Date.now()));\n if (!f) return Infinity;\n let url: string;\n try { url = probeUrl(region.url); } catch { return Infinity; }\n const once = async (): Promise<number> => {\n const ctl = typeof AbortController === 'function' ? new AbortController() : undefined;\n const timer = setTimeout(() => ctl?.abort(), timeoutMs);\n const t0 = now();\n try {\n await f(url, { mode: 'no-cors', cache: 'no-store', credentials: 'omit', signal: ctl?.signal });\n return now() - t0;\n } catch {\n return Infinity;\n } finally {\n clearTimeout(timer);\n }\n };\n const warm = await once();\n if (warm === Infinity) return Infinity;\n return once();\n}\n\n/** Picks the region to connect through. Pinned wins; one region skips the probe; otherwise the fastest probe. */\nexport async function chooseRegion(regions: Region[], pinned?: string | null, opts: ProbeOptions = {}): Promise<RegionChoice> {\n if (regions.length === 0) throw new RangeError('No regions to choose from');\n if (pinned) {\n const r = regions.find((x) => x.name === pinned);\n if (!r) throw new RangeError(`Region \"${pinned}\" is not in the credential. Available: ${regions.map((x) => x.name).join(', ')}`);\n return { region: r, probe: {}, how: 'pinned' };\n }\n if (regions.length === 1) return { region: regions[0]!, probe: {}, how: 'single' };\n const results = await Promise.all(regions.map((r) => probeRegion(r, opts)));\n const probe: Record<string, number> = {};\n regions.forEach((r, i) => { probe[r.name] = Math.round(results[i]! * 10) / 10; });\n let best = -1;\n results.forEach((ms, i) => { if (ms !== Infinity && (best < 0 || ms < results[best]!)) best = i; });\n if (best < 0) return { region: regions[0]!, probe, how: 'fallback' };\n return { region: regions[best]!, probe, how: 'probe' };\n}\n", "/**\n * Per-second quality numbers from WebRTC getStats, ported from the bench page. Everything here is\n * pure over an RTCStatsReport-like map so it can be tested without a browser.\n */\n\nexport type Transport = 'udp' | 'tcp' | 'relay-udp' | 'relay-tcp';\nexport type CandidateType = 'host' | 'srflx' | 'prflx' | 'relay';\nexport type AudioRoute = 'speaker' | 'earpiece' | 'wired' | 'bluetooth' | 'unknown';\nexport type Quality = 'good' | 'fair' | 'poor';\nexport type Direction = 'recv' | 'send';\n\n/** What this participant receives from the peer. */\nexport interface RecvStats {\n rttMs: number | null;\n jitterBufferMs: number | null;\n decodeMs: number | null;\n fps: number | null;\n width: number | null;\n height: number | null;\n kbps: number | null;\n lossPct: number | null;\n jitterMs: number | null;\n freezes: number | null;\n freezeMs: number | null;\n /** Receive-to-render time per frame: \u0394`totalProcessingDelay` / \u0394`framesDecoded`. */\n processingMs: number | null;\n /**\n * Sender capture to local now through the abs-capture-time header extension, when the\n * browser and the media node carry it (Chromium; null elsewhere). A cross-check for the\n * estimate, not a substitute for a measured glass-to-glass number.\n */\n absCaptureLatencyMs: number | null;\n codec: string | null;\n transport: Transport | null;\n candidateType: CandidateType | null;\n}\n\n/** What this participant sends. */\nexport interface SendStats {\n rttMs: number | null;\n encodeMs: number | null;\n fps: number | null;\n width: number | null;\n height: number | null;\n kbps: number | null;\n /** The encoder's current bitrate target, kbps. */\n targetKbps: number | null;\n qualityLimitation: string | null;\n /** Loss the media node reports for our outbound stream (remote-inbound-rtp), percent. */\n lossPct: number | null;\n codec: string | null;\n transport: Transport | null;\n candidateType: CandidateType | null;\n}\n\n/** One snapshot, emitted once per second on `stats`. */\nexport interface CallStats {\n /** Epoch milliseconds. */\n ts: number;\n recv: RecvStats;\n send: SendStats;\n /** The peer's own RTT to the media node, exchanged over the data channel; null until received. */\n peerRttMs: number | null;\n /** rtt/2 + peerRtt/2 + jitter buffer + decode + one frame interval. An estimate, not a measurement. */\n estimatedLatencyMs: number | null;\n quality: { recv: Quality; send: Quality };\n region: string | null;\n nodeId: string | null;\n serverVersion: string | null;\n joinMs: number | null;\n audioRoute: AudioRoute;\n}\n\ntype StatsLike = { forEach(cb: (s: any) => void): void; get(id: string): any };\n\ninterface Prev { t: number; [k: string]: number }\n\n/** Delta tracker across polls; one instance per direction per call. */\nexport class DeltaTracker {\n private prev: Prev | null = null;\n\n /** Returns per-interval deltas of the given counters, or null on the first sample. */\n step(nowMs: number, counters: Record<string, number | undefined>): { dt: number; d: (k: string) => number } | null {\n const cur: Prev = { t: nowMs };\n for (const [k, v] of Object.entries(counters)) cur[k] = typeof v === 'number' && Number.isFinite(v) ? v : 0;\n const prev = this.prev;\n this.prev = cur;\n if (!prev) return null;\n const dt = Math.max(1, nowMs - prev.t) / 1000;\n return { dt, d: (k) => (cur[k] ?? 0) - (prev[k] ?? 0) };\n }\n\n reset(): void { this.prev = null; }\n}\n\nexport function pickSelectedPair(report: StatsLike): any | null {\n let pair: any = null;\n report.forEach((s) => { if (s.type === 'transport' && s.selectedCandidatePairId) pair = report.get(s.selectedCandidatePairId) ?? pair; });\n if (!pair) report.forEach((s) => { if (s.type === 'candidate-pair' && s.nominated && s.state === 'succeeded') pair = s; });\n return pair;\n}\n\nexport function transportOf(report: StatsLike, pair: any | null): { transport: Transport | null; candidateType: CandidateType | null; rttMs: number | null } {\n if (!pair) return { transport: null, candidateType: null, rttMs: null };\n const local = report.get(pair.localCandidateId) ?? {};\n const proto = String(local.relayProtocol ?? local.protocol ?? '').toLowerCase();\n const ctype = (local.candidateType ?? null) as CandidateType | null;\n const base = proto === 'tcp' || proto === 'tls' ? 'tcp' : 'udp';\n const transport: Transport | null = ctype === 'relay' ? (`relay-${base}` as Transport) : (proto ? base : null);\n const rtt = typeof pair.currentRoundTripTime === 'number' ? round1(pair.currentRoundTripTime * 1000) : null;\n return { transport, candidateType: ctype, rttMs: rtt };\n}\n\nfunction codecName(report: StatsLike, codecId: string | undefined): string | null {\n if (!codecId) return null;\n const c = report.get(codecId);\n const mime: string | undefined = c?.mimeType;\n return mime ? mime.replace(/^video\\//i, '').replace(/^audio\\//i, '').toUpperCase() : null;\n}\n\nexport function collectRecv(report: StatsLike, tracker: DeltaTracker, nowMs: number): RecvStats {\n let inbound: any = null;\n report.forEach((s) => { if (s.type === 'inbound-rtp' && (s.kind === 'video' || s.mediaType === 'video')) inbound = s; });\n const pair = pickSelectedPair(report);\n const t = transportOf(report, pair);\n const empty: RecvStats = { rttMs: t.rttMs, jitterBufferMs: null, decodeMs: null, fps: null, width: null, height: null, kbps: null, lossPct: null, jitterMs: null, freezes: null, freezeMs: null, processingMs: null, absCaptureLatencyMs: null, codec: null, transport: t.transport, candidateType: t.candidateType };\n if (!inbound) return empty;\n const step = tracker.step(nowMs, {\n jbd: inbound.jitterBufferDelay, jbc: inbound.jitterBufferEmittedCount,\n dec: inbound.totalDecodeTime, frames: inbound.framesDecoded, proc: inbound.totalProcessingDelay,\n lost: inbound.packetsLost, recv: inbound.packetsReceived, bytes: inbound.bytesReceived,\n freezes: inbound.freezeCount, freezeMs: inbound.totalFreezesDuration,\n });\n const out: RecvStats = { ...empty,\n fps: typeof inbound.framesPerSecond === 'number' ? round1(inbound.framesPerSecond) : null,\n width: inbound.frameWidth ?? null, height: inbound.frameHeight ?? null,\n jitterMs: typeof inbound.jitter === 'number' ? round1(inbound.jitter * 1000) : null,\n codec: codecName(report, inbound.codecId),\n };\n if (!step) return out;\n const { dt, d } = step;\n out.jitterBufferMs = d('jbc') > 0 ? round1((d('jbd') / d('jbc')) * 1000) : null;\n out.decodeMs = d('frames') > 0 ? round1((d('dec') / d('frames')) * 1000) : null;\n out.processingMs = d('frames') > 0 ? round1((d('proc') / d('frames')) * 1000) : null;\n const lostAndRecv = d('lost') + d('recv');\n out.lossPct = lostAndRecv > 0 ? round1((d('lost') / lostAndRecv) * 100) : 0;\n out.kbps = round1((d('bytes') * 8) / dt / 1000);\n out.freezes = Math.max(0, d('freezes'));\n out.freezeMs = round1(Math.max(0, d('freezeMs')) * 1000);\n return out;\n}\n\nexport function collectSend(report: StatsLike, tracker: DeltaTracker, nowMs: number): SendStats {\n let outbound: any = null;\n report.forEach((s) => { if (s.type === 'outbound-rtp' && (s.kind === 'video' || s.mediaType === 'video') && (outbound === null || (s.bytesSent ?? 0) > (outbound.bytesSent ?? 0))) outbound = s; });\n const pair = pickSelectedPair(report);\n const t = transportOf(report, pair);\n let remoteInbound: any = null;\n report.forEach((s) => { if (s.type === 'remote-inbound-rtp' && (s.kind === 'video' || s.mediaType === 'video')) remoteInbound = s; });\n const lossPct = remoteInbound && typeof remoteInbound.fractionLost === 'number' ? round1(remoteInbound.fractionLost * 100) : null;\n const empty: SendStats = { rttMs: t.rttMs, encodeMs: null, fps: null, width: null, height: null, kbps: null, targetKbps: null, qualityLimitation: null, lossPct, codec: null, transport: t.transport, candidateType: t.candidateType };\n if (!outbound) return empty;\n const step = tracker.step(nowMs, { enc: outbound.totalEncodeTime, frames: outbound.framesEncoded, bytes: outbound.bytesSent });\n const out: SendStats = { ...empty,\n fps: typeof outbound.framesPerSecond === 'number' ? round1(outbound.framesPerSecond) : null,\n width: outbound.frameWidth ?? null, height: outbound.frameHeight ?? null,\n targetKbps: typeof outbound.targetBitrate === 'number' ? round1(outbound.targetBitrate / 1000) : null,\n qualityLimitation: outbound.qualityLimitationReason ?? null,\n codec: codecName(report, outbound.codecId),\n };\n if (!step) return out;\n const { dt, d } = step;\n out.encodeMs = d('frames') > 0 ? round1((d('enc') / d('frames')) * 1000) : null;\n out.kbps = round1((d('bytes') * 8) / dt / 1000);\n return out;\n}\n\nconst NTP_EPOCH_OFFSET_MS = 2_208_988_800_000; // 1900-01-01 to 1970-01-01\n\ntype SyncSource = { timestamp: number; captureTimestamp?: number; senderCaptureTimeOffset?: number };\n\n/**\n * Latency from the sender's capture clock to now, from `RTCRtpReceiver.getSynchronizationSources()`\n * when the abs-capture-time extension is present. `captureTimestamp` and `senderCaptureTimeOffset`\n * are milliseconds since the NTP epoch on the sender's clock (already offset-corrected by the\n * browser); `timestamp` is when the last frame reached the track, relative either to the epoch\n * (spec) or to the page's time origin (some builds), so both are accepted. Null when absent.\n */\nexport function absCaptureLatency(sources: ArrayLike<SyncSource> | null | undefined, unixNowMs: number, perfNowMs: number): number | null {\n const s0 = sources && sources.length ? sources[0] : undefined;\n if (!s0 || typeof s0.captureTimestamp !== 'number' || typeof s0.senderCaptureTimeOffset !== 'number') return null;\n const captureNtp = s0.captureTimestamp + s0.senderCaptureTimeOffset;\n const ageMs = typeof s0.timestamp === 'number' ? (s0.timestamp > 1e12 ? unixNowMs - s0.timestamp : perfNowMs - s0.timestamp) : 0;\n const v = unixNowMs + NTP_EPOCH_OFFSET_MS - captureNtp - Math.max(0, ageMs);\n return Number.isFinite(v) ? Math.round(v) : null;\n}\n\n/** rtt/2 + peerRtt/2 + jitter buffer + decode + one frame interval. Null until the pieces exist. */\nexport function estimateLatency(p: { rttMs: number | null; peerRttMs: number | null; jitterBufferMs: number | null; decodeMs: number | null; fps: number | null }): number | null {\n if (p.rttMs === null || p.jitterBufferMs === null) return null;\n const peer = p.peerRttMs ?? p.rttMs; // assume symmetry until the peer reports\n const frame = p.fps && p.fps > 0 ? 1000 / p.fps : 33;\n return round1(p.rttMs / 2 + peer / 2 + p.jitterBufferMs + (p.decodeMs ?? 0) + frame);\n}\n\n/**\n * good / fair / poor with hysteresis: a new level must be observed on two consecutive polls\n * before it is reported, so a single bad second does not flip the indicator.\n *\n * poor: loss > 3 % or jitter buffer > 200 ms or any freeze in the interval\n * fair: loss > 1 % or jitter buffer > 120 ms or rtt > 300 ms\n * good: otherwise\n */\nexport class QualityTracker {\n private current: Quality = 'good';\n private candidate: Quality | null = null;\n private streak = 0;\n\n static classify(s: { lossPct: number | null; jitterBufferMs: number | null; freezes: number | null; rttMs: number | null }): Quality {\n const loss = s.lossPct ?? 0, jb = s.jitterBufferMs ?? 0, fr = s.freezes ?? 0, rtt = s.rttMs ?? 0;\n if (loss > 3 || jb > 200 || fr > 0) return 'poor';\n if (loss > 1 || jb > 120 || rtt > 300) return 'fair';\n return 'good';\n }\n\n /** Feed one poll; returns the reported level after hysteresis. */\n update(s: { lossPct: number | null; jitterBufferMs: number | null; freezes: number | null; rttMs: number | null }): Quality {\n const observed = QualityTracker.classify(s);\n if (observed === this.current) { this.candidate = null; this.streak = 0; return this.current; }\n if (observed === this.candidate) this.streak += 1; else { this.candidate = observed; this.streak = 1; }\n if (this.streak >= 2) { this.current = observed; this.candidate = null; this.streak = 0; }\n return this.current;\n }\n\n get value(): Quality { return this.current; }\n reset(): void { this.current = 'good'; this.candidate = null; this.streak = 0; }\n}\n\nfunction round1(v: number): number { return Math.round(v * 10) / 10; }\n", "import type { CallStats, Direction } from './stats';\n\n/** App-supplied fields for one telemetry row; see `Telemetry.push`. */\nexport type TelemetryFields = Record<string, unknown>;\n\n/** Contract columns an app may fill: its own measured glass-to-glass latency over the last window. */\nexport const MEASURED_COLUMNS: ReadonlySet<string> = new Set(['g2g_p50', 'g2g_p95', 'g2g_samples']);\n\n/** One row of the calls stats contract (`POST /v1/calls/{id}/stats`). */\nexport interface TelemetrySample {\n ts: number;\n direction: Direction;\n peer_identity?: string | null;\n /** App-measured glass-to-glass latency, ms, over the app's own window; the SDK never fills these. */\n g2g_p50?: number | null; g2g_p95?: number | null; g2g_samples?: number | null;\n rtt_ms?: number | null; net_one_way_ms?: number | null;\n jb_ms?: number | null; decode_ms?: number | null; encode_ms?: number | null;\n fps?: number | null; kbps?: number | null; loss_pct?: number | null; jitter_ms?: number | null;\n freezes?: number | null; freeze_ms?: number | null;\n transport?: string | null; candidate_type?: string | null; codec?: string | null;\n width?: number | null; height?: number | null;\n server_region?: string | null; server_version?: string | null; node_id?: string | null;\n join_ms?: number | null;\n extra?: Record<string, unknown>;\n}\n\nexport interface TelemetryOptions {\n apiBase: string;\n callId: string | null;\n token: string;\n enabled: boolean;\n sdkVersion: string;\n /** Flush interval in ms; 5000 by default. */\n intervalMs?: number;\n fetchFn?: typeof fetch;\n userAgent?: string;\n}\n\n/**\n * Batches stats snapshots and posts them every 5 s with the participant token. Silent when\n * disabled or when the credential carries no call id (manual credentials). Never throws.\n */\nexport class Telemetry {\n private queue: TelemetrySample[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private firstPost = true;\n private joinMs: number | null = null;\n readonly enabled: boolean;\n readonly url: string | null;\n\n constructor(private readonly opts: TelemetryOptions) {\n this.enabled = !!opts.enabled && !!opts.callId && typeof (opts.fetchFn ?? (typeof fetch === 'function' ? fetch : undefined)) === 'function';\n this.url = opts.callId ? `${opts.apiBase.replace(/\\/+$/, '')}/v1/calls/${encodeURIComponent(opts.callId)}/stats` : null;\n }\n\n start(joinMs: number | null): void {\n this.joinMs = joinMs;\n if (!this.enabled || this.timer) return;\n this.timer = setInterval(() => { void this.flush(); }, this.opts.intervalMs ?? 5000);\n }\n\n /**\n * Converts one snapshot into the two contract rows and queues them. `extra` adds app fields per\n * direction: the measured-latency columns (`MEASURED_COLUMNS`) are stored as columns, anything\n * else goes under `extra` next to the SDK's own keys, which win on a name clash.\n */\n push(s: CallStats, peerIdentity: string | null, extra?: { recv?: TelemetryFields | null; send?: TelemetryFields | null }): void {\n if (!this.enabled) return;\n const common = { ts: s.ts, peer_identity: peerIdentity, server_region: s.region, server_version: s.serverVersion, node_id: s.nodeId };\n const oneWay = s.recv.rttMs !== null ? Math.round(((s.recv.rttMs + (s.peerRttMs ?? s.recv.rttMs)) / 2) * 10) / 10 : null;\n this.queue.push(withFields({ ...common, direction: 'recv',\n rtt_ms: s.recv.rttMs, net_one_way_ms: oneWay, jb_ms: s.recv.jitterBufferMs, decode_ms: s.recv.decodeMs,\n fps: s.recv.fps, kbps: s.recv.kbps, loss_pct: s.recv.lossPct, jitter_ms: s.recv.jitterMs,\n freezes: s.recv.freezes, freeze_ms: s.recv.freezeMs, transport: s.recv.transport, candidate_type: s.recv.candidateType,\n codec: s.recv.codec, width: s.recv.width, height: s.recv.height,\n extra: { estimated_latency_ms: s.estimatedLatencyMs, abs_capture_ms: s.recv.absCaptureLatencyMs, processing_ms: s.recv.processingMs, quality: s.quality.recv, audio_route: s.audioRoute } }, extra?.recv));\n this.queue.push(withFields({ ...common, direction: 'send',\n rtt_ms: s.send.rttMs, encode_ms: s.send.encodeMs, fps: s.send.fps, kbps: s.send.kbps,\n transport: s.send.transport, candidate_type: s.send.candidateType, codec: s.send.codec, width: s.send.width, height: s.send.height,\n extra: { quality_limitation: s.send.qualityLimitation, target_kbps: s.send.targetKbps, quality: s.quality.send } }, extra?.send));\n if (this.queue.length > 120) this.queue.splice(0, this.queue.length - 120);\n }\n\n async flush(): Promise<void> {\n if (!this.enabled || !this.url || this.queue.length === 0) return;\n const samples = this.queue.splice(0, this.queue.length);\n const ua = this.opts.userAgent ?? (typeof navigator !== 'undefined' ? navigator.userAgent : '');\n for (const s of samples) {\n s.extra = { ...(s.extra ?? {}), sdk: this.opts.sdkVersion, platform: 'web', user_agent: ua };\n if (this.firstPost && this.joinMs !== null) s.join_ms = this.joinMs;\n }\n this.firstPost = false;\n const f = this.opts.fetchFn ?? fetch;\n try {\n await f(this.url, {\n method: 'POST',\n headers: { 'content-type': 'application/json', authorization: `Bearer ${this.opts.token}` },\n body: JSON.stringify({ samples }),\n keepalive: true,\n });\n } catch {\n /* telemetry is best effort; a failed post is dropped, never retried, never surfaced */\n }\n }\n\n async stop(): Promise<void> {\n if (this.timer) { clearInterval(this.timer); this.timer = null; }\n await this.flush();\n }\n}\n\nfunction withFields(row: TelemetrySample, fields: TelemetryFields | null | undefined): TelemetrySample {\n if (!fields || typeof fields !== 'object') return row;\n const extra: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(fields)) {\n if (MEASURED_COLUMNS.has(k)) (row as unknown as Record<string, unknown>)[k] = typeof v === 'number' && Number.isFinite(v) ? v : null;\n else extra[k] = v;\n }\n row.extra = { ...extra, ...(row.extra ?? {}) };\n return row;\n}\n", "import type { Room } from 'livekit-client';\nimport { Emitter } from './events';\nimport { CallError, mapEngineError } from './errors';\n\nexport interface DeviceInfo { id: string; label: string }\nexport interface DeviceList { cameras: DeviceInfo[]; microphones: DeviceInfo[]; speakers: DeviceInfo[] }\n\ntype DevicesEvents = { change: [DeviceList] };\n\n/**\n * Device selection. Labels are empty until the first getUserMedia permission is granted; after\n * `connect()` the list is complete. Speaker selection needs `setSinkId`, which Safari lacks.\n */\nexport class Devices {\n private readonly emitter = new Emitter<DevicesEvents>();\n private room: Room | null = null;\n private readonly audioElements = new Set<HTMLMediaElement>();\n private speakerId = '';\n private customVideo = false;\n private readonly onDeviceChange = () => { void this.list().then((l) => this.emitter.emit('change', l)); };\n\n /** @internal */\n _attachRoom(room: Room | null): void { this.room = room; }\n /** @internal The call publishes a custom video source, so the engine must not replace it with a camera. */\n _setCustomVideo(on: boolean): void { this.customVideo = on; }\n /** @internal */\n _registerAudioElement(el: HTMLMediaElement): void {\n this.audioElements.add(el);\n if (this.speakerId) void this.applySink(el);\n }\n /** @internal */\n _start(): void {\n if (typeof navigator !== 'undefined' && navigator.mediaDevices?.addEventListener) navigator.mediaDevices.addEventListener('devicechange', this.onDeviceChange);\n }\n /** @internal */\n _stop(): void {\n if (typeof navigator !== 'undefined' && navigator.mediaDevices?.removeEventListener) navigator.mediaDevices.removeEventListener('devicechange', this.onDeviceChange);\n this.audioElements.clear();\n }\n\n async list(): Promise<DeviceList> {\n const out: DeviceList = { cameras: [], microphones: [], speakers: [] };\n if (typeof navigator === 'undefined' || !navigator.mediaDevices?.enumerateDevices) return out;\n let devs: MediaDeviceInfo[] = [];\n try { devs = await navigator.mediaDevices.enumerateDevices(); } catch { return out; }\n devs.forEach((d, i) => {\n const info = { id: d.deviceId, label: d.label || `${kindLabel(d.kind)} ${i + 1}` };\n if (d.kind === 'videoinput') out.cameras.push(info);\n else if (d.kind === 'audioinput') out.microphones.push(info);\n else if (d.kind === 'audiooutput' && this.canSelectSpeaker) out.speakers.push(info);\n });\n return out;\n }\n\n get canSelectSpeaker(): boolean {\n return typeof HTMLMediaElement !== 'undefined' && typeof (HTMLMediaElement.prototype as { setSinkId?: unknown }).setSinkId === 'function';\n }\n\n async setCamera(deviceId: string): Promise<void> { await this.switch('videoinput', deviceId); }\n async setMicrophone(deviceId: string): Promise<void> { await this.switch('audioinput', deviceId); }\n\n async setSpeaker(deviceId: string): Promise<void> {\n if (!this.canSelectSpeaker) throw new CallError('unsupported', 'This browser cannot choose the audio output device.', { retryable: false });\n this.speakerId = deviceId;\n for (const el of this.audioElements) await this.applySink(el);\n if (this.room) { try { await this.room.switchActiveDevice('audiooutput', deviceId, true); } catch { /* elements already switched */ } }\n }\n\n onChange(handler: (list: DeviceList) => void): () => void { return this.emitter.on('change', handler); }\n\n private async switch(kind: MediaDeviceKind, deviceId: string): Promise<void> {\n if (!this.room) throw new CallError('internal', 'Devices can be switched after connect(); before that, pass the device id in options.', { retryable: false });\n if (kind === 'videoinput' && this.customVideo) throw new CallError('unsupported', 'The video comes from a custom videoSource; switch cameras in the code that produces it.', { retryable: false });\n try {\n const ok = await this.room.switchActiveDevice(kind, deviceId, true);\n if (!ok) throw new CallError('deviceUnavailable', `Could not switch to device ${deviceId}.`);\n } catch (e) {\n throw mapEngineError(e);\n }\n }\n\n private async applySink(el: HTMLMediaElement): Promise<void> {\n const sink = (el as HTMLMediaElement & { setSinkId?: (id: string) => Promise<void> }).setSinkId;\n if (typeof sink !== 'function') return;\n try { await sink.call(el, this.speakerId); } catch (e) { throw new CallError('deviceUnavailable', `Speaker switch failed: ${(e as Error)?.message ?? e}`, { cause: e }); }\n }\n}\n\nfunction kindLabel(k: MediaDeviceKind): string {\n return k === 'videoinput' ? 'camera' : k === 'audioinput' ? 'microphone' : 'speaker';\n}\n", "/** A renderable track. `attach` returns the element for chaining; `detach` with no element releases all. */\nexport interface VideoHandle {\n readonly kind: 'video' | 'audio';\n readonly mediaStreamTrack: MediaStreamTrack;\n /** Accepts a `<video>`/`<audio>` element or a `<qencode-video>` element; returns the media element that plays it. */\n attach(element: HTMLMediaElement | QencodeVideoElement): HTMLMediaElement;\n detach(element?: HTMLMediaElement | QencodeVideoElement): void;\n}\n\n/** True for `<qencode-video>` and anything else exposing a `track` setter and a `videoElement`. */\nfunction isVideoFrame(el: unknown): el is QencodeVideoElement {\n return !!el && typeof el === 'object' && 'videoElement' in (el as object) && 'track' in (el as object);\n}\n\ntype EngineTrack = {\n kind: string;\n mediaStreamTrack: MediaStreamTrack;\n attach(element: HTMLMediaElement): HTMLMediaElement;\n detach(element?: HTMLMediaElement): HTMLMediaElement | HTMLMediaElement[];\n};\n\n/** @internal Wraps an engine track so no engine type reaches the public API. */\nexport function wrapTrack(track: EngineTrack): VideoHandle {\n const handle: VideoHandle = {\n kind: track.kind === 'audio' ? 'audio' : 'video',\n get mediaStreamTrack() { return track.mediaStreamTrack; },\n attach: (el) => {\n if (isVideoFrame(el)) { el.track = handle; return el.videoElement; }\n return track.attach(el);\n },\n detach: (el) => {\n if (isVideoFrame(el)) { if (el.track === handle) el.track = null; return; }\n if (el) track.detach(el); else track.detach();\n },\n };\n return handle;\n}\n\nconst TEMPLATE = `\n<style>\n :host{display:block;position:relative;overflow:hidden;background:#000;aspect-ratio:16/9}\n video{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;background:#000}\n :host([fit=\"cover\"]) video{object-fit:cover}\n :host([mirror]) video{transform:scaleX(-1)}\n</style>\n<video autoplay playsinline muted></video>`;\n\n/**\n * `<qencode-video>`: a frame that renders a VideoHandle at its own aspect ratio.\n * Attributes: `mirror` (self view), `fit=\"contain|cover\"`. Property: `track` (VideoHandle | null).\n * Audio is never played by this element; the SDK plays remote audio itself.\n */\nexport class QencodeVideoElement extends HTMLElement {\n private _track: VideoHandle | null = null;\n private readonly video: HTMLVideoElement;\n\n constructor() {\n super();\n const root = this.attachShadow({ mode: 'open' });\n root.innerHTML = TEMPLATE;\n this.video = root.querySelector('video') as HTMLVideoElement;\n this.video.addEventListener('loadedmetadata', () => this.updateAspect());\n this.video.addEventListener('resize', () => this.updateAspect());\n }\n\n /** The inner `<video>` that plays the track. */\n get videoElement(): HTMLVideoElement { return this.video; }\n\n get track(): VideoHandle | null { return this._track; }\n set track(t: VideoHandle | null) {\n if (this._track === t) return;\n if (this._track) this._track.detach(this.video);\n this._track = t;\n if (t) t.attach(this.video);\n else this.video.srcObject = null;\n }\n\n disconnectedCallback(): void { if (this._track) this._track.detach(this.video); }\n\n private updateAspect(): void {\n const w = this.video.videoWidth, h = this.video.videoHeight;\n if (w && h && this.getAttribute('fit') !== 'cover') this.style.aspectRatio = `${w} / ${h}`;\n }\n}\n\n/** Registers `<qencode-video>` once; safe to call repeatedly and outside browsers. */\nexport function registerVideoElement(tag = 'qencode-video'): boolean {\n if (typeof customElements === 'undefined' || typeof HTMLElement === 'undefined') return false;\n if (!customElements.get(tag)) customElements.define(tag, QencodeVideoElement);\n return true;\n}\n", "/** SDK version, reported in telemetry as `extra.sdk`. Kept in sync with package.json by the build. */\nexport const SDK_VERSION = '0.2.0';\n", "export { Call, encodeMessage, decodeMessage } from './call';\nexport type { CallOptions, CallEvents, CallState, EndReason, Peer, MessagePayload, ModerationEvent, LogLevelName, VideoCodec, VideoSource, VideoSourceFactory, JitterBufferSupport, TelemetryExtra } from './call';\nexport { VIDEO_CODECS } from './call';\nexport type { TelemetryFields } from './telemetry';\nexport { CallError, isCallError } from './errors';\nexport type { CallErrorCode } from './errors';\nexport type { CallCredential, Region } from './credential';\nexport { PROFILES, DEFAULT_PROFILE } from './profiles';\nexport type { VideoProfileName, VideoProfile } from './profiles';\nexport { LATENCY_SETTINGS, DEFAULT_LATENCY_MODE } from './latency';\nexport type { LatencyMode, LatencySettings } from './latency';\nexport type { CallStats, RecvStats, SendStats, Quality, Direction, Transport, CandidateType, AudioRoute } from './stats';\nexport type { DeviceInfo, DeviceList } from './devices';\nexport type { VideoHandle } from './render';\nexport { QencodeVideoElement, registerVideoElement } from './render';\nexport { SDK_VERSION } from './version';\n\nimport { registerVideoElement } from './render';\n// Register <qencode-video> on import in browsers; a no-op elsewhere and when already defined.\nregisterVideoElement();\n"],
5
- "mappings": "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",
6
- "names": ["Room", "RoomEvent", "ConnectionState", "DisconnectReason", "Track", "setLogLevel", "DataPacket_Kind", "ConnectionError", "ConnectionErrorReason", "ConnectionError", "ConnectionErrorReason", "CallError", "code", "message", "opts", "DEFAULT_RETRYABLE", "isCallError", "e", "mapEngineError", "msg", "messageOf", "name", "Emitter", "event", "handler", "set", "off", "args", "h", "err", "EXPIRY_WARNING_MS", "parseCredential", "input", "CallError", "token", "url", "payload", "decodeJwtPayload", "video", "identity", "firstString", "roomName", "expiresAt", "parseExpiry", "regions", "r", "isExpired", "c", "now", "msUntilExpiryWarning", "v", "asNum", "iso", "t", "part", "b64", "json", "bytes", "i", "parsed", "vals", "PROFILES", "DEFAULT_PROFILE", "AUDIO_BITRATE", "resolveProfile", "name", "p", "LATENCY_SETTINGS", "DEFAULT_LATENCY_MODE", "latencySettings", "mode", "s", "applyJitterBufferTarget", "receiver", "ms", "r", "applyDegradationPreference", "sender", "pref", "params", "probeUrl", "signalingUrl", "u", "probeRegion", "region", "opts", "timeoutMs", "f", "now", "url", "once", "ctl", "timer", "t0", "chooseRegion", "regions", "pinned", "r", "x", "results", "probe", "i", "best", "ms", "DeltaTracker", "nowMs", "counters", "cur", "k", "v", "prev", "pickSelectedPair", "report", "pair", "s", "transportOf", "local", "proto", "ctype", "base", "transport", "rtt", "round1", "codecName", "codecId", "mime", "collectRecv", "tracker", "inbound", "t", "empty", "step", "out", "dt", "d", "lostAndRecv", "collectSend", "outbound", "remoteInbound", "lossPct", "NTP_EPOCH_OFFSET_MS", "absCaptureLatency", "sources", "unixNowMs", "perfNowMs", "s0", "captureNtp", "ageMs", "estimateLatency", "p", "peer", "frame", "QualityTracker", "_QualityTracker", "loss", "jb", "fr", "observed", "MEASURED_COLUMNS", "Telemetry", "opts", "joinMs", "s", "peerIdentity", "extra", "common", "oneWay", "withFields", "samples", "ua", "f", "row", "fields", "k", "v", "Devices", "Emitter", "l", "room", "on", "el", "out", "devs", "d", "i", "info", "kindLabel", "deviceId", "CallError", "handler", "kind", "e", "mapEngineError", "sink", "k", "isVideoFrame", "el", "wrapTrack", "track", "handle", "TEMPLATE", "QencodeVideoElement", "root", "w", "h", "registerVideoElement", "tag", "SDK_VERSION", "VIDEO_CODECS", "DEFAULT_API_BASE", "MSG_TOPIC", "STATS_TOPIC", "MSG_MAX_BYTES", "MSG_MAX_PER_SECOND", "STATS_INTERVAL_MS", "RECONNECT_WINDOW_MS", "enc", "dec", "Call", "_Call", "cred", "options", "Devices", "Emitter", "DeltaTracker", "QualityTracker", "DEFAULT_PROFILE", "DEFAULT_LATENCY_MODE", "resolveProfile", "latencySettings", "checkCodec", "checkJitterTarget", "setLogLevel", "credential", "parseCredential", "p", "event", "handler", "CallError", "isExpired", "t0", "now", "chooseRegion", "room", "connectOpts", "Telemetry", "SDK_VERSION", "e", "err", "mapEngineError", "reasonForError", "next", "ConnectionError", "ConnectionErrorReason", "region", "url", "ctl", "timer", "enabled", "Track", "name", "prev", "pub", "track", "mode", "s", "sender", "applyDegradationPreference", "ms", "opts", "source", "payload", "reliable", "bytes", "encodeMessage", "t", "x", "toNonShared", "adaptive", "Room", "RoomEvent", "_pub", "kind", "topic", "DataPacket_Kind", "reason", "l", "degradation", "AUDIO_BITRATE", "wrapTrack", "src", "wasMuted", "params", "receiver", "took", "applyJitterBufferTarget", "isAgent", "peerOf", "n", "left", "el", "muted", "m", "decodeMessage", "endReasonOf", "recvReport", "lp", "sendReport", "recv", "collectRecv", "emptyRecv", "send", "collectSend", "emptySend", "rx", "absCaptureLatency", "estimatedLatencyMs", "estimateLatency", "qr", "qs", "snap", "rtt", "ConnectionState", "fn", "one", "d", "v", "msUntilExpiryWarning", "at", "state", "out", "asAny", "leaving", "DisconnectReason", "c", "tag", "body", "registerVideoElement"]
4
+ "sourcesContent": ["import {\n Room, RoomEvent, ConnectionState, DisconnectReason, Track, setLogLevel,\n type RemoteParticipant, type RemoteTrack, type Participant, type TrackPublication,\n type RoomConnectOptions, type TrackPublishOptions, type VideoCaptureOptions, type AudioCaptureOptions,\n type LocalVideoTrack, DataPacket_Kind, ConnectionError, ConnectionErrorReason } from 'livekit-client';\nimport { CallError, mapEngineError } from './errors';\nimport { Emitter } from './events';\nimport { parseCredential, isExpired, msUntilExpiryWarning, type CallCredential, type ParsedCredential } from './credential';\nimport { resolveProfile, DEFAULT_PROFILE, AUDIO_BITRATE, type VideoProfileName, type VideoProfile } from './profiles';\nimport { latencySettings, applyJitterBufferTarget, applyDegradationPreference, DEFAULT_LATENCY_MODE, type LatencyMode } from './latency';\nimport { chooseRegion, type RegionChoice } from './regions';\nimport { DeltaTracker, QualityTracker, collectRecv, collectSend, estimateLatency, absCaptureLatency, type CallStats, type Quality, type Direction, type AudioRoute } from './stats';\nimport { Telemetry, type TelemetryFields } from './telemetry';\nimport { Devices, type DeviceList } from './devices';\nimport { wrapTrack, type VideoHandle } from './render';\nimport { SDK_VERSION } from './version';\n\nexport type CallState = 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'ended';\nexport type EndReason = 'left' | 'peerLeft' | 'roomClosed' | 'network' | 'credential' | 'error' | 'roomFull';\nexport type LogLevelName = 'debug' | 'info' | 'warn' | 'error' | 'silent';\n\nexport interface Peer {\n identity: string;\n name: string | null;\n audioMuted: boolean;\n videoMuted: boolean;\n}\n\n/** A data message from the peer. Strings and JSON objects arrive as sent; bytes arrive as Uint8Array. */\nexport type MessagePayload = string | Uint8Array | Record<string, unknown> | unknown[];\n\nexport interface ModerationEvent { level: 'warn' | 'mute' | 'end'; classes: string[]; at: number }\n\n/** Video codecs an app may ask for. H.264 is the default; the engine negotiates VP8 when a peer cannot decode the choice. */\nexport type VideoCodec = 'h264' | 'vp8' | 'vp9' | 'av1';\nexport const VIDEO_CODECS: readonly VideoCodec[] = Object.freeze(['h264', 'vp8', 'vp9', 'av1']);\n\n/**\n * Builds the video track to publish for a profile: size a canvas, open a screen, wrap a processed\n * camera. Called on every publish and republish, so a profile switch reaches it with the new size.\n */\nexport type VideoSourceFactory = (profile: VideoProfile) => MediaStreamTrack | Promise<MediaStreamTrack>;\nexport type VideoSource = MediaStreamTrack | VideoSourceFactory;\n\n/** Which receiver property took the jitter buffer target; null before the first remote video track. */\nexport type JitterBufferSupport = 'jitterBufferTarget' | 'playoutDelayHint' | 'unsupported' | null;\n\n/**\n * App fields for every telemetry row, called once per row with its direction. `g2g_p50`, `g2g_p95`\n * and `g2g_samples` (the app's own measured glass-to-glass latency, ms) are stored as columns;\n * every other key lands in the row's `extra` object.\n */\nexport type TelemetryExtra = (direction: Direction) => TelemetryFields | null | undefined;\n\nexport interface CallOptions {\n /** Publish the microphone on connect. Default true. */\n audio?: boolean;\n /** Publish the camera on connect. Default true. */\n video?: boolean;\n /** Named media tier. Default p540_60. */\n videoProfile?: VideoProfileName;\n /** `lowest` (default) or `smooth`. */\n latencyMode?: LatencyMode;\n /** Pin a region name from the credential; default picks the fastest by probe. */\n region?: string | null;\n /** Post quality stats to Qencode every 5 s. Default true. */\n telemetry?: boolean;\n /** Resume after network changes for up to 60 s. Default true. */\n autoReconnect?: boolean;\n /** Default 'warn'. Never logs media or credentials. */\n logLevel?: LogLevelName;\n /** API base used only by telemetry. Default https://api.qencode.com, or the credential's api_base. */\n apiBase?: string;\n /** Initial camera and microphone device ids. */\n cameraId?: string;\n microphoneId?: string;\n /** End the call when the peer leaves. Default true: a 1:1 call is over when one side is gone. */\n endOnPeerLeft?: boolean;\n /**\n * Let the engine adapt what it sends and receives to how the video is displayed (default true).\n * The receiver asks for the layer matching the rendered size in device pixels, and the sender\n * encodes only the layers someone is subscribed to. Set false to always receive and send the\n * full profile regardless of how the video is shown, as a measurement bench does.\n */\n adaptiveStream?: boolean;\n /**\n * With `adaptiveStream`, pause the remote video on the server while the page is hidden (a\n * background tab, a minimized window) and resume it when the page is shown again. Default\n * false: a call keeps its picture flowing so it is there the moment the user comes back, and\n * the peer's encoder never has to restart. Set true to save bandwidth while hidden.\n */\n pauseVideoInBackground?: boolean;\n /**\n * Publish this track instead of opening the camera: a canvas, a screen, a processed camera. A\n * factory is called with the profile on every publish and republish. The SDK stops a track a\n * factory returned when it is replaced or the call ends; a track passed directly stays yours to\n * stop. `devices.setCamera` does not apply while a custom source is published.\n */\n videoSource?: VideoSource;\n /** Video codec to publish. Default `h264`. */\n codec?: VideoCodec;\n /** Override the profile's simulcast setting. Default follows the profile. */\n simulcast?: boolean;\n /** Jitter buffer target in ms, overriding the latency mode's. `setLatencyMode` clears it. */\n jitterBufferTargetMs?: number;\n /** Fields appended to every telemetry row. */\n telemetryExtra?: TelemetryExtra;\n /** Forces TURN relay, for measuring the relay path. */\n forceRelay?: boolean;\n}\n\ntype OptionalKey = 'cameraId' | 'microphoneId' | 'region' | 'forceRelay' | 'videoSource' | 'simulcast' | 'jitterBufferTargetMs' | 'telemetryExtra';\n\nexport type CallEvents = {\n stateChanged: [CallState, EndReason | null];\n peerJoined: [Peer];\n peerLeft: [Peer];\n remoteVideo: [VideoHandle | null];\n remoteAudio: [VideoHandle | null];\n peerMuted: ['audio' | 'video', boolean];\n stats: [CallStats];\n qualityChanged: [Quality, Direction];\n message: [MessagePayload, boolean];\n credentialExpiring: [number];\n devicesChanged: [DeviceList];\n moderation: [ModerationEvent];\n error: [CallError];\n};\n\nconst DEFAULT_API_BASE = 'https://api.qencode.com';\nconst MSG_TOPIC = 'qencode:msg';\nconst STATS_TOPIC = 'qencode:stats';\nconst MSG_MAX_BYTES = 15 * 1024;\nconst MSG_MAX_PER_SECOND = 30;\nconst STATS_INTERVAL_MS = 1000;\nconst RECONNECT_WINDOW_MS = 60_000;\n\nconst enc = new TextEncoder();\nconst dec = new TextDecoder();\n\n/**\n * One 1:1 call. Create it from a credential minted by your backend, attach the video handles to\n * your views, and call `connect()`. The engine underneath is not part of this API.\n */\nexport class Call {\n static create(credential: CallCredential, options: CallOptions = {}): Call {\n return new Call(parseCredential(credential), options);\n }\n\n readonly devices = new Devices();\n readonly options: Readonly<Required<Omit<CallOptions, OptionalKey>> & Pick<CallOptions, OptionalKey>>;\n\n private readonly emitter = new Emitter<CallEvents>();\n private cred: ParsedCredential;\n private _state: CallState = 'idle';\n private _endReason: EndReason | null = null;\n private room: Room | null = null;\n private profile: VideoProfile;\n private latency: LatencyMode;\n private _codec: VideoCodec;\n private simulcastOverride: boolean | null;\n private jbOverride: number | null;\n private jbSupport: JitterBufferSupport = null;\n private videoSource: VideoSource | null;\n /** The MediaStreamTrack currently published from `videoSource`, and whether a factory made it (then the SDK stops it). */\n private sourceTrack: MediaStreamTrack | null = null;\n private sourceOwned = false;\n private regionChoice: RegionChoice | null = null;\n private _peer: Peer | null = null;\n private agentPresent = false;\n private remoteVideoTrack: RemoteTrack | null = null;\n private remoteAudioTrack: RemoteTrack | null = null;\n private _localVideo: VideoHandle | null = null;\n private _remoteVideo: VideoHandle | null = null;\n private _remoteAudio: VideoHandle | null = null;\n private audioEl: HTMLMediaElement | null = null;\n private statsTimer: ReturnType<typeof setInterval> | null = null;\n private expiryTimer: ReturnType<typeof setTimeout> | null = null;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private telemetry: Telemetry | null = null;\n private readonly recvTracker = new DeltaTracker();\n private readonly sendTracker = new DeltaTracker();\n private readonly recvQuality = new QualityTracker();\n private readonly sendQuality = new QualityTracker();\n private peerRttMs: number | null = null;\n private joinMs: number | null = null;\n private _stats: CallStats | null = null;\n private msgTimes: number[] = [];\n private leaving = false;\n private pendingEnd: EndReason | null = null;\n\n private constructor(cred: ParsedCredential, options: CallOptions) {\n this.cred = cred;\n this.options = Object.freeze({\n audio: options.audio ?? true,\n video: options.video ?? true,\n videoProfile: options.videoProfile ?? DEFAULT_PROFILE,\n latencyMode: options.latencyMode ?? DEFAULT_LATENCY_MODE,\n telemetry: options.telemetry ?? true,\n autoReconnect: options.autoReconnect ?? true,\n logLevel: options.logLevel ?? 'warn',\n apiBase: options.apiBase ?? cred.apiBase ?? DEFAULT_API_BASE,\n endOnPeerLeft: options.endOnPeerLeft ?? true,\n adaptiveStream: options.adaptiveStream ?? true,\n pauseVideoInBackground: options.pauseVideoInBackground ?? false,\n codec: options.codec ?? 'h264',\n cameraId: options.cameraId, microphoneId: options.microphoneId, region: options.region ?? null, forceRelay: options.forceRelay,\n videoSource: options.videoSource, simulcast: options.simulcast, jitterBufferTargetMs: options.jitterBufferTargetMs, telemetryExtra: options.telemetryExtra,\n });\n this.profile = resolveProfile(this.options.videoProfile);\n this.latency = this.options.latencyMode;\n latencySettings(this.latency); // validates\n this._codec = checkCodec(this.options.codec);\n this.simulcastOverride = typeof options.simulcast === 'boolean' ? options.simulcast : null;\n this.jbOverride = options.jitterBufferTargetMs === undefined ? null : checkJitterTarget(options.jitterBufferTargetMs);\n this.videoSource = options.videoSource ?? null;\n this.devices._setCustomVideo(this.videoSource !== null);\n this.devices._setInitial(options.cameraId, options.microphoneId);\n this.devices._setCaptureOptions(() => this.captureOptions());\n try { setLogLevel(this.options.logLevel); } catch { /* logger unavailable in this build */ }\n }\n\n // ------------------------------------------------------------------ public state\n\n get state(): CallState { return this._state; }\n get endReason(): EndReason | null { return this._endReason; }\n get peer(): Peer | null { return this._peer ? { ...this._peer } : null; }\n get localVideo(): VideoHandle | null { return this._localVideo; }\n get remoteVideo(): VideoHandle | null { return this._remoteVideo; }\n get remoteAudio(): VideoHandle | null { return this._remoteAudio; }\n get stats(): CallStats | null { return this._stats; }\n get videoProfile(): VideoProfileName { return this.profile.name; }\n get latencyMode(): LatencyMode { return this.latency; }\n get videoCodec(): VideoCodec { return this._codec; }\n /** Whether video is published with simulcast layers: the override when set, else the profile's setting. */\n get simulcast(): boolean { return this.simulcastOverride ?? this.profile.simulcast; }\n /** The jitter buffer target in force: the override when set, else the latency mode's. */\n get jitterBufferTargetMs(): number { return this.jbOverride ?? latencySettings(this.latency).jitterBufferTargetMs; }\n get jitterBufferSupport(): JitterBufferSupport { return this.jbSupport; }\n /** Region probe results in ms by name, or null when no probe ran (one region, or a pinned one). */\n get regionProbe(): Record<string, number> | null { const p = this.regionChoice?.probe; return p && Object.keys(p).length ? { ...p } : null; }\n get identity(): string { return this.cred.identity; }\n get callId(): string | null { return this.cred.callId; }\n get region(): string | null { return this.regionChoice?.region.name ?? null; }\n get credentialExpiresAt(): number | null { return this.cred.expiresAt; }\n get agentJoined(): boolean { return this.agentPresent; }\n\n on<K extends keyof CallEvents>(event: K, handler: (...args: CallEvents[K]) => void): () => void { return this.emitter.on(event, handler); }\n once<K extends keyof CallEvents>(event: K, handler: (...args: CallEvents[K]) => void): () => void { return this.emitter.once(event, handler); }\n off<K extends keyof CallEvents>(event: K, handler: (...args: CallEvents[K]) => void): void { this.emitter.off(event, handler); }\n\n // ------------------------------------------------------------------ lifecycle\n\n async connect(): Promise<void> {\n if (this._state !== 'idle') throw new CallError('internal', `connect() called in state \"${this._state}\"; create a new Call to connect again.`, { retryable: false });\n if (typeof navigator === 'undefined' || !navigator.mediaDevices) throw new CallError('unsupported', 'WebRTC media devices are not available here; a secure context (HTTPS or localhost) is required.');\n if (isExpired(this.cred)) {\n this.emitter.emit('credentialExpiring', this.cred.expiresAt ?? Date.now());\n throw new CallError('credentialExpired', 'The credential has expired; fetch a new one from your backend.');\n }\n this.setState('connecting', null);\n const t0 = now();\n try {\n this.regionChoice = await chooseRegion(this.cred.regions, this.options.region);\n const room = this.buildRoom();\n this.room = room;\n this.devices._attachRoom(room);\n this.devices._start();\n const connectOpts: RoomConnectOptions = { autoSubscribe: true };\n if (this.options.forceRelay) connectOpts.rtcConfig = { iceTransportPolicy: 'relay' };\n await room.connect(this.regionChoice.region.url, this.cred.token, connectOpts);\n if (this.leaving) throw new CallError('internal', 'Left during connect.', { retryable: false });\n this.adoptExistingParticipants(room);\n if (this.countHumans(room) >= 2) {\n this.pendingEnd = 'roomFull';\n await this.teardown();\n throw new CallError('roomFull', 'The call already has two participants.');\n }\n if (this.options.audio) await this.publishAudio();\n if (this.options.video && this.profile.video) await this.publishVideo();\n this.joinMs = Math.round(now() - t0);\n this.setState('connected', null);\n // A peer already in the room never triggers ParticipantConnected; report it the same way.\n if (this._peer) this.emitter.emit('peerJoined', { ...this._peer });\n this.scheduleExpiryWarning();\n this.startStats();\n this.telemetry = new Telemetry({ apiBase: this.options.apiBase, callId: this.cred.callId, token: this.cred.token, enabled: this.options.telemetry, sdkVersion: SDK_VERSION });\n this.telemetry.start(this.joinMs);\n this.sendHello();\n } catch (e) {\n let err = mapEngineError(e);\n if (err.code === 'network' && await this.joinRefusedByServer(e)) err = new CallError('roomFull', 'The call already has two participants.', { cause: e });\n this.pendingEnd = this.pendingEnd ?? reasonForError(err);\n // End first so the error reaches listeners; the engine's Disconnected during teardown then finds the call already ended.\n this.finish(this.pendingEnd, err);\n await this.teardown();\n throw err;\n }\n }\n\n async leave(): Promise<void> {\n if (this._state === 'ended') return;\n this.leaving = true;\n this.pendingEnd = this.pendingEnd ?? 'left';\n await this.teardown();\n this.finish(this.pendingEnd, null);\n }\n\n /** Replace the credential (same call, same identity) so the next reconnect uses a fresh token. */\n updateCredential(credential: CallCredential): void {\n const next = parseCredential(credential);\n if (next.roomName !== this.cred.roomName || next.identity !== this.cred.identity) {\n throw new CallError('credentialInvalid', 'The new credential is for a different call or identity.', { retryable: false });\n }\n this.cred = next;\n if (this._state === 'connected' || this._state === 'reconnecting') this.scheduleExpiryWarning();\n }\n\n /**\n * A media server refuses a join with a bare websocket close, and a browser never sees the\n * reason. When the server's validate endpoint still accepts the very same credential, the\n * refusal was not the token, the room or the network; on a two-person room it is capacity.\n * One short request on the failure path only.\n */\n private async joinRefusedByServer(e: unknown): Promise<boolean> {\n if (!(e instanceof ConnectionError)) return false;\n if (e.reason !== ConnectionErrorReason.WebSocket && e.reason !== ConnectionErrorReason.InternalError) return false;\n const region = this.regionChoice?.region;\n if (!region || typeof fetch !== 'function') return false;\n try {\n const url = new URL(region.url);\n url.protocol = url.protocol === 'ws:' || url.protocol === 'http:' ? 'http:' : 'https:';\n url.pathname = `${url.pathname.replace(/\\/+$/, '')}/rtc/validate`;\n url.search = `access_token=${encodeURIComponent(this.cred.token)}`;\n const ctl = typeof AbortController === 'function' ? new AbortController() : undefined;\n const timer = setTimeout(() => ctl?.abort(), 3000);\n try {\n const r = await fetch(url.toString(), { cache: 'no-store', credentials: 'omit', signal: ctl?.signal });\n return r.status === 200;\n } finally { clearTimeout(timer); }\n } catch { return false; }\n }\n\n // ------------------------------------------------------------------ media controls\n\n async setMicrophoneEnabled(enabled: boolean): Promise<void> {\n const room = this.requireRoom();\n try {\n if (enabled && !room.localParticipant.getTrackPublication(Track.Source.Microphone)) await this.publishAudio();\n else await room.localParticipant.setMicrophoneEnabled(enabled);\n } catch (e) { throw mapEngineError(e); }\n }\n\n async setCameraEnabled(enabled: boolean): Promise<void> {\n const room = this.requireRoom();\n try {\n if (enabled) {\n if (!this.profile.video) this.profile = resolveProfile(DEFAULT_PROFILE);\n if (!room.localParticipant.getTrackPublication(Track.Source.Camera)) await this.publishVideo();\n else { await room.localParticipant.setCameraEnabled(true); if (!this.videoSource) await this.devices._cameraPublished(); }\n } else {\n await room.localParticipant.setCameraEnabled(false);\n }\n } catch (e) { throw mapEngineError(e); }\n }\n\n /**\n * Switch resolution, frame rate and bitrate cap mid-call. A simulcast change or a factory video\n * source republishes the track; a camera restarts capture in place; a fixed custom track only\n * gets the new encoding parameters.\n */\n async setVideoProfile(name: VideoProfileName): Promise<void> {\n const next = resolveProfile(name);\n const prev = this.profile;\n this.profile = next;\n const room = this.room;\n if (!room || this._state === 'ended') return;\n try {\n const pub = room.localParticipant.getTrackPublication(Track.Source.Camera);\n if (!next.video) { await this.unpublishVideo(); return; }\n if (!pub?.track) { await this.publishVideo(); return; }\n const simulcastChanged = (this.simulcastOverride ?? prev.simulcast) !== (this.simulcastOverride ?? next.simulcast);\n if (simulcastChanged || typeof this.videoSource === 'function') { await this.republishVideo(); return; }\n const track = pub.track as LocalVideoTrack;\n if (!this.videoSource) await track.restartTrack(this.captureOptions());\n await this.applyEncoding(track.sender, next);\n } catch (e) { throw mapEngineError(e); }\n }\n\n async setLatencyMode(mode: LatencyMode): Promise<void> {\n const s = latencySettings(mode);\n this.latency = mode;\n this.jbOverride = null;\n this.applyJitterTarget();\n const pub = this.room?.localParticipant.getTrackPublication(Track.Source.Camera);\n const sender = (pub?.track as LocalVideoTrack | undefined)?.sender;\n if (sender) await applyDegradationPreference(sender, s.degradationPreference);\n }\n\n /**\n * Pin the receiver's jitter buffer target in ms regardless of the latency mode (0 asks the\n * browser for its floor). Returns which receiver property took it; `unsupported` on Firefox.\n * `setLatencyMode` clears the pin.\n */\n setJitterBufferTarget(ms: number): JitterBufferSupport {\n this.jbOverride = checkJitterTarget(ms);\n return this.applyJitterTarget();\n }\n\n /** Change the codec or the simulcast setting mid-call; the video track is republished. */\n async setVideoEncoding(opts: { codec?: VideoCodec; simulcast?: boolean | null }): Promise<void> {\n if (opts.codec !== undefined) this._codec = checkCodec(opts.codec);\n if (opts.simulcast !== undefined) this.simulcastOverride = opts.simulcast;\n if (!this.room || this._state === 'ended') return;\n try { await this.republishVideo(); } catch (e) { throw mapEngineError(e); }\n }\n\n /** Replace the video source mid-call; `null` returns to the camera. Republishes when video is published. */\n async setVideoSource(source: VideoSource | null): Promise<void> {\n this.videoSource = source;\n this.devices._setCustomVideo(source !== null);\n if (!this.room || this._state === 'ended') return;\n try { await this.republishVideo(); } catch (e) { throw mapEngineError(e); }\n }\n\n /** Send up to 15 KB to the peer. Strings and JSON-able objects arrive as sent; Uint8Array arrives as bytes. */\n async sendMessage(payload: MessagePayload, reliable = true): Promise<void> {\n const room = this.requireRoom();\n const bytes = encodeMessage(payload);\n if (bytes.byteLength > MSG_MAX_BYTES) throw new CallError('internal', `Message is ${bytes.byteLength} bytes; the limit is ${MSG_MAX_BYTES}.`, { retryable: false });\n const t = Date.now();\n this.msgTimes = this.msgTimes.filter((x) => t - x < 1000);\n if (this.msgTimes.length >= MSG_MAX_PER_SECOND) throw new CallError('internal', `Message rate limit: at most ${MSG_MAX_PER_SECOND} messages per second.`, { retryable: true });\n this.msgTimes.push(t);\n try { await room.localParticipant.publishData(toNonShared(bytes), { reliable, topic: MSG_TOPIC }); }\n catch (e) { throw mapEngineError(e); }\n }\n\n // ------------------------------------------------------------------ engine wiring\n\n private buildRoom(): Room {\n const s = latencySettings(this.latency);\n const adaptive = this.options.adaptiveStream !== false;\n const room = new Room({\n adaptiveStream: adaptive\n ? { pauseVideoInBackground: this.options.pauseVideoInBackground === true, pixelDensity: 'screen' }\n : false,\n dynacast: adaptive,\n publishDefaults: this.publishOptions(s.degradationPreference),\n videoCaptureDefaults: this.captureOptions(),\n audioCaptureDefaults: this.audioCaptureOptions(),\n });\n room.on(RoomEvent.ParticipantConnected, (p) => this.onParticipantConnected(p));\n room.on(RoomEvent.ParticipantDisconnected, (p) => this.onParticipantDisconnected(p));\n room.on(RoomEvent.TrackSubscribed, (track, _pub, p) => this.onTrackSubscribed(track, p));\n room.on(RoomEvent.TrackUnsubscribed, (track) => this.onTrackUnsubscribed(track));\n room.on(RoomEvent.TrackMuted, (pub, p) => this.onMuteChange(pub, p, true));\n room.on(RoomEvent.TrackUnmuted, (pub, p) => this.onMuteChange(pub, p, false));\n room.on(RoomEvent.DataReceived, (payload, p, kind, topic) => this.onData(payload, p, topic, kind !== DataPacket_Kind.LOSSY));\n room.on(RoomEvent.Reconnecting, () => this.onReconnecting());\n room.on(RoomEvent.Reconnected, () => this.onReconnected());\n room.on(RoomEvent.Disconnected, (reason) => this.onDisconnected(reason));\n room.on(RoomEvent.MediaDevicesError, (e) => this.emitter.emit('error', mapEngineError(e)));\n room.on(RoomEvent.MediaDevicesChanged, () => { void this.devices.list().then((l) => this.emitter.emit('devicesChanged', l)); });\n return room;\n }\n\n private publishOptions(degradation: RTCDegradationPreference): TrackPublishOptions {\n return {\n videoCodec: this._codec,\n simulcast: this.simulcast,\n videoEncoding: this.profile.video ? { maxBitrate: this.profile.maxBitrate, maxFramerate: this.profile.fps } : undefined,\n degradationPreference: degradation,\n dtx: false,\n audioPreset: { maxBitrate: AUDIO_BITRATE },\n };\n }\n\n /** Profile resolution plus the camera the devices object currently selects (an id, a facing, or the default). */\n private captureOptions(): VideoCaptureOptions {\n const p = this.profile.video ? this.profile : resolveProfile(DEFAULT_PROFILE);\n return { resolution: { width: p.width, height: p.height, frameRate: p.fps, aspectRatio: p.width / p.height }, ...this.devices._videoSelection() };\n }\n\n private audioCaptureOptions(): AudioCaptureOptions {\n return { echoCancellation: true, noiseSuppression: true, autoGainControl: true, deviceId: this.devices._microphoneSelection() };\n }\n\n private async publishAudio(): Promise<void> {\n const room = this.requireRoom();\n try { await room.localParticipant.setMicrophoneEnabled(true, this.audioCaptureOptions(), this.publishOptions(latencySettings(this.latency).degradationPreference)); }\n catch (e) { throw mapEngineError(e); }\n }\n\n private async publishVideo(): Promise<void> {\n const room = this.requireRoom();\n try {\n const opts = this.publishOptions(latencySettings(this.latency).degradationPreference);\n let track: unknown;\n if (this.videoSource) {\n const source = await this.resolveSource();\n const pub = await room.localParticipant.publishTrack(source, { ...opts, source: Track.Source.Camera, name: 'camera' });\n track = pub?.track;\n } else {\n let pub;\n try { pub = await room.localParticipant.setCameraEnabled(true, this.captureOptions(), opts); }\n catch (e) {\n // A remembered camera that is gone or busy must not fail the call: fall back to the default one once.\n if (!this.devices.cameraId || mapEngineError(e).code !== 'deviceUnavailable') throw e;\n this.devices._clearCamera();\n pub = await room.localParticipant.setCameraEnabled(true, this.captureOptions(), opts);\n }\n track = pub?.track;\n await this.devices._cameraPublished();\n }\n this._localVideo = track ? wrapTrack(track as Parameters<typeof wrapTrack>[0]) : null;\n } catch (e) { this.releaseSource(); throw mapEngineError(e); }\n }\n\n /** Takes the track from `videoSource`; a factory's result is owned by the SDK, a passed track is not. */\n private async resolveSource(): Promise<MediaStreamTrack> {\n const src = this.videoSource as VideoSource;\n const track = typeof src === 'function' ? await src(this.profile.video ? this.profile : resolveProfile(DEFAULT_PROFILE)) : src;\n if (!track || typeof track !== 'object' || (track as MediaStreamTrack).kind !== 'video') {\n throw new CallError('internal', 'videoSource must be, or return, a video MediaStreamTrack.', { retryable: false });\n }\n this.sourceTrack = track;\n this.sourceOwned = typeof src === 'function';\n return track;\n }\n\n private releaseSource(): void {\n if (this.sourceTrack && this.sourceOwned) { try { this.sourceTrack.stop(); } catch { /* already ended */ } }\n this.sourceTrack = null;\n this.sourceOwned = false;\n }\n\n private async unpublishVideo(): Promise<void> {\n const room = this.room;\n const pub = room?.localParticipant.getTrackPublication(Track.Source.Camera);\n // A track the app handed us is never stopped by the SDK; everything else is.\n if (room && pub?.track) await room.localParticipant.unpublishTrack(pub.track, this.sourceTrack ? this.sourceOwned : true);\n this.releaseSource();\n this._localVideo = null;\n this.sendTracker.reset();\n }\n\n /** Unpublish and publish again with the current source, codec, simulcast and profile. A muted camera stays off. */\n private async republishVideo(): Promise<void> {\n const room = this.room;\n if (!room) return;\n const pub = room.localParticipant.getTrackPublication(Track.Source.Camera);\n if (!pub?.track) return; // video off or audio-only: the next enable publishes fresh\n const wasMuted = !!pub.isMuted;\n await this.unpublishVideo();\n if (!wasMuted && this.profile.video) await this.publishVideo();\n }\n\n private async applyEncoding(sender: RTCRtpSender | undefined, p: VideoProfile): Promise<void> {\n if (!sender) return;\n const params = sender.getParameters();\n params.encodings = (params.encodings && params.encodings.length ? params.encodings : [{}]).map((e) => ({ ...e, maxBitrate: p.maxBitrate, maxFramerate: p.fps }));\n await sender.setParameters(params);\n }\n\n private applyJitterTarget(): JitterBufferSupport {\n const receiver = this.remoteVideoTrack?.receiver;\n if (!receiver) return this.jbSupport;\n const took = applyJitterBufferTarget(receiver, this.jitterBufferTargetMs);\n this.jbSupport = took ?? 'unsupported';\n return this.jbSupport;\n }\n\n private adoptExistingParticipants(room: Room): void {\n room.remoteParticipants.forEach((p) => {\n if (isAgent(p)) { this.agentPresent = true; return; }\n if (!this._peer) this._peer = peerOf(p);\n });\n }\n\n private countHumans(room: Room): number {\n let n = 0;\n room.remoteParticipants.forEach((p) => { if (!isAgent(p)) n += 1; });\n return n;\n }\n\n private onParticipantConnected(p: RemoteParticipant): void {\n if (isAgent(p)) { this.agentPresent = true; return; }\n if (this._peer && this._peer.identity !== p.identity) return; // a third human; the room cap should have rejected it\n this._peer = peerOf(p);\n this.emitter.emit('peerJoined', { ...this._peer });\n this.sendHello();\n }\n\n private onParticipantDisconnected(p: RemoteParticipant): void {\n if (isAgent(p)) { this.agentPresent = false; return; }\n if (!this._peer || this._peer.identity !== p.identity) return;\n const left = { ...this._peer };\n this._peer = null;\n this.peerRttMs = null;\n this.emitter.emit('peerLeft', left);\n if (this.options.endOnPeerLeft) void this.endWith('peerLeft');\n }\n\n private onTrackSubscribed(track: RemoteTrack, p: RemoteParticipant): void {\n if (isAgent(p)) return;\n if (track.kind === Track.Kind.Video) {\n this.remoteVideoTrack = track;\n this.recvTracker.reset();\n this.applyJitterTarget();\n this._remoteVideo = wrapTrack(track as unknown as Parameters<typeof wrapTrack>[0]);\n this.emitter.emit('remoteVideo', this._remoteVideo);\n } else if (track.kind === Track.Kind.Audio) {\n this.remoteAudioTrack = track;\n const el = this.ensureAudioElement();\n if (el) track.attach(el);\n this._remoteAudio = wrapTrack(track as unknown as Parameters<typeof wrapTrack>[0]);\n this.emitter.emit('remoteAudio', this._remoteAudio);\n }\n }\n\n private onTrackUnsubscribed(track: RemoteTrack): void {\n if (track === this.remoteVideoTrack) { this.remoteVideoTrack = null; this._remoteVideo = null; this.emitter.emit('remoteVideo', null); }\n if (track === this.remoteAudioTrack) { this.remoteAudioTrack = null; this._remoteAudio = null; this.emitter.emit('remoteAudio', null); }\n try { track.detach(); } catch { /* already detached */ }\n }\n\n private onMuteChange(pub: TrackPublication, p: Participant, muted: boolean): void {\n if (!this._peer || p.identity !== this._peer.identity) return;\n const kind = pub.kind === Track.Kind.Audio ? 'audio' : 'video';\n if (kind === 'audio') this._peer.audioMuted = muted; else this._peer.videoMuted = muted;\n this.emitter.emit('peerMuted', kind, muted);\n }\n\n private onData(payload: Uint8Array, p: RemoteParticipant | undefined, topic: string | undefined, reliable = true): void {\n if (p && isAgent(p)) return;\n if (topic === STATS_TOPIC) {\n try { const m = JSON.parse(dec.decode(payload)); if (typeof m.rtt === 'number') this.peerRttMs = m.rtt; } catch { /* ignore */ }\n return;\n }\n if (topic === MSG_TOPIC) {\n try { this.emitter.emit('message', decodeMessage(payload), reliable); } catch { /* malformed */ }\n }\n }\n\n private onReconnecting(): void {\n if (this._state !== 'connected') return;\n this.setState('reconnecting', null);\n if (this.cred.expiresAt !== null && isExpired(this.cred)) this.emitter.emit('credentialExpiring', this.cred.expiresAt);\n if (!this.options.autoReconnect) { void this.endWith('network'); return; }\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n this.reconnectTimer = setTimeout(() => { if (this._state === 'reconnecting') void this.endWith('network'); }, RECONNECT_WINDOW_MS);\n }\n\n private onReconnected(): void {\n if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); this.reconnectTimer = null; }\n if (this._state === 'reconnecting') this.setState('connected', null);\n this.recvTracker.reset(); this.sendTracker.reset();\n }\n\n private onDisconnected(reason?: DisconnectReason): void {\n if (this._state === 'ended') return;\n void this.endWith(this.pendingEnd ?? endReasonOf(reason, this.leaving));\n }\n\n // ------------------------------------------------------------------ stats loop\n\n private startStats(): void {\n if (this.statsTimer) return;\n this.statsTimer = setInterval(() => { void this.pollStats(); }, STATS_INTERVAL_MS);\n }\n\n private async pollStats(): Promise<void> {\n const room = this.room;\n if (!room || (this._state !== 'connected' && this._state !== 'reconnecting')) return;\n const t = Date.now();\n try {\n const recvReport = await (this.remoteVideoTrack ?? this.remoteAudioTrack)?.receiver?.getStats?.();\n const lp = room.localParticipant;\n const localTrack = (lp.getTrackPublication(Track.Source.Camera)?.track ?? lp.getTrackPublication(Track.Source.Microphone)?.track) as LocalVideoTrack | undefined;\n const sendReport = await localTrack?.sender?.getStats?.();\n const recv = recvReport ? collectRecv(recvReport, this.recvTracker, t) : emptyRecv();\n const send = sendReport ? collectSend(sendReport, this.sendTracker, t) : emptySend();\n try {\n const rx = this.remoteVideoTrack?.receiver as (RTCRtpReceiver & { getSynchronizationSources?: () => RTCRtpSynchronizationSource[] }) | undefined;\n if (rx?.getSynchronizationSources) recv.absCaptureLatencyMs = absCaptureLatency(rx.getSynchronizationSources(), t, now());\n } catch { /* not exposed here */ }\n const estimatedLatencyMs = estimateLatency({ rttMs: recv.rttMs ?? send.rttMs, peerRttMs: this.peerRttMs, jitterBufferMs: recv.jitterBufferMs, decodeMs: recv.decodeMs, fps: recv.fps });\n const qr = this.recvQuality.update({ lossPct: recv.lossPct, jitterBufferMs: recv.jitterBufferMs, freezes: recv.freezes, rttMs: recv.rttMs });\n const qs = this.sendQuality.update({ lossPct: send.lossPct, jitterBufferMs: null, freezes: null, rttMs: send.rttMs });\n const prev = this._stats;\n const snap: CallStats = {\n ts: t, recv, send, peerRttMs: this.peerRttMs, estimatedLatencyMs,\n quality: { recv: qr, send: qs },\n region: room.serverInfo?.region ?? this.regionChoice?.region.name ?? null,\n nodeId: room.serverInfo?.nodeId ?? null,\n serverVersion: room.serverInfo?.version ?? null,\n joinMs: this.joinMs,\n audioRoute: this.audioRoute(),\n };\n this._stats = snap;\n this.emitter.emit('stats', snap);\n if (!prev || prev.quality.recv !== qr) this.emitter.emit('qualityChanged', qr, 'recv');\n if (!prev || prev.quality.send !== qs) this.emitter.emit('qualityChanged', qs, 'send');\n if (this.telemetry?.enabled) this.telemetry.push(snap, this._peer?.identity ?? null, this.extraFields());\n const rtt = recv.rttMs ?? send.rttMs;\n if (rtt !== null && room.state === ConnectionState.Connected) {\n try { await lp.publishData(enc.encode(JSON.stringify({ t: 'rtt', rtt })), { reliable: false, topic: STATS_TOPIC }); } catch { /* channel not ready */ }\n }\n } catch (e) {\n this.emitter.emit('error', new CallError('internal', `Stats collection failed: ${(e as Error)?.message ?? e}`, { cause: e }));\n }\n }\n\n private extraFields(): { recv: TelemetryFields | null; send: TelemetryFields | null } | undefined {\n const fn = this.options.telemetryExtra;\n if (!fn) return undefined;\n const one = (d: Direction): TelemetryFields | null => {\n try { const v = fn(d); return v && typeof v === 'object' ? v : null; }\n catch (e) { this.emitter.emit('error', new CallError('internal', `telemetryExtra threw: ${(e as Error)?.message ?? e}`, { cause: e })); return null; }\n };\n return { recv: one('recv'), send: one('send') };\n }\n\n private audioRoute(): AudioRoute {\n if (typeof navigator === 'undefined') return 'unknown';\n const label = (this.audioEl as { sinkId?: string } | null)?.sinkId ?? '';\n if (!label) return 'unknown';\n return 'unknown';\n }\n\n private sendHello(): void {\n const room = this.room;\n if (!room || room.state !== ConnectionState.Connected) return;\n void room.localParticipant.publishData(enc.encode(JSON.stringify({ t: 'hello', sdk: SDK_VERSION })), { reliable: true, topic: STATS_TOPIC }).catch(() => undefined);\n }\n\n // ------------------------------------------------------------------ housekeeping\n\n private scheduleExpiryWarning(): void {\n if (this.expiryTimer) { clearTimeout(this.expiryTimer); this.expiryTimer = null; }\n const ms = msUntilExpiryWarning(this.cred);\n if (ms === null) return;\n const at = this.cred.expiresAt as number;\n this.expiryTimer = setTimeout(() => { this.expiryTimer = null; if (this._state === 'connected' || this._state === 'reconnecting') this.emitter.emit('credentialExpiring', at); }, ms);\n }\n\n private ensureAudioElement(): HTMLMediaElement | null {\n if (this.audioEl) return this.audioEl;\n if (typeof document === 'undefined') return null;\n const el = document.createElement('audio');\n el.autoplay = true;\n el.setAttribute('playsinline', '');\n el.style.display = 'none';\n document.body?.appendChild(el);\n this.audioEl = el;\n this.devices._registerAudioElement(el);\n return el;\n }\n\n private requireRoom(): Room {\n if (!this.room || this._state === 'ended' || this._state === 'idle') throw new CallError('internal', `Not connected (state \"${this._state}\").`, { retryable: false });\n return this.room;\n }\n\n private setState(state: CallState, reason: EndReason | null): void {\n if (this._state === state && state !== 'ended') return;\n this._state = state;\n if (state === 'ended') this._endReason = reason;\n this.emitter.emit('stateChanged', state, state === 'ended' ? reason : null);\n }\n\n private async endWith(reason: EndReason): Promise<void> {\n if (this._state === 'ended') return;\n // teardown() disconnects the engine, which emits Disconnected(CLIENT_INITIATED) before we\n // get back here; remember why we are ending so that handler does not relabel it as 'left'.\n this.pendingEnd = this.pendingEnd ?? reason;\n await this.teardown();\n this.finish(this.pendingEnd, null);\n }\n\n private finish(reason: EndReason, err: CallError | null): void {\n if (this._state === 'ended') return;\n if (err) this.emitter.emit('error', err);\n this.setState('ended', reason);\n }\n\n private async teardown(): Promise<void> {\n if (this.statsTimer) { clearInterval(this.statsTimer); this.statsTimer = null; }\n if (this.expiryTimer) { clearTimeout(this.expiryTimer); this.expiryTimer = null; }\n if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); this.reconnectTimer = null; }\n if (this.telemetry) { await this.telemetry.stop(); this.telemetry = null; }\n this.devices._stop();\n this.devices._attachRoom(null);\n const room = this.room;\n this.room = null;\n if (room) {\n // The engine's disconnect stops every published track; a track the app handed us must survive it.\n if (this.sourceTrack && !this.sourceOwned) {\n const pub = room.localParticipant.getTrackPublication(Track.Source.Camera);\n if (pub?.track) { try { await room.localParticipant.unpublishTrack(pub.track, false); } catch { /* already gone */ } }\n }\n try { await room.disconnect(true); } catch { /* already closed */ }\n }\n this.releaseSource();\n this.jbSupport = null;\n if (this.audioEl) { try { this.audioEl.srcObject = null; this.audioEl.remove(); } catch { /* detached */ } this.audioEl = null; }\n this.remoteVideoTrack = null; this.remoteAudioTrack = null;\n this._remoteVideo = null; this._remoteAudio = null; this._localVideo = null;\n }\n}\n\n// ------------------------------------------------------------------ helpers\n\nfunction now(): number { return typeof performance !== 'undefined' ? performance.now() : Date.now(); }\n\n/** The engine requires a Uint8Array over a plain ArrayBuffer (never a SharedArrayBuffer). */\nfunction toNonShared(bytes: Uint8Array): Uint8Array<ArrayBuffer> {\n const out = new Uint8Array(new ArrayBuffer(bytes.byteLength));\n out.set(bytes);\n return out;\n}\n\nfunction isAgent(p: Participant): boolean {\n const asAny = p as { isAgent?: boolean; kind?: unknown };\n if (typeof asAny.isAgent === 'boolean') return asAny.isAgent;\n return asAny.kind === 4; // ParticipantKind.AGENT\n}\n\nfunction peerOf(p: RemoteParticipant): Peer {\n return {\n identity: p.identity,\n name: p.name || null,\n audioMuted: p.getTrackPublication(Track.Source.Microphone)?.isMuted ?? false,\n videoMuted: p.getTrackPublication(Track.Source.Camera)?.isMuted ?? false,\n };\n}\n\nfunction reasonForError(err: CallError): EndReason {\n switch (err.code) {\n case 'roomFull': return 'roomFull';\n case 'roomClosed': return 'roomClosed';\n case 'credentialInvalid': case 'credentialExpired': return 'credential';\n case 'network': return 'network';\n default: return 'error';\n }\n}\n\n/** Engine disconnect reasons to the SDK's end reasons. */\nfunction endReasonOf(reason: DisconnectReason | undefined, leaving: boolean): EndReason {\n if (leaving) return 'left';\n switch (reason) {\n case DisconnectReason.CLIENT_INITIATED: return 'left';\n case DisconnectReason.ROOM_DELETED:\n case DisconnectReason.ROOM_CLOSED:\n case DisconnectReason.SERVER_SHUTDOWN:\n case DisconnectReason.PARTICIPANT_REMOVED: return 'roomClosed';\n case DisconnectReason.DUPLICATE_IDENTITY:\n case DisconnectReason.USER_REJECTED: return 'credential';\n case DisconnectReason.JOIN_FAILURE: return 'error';\n default: return 'network';\n }\n}\n\nfunction emptyRecv(): CallStats['recv'] {\n return { rttMs: null, jitterBufferMs: null, decodeMs: null, fps: null, width: null, height: null, kbps: null, lossPct: null, jitterMs: null, freezes: null, freezeMs: null, processingMs: null, absCaptureLatencyMs: null, codec: null, transport: null, candidateType: null };\n}\nfunction emptySend(): CallStats['send'] {\n return { rttMs: null, encodeMs: null, fps: null, width: null, height: null, kbps: null, targetKbps: null, qualityLimitation: null, lossPct: null, codec: null, transport: null, candidateType: null };\n}\n\nfunction checkCodec(c: unknown): VideoCodec {\n if (typeof c === 'string' && (VIDEO_CODECS as readonly string[]).includes(c)) return c as VideoCodec;\n throw new RangeError(`Unknown video codec \"${String(c)}\". Known: ${VIDEO_CODECS.join(', ')}`);\n}\n\nfunction checkJitterTarget(ms: unknown): number {\n if (typeof ms !== 'number' || !Number.isFinite(ms) || ms < 0 || ms > 4000) throw new RangeError('jitterBufferTargetMs must be a number between 0 and 4000.');\n return ms;\n}\n\n/** Envelope: 1 tag byte (1 string, 2 json, 3 bytes) followed by the payload. */\nexport function encodeMessage(payload: MessagePayload): Uint8Array {\n let tag: number, body: Uint8Array;\n if (typeof payload === 'string') { tag = 1; body = enc.encode(payload); }\n else if (payload instanceof Uint8Array) { tag = 3; body = payload; }\n else { tag = 2; body = enc.encode(JSON.stringify(payload)); }\n const out = new Uint8Array(body.byteLength + 1);\n out[0] = tag; out.set(body, 1);\n return out;\n}\n\nexport function decodeMessage(bytes: Uint8Array): MessagePayload {\n const tag = bytes[0], body = bytes.subarray(1);\n if (tag === 1) return dec.decode(body);\n if (tag === 2) return JSON.parse(dec.decode(body)) as MessagePayload;\n if (tag === 3) return body.slice();\n throw new Error('unknown message envelope');\n}\n", "import { ConnectionError, ConnectionErrorReason } from 'livekit-client';\n\n/** Stable error codes, identical on every platform (web, iOS, Android). */\nexport type CallErrorCode =\n | 'credentialInvalid'\n | 'credentialExpired'\n | 'roomFull'\n | 'roomClosed'\n | 'permissionDenied'\n | 'deviceUnavailable'\n | 'network'\n | 'unsupported'\n | 'internal';\n\nexport class CallError extends Error {\n readonly code: CallErrorCode;\n /** Whether trying again, possibly after user action, can succeed. */\n readonly retryable: boolean;\n readonly cause?: unknown;\n\n constructor(code: CallErrorCode, message: string, opts: { retryable?: boolean; cause?: unknown } = {}) {\n super(message);\n this.name = 'CallError';\n this.code = code;\n this.retryable = opts.retryable ?? DEFAULT_RETRYABLE[code];\n this.cause = opts.cause;\n }\n}\n\nconst DEFAULT_RETRYABLE: Record<CallErrorCode, boolean> = {\n credentialInvalid: false,\n credentialExpired: true, // after the app fetches a new credential\n roomFull: false,\n roomClosed: false,\n permissionDenied: true, // after the user grants access\n deviceUnavailable: true,\n network: true,\n unsupported: false,\n internal: true,\n};\n\nexport function isCallError(e: unknown): e is CallError {\n return e instanceof CallError;\n}\n\n/**\n * Map an engine or browser error to a CallError. Engine mapping (livekit-client 2.22):\n *\n * - message matches \"room is full\" / \"max participants\" -> roomFull\n * - ConnectionError NotAllowed (HTTP 401/403 on join) -> credentialInvalid\n * - ConnectionError ServerUnreachable / WebSocket / Timeout -> network\n * (Call.connect() turns a WebSocket refusal into roomFull when the server's validate\n * endpoint still accepts the credential; the server sends no reason a browser can read)\n * - ConnectionError ServiceNotFound (wrong URL path) -> credentialInvalid (the url in the credential is wrong)\n * - ConnectionError Cancelled / LeaveRequest -> internal, not retryable (connect() was abandoned by leave())\n * - ConnectionError InternalError -> internal\n * - DOMException NotAllowedError / PermissionDeniedError -> permissionDenied\n * - DOMException NotFoundError / NotReadableError / OverconstrainedError / AbortError -> deviceUnavailable\n * - anything else -> internal, with the original message attached\n */\nexport function mapEngineError(e: unknown): CallError {\n if (isCallError(e)) return e;\n const msg = messageOf(e);\n if (/room is full|max(imum)? participants|participant limit/i.test(msg)) {\n return new CallError('roomFull', 'The call already has two participants.', { cause: e });\n }\n if (e instanceof ConnectionError) {\n switch (e.reason) {\n case ConnectionErrorReason.NotAllowed:\n return new CallError('credentialInvalid', `The credential was rejected by the media server (${e.status ?? 'no status'}): ${msg}`, { cause: e });\n case ConnectionErrorReason.ServerUnreachable:\n case ConnectionErrorReason.WebSocket:\n case ConnectionErrorReason.Timeout:\n return new CallError('network', `Could not reach the media server: ${msg}`, { cause: e });\n case ConnectionErrorReason.ServiceNotFound:\n return new CallError('credentialInvalid', `The credential's url does not point at a media server: ${msg}`, { cause: e });\n case ConnectionErrorReason.Cancelled:\n case ConnectionErrorReason.LeaveRequest:\n return new CallError('internal', `Connection was cancelled: ${msg}`, { retryable: false, cause: e });\n default:\n return new CallError('internal', `Media server error: ${msg}`, { cause: e });\n }\n }\n const name = (e as { name?: string } | null)?.name ?? '';\n if (name === 'NotAllowedError' || name === 'PermissionDeniedError' || name === 'SecurityError') {\n return new CallError('permissionDenied', 'Camera or microphone permission was not granted.', { cause: e });\n }\n if (name === 'NotFoundError' || name === 'NotReadableError' || name === 'OverconstrainedError' || name === 'AbortError' || name === 'TrackInvalidError') {\n return new CallError('deviceUnavailable', `The requested device is unavailable: ${msg}`, { cause: e });\n }\n return new CallError('internal', msg || 'Unknown error', { cause: e });\n}\n\nfunction messageOf(e: unknown): string {\n if (typeof e === 'string') return e;\n if (e && typeof e === 'object' && 'message' in e && typeof (e as { message: unknown }).message === 'string') {\n return (e as { message: string }).message;\n }\n return String(e);\n}\n", "/** Minimal typed event emitter. Handlers run synchronously on the calling thread; a throwing\n * handler is reported through console.error and never breaks the emitter or the SDK. */\nexport type Listener<T extends unknown[]> = (...args: T) => void;\n\nexport class Emitter<M extends Record<string, unknown[]>> {\n private readonly handlers = new Map<keyof M, Set<Listener<any>>>();\n\n on<K extends keyof M>(event: K, handler: Listener<M[K]>): () => void {\n let set = this.handlers.get(event);\n if (!set) { set = new Set(); this.handlers.set(event, set); }\n set.add(handler);\n return () => this.off(event, handler);\n }\n\n once<K extends keyof M>(event: K, handler: Listener<M[K]>): () => void {\n const off = this.on(event, ((...args: M[K]) => { off(); handler(...args); }) as Listener<M[K]>);\n return off;\n }\n\n off<K extends keyof M>(event: K, handler: Listener<M[K]>): void {\n this.handlers.get(event)?.delete(handler);\n }\n\n emit<K extends keyof M>(event: K, ...args: M[K]): void {\n const set = this.handlers.get(event);\n if (!set) return;\n for (const h of Array.from(set)) {\n try { h(...args); } catch (err) { console.error(`[qencode-calls] handler for \"${String(event)}\" threw`, err); }\n }\n }\n\n removeAll(): void { this.handlers.clear(); }\n}\n", "import { CallError } from './errors';\n\n/** One region a credential may connect through. */\nexport interface Region { name: string; url: string }\n\n/**\n * The token response from `POST /v1/calls/{id}/tokens`, passed to the app unchanged by the\n * customer's backend. Only `token` and `url` are required; the rest is read from the JWT\n * payload when missing.\n */\nexport interface CallCredential {\n token: string;\n url: string;\n regions?: Region[];\n identity?: string;\n room_name?: string;\n /** ISO 8601 string, epoch seconds, or epoch milliseconds. */\n expires_at?: string | number;\n call_id?: string;\n /** Optional API base for telemetry; overrides the SDK default. */\n api_base?: string;\n}\n\nexport interface ParsedCredential {\n token: string;\n url: string;\n regions: Region[];\n identity: string;\n roomName: string;\n /** Epoch milliseconds, or null when unknown. */\n expiresAt: number | null;\n callId: string | null;\n apiBase: string | null;\n}\n\n/** Fires `credentialExpiring` this long before `expiresAt`. */\nexport const EXPIRY_WARNING_MS = 2 * 60 * 1000;\n\nexport function parseCredential(input: CallCredential): ParsedCredential {\n if (!input || typeof input !== 'object') throw new CallError('credentialInvalid', 'Credential must be an object.');\n const token = typeof input.token === 'string' ? input.token.trim() : '';\n if (!token || token.split('.').length !== 3) throw new CallError('credentialInvalid', 'Credential token is missing or not a JWT.');\n const url = typeof input.url === 'string' ? input.url.trim() : '';\n if (!/^(wss?|https?):\\/\\/\\S+$/i.test(url)) throw new CallError('credentialInvalid', 'Credential url must be a ws(s) or http(s) URL.');\n\n const payload = decodeJwtPayload(token);\n const video = (payload.video ?? {}) as { room?: unknown };\n const identity = firstString(input.identity, payload.sub);\n const roomName = firstString(input.room_name, video.room);\n if (!identity) throw new CallError('credentialInvalid', 'Credential has no identity (neither identity nor the JWT sub claim).');\n if (!roomName) throw new CallError('credentialInvalid', 'Credential has no room (neither room_name nor the JWT video.room grant).');\n\n let expiresAt = parseExpiry(input.expires_at);\n if (expiresAt === null && typeof payload.exp === 'number') expiresAt = payload.exp * 1000;\n\n const regions = Array.isArray(input.regions)\n ? input.regions.filter((r): r is Region => !!r && typeof r.name === 'string' && typeof r.url === 'string')\n : [];\n if (regions.length === 0) regions.push({ name: 'default', url });\n\n return {\n token, url, regions, identity, roomName, expiresAt,\n callId: firstString(input.call_id) || null,\n apiBase: firstString(input.api_base) || null,\n };\n}\n\nexport function isExpired(c: ParsedCredential, now: number = Date.now()): boolean {\n return c.expiresAt !== null && now >= c.expiresAt;\n}\n\n/** Milliseconds until the expiry warning should fire; 0 when already due; null when unknown. */\nexport function msUntilExpiryWarning(c: ParsedCredential, now: number = Date.now()): number | null {\n if (c.expiresAt === null) return null;\n return Math.max(0, c.expiresAt - EXPIRY_WARNING_MS - now);\n}\n\nexport function parseExpiry(v: string | number | undefined): number | null {\n if (v === undefined || v === null || v === '') return null;\n if (typeof v === 'number' && Number.isFinite(v)) return v < 1e12 ? v * 1000 : v;\n if (typeof v === 'string') {\n const asNum = Number(v);\n if (v.trim() !== '' && Number.isFinite(asNum)) return asNum < 1e12 ? asNum * 1000 : asNum;\n // The API returns 'YYYY-MM-DD HH:MM:SS' in UTC without a zone; make that explicit.\n const iso = /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$/.test(v) ? v.replace(' ', 'T') + 'Z' : v;\n const t = Date.parse(iso);\n return Number.isFinite(t) ? t : null;\n }\n return null;\n}\n\n/** Decodes the JWT payload without verifying the signature; the media server verifies it. */\nexport function decodeJwtPayload(token: string): Record<string, unknown> {\n try {\n const part = token.split('.')[1] ?? '';\n const b64 = part.replace(/-/g, '+').replace(/_/g, '/').padEnd(Math.ceil(part.length / 4) * 4, '=');\n if (typeof atob !== 'function') return {};\n const json = atob(b64);\n const bytes = new Uint8Array(json.length);\n for (let i = 0; i < json.length; i++) bytes[i] = json.charCodeAt(i);\n const parsed = JSON.parse(new TextDecoder().decode(bytes));\n return parsed && typeof parsed === 'object' ? (parsed as Record<string, unknown>) : {};\n } catch {\n return {};\n }\n}\n\nfunction firstString(...vals: unknown[]): string {\n for (const v of vals) if (typeof v === 'string' && v.trim()) return v.trim();\n return '';\n}\n", "/** Named media tiers. Quality, cost and the pricing tier line up on these; apps pick a name, never raw constraints. */\nexport type VideoProfileName = 'audioOnly' | 'p360_30' | 'p540_30' | 'p540_60' | 'p720_30' | 'p720_60' | 'p1080_30';\n\nexport interface VideoProfile {\n name: VideoProfileName;\n width: number;\n height: number;\n fps: number;\n /** Encoder bitrate cap in bits per second. */\n maxBitrate: number;\n /** Simulcast layers are published at 720p and above; below, the single layer is cheaper to encode. */\n simulcast: boolean;\n video: boolean;\n}\n\nexport const PROFILES: Readonly<Record<VideoProfileName, VideoProfile>> = Object.freeze({\n audioOnly: { name: 'audioOnly', width: 0, height: 0, fps: 0, maxBitrate: 0, simulcast: false, video: false },\n p360_30: { name: 'p360_30', width: 640, height: 360, fps: 30, maxBitrate: 450_000, simulcast: false, video: true },\n p540_30: { name: 'p540_30', width: 960, height: 540, fps: 30, maxBitrate: 800_000, simulcast: false, video: true },\n p540_60: { name: 'p540_60', width: 960, height: 540, fps: 60, maxBitrate: 1_200_000, simulcast: false, video: true },\n p720_30: { name: 'p720_30', width: 1280, height: 720, fps: 30, maxBitrate: 1_200_000, simulcast: true, video: true },\n p720_60: { name: 'p720_60', width: 1280, height: 720, fps: 60, maxBitrate: 1_800_000, simulcast: true, video: true },\n p1080_30: { name: 'p1080_30', width: 1920, height: 1080, fps: 30, maxBitrate: 2_200_000, simulcast: true, video: true },\n});\n\nexport const DEFAULT_PROFILE: VideoProfileName = 'p540_60';\n\n/** Opus bitrate for the microphone track, bits per second. */\nexport const AUDIO_BITRATE = 48_000;\n\nexport function resolveProfile(name: VideoProfileName | undefined): VideoProfile {\n const p = PROFILES[name ?? DEFAULT_PROFILE];\n if (!p) throw new RangeError(`Unknown video profile \"${String(name)}\". Known: ${Object.keys(PROFILES).join(', ')}`);\n return p;\n}\n", "/**\n * Latency modes move several engine knobs together.\n *\n * - `lowest`: jitter buffer target at the platform minimum (0 ms asks the browser for its floor),\n * degradation drops resolution before frame rate, 10 ms Opus frames where the platform lets us.\n * - `smooth`: jitter buffer target 150 ms, degradation drops frame rate before resolution,\n * 20 ms Opus frames.\n */\nexport type LatencyMode = 'lowest' | 'smooth';\n\nexport interface LatencySettings {\n jitterBufferTargetMs: number;\n degradationPreference: RTCDegradationPreference;\n audioFrameMs: 10 | 20;\n}\n\nexport const LATENCY_SETTINGS: Readonly<Record<LatencyMode, LatencySettings>> = Object.freeze({\n lowest: { jitterBufferTargetMs: 0, degradationPreference: 'maintain-framerate', audioFrameMs: 10 },\n smooth: { jitterBufferTargetMs: 150, degradationPreference: 'maintain-resolution', audioFrameMs: 20 },\n});\n\nexport const DEFAULT_LATENCY_MODE: LatencyMode = 'lowest';\n\nexport function latencySettings(mode: LatencyMode | undefined): LatencySettings {\n const s = LATENCY_SETTINGS[mode ?? DEFAULT_LATENCY_MODE];\n if (!s) throw new RangeError(`Unknown latency mode \"${String(mode)}\". Known: lowest, smooth`);\n return s;\n}\n\ntype ReceiverWithTarget = RTCRtpReceiver & { jitterBufferTarget?: number | null; playoutDelayHint?: number | null };\n\n/**\n * Applies a jitter buffer target to a receiver. Returns which property took it:\n * `jitterBufferTarget` (Chromium 108+, Safari 17.4+), `playoutDelayHint` (older Chromium), or\n * `null` when the browser exposes neither (Firefox). Never throws.\n */\nexport function applyJitterBufferTarget(receiver: RTCRtpReceiver | undefined | null, ms: number): 'jitterBufferTarget' | 'playoutDelayHint' | null {\n if (!receiver) return null;\n const r = receiver as unknown as Record<string, unknown>;\n try {\n if ('jitterBufferTarget' in r) { (receiver as ReceiverWithTarget).jitterBufferTarget = ms; return 'jitterBufferTarget'; }\n if ('playoutDelayHint' in r) { (receiver as ReceiverWithTarget).playoutDelayHint = ms / 1000; return 'playoutDelayHint'; }\n } catch { /* unsupported value range or read-only implementation */ }\n return null;\n}\n\n/** Applies a degradation preference to a live sender without republishing. Returns false when unsupported. */\nexport async function applyDegradationPreference(sender: RTCRtpSender | undefined | null, pref: RTCDegradationPreference): Promise<boolean> {\n if (!sender || typeof sender.getParameters !== 'function') return false;\n try {\n const params = sender.getParameters();\n (params as RTCRtpSendParameters & { degradationPreference?: RTCDegradationPreference }).degradationPreference = pref;\n await sender.setParameters(params);\n return true;\n } catch {\n return false;\n }\n}\n", "import type { Region } from './credential';\n\nexport interface RegionChoice {\n region: Region;\n /** Probe result per region name in milliseconds; Infinity when unreachable. Empty when no probe ran. */\n probe: Record<string, number>;\n /** How the choice was made. */\n how: 'single' | 'pinned' | 'probe' | 'fallback';\n}\n\nexport interface ProbeOptions {\n timeoutMs?: number;\n fetchFn?: typeof fetch;\n now?: () => number;\n}\n\n/** Turns a signaling URL into the media node's HTTPS root, which LiveKit answers with \"OK\". */\nexport function probeUrl(signalingUrl: string): string {\n const u = new URL(signalingUrl);\n const proto = u.protocol === 'ws:' || u.protocol === 'http:' ? 'http:' : 'https:';\n return `${proto}//${u.host}/`;\n}\n\n/**\n * Times one request to a region after one warm-up request. `no-cors` so the timing works even\n * when the node sends no CORS headers; the body is not readable and does not need to be.\n */\nexport async function probeRegion(region: Region, opts: ProbeOptions = {}): Promise<number> {\n const timeoutMs = opts.timeoutMs ?? 3000;\n const f = opts.fetchFn ?? (typeof fetch === 'function' ? fetch : undefined);\n const now = opts.now ?? (() => (typeof performance !== 'undefined' ? performance.now() : Date.now()));\n if (!f) return Infinity;\n let url: string;\n try { url = probeUrl(region.url); } catch { return Infinity; }\n const once = async (): Promise<number> => {\n const ctl = typeof AbortController === 'function' ? new AbortController() : undefined;\n const timer = setTimeout(() => ctl?.abort(), timeoutMs);\n const t0 = now();\n try {\n await f(url, { mode: 'no-cors', cache: 'no-store', credentials: 'omit', signal: ctl?.signal });\n return now() - t0;\n } catch {\n return Infinity;\n } finally {\n clearTimeout(timer);\n }\n };\n const warm = await once();\n if (warm === Infinity) return Infinity;\n return once();\n}\n\n/** Picks the region to connect through. Pinned wins; one region skips the probe; otherwise the fastest probe. */\nexport async function chooseRegion(regions: Region[], pinned?: string | null, opts: ProbeOptions = {}): Promise<RegionChoice> {\n if (regions.length === 0) throw new RangeError('No regions to choose from');\n if (pinned) {\n const r = regions.find((x) => x.name === pinned);\n if (!r) throw new RangeError(`Region \"${pinned}\" is not in the credential. Available: ${regions.map((x) => x.name).join(', ')}`);\n return { region: r, probe: {}, how: 'pinned' };\n }\n if (regions.length === 1) return { region: regions[0]!, probe: {}, how: 'single' };\n const results = await Promise.all(regions.map((r) => probeRegion(r, opts)));\n const probe: Record<string, number> = {};\n regions.forEach((r, i) => { probe[r.name] = Math.round(results[i]! * 10) / 10; });\n let best = -1;\n results.forEach((ms, i) => { if (ms !== Infinity && (best < 0 || ms < results[best]!)) best = i; });\n if (best < 0) return { region: regions[0]!, probe, how: 'fallback' };\n return { region: regions[best]!, probe, how: 'probe' };\n}\n", "/**\n * Per-second quality numbers from WebRTC getStats, ported from the bench page. Everything here is\n * pure over an RTCStatsReport-like map so it can be tested without a browser.\n */\n\nexport type Transport = 'udp' | 'tcp' | 'relay-udp' | 'relay-tcp';\nexport type CandidateType = 'host' | 'srflx' | 'prflx' | 'relay';\nexport type AudioRoute = 'speaker' | 'earpiece' | 'wired' | 'bluetooth' | 'unknown';\nexport type Quality = 'good' | 'fair' | 'poor';\nexport type Direction = 'recv' | 'send';\n\n/** What this participant receives from the peer. */\nexport interface RecvStats {\n rttMs: number | null;\n jitterBufferMs: number | null;\n decodeMs: number | null;\n fps: number | null;\n width: number | null;\n height: number | null;\n kbps: number | null;\n lossPct: number | null;\n jitterMs: number | null;\n freezes: number | null;\n freezeMs: number | null;\n /** Receive-to-render time per frame: \u0394`totalProcessingDelay` / \u0394`framesDecoded`. */\n processingMs: number | null;\n /**\n * Sender capture to local now through the abs-capture-time header extension, when the\n * browser and the media node carry it (Chromium; null elsewhere). A cross-check for the\n * estimate, not a substitute for a measured glass-to-glass number.\n */\n absCaptureLatencyMs: number | null;\n codec: string | null;\n transport: Transport | null;\n candidateType: CandidateType | null;\n}\n\n/** What this participant sends. */\nexport interface SendStats {\n rttMs: number | null;\n encodeMs: number | null;\n fps: number | null;\n width: number | null;\n height: number | null;\n kbps: number | null;\n /** The encoder's current bitrate target, kbps. */\n targetKbps: number | null;\n qualityLimitation: string | null;\n /** Loss the media node reports for our outbound stream (remote-inbound-rtp), percent. */\n lossPct: number | null;\n codec: string | null;\n transport: Transport | null;\n candidateType: CandidateType | null;\n}\n\n/** One snapshot, emitted once per second on `stats`. */\nexport interface CallStats {\n /** Epoch milliseconds. */\n ts: number;\n recv: RecvStats;\n send: SendStats;\n /** The peer's own RTT to the media node, exchanged over the data channel; null until received. */\n peerRttMs: number | null;\n /** rtt/2 + peerRtt/2 + jitter buffer + decode + one frame interval. An estimate, not a measurement. */\n estimatedLatencyMs: number | null;\n quality: { recv: Quality; send: Quality };\n region: string | null;\n nodeId: string | null;\n serverVersion: string | null;\n joinMs: number | null;\n audioRoute: AudioRoute;\n}\n\ntype StatsLike = { forEach(cb: (s: any) => void): void; get(id: string): any };\n\ninterface Prev { t: number; [k: string]: number }\n\n/** Delta tracker across polls; one instance per direction per call. */\nexport class DeltaTracker {\n private prev: Prev | null = null;\n\n /** Returns per-interval deltas of the given counters, or null on the first sample. */\n step(nowMs: number, counters: Record<string, number | undefined>): { dt: number; d: (k: string) => number } | null {\n const cur: Prev = { t: nowMs };\n for (const [k, v] of Object.entries(counters)) cur[k] = typeof v === 'number' && Number.isFinite(v) ? v : 0;\n const prev = this.prev;\n this.prev = cur;\n if (!prev) return null;\n const dt = Math.max(1, nowMs - prev.t) / 1000;\n return { dt, d: (k) => (cur[k] ?? 0) - (prev[k] ?? 0) };\n }\n\n reset(): void { this.prev = null; }\n}\n\nexport function pickSelectedPair(report: StatsLike): any | null {\n let pair: any = null;\n report.forEach((s) => { if (s.type === 'transport' && s.selectedCandidatePairId) pair = report.get(s.selectedCandidatePairId) ?? pair; });\n if (!pair) report.forEach((s) => { if (s.type === 'candidate-pair' && s.nominated && s.state === 'succeeded') pair = s; });\n return pair;\n}\n\nexport function transportOf(report: StatsLike, pair: any | null): { transport: Transport | null; candidateType: CandidateType | null; rttMs: number | null } {\n if (!pair) return { transport: null, candidateType: null, rttMs: null };\n const local = report.get(pair.localCandidateId) ?? {};\n const proto = String(local.relayProtocol ?? local.protocol ?? '').toLowerCase();\n const ctype = (local.candidateType ?? null) as CandidateType | null;\n const base = proto === 'tcp' || proto === 'tls' ? 'tcp' : 'udp';\n const transport: Transport | null = ctype === 'relay' ? (`relay-${base}` as Transport) : (proto ? base : null);\n const rtt = typeof pair.currentRoundTripTime === 'number' ? round1(pair.currentRoundTripTime * 1000) : null;\n return { transport, candidateType: ctype, rttMs: rtt };\n}\n\nfunction codecName(report: StatsLike, codecId: string | undefined): string | null {\n if (!codecId) return null;\n const c = report.get(codecId);\n const mime: string | undefined = c?.mimeType;\n return mime ? mime.replace(/^video\\//i, '').replace(/^audio\\//i, '').toUpperCase() : null;\n}\n\nexport function collectRecv(report: StatsLike, tracker: DeltaTracker, nowMs: number): RecvStats {\n let inbound: any = null;\n report.forEach((s) => { if (s.type === 'inbound-rtp' && (s.kind === 'video' || s.mediaType === 'video')) inbound = s; });\n const pair = pickSelectedPair(report);\n const t = transportOf(report, pair);\n const empty: RecvStats = { rttMs: t.rttMs, jitterBufferMs: null, decodeMs: null, fps: null, width: null, height: null, kbps: null, lossPct: null, jitterMs: null, freezes: null, freezeMs: null, processingMs: null, absCaptureLatencyMs: null, codec: null, transport: t.transport, candidateType: t.candidateType };\n if (!inbound) return empty;\n const step = tracker.step(nowMs, {\n jbd: inbound.jitterBufferDelay, jbc: inbound.jitterBufferEmittedCount,\n dec: inbound.totalDecodeTime, frames: inbound.framesDecoded, proc: inbound.totalProcessingDelay,\n lost: inbound.packetsLost, recv: inbound.packetsReceived, bytes: inbound.bytesReceived,\n freezes: inbound.freezeCount, freezeMs: inbound.totalFreezesDuration,\n });\n const out: RecvStats = { ...empty,\n fps: typeof inbound.framesPerSecond === 'number' ? round1(inbound.framesPerSecond) : null,\n width: inbound.frameWidth ?? null, height: inbound.frameHeight ?? null,\n jitterMs: typeof inbound.jitter === 'number' ? round1(inbound.jitter * 1000) : null,\n codec: codecName(report, inbound.codecId),\n };\n if (!step) return out;\n const { dt, d } = step;\n out.jitterBufferMs = d('jbc') > 0 ? round1((d('jbd') / d('jbc')) * 1000) : null;\n out.decodeMs = d('frames') > 0 ? round1((d('dec') / d('frames')) * 1000) : null;\n out.processingMs = d('frames') > 0 ? round1((d('proc') / d('frames')) * 1000) : null;\n const lostAndRecv = d('lost') + d('recv');\n out.lossPct = lostAndRecv > 0 ? round1((d('lost') / lostAndRecv) * 100) : 0;\n out.kbps = round1((d('bytes') * 8) / dt / 1000);\n out.freezes = Math.max(0, d('freezes'));\n out.freezeMs = round1(Math.max(0, d('freezeMs')) * 1000);\n return out;\n}\n\nexport function collectSend(report: StatsLike, tracker: DeltaTracker, nowMs: number): SendStats {\n let outbound: any = null;\n report.forEach((s) => { if (s.type === 'outbound-rtp' && (s.kind === 'video' || s.mediaType === 'video') && (outbound === null || (s.bytesSent ?? 0) > (outbound.bytesSent ?? 0))) outbound = s; });\n const pair = pickSelectedPair(report);\n const t = transportOf(report, pair);\n let remoteInbound: any = null;\n report.forEach((s) => { if (s.type === 'remote-inbound-rtp' && (s.kind === 'video' || s.mediaType === 'video')) remoteInbound = s; });\n const lossPct = remoteInbound && typeof remoteInbound.fractionLost === 'number' ? round1(remoteInbound.fractionLost * 100) : null;\n const empty: SendStats = { rttMs: t.rttMs, encodeMs: null, fps: null, width: null, height: null, kbps: null, targetKbps: null, qualityLimitation: null, lossPct, codec: null, transport: t.transport, candidateType: t.candidateType };\n if (!outbound) return empty;\n const step = tracker.step(nowMs, { enc: outbound.totalEncodeTime, frames: outbound.framesEncoded, bytes: outbound.bytesSent });\n const out: SendStats = { ...empty,\n fps: typeof outbound.framesPerSecond === 'number' ? round1(outbound.framesPerSecond) : null,\n width: outbound.frameWidth ?? null, height: outbound.frameHeight ?? null,\n targetKbps: typeof outbound.targetBitrate === 'number' ? round1(outbound.targetBitrate / 1000) : null,\n qualityLimitation: outbound.qualityLimitationReason ?? null,\n codec: codecName(report, outbound.codecId),\n };\n if (!step) return out;\n const { dt, d } = step;\n out.encodeMs = d('frames') > 0 ? round1((d('enc') / d('frames')) * 1000) : null;\n out.kbps = round1((d('bytes') * 8) / dt / 1000);\n return out;\n}\n\nconst NTP_EPOCH_OFFSET_MS = 2_208_988_800_000; // 1900-01-01 to 1970-01-01\n\ntype SyncSource = { timestamp: number; captureTimestamp?: number; senderCaptureTimeOffset?: number };\n\n/**\n * Latency from the sender's capture clock to now, from `RTCRtpReceiver.getSynchronizationSources()`\n * when the abs-capture-time extension is present. `captureTimestamp` and `senderCaptureTimeOffset`\n * are milliseconds since the NTP epoch on the sender's clock (already offset-corrected by the\n * browser); `timestamp` is when the last frame reached the track, relative either to the epoch\n * (spec) or to the page's time origin (some builds), so both are accepted. Null when absent.\n */\nexport function absCaptureLatency(sources: ArrayLike<SyncSource> | null | undefined, unixNowMs: number, perfNowMs: number): number | null {\n const s0 = sources && sources.length ? sources[0] : undefined;\n if (!s0 || typeof s0.captureTimestamp !== 'number' || typeof s0.senderCaptureTimeOffset !== 'number') return null;\n const captureNtp = s0.captureTimestamp + s0.senderCaptureTimeOffset;\n const ageMs = typeof s0.timestamp === 'number' ? (s0.timestamp > 1e12 ? unixNowMs - s0.timestamp : perfNowMs - s0.timestamp) : 0;\n const v = unixNowMs + NTP_EPOCH_OFFSET_MS - captureNtp - Math.max(0, ageMs);\n return Number.isFinite(v) ? Math.round(v) : null;\n}\n\n/** rtt/2 + peerRtt/2 + jitter buffer + decode + one frame interval. Null until the pieces exist. */\nexport function estimateLatency(p: { rttMs: number | null; peerRttMs: number | null; jitterBufferMs: number | null; decodeMs: number | null; fps: number | null }): number | null {\n if (p.rttMs === null || p.jitterBufferMs === null) return null;\n const peer = p.peerRttMs ?? p.rttMs; // assume symmetry until the peer reports\n const frame = p.fps && p.fps > 0 ? 1000 / p.fps : 33;\n return round1(p.rttMs / 2 + peer / 2 + p.jitterBufferMs + (p.decodeMs ?? 0) + frame);\n}\n\n/**\n * good / fair / poor with hysteresis: a new level must be observed on two consecutive polls\n * before it is reported, so a single bad second does not flip the indicator.\n *\n * poor: loss > 3 % or jitter buffer > 200 ms or any freeze in the interval\n * fair: loss > 1 % or jitter buffer > 120 ms or rtt > 300 ms\n * good: otherwise\n */\nexport class QualityTracker {\n private current: Quality = 'good';\n private candidate: Quality | null = null;\n private streak = 0;\n\n static classify(s: { lossPct: number | null; jitterBufferMs: number | null; freezes: number | null; rttMs: number | null }): Quality {\n const loss = s.lossPct ?? 0, jb = s.jitterBufferMs ?? 0, fr = s.freezes ?? 0, rtt = s.rttMs ?? 0;\n if (loss > 3 || jb > 200 || fr > 0) return 'poor';\n if (loss > 1 || jb > 120 || rtt > 300) return 'fair';\n return 'good';\n }\n\n /** Feed one poll; returns the reported level after hysteresis. */\n update(s: { lossPct: number | null; jitterBufferMs: number | null; freezes: number | null; rttMs: number | null }): Quality {\n const observed = QualityTracker.classify(s);\n if (observed === this.current) { this.candidate = null; this.streak = 0; return this.current; }\n if (observed === this.candidate) this.streak += 1; else { this.candidate = observed; this.streak = 1; }\n if (this.streak >= 2) { this.current = observed; this.candidate = null; this.streak = 0; }\n return this.current;\n }\n\n get value(): Quality { return this.current; }\n reset(): void { this.current = 'good'; this.candidate = null; this.streak = 0; }\n}\n\nfunction round1(v: number): number { return Math.round(v * 10) / 10; }\n", "import type { CallStats, Direction } from './stats';\n\n/** App-supplied fields for one telemetry row; see `Telemetry.push`. */\nexport type TelemetryFields = Record<string, unknown>;\n\n/** Contract columns an app may fill: its own measured glass-to-glass latency over the last window. */\nexport const MEASURED_COLUMNS: ReadonlySet<string> = new Set(['g2g_p50', 'g2g_p95', 'g2g_samples']);\n\n/** One row of the calls stats contract (`POST /v1/calls/{id}/stats`). */\nexport interface TelemetrySample {\n ts: number;\n direction: Direction;\n peer_identity?: string | null;\n /** App-measured glass-to-glass latency, ms, over the app's own window; the SDK never fills these. */\n g2g_p50?: number | null; g2g_p95?: number | null; g2g_samples?: number | null;\n rtt_ms?: number | null; net_one_way_ms?: number | null;\n jb_ms?: number | null; decode_ms?: number | null; encode_ms?: number | null;\n fps?: number | null; kbps?: number | null; loss_pct?: number | null; jitter_ms?: number | null;\n freezes?: number | null; freeze_ms?: number | null;\n transport?: string | null; candidate_type?: string | null; codec?: string | null;\n width?: number | null; height?: number | null;\n server_region?: string | null; server_version?: string | null; node_id?: string | null;\n join_ms?: number | null;\n extra?: Record<string, unknown>;\n}\n\nexport interface TelemetryOptions {\n apiBase: string;\n callId: string | null;\n token: string;\n enabled: boolean;\n sdkVersion: string;\n /** Flush interval in ms; 5000 by default. */\n intervalMs?: number;\n fetchFn?: typeof fetch;\n userAgent?: string;\n}\n\n/**\n * Batches stats snapshots and posts them every 5 s with the participant token. Silent when\n * disabled or when the credential carries no call id (manual credentials). Never throws.\n */\nexport class Telemetry {\n private queue: TelemetrySample[] = [];\n private timer: ReturnType<typeof setInterval> | null = null;\n private firstPost = true;\n private joinMs: number | null = null;\n readonly enabled: boolean;\n readonly url: string | null;\n\n constructor(private readonly opts: TelemetryOptions) {\n this.enabled = !!opts.enabled && !!opts.callId && typeof (opts.fetchFn ?? (typeof fetch === 'function' ? fetch : undefined)) === 'function';\n this.url = opts.callId ? `${opts.apiBase.replace(/\\/+$/, '')}/v1/calls/${encodeURIComponent(opts.callId)}/stats` : null;\n }\n\n start(joinMs: number | null): void {\n this.joinMs = joinMs;\n if (!this.enabled || this.timer) return;\n this.timer = setInterval(() => { void this.flush(); }, this.opts.intervalMs ?? 5000);\n }\n\n /**\n * Converts one snapshot into the two contract rows and queues them. `extra` adds app fields per\n * direction: the measured-latency columns (`MEASURED_COLUMNS`) are stored as columns, anything\n * else goes under `extra` next to the SDK's own keys, which win on a name clash.\n */\n push(s: CallStats, peerIdentity: string | null, extra?: { recv?: TelemetryFields | null; send?: TelemetryFields | null }): void {\n if (!this.enabled) return;\n const common = { ts: s.ts, peer_identity: peerIdentity, server_region: s.region, server_version: s.serverVersion, node_id: s.nodeId };\n const oneWay = s.recv.rttMs !== null ? Math.round(((s.recv.rttMs + (s.peerRttMs ?? s.recv.rttMs)) / 2) * 10) / 10 : null;\n this.queue.push(withFields({ ...common, direction: 'recv',\n rtt_ms: s.recv.rttMs, net_one_way_ms: oneWay, jb_ms: s.recv.jitterBufferMs, decode_ms: s.recv.decodeMs,\n fps: s.recv.fps, kbps: s.recv.kbps, loss_pct: s.recv.lossPct, jitter_ms: s.recv.jitterMs,\n freezes: s.recv.freezes, freeze_ms: s.recv.freezeMs, transport: s.recv.transport, candidate_type: s.recv.candidateType,\n codec: s.recv.codec, width: s.recv.width, height: s.recv.height,\n extra: { estimated_latency_ms: s.estimatedLatencyMs, abs_capture_ms: s.recv.absCaptureLatencyMs, processing_ms: s.recv.processingMs, quality: s.quality.recv, audio_route: s.audioRoute } }, extra?.recv));\n this.queue.push(withFields({ ...common, direction: 'send',\n rtt_ms: s.send.rttMs, encode_ms: s.send.encodeMs, fps: s.send.fps, kbps: s.send.kbps,\n transport: s.send.transport, candidate_type: s.send.candidateType, codec: s.send.codec, width: s.send.width, height: s.send.height,\n extra: { quality_limitation: s.send.qualityLimitation, target_kbps: s.send.targetKbps, quality: s.quality.send } }, extra?.send));\n if (this.queue.length > 120) this.queue.splice(0, this.queue.length - 120);\n }\n\n async flush(): Promise<void> {\n if (!this.enabled || !this.url || this.queue.length === 0) return;\n const samples = this.queue.splice(0, this.queue.length);\n const ua = this.opts.userAgent ?? (typeof navigator !== 'undefined' ? navigator.userAgent : '');\n for (const s of samples) {\n s.extra = { ...(s.extra ?? {}), sdk: this.opts.sdkVersion, platform: 'web', user_agent: ua };\n if (this.firstPost && this.joinMs !== null) s.join_ms = this.joinMs;\n }\n this.firstPost = false;\n const f = this.opts.fetchFn ?? fetch;\n try {\n await f(this.url, {\n method: 'POST',\n headers: { 'content-type': 'application/json', authorization: `Bearer ${this.opts.token}` },\n body: JSON.stringify({ samples }),\n keepalive: true,\n });\n } catch {\n /* telemetry is best effort; a failed post is dropped, never retried, never surfaced */\n }\n }\n\n async stop(): Promise<void> {\n if (this.timer) { clearInterval(this.timer); this.timer = null; }\n await this.flush();\n }\n}\n\nfunction withFields(row: TelemetrySample, fields: TelemetryFields | null | undefined): TelemetrySample {\n if (!fields || typeof fields !== 'object') return row;\n const extra: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(fields)) {\n if (MEASURED_COLUMNS.has(k)) (row as unknown as Record<string, unknown>)[k] = typeof v === 'number' && Number.isFinite(v) ? v : null;\n else extra[k] = v;\n }\n row.extra = { ...extra, ...(row.extra ?? {}) };\n return row;\n}\n", "import { Track, type Room, type LocalVideoTrack, type VideoCaptureOptions } from 'livekit-client';\nimport { Emitter } from './events';\nimport { CallError, mapEngineError } from './errors';\n\n/** Which way a camera points: `user` faces the person, `environment` faces away (the rear camera on a phone). */\nexport type CameraFacing = 'user' | 'environment';\n\nexport interface DeviceInfo {\n id: string;\n label: string;\n /** For cameras: which way it points when the label says so (phones do); null when unknown. */\n facing?: CameraFacing | null;\n}\nexport interface DeviceList { cameras: DeviceInfo[]; microphones: DeviceInfo[]; speakers: DeviceInfo[] }\n\ntype DevicesEvents = { change: [DeviceList] };\n\n/**\n * Device selection. Labels are empty until the first getUserMedia permission is granted; after\n * `connect()` the list is complete. A camera or microphone chosen before `connect()` is used\n * when the track is first published; chosen mid-call it is switched in place; chosen while the\n * camera is off it takes effect when the camera is turned back on. Speaker selection needs\n * `setSinkId`, which Safari lacks.\n */\nexport class Devices {\n private readonly emitter = new Emitter<DevicesEvents>();\n private room: Room | null = null;\n private readonly audioElements = new Set<HTMLMediaElement>();\n private speakerId = '';\n private customVideo = false;\n private cameraIdValue: string | null = null;\n private microphoneIdValue: string | null = null;\n /** A facing request not yet turned into a concrete device id. */\n private facingWish: CameraFacing | null = null;\n /** True when a camera choice is waiting for the camera to be published or unmuted. */\n private pending = false;\n private captureOptions: (() => VideoCaptureOptions) | null = null;\n private readonly onDeviceChange = () => { void this.list().then((l) => this.emitter.emit('change', l)); };\n\n /** @internal */\n _attachRoom(room: Room | null): void { this.room = room; }\n /** @internal The call publishes a custom video source, so the engine must not replace it with a camera. */\n _setCustomVideo(on: boolean): void { this.customVideo = on; }\n /** @internal Initial ids from CallOptions. */\n _setInitial(cameraId?: string, microphoneId?: string): void {\n this.cameraIdValue = cameraId || null;\n this.microphoneIdValue = microphoneId || null;\n }\n /** @internal The call's capture options (profile resolution plus the selection below), used to restart the camera. */\n _setCaptureOptions(fn: () => VideoCaptureOptions): void { this.captureOptions = fn; }\n /**\n * @internal The camera selection part of the capture constraints. A chosen id is exact: a\n * preference lets the browser keep the camera it already has (Chrome does when the other one\n * takes a moment to wake, as a phone used as a webcam does). A facing stays a preference so\n * desktops, which cannot honour it, do not fail.\n */\n _videoSelection(): Pick<VideoCaptureOptions, 'deviceId' | 'facingMode'> {\n if (this.facingWish) return { facingMode: this.facingWish };\n if (this.cameraIdValue) return { deviceId: { exact: this.cameraIdValue } };\n return {};\n }\n /** @internal The chosen camera could not be opened at publish time; fall back to the default one. */\n _clearCamera(): void { this.cameraIdValue = null; this.facingWish = null; }\n /** @internal */\n _microphoneSelection(): string | undefined { return this.microphoneIdValue ?? undefined; }\n /** @internal Called by the call when the camera is (re)published or unmuted: applies a deferred choice and records what is in use. */\n async _cameraPublished(): Promise<void> {\n const track = this.cameraTrack();\n if (!track) return;\n if (this.pending && !track.isMuted && this.captureOptions) {\n try { await track.restartTrack(this.captureOptions()); } catch (e) { throw mapEngineError(e); }\n }\n this.pending = false;\n this.syncFromTrack(track);\n }\n /** @internal */\n _registerAudioElement(el: HTMLMediaElement): void {\n this.audioElements.add(el);\n if (this.speakerId) void this.applySink(el);\n }\n /** @internal */\n _start(): void {\n if (typeof navigator !== 'undefined' && navigator.mediaDevices?.addEventListener) navigator.mediaDevices.addEventListener('devicechange', this.onDeviceChange);\n }\n /** @internal */\n _stop(): void {\n if (typeof navigator !== 'undefined' && navigator.mediaDevices?.removeEventListener) navigator.mediaDevices.removeEventListener('devicechange', this.onDeviceChange);\n this.audioElements.clear();\n }\n\n async list(): Promise<DeviceList> {\n const out: DeviceList = { cameras: [], microphones: [], speakers: [] };\n if (typeof navigator === 'undefined' || !navigator.mediaDevices?.enumerateDevices) return out;\n let devs: MediaDeviceInfo[] = [];\n try { devs = await navigator.mediaDevices.enumerateDevices(); } catch { return out; }\n devs.forEach((d, i) => {\n const info: DeviceInfo = { id: d.deviceId, label: d.label || `${kindLabel(d.kind)} ${i + 1}` };\n if (d.kind === 'videoinput') { info.facing = facingFromLabel(d.label); out.cameras.push(info); }\n else if (d.kind === 'audioinput') out.microphones.push(info);\n else if (d.kind === 'audiooutput' && this.canSelectSpeaker) out.speakers.push(info);\n });\n return out;\n }\n\n get canSelectSpeaker(): boolean {\n return typeof HTMLMediaElement !== 'undefined' && typeof (HTMLMediaElement.prototype as { setSinkId?: unknown }).setSinkId === 'function';\n }\n\n /** The camera in use, or the one chosen for when the camera is next published; null for the system default. */\n get cameraId(): string | null { return this.cameraIdValue; }\n get microphoneId(): string | null { return this.microphoneIdValue; }\n /** Which way the camera in use points, when the browser says (phones do); otherwise the last facing asked for, or null. */\n get cameraFacing(): CameraFacing | null {\n const f = this.trackSettings()?.facingMode;\n if (f === 'user' || f === 'environment') return f;\n return this.facingWish;\n }\n\n /** Use this camera: now when it is published and on, otherwise as soon as it is. */\n async setCamera(deviceId: string): Promise<void> {\n this.refuseIfCustomVideo();\n await this.select(deviceId, null);\n }\n\n /**\n * Use the camera that faces the given way: the front (`user`) or the rear (`environment`)\n * camera on a phone. Browsers on phones honour the request directly; elsewhere a camera whose\n * label says which way it points is used, and `deviceUnavailable` is thrown when there is none.\n */\n async setCameraFacing(mode: CameraFacing): Promise<void> {\n if (mode !== 'user' && mode !== 'environment') throw new RangeError(`Unknown camera facing \"${String(mode)}\". Known: user, environment`);\n this.refuseIfCustomVideo();\n const applied = await this.select(null, mode);\n if (!applied) return; // takes effect when the camera is next published or unmuted\n if (this.trackSettings()?.facingMode === mode) return; // the browser honoured the hint\n // The hint was ignored, as desktops do; fall back to a camera whose label says which way it points.\n const list = await this.list();\n const alt = list.cameras.find((c) => c.facing === mode);\n if (!alt) throw new CallError('deviceUnavailable', mode === 'user' ? 'No camera facing the user was found.' : 'No camera facing away from the user was found.');\n await this.select(alt.id, null);\n this.facingWish = mode; // remembered for `cameraFacing` where settings stay silent\n }\n\n async setMicrophone(deviceId: string): Promise<void> {\n this.microphoneIdValue = deviceId;\n if (!this.room) return; // used when the microphone is first published\n await this.switch('audioinput', deviceId);\n }\n\n async setSpeaker(deviceId: string): Promise<void> {\n if (!this.canSelectSpeaker) throw new CallError('unsupported', 'This browser cannot choose the audio output device.', { retryable: false });\n this.speakerId = deviceId;\n for (const el of this.audioElements) await this.applySink(el);\n if (this.room) { try { await this.room.switchActiveDevice('audiooutput', deviceId, true); } catch { /* elements already switched */ } }\n }\n\n onChange(handler: (list: DeviceList) => void): () => void { return this.emitter.on('change', handler); }\n\n /**\n * Records a selection and restarts the published, unmuted camera with it. Returns false when\n * that has to wait. The engine stops the old capture before it opens the new one, so when the\n * new camera cannot be opened the previous selection is put back and reopened, and the call\n * keeps its picture; the failure is still thrown.\n */\n private async select(id: string | null, facing: CameraFacing | null): Promise<boolean> {\n const prevId = this.cameraIdValue, prevFacing = this.facingWish;\n this.cameraIdValue = id;\n this.facingWish = facing;\n const track = this.cameraTrack();\n if (!track || track.isMuted || !this.captureOptions) { this.pending = true; return false; }\n try {\n await track.restartTrack(this.captureOptions());\n } catch (e) {\n this.cameraIdValue = prevId;\n this.facingWish = prevFacing;\n try { await track.restartTrack(this.captureOptions()); } catch { /* the previous camera is gone too */ }\n throw mapEngineError(e);\n }\n this.pending = false;\n this.syncFromTrack(track);\n return true;\n }\n\n private syncFromTrack(track: LocalVideoTrack): void {\n const s = settingsOf(track);\n if (s?.deviceId) { this.cameraIdValue = s.deviceId; this.facingWish = null; }\n }\n\n private cameraTrack(): LocalVideoTrack | undefined {\n return this.room?.localParticipant.getTrackPublication(Track.Source.Camera)?.track as LocalVideoTrack | undefined;\n }\n\n private trackSettings(): MediaTrackSettings | undefined {\n const t = this.cameraTrack();\n return t ? settingsOf(t) : undefined;\n }\n\n private refuseIfCustomVideo(): void {\n if (this.customVideo) throw new CallError('unsupported', 'The video comes from a custom videoSource; switch cameras in the code that produces it.', { retryable: false });\n }\n\n private async switch(kind: MediaDeviceKind, deviceId: string): Promise<void> {\n if (!this.room) throw new CallError('internal', 'Not connected.', { retryable: false });\n try {\n const ok = await this.room.switchActiveDevice(kind, deviceId, true);\n if (!ok) throw new CallError('deviceUnavailable', `Could not switch to device ${deviceId}.`);\n } catch (e) {\n throw mapEngineError(e);\n }\n }\n\n private async applySink(el: HTMLMediaElement): Promise<void> {\n const sink = (el as HTMLMediaElement & { setSinkId?: (id: string) => Promise<void> }).setSinkId;\n if (typeof sink !== 'function') return;\n try { await sink.call(el, this.speakerId); } catch (e) { throw new CallError('deviceUnavailable', `Speaker switch failed: ${(e as Error)?.message ?? e}`, { cause: e }); }\n }\n}\n\nfunction settingsOf(track: LocalVideoTrack): MediaTrackSettings | undefined {\n const mst = track.mediaStreamTrack as MediaStreamTrack | undefined;\n return typeof mst?.getSettings === 'function' ? mst.getSettings() : undefined;\n}\n\n/** Phones label their cameras by direction (\"Back Camera\", \"camera2 0, facing back\"); desktops rarely do. */\nexport function facingFromLabel(label: string): CameraFacing | null {\n const l = (label || '').toLowerCase();\n if (/\\b(back|rear|environment|world)\\b/.test(l)) return 'environment';\n if (/\\b(front|user|face|selfie)\\b/.test(l)) return 'user';\n return null;\n}\n\nfunction kindLabel(k: MediaDeviceKind): string {\n return k === 'videoinput' ? 'camera' : k === 'audioinput' ? 'microphone' : 'speaker';\n}\n", "/** A renderable track. `attach` returns the element for chaining; `detach` with no element releases all. */\nexport interface VideoHandle {\n readonly kind: 'video' | 'audio';\n readonly mediaStreamTrack: MediaStreamTrack;\n /** Accepts a `<video>`/`<audio>` element or a `<qencode-video>` element; returns the media element that plays it. */\n attach(element: HTMLMediaElement | QencodeVideoElement): HTMLMediaElement;\n detach(element?: HTMLMediaElement | QencodeVideoElement): void;\n}\n\n/** True for `<qencode-video>` and anything else exposing a `track` setter and a `videoElement`. */\nfunction isVideoFrame(el: unknown): el is QencodeVideoElement {\n return !!el && typeof el === 'object' && 'videoElement' in (el as object) && 'track' in (el as object);\n}\n\ntype EngineTrack = {\n kind: string;\n mediaStreamTrack: MediaStreamTrack;\n attach(element: HTMLMediaElement): HTMLMediaElement;\n detach(element?: HTMLMediaElement): HTMLMediaElement | HTMLMediaElement[];\n};\n\n/** @internal Wraps an engine track so no engine type reaches the public API. */\nexport function wrapTrack(track: EngineTrack): VideoHandle {\n const handle: VideoHandle = {\n kind: track.kind === 'audio' ? 'audio' : 'video',\n get mediaStreamTrack() { return track.mediaStreamTrack; },\n attach: (el) => {\n if (isVideoFrame(el)) { el.track = handle; return el.videoElement; }\n return track.attach(el);\n },\n detach: (el) => {\n if (isVideoFrame(el)) { if (el.track === handle) el.track = null; return; }\n if (el) track.detach(el); else track.detach();\n },\n };\n return handle;\n}\n\nconst TEMPLATE = `\n<style>\n :host{display:block;position:relative;overflow:hidden;background:#000;aspect-ratio:16/9}\n video{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;background:#000}\n :host([fit=\"cover\"]) video{object-fit:cover}\n :host([mirror]) video{transform:scaleX(-1)}\n</style>\n<video autoplay playsinline muted></video>`;\n\n/**\n * `<qencode-video>`: a frame that renders a VideoHandle at its own aspect ratio.\n * Attributes: `mirror` (self view), `fit=\"contain|cover\"`. Property: `track` (VideoHandle | null).\n * Audio is never played by this element; the SDK plays remote audio itself.\n */\nexport class QencodeVideoElement extends HTMLElement {\n private _track: VideoHandle | null = null;\n private readonly video: HTMLVideoElement;\n\n constructor() {\n super();\n const root = this.attachShadow({ mode: 'open' });\n root.innerHTML = TEMPLATE;\n this.video = root.querySelector('video') as HTMLVideoElement;\n this.video.addEventListener('loadedmetadata', () => this.updateAspect());\n this.video.addEventListener('resize', () => this.updateAspect());\n }\n\n /** The inner `<video>` that plays the track. */\n get videoElement(): HTMLVideoElement { return this.video; }\n\n get track(): VideoHandle | null { return this._track; }\n set track(t: VideoHandle | null) {\n if (this._track === t) return;\n if (this._track) this._track.detach(this.video);\n this._track = t;\n if (t) t.attach(this.video);\n else this.video.srcObject = null;\n }\n\n disconnectedCallback(): void { if (this._track) this._track.detach(this.video); }\n\n private updateAspect(): void {\n const w = this.video.videoWidth, h = this.video.videoHeight;\n if (w && h && this.getAttribute('fit') !== 'cover') this.style.aspectRatio = `${w} / ${h}`;\n }\n}\n\n/** Registers `<qencode-video>` once; safe to call repeatedly and outside browsers. */\nexport function registerVideoElement(tag = 'qencode-video'): boolean {\n if (typeof customElements === 'undefined' || typeof HTMLElement === 'undefined') return false;\n if (!customElements.get(tag)) customElements.define(tag, QencodeVideoElement);\n return true;\n}\n", "/** SDK version, reported in telemetry as `extra.sdk`. Kept in sync with package.json by the build. */\nexport const SDK_VERSION = '0.3.0';\n", "export { Call, encodeMessage, decodeMessage } from './call';\nexport type { CallOptions, CallEvents, CallState, EndReason, Peer, MessagePayload, ModerationEvent, LogLevelName, VideoCodec, VideoSource, VideoSourceFactory, JitterBufferSupport, TelemetryExtra } from './call';\nexport { VIDEO_CODECS } from './call';\nexport type { TelemetryFields } from './telemetry';\nexport { CallError, isCallError } from './errors';\nexport type { CallErrorCode } from './errors';\nexport type { CallCredential, Region } from './credential';\nexport { PROFILES, DEFAULT_PROFILE } from './profiles';\nexport type { VideoProfileName, VideoProfile } from './profiles';\nexport { LATENCY_SETTINGS, DEFAULT_LATENCY_MODE } from './latency';\nexport type { LatencyMode, LatencySettings } from './latency';\nexport type { CallStats, RecvStats, SendStats, Quality, Direction, Transport, CandidateType, AudioRoute } from './stats';\nexport type { DeviceInfo, DeviceList, CameraFacing } from './devices';\nexport type { VideoHandle } from './render';\nexport { QencodeVideoElement, registerVideoElement } from './render';\nexport { SDK_VERSION } from './version';\n\nimport { registerVideoElement } from './render';\n// Register <qencode-video> on import in browsers; a no-op elsewhere and when already defined.\nregisterVideoElement();\n"],
5
+ "mappings": "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",
6
+ "names": ["Room", "RoomEvent", "ConnectionState", "DisconnectReason", "Track", "setLogLevel", "DataPacket_Kind", "ConnectionError", "ConnectionErrorReason", "ConnectionError", "ConnectionErrorReason", "CallError", "code", "message", "opts", "DEFAULT_RETRYABLE", "isCallError", "e", "mapEngineError", "msg", "messageOf", "name", "Emitter", "event", "handler", "set", "off", "args", "h", "err", "EXPIRY_WARNING_MS", "parseCredential", "input", "CallError", "token", "url", "payload", "decodeJwtPayload", "video", "identity", "firstString", "roomName", "expiresAt", "parseExpiry", "regions", "r", "isExpired", "c", "now", "msUntilExpiryWarning", "v", "asNum", "iso", "t", "part", "b64", "json", "bytes", "i", "parsed", "vals", "PROFILES", "DEFAULT_PROFILE", "AUDIO_BITRATE", "resolveProfile", "name", "p", "LATENCY_SETTINGS", "DEFAULT_LATENCY_MODE", "latencySettings", "mode", "s", "applyJitterBufferTarget", "receiver", "ms", "r", "applyDegradationPreference", "sender", "pref", "params", "probeUrl", "signalingUrl", "u", "probeRegion", "region", "opts", "timeoutMs", "f", "now", "url", "once", "ctl", "timer", "t0", "chooseRegion", "regions", "pinned", "r", "x", "results", "probe", "i", "best", "ms", "DeltaTracker", "nowMs", "counters", "cur", "k", "v", "prev", "pickSelectedPair", "report", "pair", "s", "transportOf", "local", "proto", "ctype", "base", "transport", "rtt", "round1", "codecName", "codecId", "mime", "collectRecv", "tracker", "inbound", "t", "empty", "step", "out", "dt", "d", "lostAndRecv", "collectSend", "outbound", "remoteInbound", "lossPct", "NTP_EPOCH_OFFSET_MS", "absCaptureLatency", "sources", "unixNowMs", "perfNowMs", "s0", "captureNtp", "ageMs", "estimateLatency", "p", "peer", "frame", "QualityTracker", "_QualityTracker", "loss", "jb", "fr", "observed", "MEASURED_COLUMNS", "Telemetry", "opts", "joinMs", "s", "peerIdentity", "extra", "common", "oneWay", "withFields", "samples", "ua", "f", "row", "fields", "k", "v", "Track", "Devices", "Emitter", "l", "room", "on", "cameraId", "microphoneId", "fn", "track", "e", "mapEngineError", "el", "out", "devs", "d", "i", "info", "kindLabel", "facingFromLabel", "f", "deviceId", "mode", "alt", "c", "CallError", "handler", "id", "facing", "prevId", "prevFacing", "s", "settingsOf", "Track", "t", "kind", "sink", "mst", "label", "k", "isVideoFrame", "el", "wrapTrack", "track", "handle", "TEMPLATE", "QencodeVideoElement", "root", "w", "h", "registerVideoElement", "tag", "SDK_VERSION", "VIDEO_CODECS", "DEFAULT_API_BASE", "MSG_TOPIC", "STATS_TOPIC", "MSG_MAX_BYTES", "MSG_MAX_PER_SECOND", "STATS_INTERVAL_MS", "RECONNECT_WINDOW_MS", "enc", "dec", "Call", "_Call", "cred", "options", "Devices", "Emitter", "DeltaTracker", "QualityTracker", "DEFAULT_PROFILE", "DEFAULT_LATENCY_MODE", "resolveProfile", "latencySettings", "checkCodec", "checkJitterTarget", "setLogLevel", "credential", "parseCredential", "p", "event", "handler", "CallError", "isExpired", "t0", "now", "chooseRegion", "room", "connectOpts", "Telemetry", "SDK_VERSION", "e", "err", "mapEngineError", "reasonForError", "next", "ConnectionError", "ConnectionErrorReason", "region", "url", "ctl", "timer", "enabled", "Track", "name", "prev", "pub", "track", "mode", "s", "sender", "applyDegradationPreference", "ms", "opts", "source", "payload", "reliable", "bytes", "encodeMessage", "t", "x", "toNonShared", "adaptive", "Room", "RoomEvent", "_pub", "kind", "topic", "DataPacket_Kind", "reason", "l", "degradation", "AUDIO_BITRATE", "wrapTrack", "src", "wasMuted", "params", "receiver", "took", "applyJitterBufferTarget", "isAgent", "peerOf", "n", "left", "el", "muted", "m", "decodeMessage", "endReasonOf", "recvReport", "lp", "sendReport", "recv", "collectRecv", "emptyRecv", "send", "collectSend", "emptySend", "rx", "absCaptureLatency", "estimatedLatencyMs", "estimateLatency", "qr", "qs", "snap", "rtt", "ConnectionState", "fn", "one", "d", "v", "msUntilExpiryWarning", "at", "state", "out", "asAny", "leaving", "DisconnectReason", "c", "tag", "body", "registerVideoElement"]
7
7
  }