@xmov/avatar 2.1.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/avatar.cjs +1 -2
- package/dist/agent/avatar.modern.js +1 -2
- package/dist/agent/avatar.module.js +1 -2
- package/dist/agent/avatar.umd.js +1 -2
- package/dist/agent/index.cjs +1 -4
- package/dist/agent/index.d.ts +12 -5
- package/dist/agent/index.umd.js +3 -5
- package/dist/agent/types.d.ts +5 -43
- package/dist/index.cjs +1 -1
- package/dist/index.modern.js +1 -1
- package/dist/index.module.js +1 -1
- package/dist/index.umd.js +1 -1
- package/package.json +21 -4
- package/dist/agent/__tests__/agent.test.d.ts +0 -1
- package/dist/agent/audio-debug.d.ts +0 -3
- package/dist/agent/audio-uplink.d.ts +0 -62
- package/dist/agent/avatar.cjs.map +0 -1
- package/dist/agent/avatar.modern.js.map +0 -1
- package/dist/agent/avatar.module.js.map +0 -1
- package/dist/agent/avatar.umd.js.map +0 -1
- package/dist/agent/cdn-entry.d.ts +0 -1
- package/dist/agent/e2e-client.d.ts +0 -32
- package/dist/agent/fixed-audio-track.d.ts +0 -48
- package/dist/agent/microphone.d.ts +0 -49
- package/src/agent/__tests__/agent.test.ts +0 -3787
- package/src/agent/audio-debug.ts +0 -36
- package/src/agent/audio-uplink.ts +0 -392
- package/src/agent/cdn-entry.ts +0 -15
- package/src/agent/e2e-client.ts +0 -215
- package/src/agent/fixed-audio-track.ts +0 -547
- package/src/agent/index.ts +0 -1393
- package/src/agent/microphone.ts +0 -534
- package/src/agent/types.ts +0 -197
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"avatar.modern.js","sources":["../../src/agent/e2e-client.ts","../../src/agent/fixed-audio-track.ts","../../src/agent/types.ts","../../src/agent/audio-debug.ts","../../src/utils/audio-session.ts","../../src/utils/media-recorder-timestamp.ts","../../src/encoding/webcodec-opus-encoder.ts","../../src/encoding/webm-muxer.ts","../../src/encoding/pcm-webm-encoder.ts","../../src/agent/microphone.ts","../../src/agent/audio-uplink.ts","../../src/agent/index.ts"],"sourcesContent":["import type { AgentClientMessage, AgentServerEvent, AgentSocketState } from \"./types\";\n\nconst MAX_BUFFERED_AMOUNT = 2 * 1024 * 1024;\n\nexport interface AgentE2EClientOptions {\n wsUrl: string;\n token: string;\n audioInputEnabled?: boolean;\n WebSocketCtor?: typeof WebSocket;\n onStateChange?: (state: AgentSocketState) => void;\n onEvent?: (event: AgentServerEvent) => void;\n onError?: (error: Error) => void;\n onClose?: (event: CloseEvent) => void;\n}\n\nexport class AgentE2EClient {\n private ws: WebSocket | null = null;\n private connectPromise: Promise<void> | null = null;\n private rejectConnect: ((error: Error) => void) | null = null;\n private audioInputEnabled: boolean;\n private readonly WebSocketCtor: typeof WebSocket;\n private readonly options: AgentE2EClientOptions;\n\n constructor(options: AgentE2EClientOptions) {\n this.options = options;\n this.audioInputEnabled = options.audioInputEnabled ?? true;\n const WebSocketCtor = options.WebSocketCtor || globalThis.WebSocket;\n if (!WebSocketCtor) {\n throw new Error(\"当前环境不支持 WebSocket\");\n }\n this.WebSocketCtor = WebSocketCtor;\n }\n\n get isOpen() {\n return this.ws?.readyState === this.WebSocketCtor.OPEN;\n }\n\n connect(): Promise<void> {\n if (this.isOpen) {\n return Promise.resolve();\n }\n if (this.connectPromise) {\n return this.connectPromise;\n }\n\n this.options.onStateChange?.(\"connecting\");\n\n let connection: Promise<void>;\n connection = new Promise<void>((resolve, reject) => {\n this.rejectConnect = reject;\n let settled = false;\n const ws = new this.WebSocketCtor(this.buildWsUrl(this.options.wsUrl, this.options.token));\n this.ws = ws;\n\n ws.onopen = () => {\n if (this.ws !== ws) {\n return;\n }\n settled = true;\n if (this.connectPromise === connection) {\n this.connectPromise = null;\n }\n this.rejectConnect = null;\n this.options.onStateChange?.(\"open\");\n resolve();\n };\n\n ws.onmessage = (message) => {\n if (this.ws !== ws) {\n return;\n }\n const event = this.parseMessage(message.data);\n if (event) {\n this.options.onEvent?.(event);\n }\n };\n\n ws.onerror = () => {\n if (this.ws !== ws) {\n return;\n }\n const error = new Error(\"E2E WebSocket 连接异常\");\n if (!settled) {\n settled = true;\n if (this.connectPromise === connection) {\n this.connectPromise = null;\n }\n this.rejectConnect = null;\n reject(error);\n }\n this.options.onStateChange?.(\"error\");\n this.options.onError?.(error);\n };\n\n ws.onclose = (event) => {\n if (this.ws !== ws) {\n return;\n }\n this.ws = null;\n if (!settled) {\n settled = true;\n if (this.connectPromise === connection) {\n this.connectPromise = null;\n }\n this.rejectConnect = null;\n reject(new Error(`E2E WebSocket 已关闭: ${event.code} ${event.reason || \"\"}`.trim()));\n }\n this.options.onStateChange?.(\"closed\");\n this.options.onClose?.(event);\n };\n });\n this.connectPromise = connection;\n return this.connectPromise;\n }\n\n disconnect(code = 1000, reason = \"client_close\") {\n if (!this.ws) {\n return;\n }\n\n const ws = this.ws;\n this.ws = null;\n this.connectPromise = null;\n const rejectConnect = this.rejectConnect;\n this.rejectConnect = null;\n rejectConnect?.(new Error(\"E2E WebSocket 连接已取消\"));\n\n if (ws.readyState === this.WebSocketCtor.OPEN || ws.readyState === this.WebSocketCtor.CONNECTING) {\n ws.close(code, reason);\n }\n }\n\n send(message: AgentClientMessage) {\n this.assertOpen();\n this.ws?.send(JSON.stringify(message));\n }\n\n trySend(message: AgentClientMessage) {\n this.assertOpen();\n if (this.ws && this.ws.bufferedAmount > MAX_BUFFERED_AMOUNT) {\n return false;\n }\n this.ws?.send(JSON.stringify(message));\n return true;\n }\n\n sendBinary(frame: ArrayBuffer | ArrayBufferView | Blob) {\n this.assertOpen();\n if (this.ws && this.ws.bufferedAmount > MAX_BUFFERED_AMOUNT) {\n const error = new Error(\"E2E WebSocket 发送缓冲区超限\");\n error.name = \"WebSocketBackpressureError\";\n throw error;\n }\n this.ws?.send(frame as any);\n }\n\n ping() {\n this.send({ type: \"ping\" });\n }\n\n setAudioInputEnabled(enabled: boolean) {\n this.audioInputEnabled = enabled;\n }\n\n private assertOpen() {\n if (!this.isOpen) {\n throw new Error(\"E2E WebSocket 未连接\");\n }\n }\n\n private parseMessage(data: unknown): AgentServerEvent | null {\n if (typeof data !== \"string\") {\n return null;\n }\n\n try {\n const parsed = JSON.parse(data);\n if (parsed && typeof parsed.type === \"string\") {\n return parsed as AgentServerEvent;\n }\n return null;\n } catch (error) {\n this.options.onError?.(new Error(\"E2E WebSocket 消息不是合法 JSON\"));\n return null;\n }\n }\n\n private buildWsUrl(wsUrl: string, token: string) {\n try {\n const url = new URL(wsUrl);\n if (token && !url.searchParams.has(\"token\") && !url.searchParams.has(\"e2e_token\")) {\n url.searchParams.set(\"token\", token);\n }\n this.updateAudioInputQuery(url.searchParams);\n return url.toString();\n } catch {\n const [baseUrl, query = \"\"] = wsUrl.split(\"?\", 2);\n const searchParams = new URLSearchParams(query);\n if (token && !searchParams.has(\"token\") && !searchParams.has(\"e2e_token\")) {\n searchParams.set(\"token\", token);\n }\n this.updateAudioInputQuery(searchParams);\n const nextQuery = searchParams.toString();\n return nextQuery ? `${baseUrl}?${nextQuery}` : baseUrl;\n }\n }\n\n private updateAudioInputQuery(searchParams: URLSearchParams) {\n if (!this.audioInputEnabled) {\n searchParams.set(\"audio_input_off\", \"1\");\n return;\n }\n searchParams.delete(\"audio_input_off\");\n }\n}\n","const TARGET_SAMPLE_RATE = 16_000;\nconst TARGET_CHANNELS = 1;\nconst OUTPUT_FRAME_SIZE = 320;\nconst MIN_INPUT_SAMPLE_RATE = 8_000;\nconst MAX_INPUT_SAMPLE_RATE = 192_000;\nconst MAX_INPUT_FRAMES_PER_READ = 96_000;\nconst MAX_RESAMPLE_BUFFER_LENGTH = MAX_INPUT_FRAMES_PER_READ * 2;\n\ninterface AudioDataLike {\n sampleRate: number;\n numberOfChannels: number;\n numberOfFrames: number;\n timestamp: number;\n copyTo(destination: Float32Array, options?: { format?: string; planeIndex?: number }): void;\n close(): void;\n}\n\ninterface AudioDataConstructorLike {\n new (init: {\n format: \"f32-planar\";\n sampleRate: number;\n numberOfFrames: number;\n numberOfChannels: number;\n timestamp: number;\n data: Float32Array;\n }): AudioDataLike;\n}\n\ninterface AudioTrackProcessorLike {\n readable: ReadableStream<AudioDataLike>;\n}\n\ninterface AudioTrackProcessorConstructorLike {\n new (init: { track: MediaStreamTrack }): AudioTrackProcessorLike;\n}\n\ninterface AudioTrackGeneratorLike extends MediaStreamTrack {\n writable: WritableStream<AudioDataLike>;\n}\n\ninterface AudioTrackGeneratorConstructorLike {\n new (init: { kind: \"audio\" }): AudioTrackGeneratorLike;\n}\n\ninterface AudioRuntimeGlobals {\n AudioData?: AudioDataConstructorLike;\n MediaStreamTrackProcessor?: AudioTrackProcessorConstructorLike;\n MediaStreamTrackGenerator?: AudioTrackGeneratorConstructorLike;\n webkitAudioContext?: typeof AudioContext;\n}\n\ntype AgentCodedError = Error & {\n agentCode?: string;\n retryable?: boolean;\n cause?: unknown;\n};\n\nexport interface FixedAudioTrackOptions {\n onError?: (error: Error) => void;\n}\n\n/**\n * Converts a microphone MediaStreamTrack to a verifiable 16 kHz mono track\n * before it is handed to MediaRecorder. WebM/Opus remains the container/codec\n * used on the wire; this class only owns the decoded audio track conversion.\n */\nexport class FixedAudioTrack {\n private readonly options: FixedAudioTrackOptions;\n private inputTrack: MediaStreamTrack | null = null;\n private reader: ReadableStreamDefaultReader<AudioDataLike> | null = null;\n private writer: WritableStreamDefaultWriter<AudioDataLike> | null = null;\n private generator: AudioTrackGeneratorLike | null = null;\n private audioContext: AudioContext | null = null;\n private audioSource: MediaStreamAudioSourceNode | null = null;\n private audioDestination: MediaStreamAudioDestinationNode | null = null;\n private pumpPromise: Promise<void> | null = null;\n private pumpFinished = false;\n private outputClosed = false;\n private draining = false;\n private inputSampleRate: number | null = null;\n private resampleBuffer: number[] = [];\n private resamplePosition = 0;\n private outputBuffer: number[] = [];\n private outputTimestamp: number | null = null;\n private startGeneration = 0;\n\n constructor(options: FixedAudioTrackOptions = {}) {\n this.options = options;\n }\n\n async start(inputTrack: MediaStreamTrack): Promise<MediaStream> {\n const startGeneration = ++this.startGeneration;\n this.inputTrack = inputTrack;\n this.inputSampleRate = null;\n this.resampleBuffer = [];\n this.resamplePosition = 0;\n this.outputBuffer = [];\n this.outputTimestamp = null;\n this.pumpFinished = false;\n this.outputClosed = false;\n this.draining = false;\n const globals = globalThis as typeof globalThis & AudioRuntimeGlobals;\n const ProcessorCtor = globals.MediaStreamTrackProcessor;\n const GeneratorCtor = globals.MediaStreamTrackGenerator;\n const AudioDataCtor = globals.AudioData;\n if (!ProcessorCtor || !GeneratorCtor || !AudioDataCtor) {\n return this.startWebAudio(inputTrack, globals, startGeneration);\n }\n\n const processor = new ProcessorCtor({ track: inputTrack });\n const generator = new GeneratorCtor({ kind: \"audio\" });\n const stream = new MediaStream([generator]);\n const outputTrack = stream.getAudioTracks()[0];\n const settings = outputTrack?.getSettings() as (MediaTrackSettings & {\n sampleRate?: number;\n channelCount?: number;\n }) | undefined;\n // Chrome does not expose generator settings until its first AudioData is\n // written. The format is nevertheless fixed by every AudioData created in\n // writeChunk; when settings are available, reject an implementation that\n // reports a different output track.\n if (\n (settings?.sampleRate !== undefined && settings.sampleRate !== TARGET_SAMPLE_RATE) ||\n (settings?.channelCount !== undefined && settings.channelCount !== TARGET_CHANNELS)\n ) {\n generator.stop();\n throw this.unsupported(\n `浏览器音频输出格式不符合要求: ${settings?.sampleRate || \"unknown\"} Hz / ${settings?.channelCount || \"unknown\"} channel`,\n );\n }\n\n try {\n this.reader = processor.readable.getReader();\n this.writer = generator.writable.getWriter();\n } catch (error) {\n generator.stop();\n if (inputTrack.readyState !== \"ended\") {\n inputTrack.stop();\n }\n this.inputTrack = null;\n throw error;\n }\n this.generator = generator;\n this.pumpPromise = this.pump(AudioDataCtor);\n return stream;\n }\n\n private async startWebAudio(\n inputTrack: MediaStreamTrack,\n globals: AudioRuntimeGlobals,\n startGeneration: number,\n ) {\n const AudioContextCtor = globalThis.AudioContext || globals.webkitAudioContext;\n if (!AudioContextCtor) {\n throw this.unsupported(\"当前浏览器不支持 16 kHz mono 音频处理\");\n }\n\n let context: AudioContext | null = null;\n let source: MediaStreamAudioSourceNode | null = null;\n let destination: MediaStreamAudioDestinationNode | null = null;\n try {\n context = new AudioContextCtor({ sampleRate: TARGET_SAMPLE_RATE });\n this.audioContext = context;\n if (context.sampleRate !== TARGET_SAMPLE_RATE) {\n throw this.unsupported(`浏览器无法创建 16 kHz AudioContext: ${context.sampleRate} Hz`);\n }\n if (context.state === \"suspended\") {\n try {\n await context.resume();\n } catch (cause) {\n throw this.contextSuspended(cause);\n }\n }\n this.assertStartActive(startGeneration);\n if (context.state !== \"running\") {\n throw this.contextSuspended();\n }\n\n source = context.createMediaStreamSource(new MediaStream([inputTrack]));\n this.audioSource = source;\n destination = context.createMediaStreamDestination();\n this.audioDestination = destination;\n destination.channelCount = TARGET_CHANNELS;\n destination.channelCountMode = \"explicit\";\n destination.channelInterpretation = \"speakers\";\n source.connect(destination);\n\n const outputTrack = destination.stream.getAudioTracks()[0];\n if (!outputTrack) {\n throw new Error(\"Web Audio 未返回音频输出轨道\");\n }\n this.validateOutputTrack(outputTrack);\n this.assertStartActive(startGeneration);\n return destination.stream;\n } catch (error) {\n source?.disconnect();\n destination?.stream.getTracks().forEach((track) => track.stop());\n if (context && context.state !== \"closed\") {\n await context.close().catch(() => undefined);\n }\n if (inputTrack.readyState !== \"ended\") {\n inputTrack.stop();\n }\n this.inputTrack = null;\n if (this.audioContext === context) {\n this.audioContext = null;\n this.audioSource = null;\n this.audioDestination = null;\n }\n throw this.normalizeWebAudioError(error);\n }\n }\n\n async stop() {\n await this.drain();\n if (this.audioContext) {\n await this.closeWebAudioOutput();\n return;\n }\n await this.closeOutput();\n }\n\n /** Stop input and flush decoded samples while keeping the output track live. */\n async drain() {\n this.startGeneration += 1;\n this.draining = true;\n this.inputTrack?.stop();\n this.inputTrack = null;\n\n if (this.audioContext) {\n return;\n }\n\n const pump = this.pumpPromise;\n if (pump) {\n const settled = pump.then(\n () => true,\n () => true,\n );\n const finished = await Promise.race([settled, this.delay(1000)]);\n if (!finished) {\n await Promise.race([\n this.reader?.cancel().catch(() => undefined),\n this.delay(100),\n ]);\n await Promise.race([\n this.writer?.abort(new Error(\"16 kHz mono 音频处理停止超时\")).catch(() => undefined),\n this.delay(100),\n ]);\n this.stopGenerator();\n // Do not await an implementation that is stuck in writer.write(). The\n // rejection handler above keeps the eventual pump settlement observed.\n void settled;\n }\n }\n }\n\n private async closeOutput() {\n const writer = this.writer;\n this.outputClosed = true;\n if (writer && this.pumpFinished) {\n await Promise.race([\n writer.close().catch(() => undefined),\n this.delay(100),\n ]);\n } else {\n await Promise.race([\n writer?.abort(new Error(\"16 kHz mono 音频处理停止超时\")).catch(() => undefined),\n this.delay(100),\n ]);\n }\n this.stopGenerator();\n if (writer && this.pumpFinished) {\n writer.releaseLock();\n }\n this.reader = null;\n this.writer = null;\n this.generator = null;\n this.pumpPromise = null;\n }\n\n private async closeWebAudioOutput() {\n const context = this.audioContext;\n const source = this.audioSource;\n const destination = this.audioDestination;\n this.audioContext = null;\n this.audioSource = null;\n this.audioDestination = null;\n\n source?.disconnect();\n destination?.disconnect();\n destination?.stream.getTracks().forEach((track) => track.stop());\n if (context && context.state !== \"closed\") {\n await context.close().catch(() => undefined);\n }\n }\n\n private async pump(AudioDataCtor: AudioDataConstructorLike) {\n const reader = this.reader;\n const writer = this.writer;\n if (!reader || !writer) {\n return;\n }\n\n try {\n let inputEnded = false;\n while (true) {\n const result = await reader.read();\n if (result.done) {\n inputEnded = true;\n break;\n }\n if (!result.value) {\n continue;\n }\n\n const audioData = result.value;\n try {\n this.validateAudioData(audioData);\n const mono = this.toMono(audioData);\n const chunks = this.resample(mono, audioData.sampleRate, false);\n if (this.outputTimestamp === null) {\n this.outputTimestamp = Number.isFinite(audioData.timestamp) ? audioData.timestamp : 0;\n }\n for (const chunk of chunks) {\n await this.writeChunk(writer, AudioDataCtor, chunk);\n }\n } finally {\n audioData.close();\n }\n }\n\n for (const chunk of this.resample(new Float32Array(), this.inputSampleRate || TARGET_SAMPLE_RATE, true)) {\n await this.writeChunk(writer, AudioDataCtor, chunk);\n }\n if (inputEnded && !this.draining && this.inputTrack?.readyState === \"ended\") {\n const error = new Error(\"麦克风音频轨道已结束\");\n error.name = \"AudioTransformError\";\n this.options.onError?.(error);\n this.stopGenerator();\n }\n } catch (error) {\n const normalized = error instanceof Error ? error : new Error(\"16 kHz mono 音频处理失败\");\n normalized.name = \"AudioTransformError\";\n this.options.onError?.(normalized);\n } finally {\n reader.releaseLock();\n this.pumpFinished = true;\n if (this.outputClosed) {\n writer.releaseLock();\n }\n }\n }\n\n private toMono(audioData: AudioDataLike) {\n const channels = Math.max(1, audioData.numberOfChannels);\n const mono = new Float32Array(audioData.numberOfFrames);\n for (let channel = 0; channel < channels; channel += 1) {\n const plane = new Float32Array(audioData.numberOfFrames);\n audioData.copyTo(plane, { format: \"f32-planar\", planeIndex: channel });\n for (let index = 0; index < plane.length; index += 1) {\n mono[index] += plane[index] / channels;\n }\n }\n return mono;\n }\n\n private resample(input: Float32Array, inputSampleRate: number, flush: boolean) {\n if (this.inputSampleRate === null) {\n this.inputSampleRate = inputSampleRate;\n } else if (this.inputSampleRate !== inputSampleRate) {\n throw new Error(`输入音频采样率发生变化: ${this.inputSampleRate} -> ${inputSampleRate}`);\n }\n\n for (const sample of input) {\n this.resampleBuffer.push(sample);\n }\n if (this.resampleBuffer.length > MAX_RESAMPLE_BUFFER_LENGTH) {\n throw new Error(\"输入音频重采样缓冲区超限\");\n }\n if (flush && this.resampleBuffer.length > 0) {\n this.resampleBuffer.push(this.resampleBuffer[this.resampleBuffer.length - 1]);\n }\n\n const step = inputSampleRate / TARGET_SAMPLE_RATE;\n const chunks: Float32Array[] = [];\n while (this.resamplePosition + 1 < this.resampleBuffer.length) {\n const before = Math.floor(this.resamplePosition);\n const after = Math.min(before + 1, this.resampleBuffer.length - 1);\n const weight = this.resamplePosition - before;\n this.outputBuffer.push(\n this.resampleBuffer[before] * (1 - weight) + this.resampleBuffer[after] * weight,\n );\n this.resamplePosition += step;\n\n const consumed = Math.floor(this.resamplePosition);\n if (consumed > 0) {\n this.resampleBuffer.splice(0, consumed);\n this.resamplePosition -= consumed;\n }\n\n if (this.outputBuffer.length >= OUTPUT_FRAME_SIZE) {\n chunks.push(new Float32Array(this.outputBuffer.splice(0, OUTPUT_FRAME_SIZE)));\n }\n }\n\n if (flush && this.outputBuffer.length > 0) {\n chunks.push(new Float32Array(this.outputBuffer.splice(0)));\n }\n return chunks;\n }\n\n private async writeChunk(\n writer: WritableStreamDefaultWriter<AudioDataLike>,\n AudioDataCtor: AudioDataConstructorLike,\n samples: Float32Array,\n ) {\n if (!samples.length) {\n return;\n }\n const timestamp = this.outputTimestamp || 0;\n const audioData = new AudioDataCtor({\n format: \"f32-planar\",\n sampleRate: TARGET_SAMPLE_RATE,\n numberOfFrames: samples.length,\n numberOfChannels: TARGET_CHANNELS,\n timestamp,\n data: samples,\n });\n this.outputTimestamp = timestamp + Math.round((samples.length * 1_000_000) / TARGET_SAMPLE_RATE);\n await writer.write(audioData);\n audioData.close();\n const settings = this.generator?.getSettings() as\n | (MediaTrackSettings & { sampleRate?: number; channelCount?: number })\n | undefined;\n if (\n settings &&\n ((settings.sampleRate !== undefined && settings.sampleRate !== TARGET_SAMPLE_RATE) ||\n (settings.channelCount !== undefined && settings.channelCount !== TARGET_CHANNELS))\n ) {\n throw this.unsupported(\n `浏览器音频输出格式不符合要求: ${settings.sampleRate || \"unknown\"} Hz / ${settings.channelCount || \"unknown\"} channel`,\n );\n }\n }\n\n private validateAudioData(audioData: AudioDataLike) {\n if (\n !Number.isFinite(audioData.sampleRate) ||\n !Number.isInteger(audioData.sampleRate) ||\n audioData.sampleRate < MIN_INPUT_SAMPLE_RATE ||\n audioData.sampleRate > MAX_INPUT_SAMPLE_RATE\n ) {\n throw new Error(`输入音频采样率无效: ${audioData.sampleRate}`);\n }\n if (\n !Number.isInteger(audioData.numberOfChannels) ||\n audioData.numberOfChannels < 1 ||\n audioData.numberOfChannels > 8\n ) {\n throw new Error(`输入音频声道数无效: ${audioData.numberOfChannels}`);\n }\n if (\n !Number.isInteger(audioData.numberOfFrames) ||\n audioData.numberOfFrames < 1 ||\n audioData.numberOfFrames > MAX_INPUT_FRAMES_PER_READ\n ) {\n throw new Error(`输入音频帧数无效: ${audioData.numberOfFrames}`);\n }\n if (!Number.isFinite(audioData.timestamp) || Math.abs(audioData.timestamp) > 1e15) {\n throw new Error(`输入音频时间戳无效: ${audioData.timestamp}`);\n }\n }\n\n private delay(timeoutMs: number) {\n return new Promise<boolean>((resolve) => {\n globalThis.setTimeout(() => resolve(false), timeoutMs);\n });\n }\n\n private stopGenerator() {\n if (this.generator && this.generator.readyState !== \"ended\") {\n this.generator.stop();\n }\n }\n\n private unsupported(message: string, cause?: unknown) {\n const error = new Error(message) as AgentCodedError;\n error.name = \"NotSupportedError\";\n error.agentCode = \"AUDIO_FIXED_TRACK_UNSUPPORTED\";\n error.retryable = false;\n error.cause = cause;\n return error;\n }\n\n private contextSuspended(cause?: unknown) {\n const error = new Error(\"AudioContext 未运行,请在用户操作后重试\") as AgentCodedError;\n error.name = \"NotAllowedError\";\n error.agentCode = \"AUDIO_CONTEXT_SUSPENDED\";\n error.retryable = true;\n error.cause = cause;\n return error;\n }\n\n private assertStartActive(startGeneration: number) {\n if (startGeneration !== this.startGeneration) {\n const error = new Error(\"16 kHz mono 音频处理启动已取消\") as AgentCodedError;\n error.name = \"AbortError\";\n error.agentCode = \"AUDIO_FIXED_TRACK_CANCELLED\";\n error.retryable = true;\n throw error;\n }\n }\n\n private normalizeWebAudioError(error: unknown) {\n const normalized: AgentCodedError = error instanceof Error\n ? error\n : new Error(String(error));\n if (normalized.agentCode) {\n return normalized;\n }\n if (normalized.name === \"NotSupportedError\") {\n return this.unsupported(`浏览器无法初始化 16 kHz mono Web Audio: ${normalized.message}`, normalized);\n }\n const coded = new Error(`16 kHz mono Web Audio 初始化失败: ${normalized.message}`) as AgentCodedError;\n coded.name = normalized.name;\n coded.agentCode = \"AUDIO_FIXED_TRACK_FAILED\";\n coded.retryable = true;\n coded.cause = normalized;\n return coded;\n }\n\n private validateOutputTrack(outputTrack: MediaStreamTrack) {\n const settings = outputTrack.getSettings() as MediaTrackSettings & {\n sampleRate?: number;\n channelCount?: number;\n };\n if (\n (settings.sampleRate !== undefined && settings.sampleRate !== TARGET_SAMPLE_RATE) ||\n (settings.channelCount !== undefined && settings.channelCount !== TARGET_CHANNELS)\n ) {\n throw this.unsupported(\n `浏览器音频输出格式不符合要求: ${settings.sampleRate || \"unknown\"} Hz / ${settings.channelCount || \"unknown\"} channel`,\n );\n }\n }\n}\n","import type { IAvatarOptions, IInitParams, INetworkInfo, RenderState } from \"../types\";\n\nexport type AgentState =\n | \"idle\"\n | \"initializing\"\n | \"ready\"\n | \"running\"\n | \"reconnecting\"\n | \"stopped\"\n | \"destroyed\"\n | \"failed\";\nexport type AgentSocketState = \"idle\" | \"connecting\" | \"open\" | \"closed\" | \"error\";\nexport type AgentASRState = \"idle\" | \"requesting-permission\" | \"starting\" | \"listening\" | \"stopping\" | \"failed\";\nexport type AgentConversationState =\n | \"idle\"\n | \"asking\"\n | \"speaking-directly\"\n | \"speaking\"\n | \"completed\"\n | \"interrupted\"\n | \"failed\";\n\nexport type AgentErrorDomain = \"permission\" | \"network\" | \"asr\" | \"brain\" | \"ttsa\" | \"quota\" | \"sdk\";\n\nexport interface AgentAudioOptions {\n chunkMs?: number;\n inputEnabled?: boolean;\n /**\n * @deprecated Session 返回 features.speech_frontend.enable_aec 后,以服务端返回值为准。\n */\n echoCancellationEnabled?: boolean;\n}\n\nexport interface AgentReconnectOptions {\n enabled?: boolean;\n maxAttempts?: number;\n initialDelayMs?: number;\n maxDelayMs?: number;\n}\n\nexport interface AgentError {\n code: string;\n message: string;\n domain: AgentErrorDomain;\n retryable?: boolean;\n cause?: unknown;\n}\n\nexport interface AgentASRResult {\n text: string;\n isFinal: boolean;\n raw?: unknown;\n}\n\nexport interface AgentASRStartOptions {\n /**\n * Optional caller-owned audio stream used instead of requesting the physical microphone.\n * The Agent clones one live audio track and never stops the caller-owned stream.\n */\n inputStream?: MediaStream;\n}\n\nexport interface AgentLLMUsage {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n cachedTokens: number;\n}\n\nexport interface AgentLLMResponse {\n event: \"chunk\" | \"done\";\n text?: string;\n isFirst?: boolean;\n usage?: AgentLLMUsage;\n raw?: unknown;\n}\n\nexport interface AgentSemanticJudgeResult {\n query: string;\n meaningful: boolean;\n action: string;\n raw?: unknown;\n}\n\nexport interface AgentSpeakStateEvent {\n state: string;\n clientSpeakId?: string | number;\n raw?: unknown;\n}\n\nexport interface AgentConversationEvent {\n state: AgentConversationState;\n text?: string;\n raw?: unknown;\n}\n\nexport interface XingyunAvatarAgentCallbacks {\n onAgentStateChange?: (state: AgentState) => void;\n onSocketStateChange?: (state: AgentSocketState) => void;\n onASRStateChange?: (state: AgentASRState) => void;\n onASRResult?: (result: AgentASRResult) => void;\n onLLMResponse?: (response: AgentLLMResponse) => void;\n onSpeakStateChange?: (event: AgentSpeakStateEvent) => void;\n onConversationChange?: (event: AgentConversationEvent) => void;\n onSemanticJudgeResult?: (result: AgentSemanticJudgeResult) => void;\n onRenderChange?: (state: RenderState) => void;\n onNetworkInfo?: (info: INetworkInfo) => void;\n onError?: (error: AgentError) => void;\n}\n\nexport type AgentServiceConfig = Record<string, unknown>;\n\nexport interface AgentBrainConfig extends AgentServiceConfig {\n extra_body?: Record<string, unknown>;\n}\n\nexport interface AgentFeatures extends AgentServiceConfig {\n anti_interference?: {\n semantic_judge_enabled?: boolean;\n };\n speech_frontend?: {\n enabled?: boolean;\n enable_aec?: boolean;\n enable_speech_separation?: boolean;\n };\n vad_merge_mode?: boolean;\n volume_and_repetition_text_detection?: boolean;\n}\n\nexport interface XingyunAvatarAgentOptions extends IAvatarOptions {\n asr_id?: number;\n asr_config?: AgentServiceConfig;\n tts_config?: AgentServiceConfig;\n features?: AgentFeatures;\n extras?: AgentServiceConfig;\n llm_id?: number;\n brain_config?: AgentBrainConfig;\n session_speak_req_id?: 0 | 1;\n e2eServer?: string;\n authToken?: string;\n audio?: AgentAudioOptions;\n reconnect?: AgentReconnectOptions;\n agentCallbacks?: XingyunAvatarAgentCallbacks;\n webSocketCtor?: typeof WebSocket;\n}\n\nexport type XingyunAvatarAgentInitParams = Omit<IInitParams, \"onDownloadProgress\"> & {\n onDownloadProgress?: IInitParams[\"onDownloadProgress\"];\n};\n\nexport interface AgentSessionInfo {\n ws_url?: string;\n e2e_token?: string;\n monitor_ws_url?: string;\n}\n\nexport interface AgentClientMessage {\n type: string;\n message?: unknown;\n [key: string]: unknown;\n}\n\nexport interface AgentServerEvent {\n type: string;\n domain?: string;\n code?: string | number;\n event?: string;\n message?: unknown;\n text?: string;\n is_first?: boolean;\n is_final?: boolean;\n usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n cached_tokens?: number;\n };\n [key: string]: unknown;\n}\n\nexport interface AgentAudioMetadata {\n format: \"webm_opus\";\n mimeType: \"audio/webm;codecs=opus\";\n /** Fixed output track sample rate passed to the MediaRecorder pipeline. */\n sampleRate: number;\n /** Fixed output track channel count passed to the MediaRecorder pipeline. */\n channels: number;\n chunkMs: number;\n}\n\nexport const DEFAULT_AGENT_AUDIO: AgentAudioMetadata = {\n format: \"webm_opus\",\n mimeType: \"audio/webm;codecs=opus\",\n sampleRate: 16000,\n channels: 1,\n chunkMs: 100,\n};\n","const DEFAULT_AUDIO_CHUNK_PREVIEW_BYTES = 64;\n\ntype AudioChunkDebugMetadata = Record<string, unknown>;\n\nfunction toHex(byte: number) {\n return byte.toString(16).padStart(2, \"0\");\n}\n\nexport async function logAudioChunkContent(\n label: string,\n chunk: Blob | ArrayBuffer | ArrayBufferView,\n metadata: AudioChunkDebugMetadata = {},\n previewBytes = DEFAULT_AUDIO_CHUNK_PREVIEW_BYTES,\n) {\n try {\n const buffer = chunk instanceof Blob\n ? await chunk.arrayBuffer()\n : ArrayBuffer.isView(chunk)\n ? chunk.buffer.slice(chunk.byteOffset, chunk.byteOffset + chunk.byteLength)\n : chunk;\n const bytes = new Uint8Array(buffer);\n const preview = Array.from(bytes.slice(0, previewBytes));\n const type = chunk instanceof Blob ? chunk.type : metadata.type;\n\n console.log(label, {\n ...metadata,\n size: bytes.byteLength,\n type,\n previewLength: preview.length,\n bytes: preview,\n hex: preview.map(toHex).join(\" \"),\n });\n } catch (error) {\n console.warn(label, \"failed to read audio chunk\", error);\n }\n}\n","export type WebAudioSessionType = \"playback\" | \"play-and-record\";\n\ntype WebAudioSession = {\n type: string;\n};\n\ntype NavigatorWithAudioSession = Navigator & {\n audioSession?: WebAudioSession;\n};\n\ntype WebAudioPlaybackSessionRestoredListener = () => void;\n\nconst captureStates = new WeakMap<\n WebAudioSession,\n { count: number; previousType: string }\n>();\nconst playbackSessionRestoredListeners = new WeakMap<\n WebAudioSession,\n Set<WebAudioPlaybackSessionRestoredListener>\n>();\n\n/**\n * Keep Web Audio audible through the iOS Ring/Silent switch. Do not override\n * a play-and-record session that may belong to an active microphone track.\n */\nexport function configureWebAudioPlaybackSession(\n target: Navigator = navigator,\n): boolean {\n const audioSession = getAudioSession(target);\n if (!audioSession) {\n return false;\n }\n\n const captureState = captureStates.get(audioSession);\n if (captureState?.count || audioSession.type === \"play-and-record\") {\n return setAudioSessionType(audioSession, \"play-and-record\");\n }\n return setAudioSessionType(audioSession, \"playback\");\n}\n\nexport function beginWebAudioCaptureSession(\n target: Navigator = navigator,\n): boolean {\n const audioSession = getAudioSession(target);\n if (!audioSession) {\n return false;\n }\n\n const existingState = captureStates.get(audioSession);\n const previousType = existingState?.previousType ?? audioSession.type;\n if (!setAudioSessionType(audioSession, \"play-and-record\")) {\n return false;\n }\n\n captureStates.set(audioSession, {\n count: (existingState?.count ?? 0) + 1,\n previousType,\n });\n return true;\n}\n\nexport function subscribeWebAudioPlaybackSessionRestored(\n listener: WebAudioPlaybackSessionRestoredListener,\n target: Navigator = navigator,\n): () => void {\n const audioSession = getAudioSession(target);\n if (!audioSession) {\n return () => {};\n }\n\n let listeners = playbackSessionRestoredListeners.get(audioSession);\n if (!listeners) {\n listeners = new Set();\n playbackSessionRestoredListeners.set(audioSession, listeners);\n }\n listeners.add(listener);\n\n return () => {\n listeners?.delete(listener);\n if (listeners?.size === 0) {\n playbackSessionRestoredListeners.delete(audioSession);\n }\n };\n}\n\nexport function endWebAudioCaptureSession(\n target: Navigator = navigator,\n): boolean {\n const audioSession = getAudioSession(target);\n if (!audioSession) {\n return false;\n }\n\n const captureState = captureStates.get(audioSession);\n if (!captureState) {\n return configureWebAudioPlaybackSession(target);\n }\n\n captureState.count -= 1;\n if (captureState.count > 0) {\n return setAudioSessionType(audioSession, \"play-and-record\");\n }\n\n captureStates.delete(audioSession);\n const nextType = captureState.previousType === \"play-and-record\"\n ? \"play-and-record\"\n : \"playback\";\n const updated = setAudioSessionType(audioSession, nextType);\n if (updated && nextType === \"playback\") {\n notifyPlaybackSessionRestored(audioSession);\n }\n return updated;\n}\n\nfunction notifyPlaybackSessionRestored(audioSession: WebAudioSession): void {\n const listeners = playbackSessionRestoredListeners.get(audioSession);\n if (!listeners) {\n return;\n }\n\n for (const listener of [...listeners]) {\n try {\n listener();\n } catch {\n // Playback recovery must never break microphone cleanup.\n }\n }\n}\n\nfunction getAudioSession(target: Navigator): WebAudioSession | undefined {\n return (target as NavigatorWithAudioSession).audioSession;\n}\n\nfunction setAudioSessionType(\n audioSession: WebAudioSession,\n type: WebAudioSessionType,\n): boolean {\n try {\n audioSession.type = type;\n return audioSession.type === type;\n } catch {\n return false;\n }\n}\n","type EpochClock = () => number;\n\nfunction monotonicEpochNow() {\n const clock = globalThis.performance;\n if (\n clock\n && Number.isFinite(clock.timeOrigin)\n && typeof clock.now === \"function\"\n ) {\n return clock.timeOrigin + clock.now();\n }\n return Date.now();\n}\n\n/** Normalizes browser-specific BlobEvent.timecode units to epoch milliseconds. */\nexport class MediaRecorderTimestamp {\n private readonly startedAt: number;\n private readonly now: EpochClock;\n private timecodeScale: 1 | 1000 | null = null;\n private firstTimecode: number | null = null;\n private lastTimecode: number | null = null;\n private lastObservedAt: number | null = null;\n private lastTimestamp: number | null = null;\n\n constructor(\n private readonly chunkMs: number,\n now: EpochClock = monotonicEpochNow,\n ) {\n this.now = now;\n this.startedAt = now();\n }\n\n resolve(timecode: number): number {\n const observedAt = this.now();\n const validTimecode = Number.isFinite(timecode) && timecode >= 0;\n\n if (validTimecode && this.firstTimecode === null) {\n this.firstTimecode = timecode;\n }\n\n if (\n validTimecode\n && this.timecodeScale === null\n && this.lastTimecode !== null\n && timecode > this.lastTimecode\n ) {\n const timecodeDelta = timecode - this.lastTimecode;\n const observedDelta = this.lastObservedAt === null ? 0 : observedAt - this.lastObservedAt;\n const expectedDelta = observedDelta >= this.chunkMs / 4 ? observedDelta : this.chunkMs;\n const millisecondError = Math.abs(timecodeDelta - expectedDelta);\n const secondError = Math.abs(timecodeDelta * 1000 - expectedDelta);\n this.timecodeScale = secondError < millisecondError ? 1000 : 1;\n }\n\n let timestamp = observedAt - this.chunkMs;\n const relativeTimecode = validTimecode && this.firstTimecode !== null\n ? timecode - this.firstTimecode\n : null;\n if (\n relativeTimecode !== null\n && relativeTimecode >= 0\n && (this.timecodeScale !== null || relativeTimecode === 0)\n ) {\n timestamp = this.startedAt + relativeTimecode * (this.timecodeScale ?? 1);\n }\n\n if (this.lastTimestamp !== null) {\n // A non-empty MediaRecorder Blob must not collapse into an already-used\n // AU bucket when a browser repeats or resets its timecode.\n timestamp = Math.max(timestamp, this.lastTimestamp + this.chunkMs);\n }\n\n const resolved = Math.max(Math.round(this.startedAt), Math.round(timestamp));\n this.lastTimecode = validTimecode ? timecode : this.lastTimecode;\n this.lastObservedAt = observedAt;\n this.lastTimestamp = resolved;\n return resolved;\n }\n}\n","/**\n * WebCodecs AudioEncoder Opus 编码封装\n * 使用浏览器原生 WebCodecs API 将 PCM 音频编码为 Opus 帧\n */\n\nexport interface OpusEncoderConfig {\n sampleRate: number; // 16000\n channels: number; // 1 (mono)\n bitrate: number; // 24000\n frameSize: number; // 1600 (100ms @ 16kHz)\n}\n\nexport interface EncodedOpusFrame {\n data: Uint8Array;\n durationMs: number;\n}\n\nconst OPUS_FRAME_DURATION_US = 20_000;\nconst ENCODE_TIMEOUT_MS = 2_000;\n\ninterface PendingEncode {\n startTimestampUs: number;\n endTimestampUs: number;\n expectedFrameCount: number;\n chunks: EncodedAudioChunk[];\n resolve(frames: EncodedOpusFrame[]): void;\n reject(error: Error): void;\n timeoutId: number;\n}\n\nfunction buildAudioEncoderConfig(config: OpusEncoderConfig) {\n return {\n codec: 'opus',\n sampleRate: config.sampleRate,\n numberOfChannels: config.channels,\n bitrate: config.bitrate,\n // Safari may otherwise choose a 120 ms Opus packet for a 100 ms AudioData\n // input. The AU protocol clock is fixed at 100 ms, so pin packetization to\n // five 20 ms packets per input block.\n opus: {\n format: 'opus' as const,\n frameDuration: OPUS_FRAME_DURATION_US,\n },\n };\n}\n\nexport class WebCodecOpusEncoder {\n private encoder: AudioEncoder | null = null;\n private config: OpusEncoderConfig;\n private isInitialized = false;\n private pendingEncode: PendingEncode | null = null;\n private timestamp: number = 0; // 单位:微秒\n\n constructor(config: Partial<OpusEncoderConfig> = {}) {\n this.config = {\n sampleRate: 16000,\n channels: 1,\n bitrate: 24000,\n frameSize: 1600,\n ...config,\n };\n }\n\n /**\n * 检测当前浏览器是否支持 WebCodecs Opus 编码\n */\n static async isSupported(): Promise<boolean> {\n if (typeof AudioEncoder === 'undefined') return false;\n try {\n const support = await AudioEncoder.isConfigSupported(buildAudioEncoderConfig({\n sampleRate: 16000,\n channels: 1,\n bitrate: 24000,\n frameSize: 1600,\n }));\n return support.supported === true\n && support.config?.opus?.frameDuration === OPUS_FRAME_DURATION_US;\n } catch {\n return false;\n }\n }\n\n async init(): Promise<void> {\n if (this.isInitialized) return;\n\n this.encoder = this.createEncoder();\n\n this.isInitialized = true;\n }\n\n /**\n * 异步编码 PCM 为 Opus 帧\n * @param pcm S16LE PCM 数据 (Int16Array, 1600 samples = 100ms)\n * @returns 保留 packet 边界和时长的 Opus 帧数组\n */\n async encode(pcm: Int16Array): Promise<EncodedOpusFrame[]> {\n if (!this.isInitialized || !this.encoder) {\n return Promise.reject(new Error('WebCodecOpusEncoder 未初始化'));\n }\n if (this.pendingEncode) {\n return Promise.reject(new Error('WebCodecs Opus 编码器仍在处理上一音频块'));\n }\n\n // 构造 AudioData(S16 格式)\n // 复制为独立 ArrayBuffer,避免 SharedArrayBuffer 类型不兼容\n // 同时确保数据边界精确(Int16Array 可能是更大 buffer 的 view)\n const pcmCopy = new Int16Array(pcm);\n\n const startTimestampUs = this.timestamp;\n const blockDurationUs = Math.round((pcm.length * 1_000_000) / this.config.sampleRate);\n const endTimestampUs = startTimestampUs + blockDurationUs;\n const expectedFrameCount = blockDurationUs / OPUS_FRAME_DURATION_US;\n if (!Number.isInteger(expectedFrameCount)) {\n return Promise.reject(new Error('PCM 音频块无法按 20ms Opus packet 完整分包'));\n }\n\n const audioData = new AudioData({\n format: 's16',\n sampleRate: this.config.sampleRate,\n numberOfFrames: pcmCopy.length,\n numberOfChannels: this.config.channels,\n timestamp: startTimestampUs,\n data: pcmCopy,\n });\n\n const result = new Promise<EncodedOpusFrame[]>((resolve, reject) => {\n const timeoutId = globalThis.setTimeout(() => {\n this.failPending(new Error('WebCodecs Opus 编码输出超过 2 秒'));\n }, ENCODE_TIMEOUT_MS);\n this.pendingEncode = {\n startTimestampUs,\n endTimestampUs,\n expectedFrameCount,\n chunks: [],\n resolve,\n reject,\n timeoutId,\n };\n });\n\n try {\n this.encoder.encode(audioData);\n this.timestamp = endTimestampUs;\n } catch (cause) {\n this.failPending(cause instanceof Error ? cause : new Error('WebCodecs Opus 编码失败'));\n } finally {\n audioData.close();\n }\n\n return result;\n }\n\n /**\n * 重置时间戳(新 speak 段开始时调用)\n */\n reset(): void {\n this.timestamp = 0;\n this.failPending(new Error('WebCodecs Opus 编码已重置'));\n if (this.encoder) {\n try {\n this.encoder.close();\n } catch {}\n this.encoder = this.createEncoder();\n }\n }\n\n async destroy(): Promise<void> {\n const encoder = this.encoder;\n if (encoder) {\n try {\n await encoder.flush();\n } catch {}\n this.failPending(new Error('WebCodecs Opus 编码器已销毁'));\n try {\n encoder.close();\n } catch {}\n }\n this.encoder = null;\n this.isInitialized = false;\n }\n\n private createEncoder() {\n let encoder: AudioEncoder;\n encoder = new AudioEncoder({\n output: (chunk) => {\n if (this.encoder === encoder) {\n this.handleOutput(chunk);\n }\n },\n error: (cause) => {\n if (this.encoder !== encoder) return;\n const error = cause instanceof Error ? cause : new Error('WebCodecs Opus 编码失败');\n const logger = (globalThis as typeof globalThis & {\n avatarSDKLogger?: Pick<Console, 'error'>;\n }).avatarSDKLogger || console;\n logger.error('[WebCodecOpusEncoder] 编码错误:', error);\n this.failPending(error);\n },\n });\n encoder.configure(buildAudioEncoderConfig(this.config));\n return encoder;\n }\n\n private handleOutput(chunk: EncodedAudioChunk) {\n const pending = this.pendingEncode;\n if (!pending) {\n // flush() may emit one codec-delay/padding packet after all real PCM input.\n return;\n }\n if (\n chunk.timestamp < pending.startTimestampUs\n || chunk.timestamp >= pending.endTimestampUs\n || (chunk.duration !== null && chunk.duration !== OPUS_FRAME_DURATION_US)\n ) {\n this.failPending(new Error('WebCodecs Opus 未按 20ms 分包,无法生成固定 100ms AU 音频'));\n return;\n }\n\n pending.chunks.push(chunk);\n if (pending.chunks.length > pending.expectedFrameCount) {\n this.failPending(new Error('WebCodecs Opus 未按 20ms 分包,无法生成固定 100ms AU 音频'));\n return;\n }\n if (pending.chunks.length < pending.expectedFrameCount) {\n return;\n }\n\n const frames = pending.chunks.map((encodedChunk, index) => {\n const data = new Uint8Array(encodedChunk.byteLength);\n encodedChunk.copyTo(data);\n const nextTimestamp = pending.chunks[index + 1]?.timestamp ?? pending.endTimestampUs;\n const durationUs = encodedChunk.duration && encodedChunk.duration > 0\n ? encodedChunk.duration\n : Math.max(1, nextTimestamp - encodedChunk.timestamp);\n return { data, durationMs: durationUs / 1000 };\n });\n const totalDurationMs = frames.reduce((total, frame) => total + frame.durationMs, 0);\n if (\n frames.some((frame) => frame.durationMs !== OPUS_FRAME_DURATION_US / 1000)\n || totalDurationMs !== (pending.endTimestampUs - pending.startTimestampUs) / 1000\n ) {\n this.failPending(new Error('WebCodecs Opus 未按 20ms 分包,无法生成固定 100ms AU 音频'));\n return;\n }\n\n globalThis.clearTimeout(pending.timeoutId);\n this.pendingEncode = null;\n pending.resolve(frames);\n }\n\n private failPending(error: Error) {\n const pending = this.pendingEncode;\n if (!pending) return;\n globalThis.clearTimeout(pending.timeoutId);\n this.pendingEncode = null;\n pending.reject(error);\n }\n}\n","/**\n * WebM EBML 封装器\n * 将 Opus 帧封装为 WebM 容器格式,产出与 MSE 模式一致的 WebM/Opus 数据\n *\n * WebM 结构:\n * EBML Header → Segment → SegmentInfo → Tracks → Cluster(s) → SimpleBlock(s)\n */\n\n// EBML Element IDs\nconst EBML_ID = {\n EBML: 0x1A45DFA3,\n EBMLVersion: 0x4286,\n EBMLReadVersion: 0x42F7,\n EBMLMaxIDLength: 0x42F2,\n EBMLMaxSizeLength: 0x42F3,\n DocType: 0x4282,\n DocTypeVersion: 0x4287,\n DocTypeReadVersion: 0x4285,\n\n Segment: 0x18538067,\n SegmentInfo: 0x1549A966,\n TimecodeScale: 0x2AD7B1,\n MuxingApp: 0x4D80,\n WritingApp: 0x5741,\n\n Tracks: 0x1654AE6B,\n TrackEntry: 0xAE,\n TrackNumber: 0xD7,\n TrackUID: 0x73C5,\n TrackType: 0x83,\n FlagLacing: 0x9C,\n Language: 0x22B59C,\n CodecID: 0x86,\n CodecPrivate: 0x63A2,\n CodecDelay: 0x56AA,\n SeekPreRoll: 0x56BB,\n Audio: 0xE1,\n SamplingFrequency: 0xB5,\n Channels: 0x9F,\n\n Cluster: 0x1F43B675,\n Timecode: 0xE7,\n SimpleBlock: 0xA3,\n};\n\nexport class WebMMuxer {\n private chunks: Uint8Array[] = [];\n private hasHeader = false;\n private clusterTimestamp: number = 0; // 单位:毫秒\n private sampleRate: number;\n private frameDuration: number = 100; // 100ms per frame\n\n constructor(sampleRate: number = 16000) {\n this.sampleRate = sampleRate;\n }\n\n /**\n * 写入 WebM 文件头(EBML Header + Segment Info + Track)\n */\n writeHeader(): void {\n if (this.hasHeader) return;\n\n const header = this.buildEBMLHeader();\n const segmentInfo = this.buildSegmentInfo();\n const tracks = this.buildOpusTracks();\n\n // EBML Header\n this.chunks.push(header);\n // Segment (open-ended, use unknown size)\n this.chunks.push(new Uint8Array([0x18, 0x53, 0x80, 0x67, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]));\n // SegmentInfo\n this.chunks.push(segmentInfo);\n // Tracks\n this.chunks.push(tracks);\n\n this.hasHeader = true;\n this.clusterTimestamp = 0;\n }\n\n /**\n * 写入 Opus 帧\n * @param opusFrame Opus 编码后的数据\n * @param durationMs 帧时长 (默认 100ms)\n */\n feedOpusFrame(opusFrame: Uint8Array, durationMs: number = this.frameDuration): void {\n if (!this.hasHeader) {\n this.writeHeader();\n }\n\n // 每帧都创建一个新 Cluster(与 MediaRecorder 行为一致)\n const cluster = this.buildCluster(Math.round(this.clusterTimestamp), opusFrame);\n this.chunks.push(cluster);\n this.clusterTimestamp += durationMs;\n }\n\n /**\n * 获取新增的 WebM 数据(自上次 flush 以来的数据)\n * 返回后清空已返回的数据,避免重复发送\n */\n flush(): ArrayBuffer {\n if (this.chunks.length === 0) {\n return new ArrayBuffer(0);\n }\n \n const totalLength = this.chunks.reduce((sum, chunk) => sum + chunk.length, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of this.chunks) {\n result.set(chunk, offset);\n offset += chunk.length;\n }\n \n // 关键:清空已返回的数据,避免下次 flush 重复发送\n this.chunks = [];\n \n return result.buffer;\n }\n\n /**\n * 重置(新 speak 段开始时调用)\n */\n reset(): void {\n this.chunks = [];\n this.hasHeader = false;\n this.clusterTimestamp = 0;\n }\n\n // ── EBML 编码辅助方法 ──\n\n /**\n * 编码 VINT(Variable-length Integer)\n */\n private encodeVINT(value: number, width?: number): Uint8Array {\n if (width !== undefined) {\n const bytes = new Uint8Array(width);\n for (let i = width - 1; i >= 0; i--) {\n bytes[i] = value & 0xFF;\n value >>>= 8;\n }\n bytes[0] |= (1 << (8 - width));\n return bytes;\n }\n\n // 自动选择最小宽度\n if (value < 0x7F) {\n return new Uint8Array([0x80 | value]);\n } else if (value < 0x3FFF) {\n return new Uint8Array([0x40 | (value >> 8), value & 0xFF]);\n } else if (value < 0x1FFFFF) {\n return new Uint8Array([0x20 | (value >> 16), (value >> 8) & 0xFF, value & 0xFF]);\n } else if (value < 0x0FFFFFFF) {\n return new Uint8Array([0x10 | (value >> 24), (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF]);\n }\n throw new Error(`VINT value too large: ${value}`);\n }\n\n /**\n * 编码 EBML Element ID\n */\n private encodeID(id: number): Uint8Array {\n if (id <= 0xFF) return new Uint8Array([id]);\n if (id <= 0xFFFF) return new Uint8Array([id >> 8, id & 0xFF]);\n if (id <= 0xFFFFFF) return new Uint8Array([id >> 16, (id >> 8) & 0xFF, id & 0xFF]);\n return new Uint8Array([id >>> 24, (id >> 16) & 0xFF, (id >> 8) & 0xFF, id & 0xFF]);\n }\n\n /**\n * 编码无符号整数\n */\n private encodeUint(value: number): Uint8Array {\n if (value === 0) return new Uint8Array([0]);\n const bytes: number[] = [];\n let v = value;\n while (v > 0) {\n bytes.unshift(v & 0xFF);\n v = Math.floor(v / 256);\n }\n return new Uint8Array(bytes);\n }\n\n /**\n * 编码字符串\n */\n private encodeString(str: string): Uint8Array {\n return new TextEncoder().encode(str);\n }\n\n /**\n * 编码浮点数(32-bit IEEE 754)\n */\n private encodeFloat32(value: number): Uint8Array {\n const buf = new ArrayBuffer(4);\n new DataView(buf).setFloat32(0, value, false); // big-endian\n return new Uint8Array(buf);\n }\n\n /**\n * 编码 EBML Element = ID + Size + Data\n */\n private encodeElement(id: number, data: Uint8Array): Uint8Array {\n const idBytes = this.encodeID(id);\n const sizeBytes = this.encodeVINT(data.length);\n const result = new Uint8Array(idBytes.length + sizeBytes.length + data.length);\n result.set(idBytes, 0);\n result.set(sizeBytes, idBytes.length);\n result.set(data, idBytes.length + sizeBytes.length);\n return result;\n }\n\n /**\n * 编码 unsigned integer Element\n */\n private encodeUintElement(id: number, value: number): Uint8Array {\n return this.encodeElement(id, this.encodeUint(value));\n }\n\n /**\n * 编码 string Element\n */\n private encodeStringElement(id: number, value: string): Uint8Array {\n return this.encodeElement(id, this.encodeString(value));\n }\n\n /**\n * 编码 float32 Element\n */\n private encodeFloat32Element(id: number, value: number): Uint8Array {\n return this.encodeElement(id, this.encodeFloat32(value));\n }\n\n /**\n * 合并多个 Uint8Array\n */\n private concatArrays(arrays: Uint8Array[]): Uint8Array {\n const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const arr of arrays) {\n result.set(arr, offset);\n offset += arr.length;\n }\n return result;\n }\n\n /**\n * 构建 EBML Header\n */\n private buildEBMLHeader(): Uint8Array {\n const children = this.concatArrays([\n this.encodeUintElement(EBML_ID.EBMLVersion, 1),\n this.encodeUintElement(EBML_ID.EBMLReadVersion, 1),\n this.encodeUintElement(EBML_ID.EBMLMaxIDLength, 4),\n this.encodeUintElement(EBML_ID.EBMLMaxSizeLength, 8),\n this.encodeStringElement(EBML_ID.DocType, 'webm'),\n // Opus tracks use CodecDelay and SeekPreRoll, which require WebM v4.\n this.encodeUintElement(EBML_ID.DocTypeVersion, 4),\n this.encodeUintElement(EBML_ID.DocTypeReadVersion, 2),\n ]);\n return this.encodeElement(EBML_ID.EBML, children);\n }\n\n /**\n * 构建 SegmentInfo\n */\n private buildSegmentInfo(): Uint8Array {\n const children = this.concatArrays([\n this.encodeUintElement(EBML_ID.TimecodeScale, 1000000), // 1ms precision\n this.encodeStringElement(EBML_ID.MuxingApp, 'xmov-avatar-sdk'),\n this.encodeStringElement(EBML_ID.WritingApp, 'xmov-avatar-sdk'),\n ]);\n return this.encodeElement(EBML_ID.SegmentInfo, children);\n }\n\n /**\n * 构建 Opus Audio Track\n */\n private buildOpusTracks(): Uint8Array {\n // Opus CodecPrivate data (OpusHead)\n // Version(1) + Channels(1) + PreSkip(2) + InputSampleRate(4) + OutputGain(2) + ChannelMappingFamily(1)\n const opusHead = new Uint8Array([\n 0x4F, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, // \"OpusHead\"\n 0x01, // Version\n 0x01, // Channel count (mono)\n 0x00, 0x00, // Pre-skip (0)\n 0x80, 0x3E, 0x00, 0x00, // Input sample rate (16000, little-endian)\n 0x00, 0x00, // Output gain (0)\n 0x00, // Channel mapping family (0)\n ]);\n\n const audioChildren = this.concatArrays([\n this.encodeFloat32Element(EBML_ID.SamplingFrequency, this.sampleRate),\n this.encodeUintElement(EBML_ID.Channels, 1),\n ]);\n\n const trackEntryChildren = this.concatArrays([\n this.encodeUintElement(EBML_ID.TrackNumber, 1),\n this.encodeUintElement(EBML_ID.TrackUID, 1),\n this.encodeUintElement(EBML_ID.TrackType, 2), // Audio\n this.encodeUintElement(EBML_ID.FlagLacing, 0),\n this.encodeStringElement(EBML_ID.Language, 'und'),\n this.encodeStringElement(EBML_ID.CodecID, 'A_OPUS'),\n this.encodeElement(EBML_ID.CodecPrivate, opusHead),\n this.encodeUintElement(EBML_ID.CodecDelay, 0),\n this.encodeUintElement(EBML_ID.SeekPreRoll, 80000000), // 80ms in ns\n this.encodeElement(EBML_ID.Audio, audioChildren),\n ]);\n\n const trackEntry = this.encodeElement(EBML_ID.TrackEntry, trackEntryChildren);\n return this.encodeElement(EBML_ID.Tracks, trackEntry);\n }\n\n /**\n * 构建 Cluster + SimpleBlock\n */\n private buildCluster(timecodeMs: number, opusData: Uint8Array): Uint8Array {\n // Timecode element\n const timecode = this.encodeUintElement(EBML_ID.Timecode, timecodeMs);\n\n // SimpleBlock: TrackNumber(VINT) + Timecode(2 bytes, signed, relative to cluster) + Flags(1 byte) + Data\n const trackNumber = this.encodeVINT(1); // Track 1\n const relativeTimecode = new Uint8Array([0x00, 0x00]); // 0ms relative\n // WebCodecs Opus EncodedAudioChunk values are always key chunks.\n const flags = new Uint8Array([0x80]);\n\n const simpleBlockData = this.concatArrays([\n trackNumber,\n relativeTimecode,\n flags,\n opusData,\n ]);\n const simpleBlock = this.encodeElement(EBML_ID.SimpleBlock, simpleBlockData);\n\n // Cluster = Timecode + SimpleBlock\n const clusterChildren = this.concatArrays([timecode, simpleBlock]);\n return this.encodeElement(EBML_ID.Cluster, clusterChildren);\n }\n}\n","import { WebCodecOpusEncoder } from './webcodec-opus-encoder';\nimport { WebMMuxer } from './webm-muxer';\n\nexport class PcmWebMEncoder {\n private readonly opusEncoder = new WebCodecOpusEncoder({\n sampleRate: 16000,\n channels: 1,\n bitrate: 24000,\n frameSize: 1600,\n });\n private readonly muxer = new WebMMuxer(16000);\n private queue: Promise<void> = Promise.resolve();\n private generation = 0;\n private destroyed = false;\n private pendingBlocks = 0;\n\n static isSupported() {\n return WebCodecOpusEncoder.isSupported();\n }\n\n async init() {\n await this.opusEncoder.init();\n }\n\n async encode(pcm: Int16Array) {\n if (pcm.length !== 1600) {\n throw new Error(`PCM 音频块必须为 1600 samples,实际为 ${pcm.length}`);\n }\n if (this.pendingBlocks >= 20) {\n throw new Error(\"PCM/Opus 编码队列超过 2 秒\");\n }\n this.pendingBlocks += 1;\n const generation = this.generation;\n const pcmCopy = new Int16Array(pcm);\n const operation = this.queue.then(async () => {\n if (this.destroyed || generation !== this.generation) {\n return new ArrayBuffer(0);\n }\n const frames = await this.opusEncoder.encode(pcmCopy);\n if (this.destroyed || generation !== this.generation) {\n return new ArrayBuffer(0);\n }\n for (const frame of frames) {\n this.muxer.feedOpusFrame(frame.data, frame.durationMs);\n }\n return this.muxer.flush();\n });\n const trackedOperation = operation.finally(() => {\n this.pendingBlocks -= 1;\n });\n this.queue = trackedOperation.then(() => undefined, () => undefined);\n return trackedOperation;\n }\n\n reset() {\n const generation = ++this.generation;\n this.queue = this.queue.then(() => {\n if (!this.destroyed && generation === this.generation) {\n this.opusEncoder.reset();\n this.muxer.reset();\n }\n });\n }\n\n async destroy() {\n this.destroyed = true;\n this.generation += 1;\n await this.opusEncoder.destroy();\n await this.queue;\n this.muxer.reset();\n }\n}\n","import type { AgentAudioMetadata, AgentAudioOptions } from \"./types\";\nimport { FixedAudioTrack } from \"./fixed-audio-track\";\nimport { DEFAULT_AGENT_AUDIO } from \"./types\";\nimport { logAudioChunkContent } from \"./audio-debug\";\nimport {\n beginWebAudioCaptureSession,\n endWebAudioCaptureSession,\n} from \"../utils/audio-session\";\nimport { MediaRecorderTimestamp } from \"../utils/media-recorder-timestamp\";\nimport { PcmWebMEncoder } from \"../encoding/pcm-webm-encoder\";\n\nconst WEBM_OPUS_MIME_TYPE = \"audio/webm;codecs=opus\";\nconst TARGET_SAMPLE_RATE = 16_000;\nconst TARGET_CHANNELS = 1;\nconst PCM_BLOCK_MS = 100;\nconst PCM_CAPTURE_PROCESSOR = \"agent-pcm-capture-processor\";\nconst PCM_CAPTURE_WORKLET = `\nclass AgentPcmCaptureProcessor extends AudioWorkletProcessor {\n constructor() {\n super();\n this.buffer = new Float32Array(1600);\n this.bufferIndex = 0;\n this.sequence = 0;\n this.port.onmessage = (event) => {\n if (event.data?.type === 'flush') {\n this.emitBlock(true);\n this.port.postMessage({ type: 'flushed' });\n }\n };\n }\n\n emitBlock(padPartial = false) {\n if (this.bufferIndex === 0 || (!padPartial && this.bufferIndex < 1600)) return;\n const pcm = new Int16Array(1600);\n for (let index = 0; index < this.bufferIndex; index += 1) {\n const sample = Math.max(-1, Math.min(1, this.buffer[index]));\n pcm[index] = sample < 0 ? sample * 0x8000 : sample * 0x7fff;\n }\n this.port.postMessage(\n { type: 'frame', pcm: pcm.buffer, sequence: this.sequence++ },\n [pcm.buffer],\n );\n this.buffer.fill(0);\n this.bufferIndex = 0;\n }\n\n process(inputs, outputs) {\n for (const output of outputs) {\n for (const channel of output) channel.fill(0);\n }\n const channels = inputs[0];\n if (!channels?.length || !channels[0]?.length) return true;\n for (let frame = 0; frame < channels[0].length; frame += 1) {\n let sample = 0;\n for (let channel = 0; channel < channels.length; channel += 1) {\n sample += channels[channel][frame] || 0;\n }\n this.buffer[this.bufferIndex++] = sample / channels.length;\n if (this.bufferIndex === 1600) this.emitBlock();\n }\n return true;\n }\n}\nregisterProcessor('${PCM_CAPTURE_PROCESSOR}', AgentPcmCaptureProcessor);\n`;\ntype AgentCodedError = Error & {\n agentCode?: string;\n retryable?: boolean;\n};\n\nexport interface MicrophoneControllerOptions {\n audio?: AgentAudioOptions;\n debugAudioChunks?: boolean;\n /** Agent-owned input stream. When omitted, the controller requests the microphone. */\n inputStream?: MediaStream;\n /** Use deterministic 100ms PCM buckets with WebCodecs Opus encoding. */\n usePcmWebCodecs?: boolean;\n onMetadata?: (metadata: AgentAudioMetadata) => void;\n /** WebM/Opus Blob callback; timestamp is the media-block start time. */\n onFrame: (frame: Blob, timestamp?: number) => void;\n onError?: (error: Error) => void;\n}\n\nexport class MicrophoneController {\n private stream: MediaStream | null = null;\n private pendingInputStream: MediaStream | null;\n private recordingStream: MediaStream | null = null;\n private audioTransformer: FixedAudioTrack | null = null;\n private mediaRecorder: MediaRecorder | null = null;\n private pcmAudioContext: AudioContext | null = null;\n private pcmSource: MediaStreamAudioSourceNode | null = null;\n private pcmWorklet: AudioWorkletNode | null = null;\n private pcmEncoder: PcmWebMEncoder | null = null;\n private pcmEncodeQueue: Promise<void> = Promise.resolve();\n private pcmStartedAt = 0;\n private pcmGeneration = 0;\n private resolvePcmFlush: (() => void) | null = null;\n private startGeneration = 0;\n private starting = false;\n private hasAudioSessionCapture = false;\n private metadata: AgentAudioMetadata;\n private readonly options: MicrophoneControllerOptions;\n private readonly usesProvidedInput: boolean;\n\n constructor(options: MicrophoneControllerOptions) {\n this.options = options;\n this.pendingInputStream = options.inputStream ?? null;\n this.usesProvidedInput = Boolean(options.inputStream);\n this.metadata = {\n ...DEFAULT_AGENT_AUDIO,\n chunkMs: options.audio?.chunkMs || DEFAULT_AGENT_AUDIO.chunkMs,\n };\n }\n\n get isRecording() {\n return this.starting || Boolean(this.stream) || Boolean(this.pendingInputStream);\n }\n\n getAudioMetadata() {\n return this.metadata;\n }\n\n async start() {\n if (this.stream || this.starting) {\n return;\n }\n\n const startGeneration = ++this.startGeneration;\n this.starting = true;\n try {\n const inputStream = this.pendingInputStream;\n this.stream = inputStream ?? null;\n this.pendingInputStream = null;\n const mediaDevices = navigator.mediaDevices;\n if (!this.stream && !mediaDevices?.getUserMedia) {\n throw new Error(\"当前浏览器不支持麦克风采集\");\n }\n\n const MediaRecorderCtor = globalThis.MediaRecorder;\n if (this.options.usePcmWebCodecs) {\n if (!await PcmWebMEncoder.isSupported()) {\n throw this.webCodecsOpusUnsupported();\n }\n } else if (!MediaRecorderCtor?.isTypeSupported?.(WEBM_OPUS_MIME_TYPE)) {\n throw this.webMOpusUnsupported();\n }\n this.assertStartActive(startGeneration);\n\n // A playback-only session can prevent iOS WebKit from starting a\n // microphone track. Switch categories before requesting capture.\n if (!this.stream) {\n if (this.usesProvidedInput) {\n throw inputStream ? this.cancelled() : new Error(\"ASR 输入流已释放\");\n }\n this.hasAudioSessionCapture = beginWebAudioCaptureSession();\n this.stream = await mediaDevices.getUserMedia({\n audio: {\n sampleRate: { ideal: TARGET_SAMPLE_RATE },\n channelCount: { ideal: TARGET_CHANNELS },\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n },\n });\n }\n this.assertStartActive(startGeneration);\n const inputTrack = this.stream.getAudioTracks()[0];\n if (!inputTrack) {\n throw new Error(\"麦克风未返回音频轨道\");\n }\n if (this.options.usePcmWebCodecs) {\n await this.startPcmWebMRecorder(this.stream);\n this.assertStartActive(startGeneration);\n this.metadata = {\n ...this.metadata,\n sampleRate: TARGET_SAMPLE_RATE,\n channels: TARGET_CHANNELS,\n chunkMs: PCM_BLOCK_MS,\n };\n this.options.onMetadata?.(this.metadata);\n return;\n }\n const audioTransformer = new FixedAudioTrack({\n onError: (error) => {\n const normalized = error instanceof Error ? error : new Error(\"16 kHz mono 音频处理失败\");\n normalized.name = \"MediaRecorderError\";\n this.options.onError?.(normalized);\n },\n });\n this.audioTransformer = audioTransformer;\n this.recordingStream = await audioTransformer.start(inputTrack);\n this.assertStartActive(startGeneration);\n const outputTrack = this.recordingStream.getAudioTracks()[0];\n const outputSettings = outputTrack?.getSettings() as\n | (MediaTrackSettings & { sampleRate?: number; channelCount?: number })\n | undefined;\n this.metadata = {\n ...this.metadata,\n sampleRate: outputSettings?.sampleRate || TARGET_SAMPLE_RATE,\n channels: outputSettings?.channelCount || TARGET_CHANNELS,\n };\n this.startWebMRecorder(MediaRecorderCtor);\n this.options.onMetadata?.(this.metadata);\n } catch (error) {\n const startCancelled = startGeneration !== this.startGeneration;\n await this.stop();\n const normalized: AgentCodedError = startCancelled\n ? this.cancelled()\n : error instanceof Error\n ? error\n : new Error(\"麦克风启动失败\");\n if (normalized.agentCode !== \"AUDIO_FIXED_TRACK_CANCELLED\") {\n this.options.onError?.(normalized);\n }\n throw normalized;\n } finally {\n if (this.startGeneration === startGeneration) {\n this.starting = false;\n }\n }\n }\n\n async stop() {\n this.startGeneration += 1;\n this.starting = false;\n try {\n const audioTransformer = this.audioTransformer;\n try {\n // Drain the processor first, but keep the generator track live so the\n // recorder can capture the flushed tail before it is explicitly stopped.\n await audioTransformer?.drain();\n } finally {\n await this.stopPcmWebMRecorder();\n await this.stopMediaRecorder();\n await audioTransformer?.stop();\n this.audioTransformer = null;\n }\n this.recordingStream = null;\n\n if (this.stream && !audioTransformer) {\n this.stream.getTracks().forEach((track) => track.stop());\n }\n this.stream = null;\n this.pendingInputStream?.getTracks().forEach((track) => track.stop());\n this.pendingInputStream = null;\n } finally {\n if (this.hasAudioSessionCapture) {\n this.hasAudioSessionCapture = false;\n endWebAudioCaptureSession();\n }\n }\n }\n\n private startWebMRecorder(MediaRecorderCtor: typeof MediaRecorder) {\n if (!this.recordingStream) {\n throw new Error(\"16 kHz mono 音频流未就绪\");\n }\n\n let recorder: MediaRecorder;\n try {\n recorder = new MediaRecorderCtor(this.recordingStream, {\n mimeType: WEBM_OPUS_MIME_TYPE,\n audioBitsPerSecond: 24000,\n });\n } catch (error) {\n if (error instanceof Error && error.name === \"NotSupportedError\") {\n throw this.webMOpusUnsupported(error);\n }\n throw error;\n }\n const recorderTimestamp = new MediaRecorderTimestamp(this.metadata.chunkMs);\n recorder.ondataavailable = (event) => {\n if (event.data.size > 0) {\n const timestamp = recorderTimestamp.resolve(event.timecode);\n (globalThis as typeof globalThis & { avatarSDKLogger?: { log?: (...args: unknown[]) => void } })\n .avatarSDKLogger?.log?.(\"[Agent][Microphone]\", \"audio chunk\", {\n size: event.data.size,\n type: event.data.type,\n chunkMs: this.metadata.chunkMs,\n sampleRate: this.metadata.sampleRate,\n channels: this.metadata.channels,\n recorderState: recorder.state,\n timecode: event.timecode,\n });\n if (this.options.debugAudioChunks) {\n void logAudioChunkContent(\"[Agent][Microphone] nearend WebM/Opus chunk\", event.data, {\n chunkMs: this.metadata.chunkMs,\n sampleRate: this.metadata.sampleRate,\n channels: this.metadata.channels,\n recorderState: recorder.state,\n timecode: event.timecode,\n });\n }\n this.options.onFrame(event.data, timestamp);\n }\n };\n recorder.onerror = (event) => {\n const error = (event as ErrorEvent).error;\n const recorderError = new Error(error instanceof Error ? error.message : \"WebM/Opus 麦克风录制失败\");\n recorderError.name = \"MediaRecorderError\";\n this.options.onError?.(recorderError);\n };\n this.mediaRecorder = recorder;\n try {\n recorder.start(this.metadata.chunkMs);\n } catch (error) {\n if (error instanceof Error && error.name === \"NotSupportedError\") {\n throw this.webMOpusUnsupported(error);\n }\n throw error;\n }\n }\n\n private assertStartActive(startGeneration: number) {\n if (startGeneration !== this.startGeneration) {\n throw this.cancelled();\n }\n }\n\n private cancelled() {\n const error = new Error(\"麦克风启动已取消\") as AgentCodedError;\n error.name = \"AbortError\";\n error.agentCode = \"AUDIO_FIXED_TRACK_CANCELLED\";\n error.retryable = true;\n return error;\n }\n\n private webMOpusUnsupported(cause?: unknown) {\n const error = new Error(\"当前浏览器不支持 audio/webm;codecs=opus\") as AgentCodedError & {\n cause?: unknown;\n };\n error.name = \"NotSupportedError\";\n error.agentCode = \"AUDIO_WEBM_OPUS_UNSUPPORTED\";\n error.retryable = false;\n error.cause = cause;\n return error;\n }\n\n private webCodecsOpusUnsupported(cause?: unknown) {\n const error = new Error(\"当前浏览器不支持 WebCodecs AudioEncoder Opus\") as AgentCodedError & {\n cause?: unknown;\n };\n error.name = \"NotSupportedError\";\n error.agentCode = \"AUDIO_WEBCODECS_OPUS_UNSUPPORTED\";\n error.retryable = false;\n error.cause = cause;\n return error;\n }\n\n private async startPcmWebMRecorder(stream: MediaStream) {\n const globals = globalThis as typeof globalThis & {\n webkitAudioContext?: typeof AudioContext;\n };\n const AudioContextCtor = globalThis.AudioContext || globals.webkitAudioContext;\n if (!AudioContextCtor || typeof globalThis.AudioWorkletNode === \"undefined\") {\n throw this.webCodecsOpusUnsupported(new Error(\"AudioWorklet 不可用\"));\n }\n\n const encoder = new PcmWebMEncoder();\n await encoder.init();\n const context = new AudioContextCtor({ sampleRate: TARGET_SAMPLE_RATE });\n if (context.sampleRate !== TARGET_SAMPLE_RATE) {\n await encoder.destroy();\n await context.close().catch(() => undefined);\n throw this.webCodecsOpusUnsupported(\n new Error(`浏览器无法创建 ${TARGET_SAMPLE_RATE} Hz AudioContext`),\n );\n }\n this.pcmAudioContext = context;\n this.pcmEncoder = encoder;\n\n const workletUrl = URL.createObjectURL(\n new Blob([PCM_CAPTURE_WORKLET], { type: \"application/javascript\" }),\n );\n try {\n await context.audioWorklet.addModule(workletUrl);\n } finally {\n URL.revokeObjectURL(workletUrl);\n }\n if (context.state === \"suspended\") {\n await context.resume();\n }\n if (context.state !== \"running\") {\n throw this.audioContextSuspended();\n }\n\n const source = context.createMediaStreamSource(stream);\n const worklet = new AudioWorkletNode(context, PCM_CAPTURE_PROCESSOR, {\n numberOfInputs: 1,\n numberOfOutputs: 1,\n outputChannelCount: [1],\n });\n const generation = ++this.pcmGeneration;\n this.pcmSource = source;\n this.pcmWorklet = worklet;\n this.pcmEncodeQueue = Promise.resolve();\n this.pcmStartedAt = this.monotonicEpochNow();\n\n worklet.port.onmessage = (event) => {\n if (event.data?.type === \"flushed\") {\n this.resolvePcmFlush?.();\n this.resolvePcmFlush = null;\n return;\n }\n if (event.data?.type !== \"frame\" || !(event.data.pcm instanceof ArrayBuffer)) {\n return;\n }\n const timestamp = this.pcmStartedAt + Number(event.data.sequence || 0) * PCM_BLOCK_MS;\n const pcm = new Int16Array(event.data.pcm);\n this.pcmEncodeQueue = this.pcmEncodeQueue\n .then(async () => {\n const webm = await encoder.encode(pcm);\n if (generation !== this.pcmGeneration || webm.byteLength === 0) {\n return;\n }\n const frame = new Blob([webm], { type: WEBM_OPUS_MIME_TYPE });\n if (this.options.debugAudioChunks) {\n void logAudioChunkContent(\"[Agent][Microphone] nearend PCM/WebCodecs chunk\", frame, {\n chunkMs: PCM_BLOCK_MS,\n sampleRate: TARGET_SAMPLE_RATE,\n channels: TARGET_CHANNELS,\n sequence: event.data.sequence,\n });\n }\n this.options.onFrame(frame, timestamp);\n })\n .catch((cause) => {\n const error = cause instanceof Error ? cause : new Error(\"PCM/Opus 麦克风编码失败\");\n error.name = \"AudioEncoderError\";\n this.options.onError?.(error);\n });\n };\n source.connect(worklet);\n worklet.connect(context.destination);\n }\n\n private async stopPcmWebMRecorder() {\n const worklet = this.pcmWorklet;\n const source = this.pcmSource;\n const context = this.pcmAudioContext;\n const encoder = this.pcmEncoder;\n if (!worklet && !context && !encoder) {\n return;\n }\n\n source?.disconnect();\n let flushCompleted = true;\n if (worklet) {\n flushCompleted = await Promise.race([\n new Promise<boolean>((resolve) => {\n this.resolvePcmFlush = () => resolve(true);\n worklet.port.postMessage({ type: \"flush\" });\n }),\n new Promise<boolean>((resolve) => globalThis.setTimeout(() => resolve(false), 100)),\n ]);\n if (!flushCompleted) {\n this.resolvePcmFlush = null;\n worklet.port.onmessage = null;\n }\n }\n await this.pcmEncodeQueue;\n this.pcmGeneration += 1;\n this.resolvePcmFlush = null;\n if (worklet) {\n worklet.port.onmessage = null;\n worklet.disconnect();\n worklet.port.close();\n }\n if (context && context.state !== \"closed\") {\n await context.close().catch(() => undefined);\n }\n await encoder?.destroy();\n this.pcmWorklet = null;\n this.pcmSource = null;\n this.pcmAudioContext = null;\n this.pcmEncoder = null;\n this.pcmEncodeQueue = Promise.resolve();\n }\n\n private monotonicEpochNow() {\n const clock = globalThis.performance;\n if (clock && Number.isFinite(clock.timeOrigin)) {\n return Math.round(clock.timeOrigin + clock.now());\n }\n return Date.now();\n }\n\n private audioContextSuspended() {\n const error = new Error(\"AudioContext 未运行,请在用户操作后重试\") as AgentCodedError;\n error.name = \"NotAllowedError\";\n error.agentCode = \"AUDIO_CONTEXT_SUSPENDED\";\n error.retryable = true;\n return error;\n }\n\n private async stopMediaRecorder() {\n const recorder = this.mediaRecorder;\n this.mediaRecorder = null;\n if (!recorder) {\n return;\n }\n\n const shouldStop = recorder.state !== \"inactive\";\n await new Promise<void>((resolve) => {\n let settled = false;\n const finish = () => {\n if (settled) {\n return;\n }\n settled = true;\n globalThis.clearTimeout(timeoutId);\n resolve();\n };\n const onError = recorder.onerror;\n const timeoutId = globalThis.setTimeout(finish, 1000);\n recorder.onstop = finish;\n recorder.onerror = (event) => {\n onError?.call(recorder, event);\n finish();\n };\n if (shouldStop) {\n try {\n recorder.stop();\n } catch {\n finish();\n }\n }\n });\n recorder.ondataavailable = null;\n recorder.onerror = null;\n recorder.onstop = null;\n }\n\n}\n","const AU_HEADER_BYTES = 8;\nconst AU_VERSION = 1;\nconst AUDIO_BLOCK_MS = 100;\nconst MAX_FAREND_BUCKET_SKEW = 1;\nconst MAX_PENDING_FAREND_BUCKETS = 3;\nconst NEAREND_GRACE_BUCKETS = 1;\nconst WEBM_EBML_MAGIC = new Uint8Array([0x1a, 0x45, 0xdf, 0xa3]);\n\nexport const AU_STREAM_NEAREND = 1 as const;\nexport const AU_STREAM_FAREND = 2 as const;\n\nexport type AuStreamId = typeof AU_STREAM_NEAREND | typeof AU_STREAM_FAREND;\nexport type AuPayload = Blob | ArrayBuffer | ArrayBufferView;\n\nexport interface AgentAudioBlock {\n data: AuPayload;\n /** Epoch timestamp for the beginning of this 100 ms media block. */\n timestamp: number;\n /** Whether this block starts a new WebM container stream. */\n isFirstChunk?: boolean;\n}\n\ninterface PendingAudioBlock extends AgentAudioBlock {\n streamId: AuStreamId;\n tsMs: number;\n frameKey: number;\n dataParts?: AuPayload[];\n}\n\ninterface AgentAudioUplinkOptions {\n sendBinary(frame: ArrayBuffer): void;\n onError?(error: Error): void;\n}\n\nfunction logAudioUplink(event: string, details: Record<string, unknown>) {\n const logger = (globalThis as typeof globalThis & {\n avatarSDKLogger?: { log?: (...args: unknown[]) => void };\n }).avatarSDKLogger;\n logger?.log?.(\"[Agent][AudioUplink]\", event, details);\n}\n\nexport function packAuAudioFrame(\n streamId: AuStreamId,\n tsMs: number,\n payload: ArrayBuffer | ArrayBufferView,\n): ArrayBuffer {\n if (streamId !== AU_STREAM_NEAREND && streamId !== AU_STREAM_FAREND) {\n throw new Error(`AU stream_id 无效: ${streamId}`);\n }\n if (!Number.isFinite(tsMs) || tsMs < 0 || tsMs > 0xffffffff) {\n throw new Error(`AU ts_ms 无效: ${tsMs}`);\n }\n\n const body = payload instanceof ArrayBuffer\n ? new Uint8Array(payload)\n : new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength);\n const frame = new ArrayBuffer(AU_HEADER_BYTES + body.byteLength);\n const view = new DataView(frame);\n view.setUint8(0, 0x41);\n view.setUint8(1, 0x55);\n view.setUint8(2, AU_VERSION);\n view.setUint8(3, streamId);\n view.setUint32(4, Math.floor(tsMs), false);\n new Uint8Array(frame, AU_HEADER_BYTES).set(body);\n return frame;\n}\n\nasync function toPayloadBytes(payload: AuPayload | AuPayload[]): Promise<Uint8Array> {\n if (Array.isArray(payload)) {\n const chunks = await Promise.all(payload.map(toPayloadBytes));\n const merged = new Uint8Array(chunks.reduce((size, chunk) => size + chunk.byteLength, 0));\n let offset = 0;\n for (const chunk of chunks) {\n merged.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return merged;\n }\n if (payload instanceof Blob) {\n return new Uint8Array(await payload.arrayBuffer());\n }\n if (payload instanceof ArrayBuffer) {\n return new Uint8Array(payload);\n }\n return new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength);\n}\n\n/**\n * Owns the connection-level AU timeline and serializes nearend/farend writes.\n * Nearend/farend are matched by 100 ms bucket. When independent capture clocks\n * straddle a bucket boundary, an aged nearend may consume farend from\n * the immediately preceding bucket. This keeps farend-before-nearend wire\n * order without uploading farend-only buckets or dropping WebM continuations.\n */\nexport class AgentAudioUplink {\n private readonly options: AgentAudioUplinkOptions;\n private connectionStartedAt: number | null = null;\n private connectionGeneration = 0;\n private sendChain: Promise<void> = Promise.resolve();\n private failed = false;\n private readonly pendingFarend = new Map<number, PendingAudioBlock[]>();\n private readonly pendingNearend = new Map<number, PendingAudioBlock[]>();\n private readonly closedNearendBuckets = new Set<number>();\n private readonly lastTimestampByStream = new Map<AuStreamId, number>();\n private readonly lastSentTimestampByStream = new Map<AuStreamId, number>();\n private readonly pendingWebmPrefixByStream = new Map<AuStreamId, Uint8Array>();\n private farendStreamState: \"unknown\" | \"ready\" | \"awaiting-header\" = \"unknown\";\n\n constructor(options: AgentAudioUplinkOptions) {\n this.options = options;\n }\n\n reset(connectionStartedAt: number | null = null) {\n this.connectionGeneration += 1;\n this.connectionStartedAt = connectionStartedAt;\n this.pendingFarend.clear();\n this.pendingNearend.clear();\n this.closedNearendBuckets.clear();\n this.lastTimestampByStream.clear();\n this.lastSentTimestampByStream.clear();\n this.pendingWebmPrefixByStream.clear();\n this.farendStreamState = \"unknown\";\n this.failed = false;\n this.sendChain = Promise.resolve();\n }\n\n startInput() {\n this.failed = false;\n this.pendingFarend.clear();\n this.pendingNearend.clear();\n this.closedNearendBuckets.clear();\n this.pendingWebmPrefixByStream.clear();\n this.farendStreamState = \"unknown\";\n }\n\n clearFarend() {\n this.pendingFarend.clear();\n this.pendingWebmPrefixByStream.delete(AU_STREAM_FAREND);\n this.farendStreamState = \"unknown\";\n }\n\n offerFarend(block: AgentAudioBlock) {\n if (block.isFirstChunk === false && this.farendStreamState !== \"ready\") {\n logAudioUplink(\"farend.drop\", {\n reason: \"awaiting_webm_header\",\n timestamp: block.timestamp,\n isFirstChunk: false,\n });\n return;\n }\n\n const normalized = this.normalizeBlock(AU_STREAM_FAREND, block);\n if (!normalized) {\n if (block.isFirstChunk) {\n this.abandonFarendStream();\n }\n return;\n }\n\n if (block.isFirstChunk) {\n this.pendingFarend.clear();\n this.pendingWebmPrefixByStream.delete(AU_STREAM_FAREND);\n this.farendStreamState = \"ready\";\n }\n\n const bucket = this.pendingFarend.get(normalized.frameKey) ?? [];\n bucket.push(normalized);\n this.pendingFarend.set(normalized.frameKey, bucket);\n logAudioUplink(\"farend.offer\", {\n tsMs: normalized.tsMs,\n frameKey: normalized.frameKey,\n isFirstChunk: Boolean(normalized.isFirstChunk),\n pendingNearend: [...this.pendingNearend.keys()],\n });\n this.flushOlderNearend(normalized.frameKey);\n this.prune(normalized.frameKey);\n }\n\n offerNearend(block: AgentAudioBlock) {\n const nearend = this.normalizeBlock(AU_STREAM_NEAREND, block);\n if (!nearend || this.closedNearendBuckets.has(nearend.frameKey)) {\n return;\n }\n\n const bucket = this.pendingNearend.get(nearend.frameKey) ?? [];\n bucket.push(nearend);\n this.pendingNearend.set(nearend.frameKey, bucket);\n this.flushExpiredNearend(nearend.frameKey);\n this.prune(nearend.frameKey);\n }\n\n drain() {\n for (const frameKey of [...this.pendingNearend.keys()].sort((a, b) => a - b)) {\n this.flushBucket(frameKey, true);\n }\n return this.sendChain;\n }\n\n private normalizeBlock(streamId: AuStreamId, block: AgentAudioBlock): PendingAudioBlock | null {\n const connectionStartedAt = this.connectionStartedAt;\n if (connectionStartedAt === null || !Number.isFinite(block.timestamp)) {\n return null;\n }\n\n const relativeTimestamp = Math.max(0, Math.floor(block.timestamp - connectionStartedAt));\n const frameKey = Math.floor(relativeTimestamp / AUDIO_BLOCK_MS);\n const lastTimestamp = this.lastTimestampByStream.get(streamId);\n if (lastTimestamp !== undefined && relativeTimestamp <= lastTimestamp) {\n return null;\n }\n this.lastTimestampByStream.set(streamId, relativeTimestamp);\n return { ...block, streamId, tsMs: relativeTimestamp, frameKey };\n }\n\n private enqueue(blocks: PendingAudioBlock[]) {\n if (this.failed) {\n return;\n }\n const generation = this.connectionGeneration;\n this.sendChain = this.sendChain\n .then(async () => {\n if (this.failed) {\n return;\n }\n for (const block of blocks) {\n const bytes = await toPayloadBytes(block.dataParts ?? block.data);\n if (\n this.failed\n || generation !== this.connectionGeneration\n || this.connectionStartedAt === null\n || bytes.byteLength === 0\n ) {\n continue;\n }\n if (block.streamId === AU_STREAM_FAREND && block.isFirstChunk) {\n this.pendingWebmPrefixByStream.delete(AU_STREAM_FAREND);\n }\n const payload = this.coalesceSplitWebmMagic(block.streamId, bytes);\n if (!payload) {\n continue;\n }\n const lastSentTimestamp = this.lastSentTimestampByStream.get(block.streamId);\n if (lastSentTimestamp !== undefined && block.tsMs <= lastSentTimestamp) {\n continue;\n }\n this.options.sendBinary(packAuAudioFrame(block.streamId, block.tsMs, payload));\n this.lastSentTimestampByStream.set(block.streamId, block.tsMs);\n logAudioUplink(\"frame.send\", {\n streamId: block.streamId,\n tsMs: block.tsMs,\n bytes: payload.byteLength,\n });\n }\n })\n .catch((error) => {\n if (generation !== this.connectionGeneration) {\n return;\n }\n this.failed = true;\n this.pendingFarend.clear();\n this.pendingNearend.clear();\n const normalized = error instanceof Error ? error : new Error(\"AU 音频上行失败\");\n this.options.onError?.(normalized);\n });\n }\n\n /**\n * Chromium may emit the first WebM byte (0x1a) as its own MediaRecorder\n * Blob and put the remaining EBML magic in the next Blob. A one-byte AU\n * payload is not a valid timed audio block, so keep an incomplete WebM\n * magic prefix and prepend it to the next block from the same stream.\n */\n private coalesceSplitWebmMagic(streamId: AuStreamId, payload: Uint8Array) {\n const pendingPrefix = this.pendingWebmPrefixByStream.get(streamId);\n if (pendingPrefix) {\n const merged = new Uint8Array(pendingPrefix.byteLength + payload.byteLength);\n merged.set(pendingPrefix);\n merged.set(payload, pendingPrefix.byteLength);\n this.pendingWebmPrefixByStream.delete(streamId);\n payload = merged;\n }\n\n if (\n payload.byteLength < WEBM_EBML_MAGIC.byteLength\n && payload.every((byte, index) => byte === WEBM_EBML_MAGIC[index])\n ) {\n this.pendingWebmPrefixByStream.set(streamId, payload.slice());\n return null;\n }\n\n return payload;\n }\n\n private flushOlderNearend(currentFrameKey: number) {\n for (const frameKey of [...this.pendingNearend.keys()].sort((a, b) => a - b)) {\n if (frameKey >= currentFrameKey) {\n break;\n }\n this.flushBucket(frameKey, true);\n }\n }\n\n private flushExpiredNearend(currentFrameKey: number) {\n this.flushOlderNearend(currentFrameKey - NEAREND_GRACE_BUCKETS);\n }\n\n private flushBucket(frameKey: number, allowPreviousFarend = false) {\n const nearend = this.takeNearend(frameKey);\n if (!nearend) {\n return;\n }\n const previousFarendKey = frameKey - MAX_FAREND_BUCKET_SKEW;\n const hasMatchingFarend = this.pendingFarend.has(frameKey)\n || (allowPreviousFarend && this.pendingFarend.has(previousFarendKey));\n const farend = hasMatchingFarend\n ? this.takeFarendThrough(frameKey)\n : null;\n this.closedNearendBuckets.add(frameKey);\n logAudioUplink(\"bucket.flush\", {\n nearendFrameKey: frameKey,\n pairedFarend: Boolean(farend),\n pendingFarend: [...this.pendingFarend.keys()],\n });\n this.enqueue(farend ? [farend, nearend] : [nearend]);\n }\n\n private takeNearend(frameKey: number): PendingAudioBlock | null {\n const blocks = this.pendingNearend.get(frameKey);\n this.pendingNearend.delete(frameKey);\n if (!blocks?.length) {\n return null;\n }\n\n const first = blocks[0];\n return {\n ...first,\n dataParts: blocks.flatMap((block) => block.dataParts ?? [block.data]),\n };\n }\n\n private takeFarendThrough(frameKey: number): PendingAudioBlock | null {\n const blocks: PendingAudioBlock[] = [];\n for (const key of [...this.pendingFarend.keys()].sort((a, b) => a - b)) {\n if (key > frameKey) {\n break;\n }\n blocks.push(...this.pendingFarend.get(key)!);\n this.pendingFarend.delete(key);\n }\n if (blocks.length === 0) {\n return null;\n }\n\n const latest = blocks[blocks.length - 1];\n return {\n ...latest,\n dataParts: blocks.map((block) => block.data),\n isFirstChunk: blocks.some((block) => block.isFirstChunk),\n };\n }\n\n private abandonFarendStream() {\n logAudioUplink(\"farend.drop\", {\n reason: \"stale_bucket_abandons_webm_stream\",\n pendingFarend: [...this.pendingFarend.keys()],\n });\n this.pendingFarend.clear();\n this.pendingWebmPrefixByStream.delete(AU_STREAM_FAREND);\n this.farendStreamState = \"awaiting-header\";\n }\n\n private prune(currentFrameKey: number) {\n const oldestAllowed = currentFrameKey - MAX_PENDING_FAREND_BUCKETS;\n if ([...this.pendingFarend.keys()].some((frameKey) => frameKey < oldestAllowed)) {\n // Dropping an arbitrary WebM fragment would corrupt every continuation\n // after it. Abandon this container and wait for the next explicit header.\n this.abandonFarendStream();\n }\n for (const frameKey of this.pendingNearend.keys()) {\n if (frameKey < oldestAllowed) {\n this.flushBucket(frameKey, true);\n }\n }\n for (const frameKey of this.closedNearendBuckets) {\n if (frameKey < oldestAllowed) {\n this.closedNearendBuckets.delete(frameKey);\n }\n }\n }\n}\n\nexport const AU_AUDIO_BLOCK_MS = AUDIO_BLOCK_MS;\n","import XmovAvatar from \"../index\";\nimport type { ISessionResponse } from \"../modules/ResourceManager\";\nimport type { IAudioPlaybackData, IAvatarOptions, IInitParams } from \"../types\";\nimport { AgentE2EClient } from \"./e2e-client\";\nimport { MicrophoneController } from \"./microphone\";\nimport { logAudioChunkContent } from \"./audio-debug\";\nimport { AgentAudioUplink } from \"./audio-uplink\";\nimport type { AgentAudioBlock } from \"./audio-uplink\";\nimport { DEFAULT_AGENT_AUDIO } from \"./types\";\nimport type {\n AgentASRResult,\n AgentASRStartOptions,\n AgentASRState,\n AgentClientMessage,\n AgentConversationEvent,\n AgentError,\n AgentErrorDomain,\n AgentLLMResponse,\n AgentReconnectOptions,\n AgentSemanticJudgeResult,\n AgentServerEvent,\n AgentSessionInfo,\n AgentState,\n XingyunAvatarAgentCallbacks,\n XingyunAvatarAgentInitParams,\n XingyunAvatarAgentOptions,\n} from \"./types\";\n\ninterface AgentRuntimeOptions {\n e2eServer?: string;\n authToken?: string;\n audio?: XingyunAvatarAgentOptions[\"audio\"];\n requestedEnableAec?: boolean;\n callbacks?: XingyunAvatarAgentCallbacks;\n webSocketCtor?: typeof WebSocket;\n debugAudioChunks?: boolean;\n}\n\ntype AgentParentOptions = IAvatarOptions & {\n sessionRequestData: Record<string, unknown>;\n};\n\ninterface InitialSessionAttempt {\n sessionInfo: ISessionResponse;\n e2ePromise: Promise<void>;\n ttsaReadyPromise: Promise<void>;\n resolveTtsaReady: () => void;\n}\n\nfunction hasSerializableConfig(config: Record<string, unknown> | undefined) {\n if (config === undefined) {\n return false;\n }\n const serializedConfig = JSON.stringify(config);\n return serializedConfig !== undefined && serializedConfig !== \"{}\";\n}\n\nconst CLOSE_CODE_MESSAGES: Record<number, string> = {\n 1006: \"E2E WebSocket 异常断开:未收到 Close frame,请检查 E2EMPServer 日志或中间网络\",\n 4000: \"E2E WebSocket 路径未知\",\n 4001: \"E2E Token 无效\",\n 4002: \"E2E Session 不存在\",\n 4009: \"E2E 配额超限\",\n 4010: \"E2E 服务端主动断开\",\n};\n\nconst RETRYABLE_CLOSE_CODES = new Set([1001, 1006, 1011, 1012, 1013, 1014]);\nconst DEFAULT_RECONNECT_OPTIONS: Required<AgentReconnectOptions> = {\n enabled: true,\n maxAttempts: 6,\n initialDelayMs: 500,\n maxDelayMs: 8000,\n};\n\nfunction validateAgentConfigSource(\n label: \"ASR\" | \"TTS\" | \"Brain\",\n id: number | undefined,\n config: Record<string, unknown> | undefined,\n) {\n if (config !== undefined && (!config || Array.isArray(config) || typeof config !== \"object\")) {\n throw new Error(`Agent ${label} JSON Config 必须是对象`);\n }\n if (id !== undefined && hasSerializableConfig(config)) {\n throw new Error(`Agent ${label} 配置不能同时提供 ID 和 JSON Config`);\n }\n}\n\nfunction normalizeBrainConfig(config: XingyunAvatarAgentOptions[\"brain_config\"]) {\n if (!config || !hasSerializableConfig(config)) {\n return undefined;\n }\n const extraBody = config.extra_body;\n if (extraBody !== undefined && (!extraBody || Array.isArray(extraBody) || typeof extraBody !== \"object\")) {\n throw new Error(\"Agent Brain extra_body 必须是 JSON 对象\");\n }\n return {\n ...config,\n };\n}\n\nfunction validateAgentObjectConfig(\n label: \"features\" | \"extras\",\n config: Record<string, unknown> | undefined,\n) {\n if (config !== undefined && (!config || Array.isArray(config) || typeof config !== \"object\")) {\n throw new Error(`Agent ${label} 必须是对象`);\n }\n}\n\nexport default class XingyunAvatarAgent extends XmovAvatar {\n private e2eClient: AgentE2EClient | null = null;\n private microphone: MicrophoneController | null = null;\n private stopASRPromise: Promise<void> | null = null;\n private initializationPromise: Promise<ISessionResponse | null | undefined> | null = null;\n private rejectInitialization: ((error: Error) => void) | null = null;\n private initialSessionAttempt: InitialSessionAttempt | null = null;\n private initialSessionGeneration = 0;\n private readonly initialTtsaReadySessionIds = new Set<string>();\n private initialTtsaReadyBeforeSession = false;\n private asrStartGeneration = 0;\n private agentState: AgentState = \"idle\";\n private asrState: AgentASRState = \"idle\";\n private agentDestroyed = false;\n private agentDestroying = false;\n private suppressNextVoiceEnd = false;\n private audioInputEnabled: boolean;\n private farendAudioEnabled = false;\n private readonly audioUplink: AgentAudioUplink;\n private originalOnAudioPlaybackData?: IAvatarOptions[\"onAudioPlaybackData\"];\n private playbackDataHandler?: IAvatarOptions[\"onAudioPlaybackData\"];\n private readonly agentOptions: AgentRuntimeOptions;\n private readonly reconnectOptions: Required<AgentReconnectOptions>;\n private reconnectTimer: number | null = null;\n private reconnectAttempt = 0;\n private reconnectInFlight = false;\n private sessionReloadFallback = false;\n private waitingForTtsaReload = false;\n private stateBeforeReconnect: AgentState = \"ready\";\n private reportingInitializationFailure = false;\n private readonly handleOnlineForReconnect = () => {\n if (this.agentState !== \"reconnecting\" || this.reconnectInFlight || this.sessionReloadFallback) {\n return;\n }\n this.clearReconnectTimer();\n this.scheduleE2EReconnect(true);\n };\n\n constructor(options: XingyunAvatarAgentOptions) {\n validateAgentConfigSource(\"ASR\", options.asr_id, options.asr_config);\n validateAgentConfigSource(\"TTS\", undefined, options.tts_config);\n validateAgentConfigSource(\"Brain\", options.llm_id, options.brain_config);\n validateAgentObjectConfig(\"features\", options.features);\n validateAgentObjectConfig(\"extras\", options.extras);\n const {\n e2eServer,\n authToken,\n audio,\n reconnect,\n agentCallbacks,\n webSocketCtor,\n asr_id: asrId,\n asr_config: asrConfig,\n tts_config: ttsConfig,\n features,\n extras,\n llm_id: llmId,\n brain_config: brainConfig,\n session_speak_req_id: configuredSessionSpeakReqId,\n ...avatarOptions\n } = options;\n const originalOnMessage = avatarOptions.onMessage;\n const originalOnRenderChange = avatarOptions.onRenderChange;\n const originalOnNetworkInfo = avatarOptions.onNetworkInfo;\n const originalOnSpeakStateChange = avatarOptions.onSpeakStateChange;\n const originalOnVoiceStateChange = avatarOptions.onVoiceStateChange;\n const originalOnAudioPlaybackData = avatarOptions.onAudioPlaybackData;\n const playbackDataHandler = (data: IAudioPlaybackData) => {\n instance?.forwardFarendAudio(data);\n originalOnAudioPlaybackData?.(data);\n };\n const sessionSpeakReqId = configuredSessionSpeakReqId ?? 1;\n const normalizedBrainConfig = normalizeBrainConfig(brainConfig);\n let instance: XingyunAvatarAgent | undefined;\n\n const parentOptions: AgentParentOptions = {\n ...avatarOptions,\n session_speak_req_id: sessionSpeakReqId,\n sessionRequestData: {\n ...(asrId !== undefined ? { asr_id: asrId } : {}),\n ...(hasSerializableConfig(asrConfig) ? { asr_config: asrConfig } : {}),\n ...(hasSerializableConfig(ttsConfig) ? { tts_config: ttsConfig } : {}),\n ...(hasSerializableConfig(features) ? { features } : {}),\n ...(hasSerializableConfig(extras) ? { extras } : {}),\n ...(llmId !== undefined ? { llm_id: llmId } : {}),\n ...(normalizedBrainConfig !== undefined\n ? { brain_config: normalizedBrainConfig }\n : {}),\n session_speak_req_id: sessionSpeakReqId,\n },\n enableClientInterrupt: avatarOptions.enableClientInterrupt ?? true,\n onMessage: (error) => {\n originalOnMessage(error);\n if (!instance?.reportingInitializationFailure) {\n instance?.emitError(\"sdk\", String(error.code || \"AVATAR_ERROR\"), error.message || \"Avatar SDK 错误\", true, error);\n }\n },\n onRenderChange: (state) => {\n originalOnRenderChange?.(state);\n instance?.safeEmit(() => agentCallbacks?.onRenderChange?.(state));\n },\n onNetworkInfo: (info) => {\n originalOnNetworkInfo?.(info);\n instance?.safeEmit(() => agentCallbacks?.onNetworkInfo?.(info));\n },\n onSpeakStateChange: (state, clientSpeakId) => {\n originalOnSpeakStateChange?.(state, clientSpeakId);\n instance?.safeEmit(() => agentCallbacks?.onSpeakStateChange?.({ state, clientSpeakId }));\n if ([\"speak_start\", \"start\", \"started\"].includes(state)) {\n instance?.emitConversation({ state: \"speaking\" });\n }\n if ([\"speak_end\", \"end\", \"ended\", \"completed\", \"finish\", \"finished\"].includes(state)) {\n instance?.emitConversation({ state: \"completed\" });\n }\n },\n onVoiceStateChange: (state, duration, clientSpeakId) => {\n if (state === \"end\") {\n instance?.forwardVoiceEnd();\n }\n originalOnVoiceStateChange?.(state, duration, clientSpeakId);\n },\n ...(originalOnAudioPlaybackData\n ? {\n onAudioPlaybackData: playbackDataHandler,\n }\n : {}),\n };\n\n super(parentOptions);\n instance = this;\n this.agentOptions = {\n e2eServer,\n authToken,\n audio,\n requestedEnableAec: typeof features?.speech_frontend?.enable_aec === \"boolean\"\n ? features.speech_frontend.enable_aec\n : undefined,\n callbacks: agentCallbacks,\n webSocketCtor,\n debugAudioChunks: Boolean(avatarOptions.enableDebugger),\n };\n this.audioInputEnabled = audio?.inputEnabled ?? false;\n this.originalOnAudioPlaybackData = originalOnAudioPlaybackData;\n this.playbackDataHandler = playbackDataHandler;\n this.reconnectOptions = this.normalizeReconnectOptions(reconnect);\n this.audioUplink = new AgentAudioUplink({\n sendBinary: (frame) => this.e2eClient?.sendBinary(frame),\n onError: (error) => this.handleAudioUplinkError(error),\n });\n }\n\n getAgentState() {\n return this.agentState;\n }\n\n // Kept for callers that adopted the first Agent preview.\n getState() {\n return this.getAgentState();\n }\n\n getASRState() {\n return this.asrState;\n }\n\n override init(params: XingyunAvatarAgentInitParams = {}): Promise<ISessionResponse | null | undefined> {\n if (this.initializationPromise) {\n return this.initializationPromise;\n }\n const initializationPromise = this.initialize(params).finally(() => {\n if (this.initializationPromise === initializationPromise) {\n this.initializationPromise = null;\n }\n });\n this.initializationPromise = initializationPromise;\n return initializationPromise;\n }\n\n private async initialize(params: XingyunAvatarAgentInitParams): Promise<ISessionResponse | null | undefined> {\n this.assertNotDestroyed();\n this.setAgentState(\"initializing\");\n const initializationAbortPromise = new Promise<never>((_, reject) => {\n this.rejectInitialization = reject;\n });\n void initializationAbortPromise.catch(() => {});\n\n try {\n const initParams: IInitParams = {\n ...params,\n onDownloadProgress: params.onDownloadProgress || (() => {}),\n };\n const sessionInfo = await super.init(initParams);\n this.assertNotDestroyed();\n if (!sessionInfo) {\n throw new Error(\"XmovAvatar 初始化未返回 sessionInfo\");\n }\n this.applySessionFeatures(sessionInfo);\n\n this.assertNotDestroyed();\n this.beginInitialSession(sessionInfo);\n while (true) {\n const attempt = this.initialSessionAttempt;\n if (!attempt) {\n throw new Error(\"Agent 初始化缺少会话连接任务\");\n }\n await Promise.race([\n Promise.all([attempt.e2ePromise, attempt.ttsaReadyPromise]),\n initializationAbortPromise,\n ]);\n if (attempt === this.initialSessionAttempt) {\n break;\n }\n }\n this.assertNotDestroyed();\n this.assertE2EOpen();\n const initializedSessionInfo = this.initialSessionAttempt?.sessionInfo || sessionInfo;\n this.setAgentState(\"ready\");\n this.start();\n return initializedSessionInfo;\n } catch (error) {\n if (!this.agentDestroyed && !this.agentDestroying) {\n this.e2eClient?.disconnect(1000, \"agent_init_failed\");\n this.e2eClient = null;\n await this.cleanupBeforeInitComplete(\"agent_init_failed\");\n try {\n this.setAgentState(\"failed\");\n } catch {\n // Initialization failure must preserve the internal terminal state.\n }\n this.reportingInitializationFailure = true;\n try {\n this.reportInitializationFailure(\"Agent 初始化失败\", error);\n } catch {\n // A legacy callback must not replace the original initialization error.\n } finally {\n this.reportingInitializationFailure = false;\n }\n try {\n this.emitError(\"sdk\", \"AGENT_INIT_FAILED\", \"Agent 初始化失败\", true, error);\n } catch {\n // A business callback must not interrupt initialization cleanup.\n }\n this.agentDestroyed = true;\n }\n throw error;\n } finally {\n this.rejectInitialization = null;\n this.initialSessionGeneration += 1;\n this.initialSessionAttempt?.resolveTtsaReady();\n this.initialSessionAttempt = null;\n this.initialTtsaReadySessionIds.clear();\n this.initialTtsaReadyBeforeSession = false;\n }\n }\n\n private beginInitialSession(sessionInfo: ISessionResponse) {\n const previousAttempt = this.initialSessionAttempt;\n const generation = ++this.initialSessionGeneration;\n previousAttempt?.resolveTtsaReady();\n\n let resolveTtsaReady = () => {};\n const ttsaReadyPromise = new Promise<void>((resolve) => {\n resolveTtsaReady = resolve;\n });\n const e2ePromise = this.replaceE2EConnection(sessionInfo.e2e_resp).catch((error) => {\n if (generation !== this.initialSessionGeneration) {\n return;\n }\n throw error;\n });\n const attempt: InitialSessionAttempt = {\n sessionInfo,\n e2ePromise,\n ttsaReadyPromise,\n resolveTtsaReady,\n };\n this.initialSessionAttempt = attempt;\n\n if (this.initialTtsaReadySessionIds.delete(sessionInfo.session_id)) {\n attempt.resolveTtsaReady();\n } else if (!previousAttempt && this.initialTtsaReadyBeforeSession) {\n this.initialTtsaReadyBeforeSession = false;\n attempt.resolveTtsaReady();\n }\n\n void e2ePromise.catch(() => {});\n return e2ePromise;\n }\n\n override start() {\n if (this.agentState === \"initializing\") {\n return;\n }\n if (this.agentState === \"running\") {\n return;\n }\n if (this.agentState === \"reconnecting\") {\n if (\n this.waitingForTtsaReload\n && this.e2eClient?.isOpen\n ) {\n if (this.stateBeforeReconnect === \"running\") {\n super.start();\n }\n this.finishReconnect();\n }\n return;\n }\n this.assertE2EOpen();\n super.start();\n this.setAgentState(\"running\");\n }\n\n protected override onTtsaReady(sessionInfo?: ISessionResponse) {\n if (this.rejectInitialization) {\n const attempt = this.initialSessionAttempt;\n const sessionId = sessionInfo?.session_id;\n if (attempt && (!sessionId || attempt.sessionInfo.session_id === sessionId)) {\n attempt.resolveTtsaReady();\n } else if (sessionId) {\n this.initialTtsaReadySessionIds.add(sessionId);\n } else {\n this.initialTtsaReadyBeforeSession = true;\n }\n return;\n }\n if (this.agentState === \"reconnecting\") {\n this.start();\n return;\n }\n if (this.agentState === \"running\") {\n super.start();\n }\n }\n\n private abortInitialization(error: Error) {\n this.rejectInitialization?.(error);\n }\n\n override async stop() {\n if (this.agentDestroyed) {\n return;\n }\n const wasReconnecting = this.agentState === \"reconnecting\";\n if (wasReconnecting) {\n this.stateBeforeReconnect = \"stopped\";\n }\n await this.stopASR();\n await super.stop();\n if (!wasReconnecting) {\n this.setAgentState(\"stopped\");\n }\n }\n\n override speak(...args: Parameters<XmovAvatar[\"speak\"]>) {\n if (args[2] ?? true) {\n this.suppressNextVoiceEnd = true;\n }\n return super.speak(...args);\n }\n\n override async destroy(reason = \"user\") {\n if (this.agentDestroyed) {\n if (this.agentState !== \"destroyed\") {\n this.setAgentState(\"destroyed\");\n }\n return;\n }\n if (this.agentDestroying) {\n return;\n }\n this.agentDestroying = true;\n this.abortInitialization(new Error(\"Agent 初始化已取消\"));\n this.cancelReconnect();\n this.cancelSessionRestart();\n try {\n await this.stopASR();\n } catch (error) {\n this.emitError(\"sdk\", \"AGENT_ASR_STOP_FAILED\", \"Agent 销毁时停止 ASR 失败\", false, error);\n }\n\n this.e2eClient?.disconnect(1000, reason);\n this.e2eClient = null;\n this.audioUplink.reset();\n\n try {\n await super.destroy(reason);\n } finally {\n this.agentDestroyed = true;\n this.agentDestroying = false;\n this.setAgentState(\"destroyed\");\n }\n }\n\n async ask(text: string): Promise<void> {\n this.assertRunning();\n this.suppressNextVoiceEnd = false;\n this.emitConversation({ state: \"asking\", text });\n this.sendControl({\n type: \"ask\",\n message: { text },\n });\n }\n\n async speakByE2E(text: string): Promise<void> {\n this.assertRunning();\n this.suppressNextVoiceEnd = false;\n this.emitConversation({ state: \"speaking-directly\", text });\n this.sendControl({\n type: \"speak\",\n message: {\n text,\n is_start: true,\n is_end: true,\n },\n });\n }\n\n async startASR(options: AgentASRStartOptions = {}): Promise<void> {\n this.assertRunning();\n this.suppressNextVoiceEnd = false;\n if (this.stopASRPromise) {\n await this.stopASRPromise;\n this.assertRunning();\n }\n if (this.microphone?.isRecording) {\n return;\n }\n this.assertAudioChunkDuration();\n const inputStream = options.inputStream\n ? this.cloneASRInputStream(options.inputStream)\n : undefined;\n\n const asrStartGeneration = ++this.asrStartGeneration;\n const restoreDisabledStateOnFailure = !this.audioInputEnabled;\n const microphone = new MicrophoneController({\n audio: this.agentOptions.audio,\n debugAudioChunks: this.agentOptions.debugAudioChunks,\n inputStream,\n usePcmWebCodecs: this.farendAudioEnabled,\n onFrame: (data, timestamp) => {\n if (this.agentState === \"running\" && this.e2eClient?.isOpen) {\n try {\n this.sendAudioFrame({\n data,\n timestamp: timestamp ?? Date.now() - (\n this.agentOptions.audio?.chunkMs || DEFAULT_AGENT_AUDIO.chunkMs\n ),\n });\n } catch {\n // A close can race the isOpen check. Do not let the recorder\n // callback escape, and do not send control events on a broken stream.\n this.stopASRAfterSocketClose();\n }\n }\n },\n onError: (error) => this.handleMicrophoneError(microphone, error),\n });\n this.microphone = microphone;\n\n try {\n this.audioUplink.startInput();\n if (restoreDisabledStateOnFailure) {\n this.enableAudioInput();\n }\n this.emitConversation({ state: \"asking\" });\n this.assertASRStartActive(asrStartGeneration);\n this.setASRState(\"requesting-permission\");\n this.assertASRStartActive(asrStartGeneration);\n this.setASRState(\"starting\");\n this.assertASRStartActive(asrStartGeneration);\n await microphone.start();\n this.assertRunning();\n if (this.farendAudioEnabled) {\n this.restartAudioPlaybackCapture();\n }\n this.setASRState(\"listening\");\n } catch (error) {\n await microphone.stop();\n const isCancelled = (error as { agentCode?: string })?.agentCode === \"AUDIO_FIXED_TRACK_CANCELLED\";\n const isCurrentStart = asrStartGeneration === this.asrStartGeneration;\n const connectionUsable = !this.agentDestroyed\n && !this.agentDestroying\n && this.agentState === \"running\"\n && Boolean(this.e2eClient?.isOpen);\n if (this.microphone === microphone) {\n this.microphone = null;\n }\n if (isCurrentStart && !isCancelled && restoreDisabledStateOnFailure && this.e2eClient?.isOpen) {\n try {\n this.disableAudioInput();\n } catch {\n // sendControl has already reported the transport failure.\n }\n }\n if (isCurrentStart && !this.agentDestroyed && !this.agentDestroying) {\n if (isCancelled && connectionUsable) {\n this.setASRState(\"idle\");\n } else if (!isCancelled) {\n this.setASRState(\"failed\");\n }\n }\n if (isCancelled && !connectionUsable) {\n this.assertRunning();\n }\n throw error;\n }\n }\n\n private cloneASRInputStream(inputStream: MediaStream) {\n const track = inputStream.getAudioTracks().find((candidate) => candidate.readyState !== \"ended\");\n if (!track) {\n throw new Error(\"ASR 输入流不包含有效音频轨道\");\n }\n return new MediaStream([track.clone()]);\n }\n\n private assertASRStartActive(asrStartGeneration: number) {\n if (asrStartGeneration === this.asrStartGeneration) {\n return;\n }\n const error = new Error(\"麦克风启动已取消\") as Error & {\n agentCode?: string;\n retryable?: boolean;\n };\n error.name = \"AbortError\";\n error.agentCode = \"AUDIO_FIXED_TRACK_CANCELLED\";\n error.retryable = true;\n throw error;\n }\n\n stopASR(): Promise<void> {\n this.asrStartGeneration += 1;\n if (this.stopASRPromise) {\n return this.stopASRPromise;\n }\n\n const microphone = this.microphone;\n if (!microphone?.isRecording) {\n if (this.e2eClient?.isOpen) {\n this.disableAudioInput();\n }\n return Promise.resolve();\n }\n\n this.microphone = null;\n this.stopASRPromise = this.finishStopASR(microphone).finally(() => {\n this.stopASRPromise = null;\n });\n return this.stopASRPromise;\n }\n\n private async finishStopASR(microphone: MicrophoneController, notifyServer = true) {\n this.setASRState(\"stopping\");\n await microphone.stop();\n await this.audioUplink.drain();\n if (notifyServer) {\n this.disableAudioInput();\n this.setASRState(\"idle\");\n } else {\n this.setASRState(\"failed\");\n }\n }\n\n async interruptConversation(reason = \"user\") {\n if (this.agentDestroyed) {\n return;\n }\n\n void reason;\n\n this.sendControl({\n type: \"interrupt\",\n });\n super.interrupt(\"speak\");\n this.emitConversation({ state: \"interrupted\" });\n }\n\n protected override async onSessionReloaded(sessionInfo: ISessionResponse): Promise<void> {\n if (this.agentDestroyed || this.agentDestroying) {\n return;\n }\n if (this.initializationPromise && this.agentState === \"initializing\") {\n this.applySessionFeatures(sessionInfo);\n await this.beginInitialSession(sessionInfo);\n return;\n }\n if (this.agentState !== \"reconnecting\") {\n this.stateBeforeReconnect = this.readRestorableState();\n this.setAgentState(\"reconnecting\");\n }\n this.clearReconnectTimer();\n this.sessionReloadFallback = true;\n this.applySessionFeatures(sessionInfo);\n await this.replaceE2EConnection(sessionInfo.e2e_resp);\n this.waitingForTtsaReload = true;\n this.sessionReloadFallback = false;\n }\n\n protected override onSessionReloadExhausted(error?: unknown): void {\n if (this.rejectInitialization) {\n this.abortInitialization(\n error instanceof Error ? error : new Error(\"Agent 初始化期间 TTSA Session 恢复失败\"),\n );\n return;\n }\n if (this.agentState === \"reconnecting\") {\n this.failReconnect(error);\n }\n }\n\n override reloadSuccess() {\n super.reloadSuccess();\n }\n\n private async replaceE2EConnection(sessionInfo?: AgentSessionInfo) {\n const { wsUrl, token } = this.resolveE2EConnection(sessionInfo);\n const previousClient = this.e2eClient;\n this.audioUplink.reset();\n let client: AgentE2EClient;\n client = new AgentE2EClient({\n wsUrl,\n token,\n audioInputEnabled: this.audioInputEnabled,\n WebSocketCtor: this.agentOptions.webSocketCtor,\n onStateChange: (state) => {\n if (this.e2eClient === client) {\n if (state === \"open\") {\n this.audioUplink.reset(Date.now());\n }\n this.safeEmit(() => this.agentOptions.callbacks?.onSocketStateChange?.(state));\n }\n },\n onEvent: (event) => {\n if (this.e2eClient === client) {\n this.handleServerEvent(event);\n }\n },\n onError: (error) => {\n if (\n this.e2eClient === client\n && this.agentState !== \"initializing\"\n && this.agentState !== \"reconnecting\"\n ) {\n this.emitError(\"network\", \"E2E_SOCKET_ERROR\", error.message, true, error);\n }\n },\n onClose: (event) => {\n if (this.e2eClient === client) {\n this.handleSocketClose(event);\n }\n },\n });\n this.e2eClient = client;\n previousClient?.disconnect(1000, \"e2e_connection_replaced\");\n await client.connect();\n }\n\n private resolveE2EConnection(sessionInfo?: AgentSessionInfo) {\n const hasResponseWsUrl = Boolean(sessionInfo?.ws_url);\n const hasResponseToken = Boolean(sessionInfo?.e2e_token);\n if (hasResponseWsUrl !== hasResponseToken) {\n throw new Error(\"统一 session 响应的 e2e_resp 必须同时返回 ws_url 和 e2e_token\");\n }\n if (hasResponseWsUrl && hasResponseToken) {\n return { wsUrl: sessionInfo?.ws_url as string, token: sessionInfo?.e2e_token as string };\n }\n\n const hasConfiguredWsUrl = Boolean(this.agentOptions.e2eServer);\n const hasConfiguredToken = Boolean(this.agentOptions.authToken);\n if (hasConfiguredWsUrl !== hasConfiguredToken) {\n throw new Error(\"e2eServer 和 authToken 必须同时配置\");\n }\n if (!hasConfiguredWsUrl) {\n throw new Error(\"统一 session 响应未返回 e2e_resp.ws_url,且未配置 e2eServer\");\n }\n return {\n wsUrl: this.agentOptions.e2eServer as string,\n token: this.agentOptions.authToken as string,\n };\n }\n\n private sendControl(message: AgentClientMessage) {\n try {\n this.e2eClient?.send(message);\n } catch (error) {\n this.emitError(\"network\", \"E2E_SEND_FAILED\", \"E2E WebSocket 发送失败\", true, error);\n throw error;\n }\n }\n\n private assertAudioChunkDuration() {\n const chunkMs = this.agentOptions.audio?.chunkMs || DEFAULT_AGENT_AUDIO.chunkMs;\n if (!this.farendAudioEnabled || chunkMs === DEFAULT_AGENT_AUDIO.chunkMs) {\n return;\n }\n const error = new Error(\"AU v1 音频分片固定为 100ms\") as Error & {\n agentCode?: string;\n retryable?: boolean;\n };\n error.name = \"NotSupportedError\";\n error.agentCode = \"AUDIO_CHUNK_DURATION_UNSUPPORTED\";\n error.retryable = false;\n this.emitError(\"sdk\", error.agentCode, error.message, error.retryable, error);\n throw error;\n }\n\n private sendAudioFrame(frame: AgentAudioBlock) {\n if (!this.farendAudioEnabled) {\n if (this.agentOptions.debugAudioChunks) {\n void logAudioChunkContent(\"[Agent][E2E] nearend raw WebM/Opus chunk\", frame.data, {\n timestamp: frame.timestamp,\n });\n }\n try {\n this.e2eClient?.sendBinary(frame.data);\n } catch (error) {\n this.handleAudioUplinkError(\n error instanceof Error ? error : new Error(\"E2E nearend 音频帧发送失败\"),\n );\n }\n return;\n }\n\n if (this.agentOptions.debugAudioChunks) {\n void logAudioChunkContent(\"[Agent][E2E] nearend AU chunk\", frame.data, {\n timestamp: frame.timestamp,\n stream_id: 1,\n });\n }\n this.audioUplink.offerNearend(frame);\n }\n\n private handleAudioUplinkError(error: Error) {\n this.emitError(\n \"network\",\n \"E2E_AUDIO_SEND_FAILED\",\n this.farendAudioEnabled ? \"E2E AU 音频帧发送失败\" : \"E2E 音频帧发送失败\",\n true,\n error,\n );\n const microphone = this.microphone;\n if (!microphone?.isRecording || this.stopASRPromise) {\n return;\n }\n\n this.setASRState(\"failed\");\n this.microphone = null;\n const cleanupPromise = this.finishFailedASR(microphone).finally(() => {\n if (this.stopASRPromise === cleanupPromise) {\n this.stopASRPromise = null;\n }\n });\n this.stopASRPromise = cleanupPromise;\n }\n\n private applySessionFeatures(sessionInfo: ISessionResponse) {\n const returnedEnableAec = sessionInfo.e2e_resp?.features?.speech_frontend?.enable_aec\n ?? sessionInfo.features?.speech_frontend?.enable_aec;\n this.farendAudioEnabled = typeof returnedEnableAec === \"boolean\"\n ? returnedEnableAec\n : this.agentOptions.requestedEnableAec\n ?? this.agentOptions.audio?.echoCancellationEnabled\n ?? false;\n\n if (!this.farendAudioEnabled) {\n this.audioUplink.clearFarend();\n }\n\n if (this.farendAudioEnabled || this.originalOnAudioPlaybackData) {\n this.setAudioPlaybackDataHandler(this.playbackDataHandler);\n if (this.farendAudioEnabled) {\n void this.enableAudioPlaybackCapture();\n }\n return;\n }\n this.setAudioPlaybackDataHandler(undefined);\n }\n\n private forwardFarendAudio(data: IAudioPlaybackData) {\n const microphoneRecording = Boolean(this.microphone?.isRecording);\n const e2eOpen = Boolean(this.e2eClient?.isOpen);\n if (!this.farendAudioEnabled || !microphoneRecording || !e2eOpen) {\n (globalThis as typeof globalThis & {\n avatarSDKLogger?: { log?: (...args: unknown[]) => void };\n }).avatarSDKLogger?.log?.(\"[Agent][AudioUplink]\", \"farend.drop\", {\n reason: !this.farendAudioEnabled\n ? \"aec_disabled\"\n : !microphoneRecording\n ? \"microphone_not_recording\"\n : \"e2e_not_open\",\n timestamp: data.timestamp,\n isFirstChunk: data.isFirstChunk,\n });\n return;\n }\n\n if (this.agentOptions.debugAudioChunks) {\n void logAudioChunkContent(\"[Agent][E2E] farend AU chunk\", data.data, {\n timestamp: data.timestamp,\n stream_id: 2,\n codec: data.codec,\n sampleRate: data.sampleRate,\n channels: 1,\n samples: data.samples,\n speech_id: data.speech_id,\n isFirstChunk: data.isFirstChunk,\n });\n }\n this.audioUplink.offerFarend({\n data: data.data,\n timestamp: data.timestamp,\n isFirstChunk: data.isFirstChunk,\n });\n }\n\n private handleMicrophoneError(microphone: MicrophoneController, error: Error) {\n const codedError = error as Error & { agentCode?: string; retryable?: boolean };\n const isRecorderError = error.name === \"MediaRecorderError\";\n const isEncoderError = error.name === \"AudioEncoderError\";\n const isAudioPipelineError = isRecorderError || isEncoderError;\n const isCapabilityError = error.name === \"NotSupportedError\";\n const isSDKAudioError = Boolean(codedError.agentCode);\n const wasStopping = this.asrState === \"stopping\";\n const shouldCleanup = isAudioPipelineError && this.microphone === microphone && !wasStopping;\n\n if (shouldCleanup) {\n this.microphone = null;\n const cleanupPromise = this.finishFailedASR(microphone).finally(() => {\n if (this.stopASRPromise === cleanupPromise) {\n this.stopASRPromise = null;\n }\n });\n this.stopASRPromise = cleanupPromise;\n }\n\n this.emitError(\n isAudioPipelineError ? \"asr\" : isSDKAudioError || isCapabilityError ? \"sdk\" : \"permission\",\n codedError.agentCode || (\n isRecorderError\n ? \"MEDIA_RECORDER_ERROR\"\n : isEncoderError\n ? \"AUDIO_ENCODER_ERROR\"\n : \"MICROPHONE_ERROR\"\n ),\n error.message,\n codedError.retryable ?? !isCapabilityError,\n error,\n );\n }\n\n private async finishFailedASR(microphone: MicrophoneController) {\n try {\n await microphone.stop();\n await this.audioUplink.drain();\n } catch (stopError) {\n this.emitError(\"sdk\", \"MICROPHONE_CLEANUP_FAILED\", \"麦克风异常后的资源清理失败\", false, stopError);\n }\n\n try {\n this.disableAudioInput();\n } catch {\n // sendControl has already reported the transport failure.\n }\n }\n\n private enableAudioInput() {\n if (this.audioInputEnabled) {\n return;\n }\n this.sendControl({\n type: \"event\",\n message: \"audio_input_on\",\n });\n this.audioInputEnabled = true;\n this.e2eClient?.setAudioInputEnabled(true);\n }\n\n private disableAudioInput() {\n if (!this.audioInputEnabled) {\n return;\n }\n this.sendControl({\n type: \"event\",\n message: \"audio_input_off\",\n });\n this.audioInputEnabled = false;\n this.e2eClient?.setAudioInputEnabled(false);\n }\n\n private handleServerEvent(event: AgentServerEvent) {\n if (this.agentDestroyed || this.agentDestroying) {\n return;\n }\n\n switch (event.type) {\n case \"pong\":\n return;\n case \"asr_result\":\n this.handleASRResult(event);\n return;\n case \"llm_response\":\n this.handleLLMResponse(event);\n return;\n case \"semantic_judge_round_result\":\n this.handleSemanticJudgeResult(event);\n return;\n case \"error\":\n this.handleBackendError(event);\n return;\n default:\n return;\n }\n }\n\n private handleASRResult(event: AgentServerEvent) {\n const result: AgentASRResult = {\n text: typeof event.text === \"string\" ? event.text : \"\",\n isFinal: event.is_final === true,\n raw: event,\n };\n this.safeEmit(() => this.agentOptions.callbacks?.onASRResult?.(result));\n }\n\n private handleLLMResponse(event: AgentServerEvent) {\n if (event.event !== \"chunk\" && event.event !== \"done\") {\n return;\n }\n\n const usage = event.usage;\n const response: AgentLLMResponse = {\n event: event.event,\n ...(typeof event.text === \"string\" ? { text: event.text } : {}),\n ...(event.is_first === true ? { isFirst: true } : {}),\n ...(usage\n ? {\n usage: {\n promptTokens: this.readFiniteNumber(usage.prompt_tokens),\n completionTokens: this.readFiniteNumber(usage.completion_tokens),\n totalTokens: this.readFiniteNumber(usage.total_tokens),\n cachedTokens: this.readFiniteNumber(usage.cached_tokens),\n },\n }\n : {}),\n raw: event,\n };\n this.safeEmit(() => this.agentOptions.callbacks?.onLLMResponse?.(response));\n }\n\n private handleSemanticJudgeResult(event: AgentServerEvent) {\n if (!event.message || typeof event.message !== \"object\") {\n return;\n }\n\n const message = event.message as Record<string, unknown>;\n const result: AgentSemanticJudgeResult = {\n query: typeof message.query === \"string\" ? message.query : \"\",\n meaningful: message.meaningful === true,\n action: typeof message.action === \"string\" ? message.action : \"\",\n raw: event,\n };\n this.safeEmit(() => this.agentOptions.callbacks?.onSemanticJudgeResult?.(result));\n }\n\n private forwardVoiceEnd() {\n if (this.suppressNextVoiceEnd) {\n this.suppressNextVoiceEnd = false;\n return;\n }\n if (\n this.agentDestroyed ||\n this.agentDestroying ||\n this.agentState !== \"running\" ||\n !this.e2eClient?.isOpen\n ) {\n return;\n }\n\n try {\n this.sendControl({ type: \"event\", message: \"voice_end\" });\n } catch {\n // sendControl has already reported the transport failure. A render\n // callback must not throw back into the TTSA frame processing chain.\n }\n }\n\n private readFiniteNumber(value: unknown) {\n return typeof value === \"number\" && Number.isFinite(value) ? value : 0;\n }\n\n private handleBackendError(event: AgentServerEvent) {\n const supportedDomains: AgentErrorDomain[] = [\"permission\", \"network\", \"asr\", \"brain\", \"ttsa\", \"quota\", \"sdk\"];\n const domain = supportedDomains.includes(event.domain as AgentErrorDomain)\n ? event.domain as AgentErrorDomain\n : \"sdk\";\n const code = String(event.code ?? \"BACKEND_ERROR\");\n const message = typeof event.message === \"string\" ? event.message : \"E2E 后端错误\";\n if (domain === \"asr\") {\n this.stopASRAfterSocketClose();\n }\n this.emitConversation({ state: \"failed\" });\n this.emitError(domain, code, message, domain !== \"quota\", event);\n }\n\n private handleSocketClose(event: CloseEvent) {\n if (this.agentDestroyed || this.agentDestroying) {\n return;\n }\n if (this.rejectInitialization) {\n this.abortInitialization(\n new Error(`Agent 初始化期间 E2E WebSocket 已关闭: ${event.code} ${event.reason || \"\"}`.trim()),\n );\n return;\n }\n this.audioUplink.reset();\n this.stopASRAfterSocketClose();\n if (this.shouldReconnect(event)) {\n this.beginReconnect(event);\n return;\n }\n this.setAgentState(\"failed\");\n const domain: AgentErrorDomain = event.code === 4009 ? \"quota\" : \"network\";\n const message = event.reason || CLOSE_CODE_MESSAGES[event.code] || \"E2E WebSocket 已关闭\";\n this.emitError(domain, `E2E_CLOSE_${event.code}`, message, domain !== \"quota\", {\n code: event.code,\n reason: event.reason,\n wasClean: event.wasClean,\n });\n }\n\n private shouldReconnect(event: CloseEvent) {\n return this.reconnectOptions.enabled\n && this.agentState !== \"idle\"\n && this.agentState !== \"initializing\"\n && this.agentState !== \"destroyed\"\n && RETRYABLE_CLOSE_CODES.has(event.code);\n }\n\n private beginReconnect(event: CloseEvent) {\n if (this.agentState !== \"reconnecting\") {\n this.stateBeforeReconnect = this.readRestorableState();\n this.reconnectAttempt = 0;\n this.sessionReloadFallback = false;\n this.setAgentState(\"reconnecting\");\n globalThis.addEventListener?.(\"online\", this.handleOnlineForReconnect);\n this.emitError(\"network\", \"E2E_RECONNECTING\", \"E2E WebSocket 已断开,正在重连\", true, {\n code: event.code,\n reason: event.reason,\n wasClean: event.wasClean,\n });\n }\n this.audioInputEnabled = false;\n this.e2eClient?.setAudioInputEnabled(false);\n this.scheduleE2EReconnect(false);\n }\n\n private scheduleE2EReconnect(immediate: boolean) {\n if (\n this.agentDestroyed\n || this.agentDestroying\n || this.agentState !== \"reconnecting\"\n || this.reconnectTimer !== null\n || this.reconnectInFlight\n || this.sessionReloadFallback\n ) {\n return;\n }\n if (this.reconnectAttempt >= this.reconnectOptions.maxAttempts) {\n void this.fallbackToSessionReload();\n return;\n }\n\n const delay = immediate ? 0 : this.getReconnectDelay(this.reconnectAttempt);\n // @ts-ignore\n this.reconnectTimer = globalThis.setTimeout(() => {\n this.reconnectTimer = null;\n void this.attemptE2EReconnect();\n }, delay);\n }\n\n private async attemptE2EReconnect() {\n const client = this.e2eClient;\n if (!client || this.agentDestroyed || this.agentDestroying || this.agentState !== \"reconnecting\") {\n return;\n }\n\n this.reconnectInFlight = true;\n this.reconnectAttempt += 1;\n try {\n await client.connect();\n if (this.e2eClient === client && !this.agentDestroyed && !this.agentDestroying) {\n if (!this.waitingForTtsaReload) {\n this.finishReconnect();\n }\n }\n } catch {\n if (this.e2eClient === client && !this.agentDestroyed && !this.agentDestroying) {\n this.scheduleE2EReconnect(false);\n }\n } finally {\n this.reconnectInFlight = false;\n if (\n this.e2eClient === client\n && this.agentState === \"reconnecting\"\n && this.reconnectTimer === null\n && !this.sessionReloadFallback\n ) {\n this.scheduleE2EReconnect(false);\n }\n }\n }\n\n private async fallbackToSessionReload() {\n if (this.sessionReloadFallback || this.agentDestroyed || this.agentDestroying) {\n return;\n }\n this.sessionReloadFallback = true;\n this.clearReconnectTimer();\n try {\n await this.restartSessionForTransport(\"e2e_reconnect_exhausted\");\n } catch (error) {\n this.failReconnect(error);\n }\n }\n\n private finishReconnect() {\n const nextState = this.stateBeforeReconnect;\n this.cancelReconnect();\n if (this.asrState !== \"idle\") {\n this.setASRState(\"idle\");\n }\n this.setAgentState(nextState);\n }\n\n private failReconnect(cause?: unknown) {\n this.cancelReconnect();\n this.setAgentState(\"failed\");\n this.emitConversation({ state: \"failed\" });\n this.emitError(\n \"network\",\n \"E2E_RECONNECT_EXHAUSTED\",\n \"E2E WebSocket 重连失败,请重新初始化 Agent\",\n false,\n cause,\n );\n }\n\n private cancelReconnect() {\n this.clearReconnectTimer();\n globalThis.removeEventListener?.(\"online\", this.handleOnlineForReconnect);\n this.reconnectAttempt = 0;\n this.reconnectInFlight = false;\n this.sessionReloadFallback = false;\n this.waitingForTtsaReload = false;\n }\n\n private clearReconnectTimer() {\n if (this.reconnectTimer !== null) {\n globalThis.clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n }\n\n private getReconnectDelay(attempt: number) {\n const baseDelay = Math.min(\n this.reconnectOptions.maxDelayMs,\n this.reconnectOptions.initialDelayMs * (2 ** attempt),\n );\n if (baseDelay === 0) {\n return 0;\n }\n return Math.round(baseDelay * (0.8 + Math.random() * 0.4));\n }\n\n private readRestorableState(): AgentState {\n if (this.agentState === \"running\" || this.agentState === \"stopped\" || this.agentState === \"ready\") {\n return this.agentState;\n }\n return \"ready\";\n }\n\n private normalizeReconnectOptions(options?: AgentReconnectOptions): Required<AgentReconnectOptions> {\n const initialDelayMs = this.readNonNegativeNumber(\n options?.initialDelayMs,\n DEFAULT_RECONNECT_OPTIONS.initialDelayMs,\n );\n return {\n enabled: options?.enabled ?? DEFAULT_RECONNECT_OPTIONS.enabled,\n maxAttempts: Math.max(1, Math.floor(this.readNonNegativeNumber(\n options?.maxAttempts,\n DEFAULT_RECONNECT_OPTIONS.maxAttempts,\n ))),\n initialDelayMs,\n maxDelayMs: Math.max(initialDelayMs, this.readNonNegativeNumber(\n options?.maxDelayMs,\n DEFAULT_RECONNECT_OPTIONS.maxDelayMs,\n )),\n };\n }\n\n private readNonNegativeNumber(value: unknown, fallback: number) {\n return typeof value === \"number\" && Number.isFinite(value) && value >= 0 ? value : fallback;\n }\n\n private stopASRAfterSocketClose() {\n this.asrStartGeneration += 1;\n if (this.stopASRPromise) {\n return;\n }\n const microphone = this.microphone;\n if (!microphone?.isRecording) {\n return;\n }\n\n this.microphone = null;\n this.stopASRPromise = this.finishStopASR(microphone, false)\n .catch((error) => {\n this.emitError(\"sdk\", \"MICROPHONE_CLEANUP_FAILED\", \"WebSocket 断开后清理麦克风失败\", false, error);\n })\n .finally(() => {\n this.stopASRPromise = null;\n });\n }\n\n private setAgentState(state: AgentState) {\n this.agentState = state;\n if (!this.agentDestroyed || state === \"destroyed\") {\n this.agentOptions.callbacks?.onAgentStateChange?.(state);\n }\n }\n\n private setASRState(state: AgentASRState) {\n this.asrState = state;\n this.safeEmit(() => this.agentOptions.callbacks?.onASRStateChange?.(state));\n }\n\n private emitConversation(event: AgentConversationEvent) {\n this.safeEmit(() => this.agentOptions.callbacks?.onConversationChange?.(event));\n }\n\n private emitError(\n domain: AgentErrorDomain,\n code: string,\n message: string,\n retryable?: boolean,\n cause?: unknown,\n ) {\n const error: AgentError = { domain, code, message, retryable, cause };\n if (domain === \"asr\") {\n this.setASRState(\"failed\");\n }\n this.safeEmit(() => this.agentOptions.callbacks?.onError?.(error));\n }\n\n private safeEmit(callback: () => void) {\n if (!this.agentDestroyed && !this.agentDestroying) {\n callback();\n }\n }\n\n private assertRunning() {\n this.assertE2EOpen();\n if (this.agentState !== \"running\") {\n throw new Error(\"Agent 尚未启动,请先调用 start()\");\n }\n }\n\n private assertE2EOpen() {\n this.assertNotDestroyed();\n if (!this.e2eClient?.isOpen) {\n throw new Error(\"Agent 尚未连接 E2E WebSocket\");\n }\n }\n\n private assertNotDestroyed() {\n if (this.agentDestroyed || this.agentDestroying) {\n throw new Error(\"Agent 已销毁\");\n }\n }\n\n}\n\nexport * from \"./types\";\nexport { AgentE2EClient } from \"./e2e-client\";\nexport { MicrophoneController } from \"./microphone\";\n"],"names":["MAX_BUFFERED_AMOUNT","AgentE2EClient","constructor","options","_options$audioInputEn","ws","this","connectPromise","rejectConnect","audioInputEnabled","WebSocketCtor","globalThis","WebSocket","Error","isOpen","_this$ws","readyState","OPEN","connect","_this$options$onState","_this$options","Promise","resolve","connection","onStateChange","call","reject","settled","buildWsUrl","wsUrl","token","onopen","_this$options$onState2","_this$options2","onmessage","message","event","parseMessage","data","_this$options$onEvent","_this$options3","onEvent","onerror","_this$options$onState3","_this$options4","_this$options$onError","_this$options5","error","onError","onclose","_this$options$onState4","_this$options6","_this$options$onClose","_this$options7","code","reason","trim","onClose","disconnect","CONNECTING","close","send","_this$ws2","assertOpen","JSON","stringify","trySend","_this$ws3","bufferedAmount","sendBinary","frame","_this$ws4","name","ping","type","setAudioInputEnabled","enabled","parsed","parse","_this$options$onError2","_this$options8","url","URL","searchParams","has","set","updateAudioInputQuery","toString","_unused","baseUrl","query","split","URLSearchParams","nextQuery","delete","TARGET_SAMPLE_RATE","FixedAudioTrack","inputTrack","reader","writer","generator","audioContext","audioSource","audioDestination","pumpPromise","pumpFinished","outputClosed","draining","inputSampleRate","resampleBuffer","resamplePosition","outputBuffer","outputTimestamp","startGeneration","start","globals","ProcessorCtor","MediaStreamTrackProcessor","GeneratorCtor","MediaStreamTrackGenerator","AudioDataCtor","AudioData","startWebAudio","processor","track","kind","stream","MediaStream","outputTrack","getAudioTracks","settings","getSettings","undefined","sampleRate","channelCount","stop","unsupported","readable","getReader","writable","getWriter","pump","AudioContextCtor","AudioContext","webkitAudioContext","context","source","destination","state","resume","cause","contextSuspended","assertStartActive","createMediaStreamSource","createMediaStreamDestination","channelCountMode","channelInterpretation","validateOutputTrack","_source","_destination","getTracks","forEach","catch","normalizeWebAudioError","drain","closeWebAudioOutput","closeOutput","_this$inputTrack","then","_this$reader","_this$writer","race","delay","cancel","abort","stopGenerator","releaseLock","_this$inputTrack2","inputEnded","result","read","done","value","audioData","validateAudioData","mono","toMono","chunks","resample","Number","isFinite","timestamp","chunk","writeChunk","Float32Array","normalized","channels","Math","max","numberOfChannels","numberOfFrames","channel","plane","copyTo","format","planeIndex","index","length","input","flush","sample","push","MAX_INPUT_FRAMES_PER_READ","step","before","floor","after","min","weight","consumed","splice","samples","_this$generator","round","write","isInteger","abs","timeoutMs","setTimeout","agentCode","retryable","String","coded","DEFAULT_AGENT_AUDIO","mimeType","chunkMs","toHex","byte","padStart","async","logAudioChunkContent","label","metadata","previewBytes","buffer","Blob","arrayBuffer","ArrayBuffer","isView","slice","byteOffset","byteLength","bytes","Uint8Array","preview","Array","from","console","log","_extends","size","previewLength","hex","map","join","warn","captureStates","WeakMap","playbackSessionRestoredListeners","getAudioSession","target","audioSession","setAudioSessionType","_unused2","monotonicEpochNow","clock","performance","timeOrigin","now","Date","MediaRecorderTimestamp","timecodeScale","firstTimecode","lastTimecode","lastObservedAt","lastTimestamp","startedAt","timecode","observedAt","validTimecode","timecodeDelta","observedDelta","expectedDelta","millisecondError","secondError","relativeTimecode","_this$timecodeScale","resolved","OPUS_FRAME_DURATION_US","buildAudioEncoderConfig","config","codec","bitrate","opus","frameDuration","WebCodecOpusEncoder","encoder","isInitialized","pendingEncode","frameSize","isSupported","AudioEncoder","_support$config","support","isConfigSupported","supported","init","createEncoder","encode","pcm","pcmCopy","Int16Array","startTimestampUs","blockDurationUs","endTimestampUs","expectedFrameCount","timeoutId","failPending","reset","destroy","_unused3","_unused4","output","handleOutput","avatarSDKLogger","configure","pending","duration","frames","encodedChunk","_pending$chunks$times","_pending$chunks","nextTimestamp","durationMs","totalDurationMs","reduce","total","some","clearTimeout","WebMMuxer","hasHeader","clusterTimestamp","writeHeader","header","buildEBMLHeader","segmentInfo","buildSegmentInfo","tracks","buildOpusTracks","feedOpusFrame","opusFrame","cluster","buildCluster","totalLength","sum","offset","encodeVINT","width","i","encodeID","id","encodeUint","v","unshift","encodeString","str","TextEncoder","encodeFloat32","buf","DataView","setFloat32","encodeElement","idBytes","sizeBytes","encodeUintElement","encodeStringElement","encodeFloat32Element","concatArrays","arrays","arr","children","opusHead","audioChildren","trackEntryChildren","trackEntry","timecodeMs","opusData","trackNumber","flags","simpleBlockData","simpleBlock","clusterChildren","PcmWebMEncoder","opusEncoder","muxer","queue","generation","destroyed","pendingBlocks","_this","trackedOperation","finally","WEBM_OPUS_MIME_TYPE","PCM_CAPTURE_PROCESSOR","PCM_CAPTURE_WORKLET","MicrophoneController","_options$inputStream","_options$audio","recordingStream","audioTransformer","mediaRecorder","pcmAudioContext","pcmSource","pcmWorklet","pcmEncoder","pcmEncodeQueue","pcmStartedAt","pcmGeneration","resolvePcmFlush","starting","hasAudioSessionCapture","pendingInputStream","inputStream","usesProvidedInput","Boolean","audio","isRecording","getAudioMetadata","_this$options$onMetad2","mediaDevices","navigator","getUserMedia","MediaRecorderCtor","MediaRecorder","usePcmWebCodecs","webCodecsOpusUnsupported","isTypeSupported","webMOpusUnsupported","cancelled","_existingState$previo","_existingState$count","existingState","get","previousType","count","beginWebAudioCaptureSession","ideal","echoCancellation","noiseSuppression","autoGainControl","_this$options$onMetad","startPcmWebMRecorder","onMetadata","outputSettings","startWebMRecorder","startCancelled","_this$pendingInputStr","stopPcmWebMRecorder","stopMediaRecorder","captureState","configureWebAudioPlaybackSession","nextType","listeners","listener","notifyPlaybackSessionRestored","endWebAudioCaptureSession","recorder","audioBitsPerSecond","recorderTimestamp","ondataavailable","_globalThis$avatarSDK","recorderState","debugAudioChunks","onFrame","_this$options$onError3","recorderError","AudioWorkletNode","workletUrl","createObjectURL","audioWorklet","addModule","revokeObjectURL","audioContextSuspended","worklet","numberOfInputs","numberOfOutputs","outputChannelCount","port","_event$data","_event$data2","_this$resolvePcmFlush","sequence","webm","_this$options$onError4","flushCompleted","postMessage","shouldStop","finish","onstop","WEBM_EBML_MAGIC","logAudioUplink","details","logger","packAuAudioFrame","streamId","tsMs","payload","body","view","setUint8","setUint32","toPayloadBytes","isArray","all","merged","AgentAudioUplink","connectionStartedAt","connectionGeneration","sendChain","failed","pendingFarend","Map","pendingNearend","closedNearendBuckets","Set","lastTimestampByStream","lastSentTimestampByStream","pendingWebmPrefixByStream","farendStreamState","clear","startInput","clearFarend","offerFarend","block","_this$pendingFarend$g","isFirstChunk","normalizeBlock","abandonFarendStream","bucket","frameKey","keys","flushOlderNearend","prune","offerNearend","_this$pendingNearend$","nearend","flushExpiredNearend","sort","a","b","flushBucket","relativeTimestamp","enqueue","blocks","_block$dataParts","dataParts","coalesceSplitWebmMagic","lastSentTimestamp","pendingPrefix","every","currentFrameKey","allowPreviousFarend","takeNearend","previousFarendKey","farend","takeFarendThrough","add","nearendFrameKey","pairedFarend","first","flatMap","_block$dataParts2","key","latest","oldestAllowed","hasSerializableConfig","serializedConfig","CLOSE_CODE_MESSAGES","RETRYABLE_CLOSE_CODES","validateAgentConfigSource","validateAgentObjectConfig","XingyunAvatarAgent","XmovAvatar","_avatarOptions$enable","_features$speech_fron","_audio$inputEnabled","asr_id","asr_config","tts_config","llm_id","brain_config","features","extras","e2eServer","authToken","reconnect","agentCallbacks","webSocketCtor","asrId","asrConfig","ttsConfig","llmId","brainConfig","session_speak_req_id","configuredSessionSpeakReqId","avatarOptions","_objectWithoutPropertiesLoose","_excluded","originalOnMessage","onMessage","originalOnRenderChange","onRenderChange","originalOnNetworkInfo","onNetworkInfo","originalOnSpeakStateChange","onSpeakStateChange","originalOnVoiceStateChange","onVoiceStateChange","originalOnAudioPlaybackData","onAudioPlaybackData","playbackDataHandler","_instance","instance","forwardFarendAudio","sessionSpeakReqId","normalizedBrainConfig","extraBody","extra_body","normalizeBrainConfig","super","sessionRequestData","enableClientInterrupt","_instance2","_instance3","reportingInitializationFailure","emitError","_instance4","safeEmit","info","_instance5","clientSpeakId","_instance6","_instance7","_instance8","includes","emitConversation","_instance9","forwardVoiceEnd","e2eClient","microphone","stopASRPromise","initializationPromise","rejectInitialization","initialSessionAttempt","initialSessionGeneration","initialTtsaReadySessionIds","initialTtsaReadyBeforeSession","asrStartGeneration","agentState","asrState","agentDestroyed","agentDestroying","suppressNextVoiceEnd","farendAudioEnabled","reconnectTimer","reconnectAttempt","reconnectInFlight","sessionReloadFallback","waitingForTtsaReload","stateBeforeReconnect","handleOnlineForReconnect","clearReconnectTimer","scheduleE2EReconnect","agentOptions","requestedEnableAec","speech_frontend","enable_aec","callbacks","enableDebugger","inputEnabled","reconnectOptions","normalizeReconnectOptions","audioUplink","_this$e2eClient","handleAudioUplinkError","getAgentState","getState","getASRState","params","initialize","assertNotDestroyed","setAgentState","initializationAbortPromise","_","_this$initialSessionA","initParams","onDownloadProgress","sessionInfo","applySessionFeatures","beginInitialSession","attempt","e2ePromise","ttsaReadyPromise","assertE2EOpen","initializedSessionInfo","_this$e2eClient2","cleanupBeforeInitComplete","reportInitializationFailure","_this$initialSessionA2","resolveTtsaReady","previousAttempt","replaceE2EConnection","e2e_resp","session_id","_this$e2eClient3","finishReconnect","onTtsaReady","sessionId","abortInitialization","_this$rejectInitializ","wasReconnecting","stopASR","speak","args","_args$","_this$e2eClient4","cancelReconnect","cancelSessionRestart","ask","text","assertRunning","sendControl","speakByE2E","is_start","is_end","startASR","_this$microphone","assertAudioChunkDuration","cloneASRInputStream","restoreDisabledStateOnFailure","_this$e2eClient5","_this$agentOptions$au","sendAudioFrame","stopASRAfterSocketClose","handleMicrophoneError","enableAudioInput","assertASRStartActive","setASRState","restartAudioPlaybackCapture","_this$e2eClient6","_this$e2eClient7","isCancelled","isCurrentStart","connectionUsable","disableAudioInput","_unused5","find","candidate","clone","_this$e2eClient8","finishStopASR","notifyServer","interruptConversation","interrupt","onSessionReloaded","readRestorableState","onSessionReloadExhausted","failReconnect","reloadSuccess","resolveE2EConnection","previousClient","client","_this$agentOptions$ca","onSocketStateChange","handleServerEvent","handleSocketClose","hasResponseWsUrl","ws_url","hasResponseToken","e2e_token","hasConfiguredWsUrl","_this$e2eClient9","_this$agentOptions$au2","stream_id","_this$e2eClient0","cleanupPromise","finishFailedASR","_sessionInfo$e2e_resp","_sessionInfo$e2e_resp2","_sessionInfo$features","_ref","_this$agentOptions$re","_this$agentOptions$au3","returnedEnableAec","echoCancellationEnabled","setAudioPlaybackDataHandler","enableAudioPlaybackCapture","_this$microphone2","_this$e2eClient1","microphoneRecording","e2eOpen","speech_id","_codedError$retryable","codedError","isRecorderError","isEncoderError","isAudioPipelineError","isCapabilityError","isSDKAudioError","stopError","_unused6","_this$e2eClient10","_this$e2eClient11","handleASRResult","handleLLMResponse","handleSemanticJudgeResult","handleBackendError","isFinal","is_final","raw","_this$agentOptions$ca2","onASRResult","usage","response","is_first","isFirst","promptTokens","readFiniteNumber","prompt_tokens","completionTokens","completion_tokens","totalTokens","total_tokens","cachedTokens","cached_tokens","_this$agentOptions$ca3","onLLMResponse","meaningful","action","_this$agentOptions$ca4","onSemanticJudgeResult","_this$e2eClient12","_unused7","_event$code","domain","shouldReconnect","beginReconnect","wasClean","_this$e2eClient13","addEventListener","immediate","maxAttempts","fallbackToSessionReload","getReconnectDelay","attemptE2EReconnect","_unused8","restartSessionForTransport","nextState","removeEventListener","baseDelay","maxDelayMs","initialDelayMs","random","_options$enabled","readNonNegativeNumber","fallback","_this$agentOptions$ca5","onAgentStateChange","_this$agentOptions$ca6","onASRStateChange","_this$agentOptions$ca7","onConversationChange","_this$agentOptions$ca8","callback","_this$e2eClient14"],"mappings":"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"}
|