{"version":3,"sources":["../src/index.ts","../src/utils/audio.ts","../src/utils/errorMap.ts","../src/react/useIat.ts","../src/core/BaseXfyunClient.ts","../src/core/IatClient.ts","../src/react/useBaseXfyun.ts","../src/react/useTts.ts","../src/core/TtsClient.ts","../src/react/useRtasr.ts","../src/core/RtasrClient.ts","../src/core/RtasrConnectionPool.ts","../src/react/useDts.ts","../src/core/DtsClient.ts","../src/react/useIatRecorder.ts","../src/react/useRtasrStream.ts","../src/react/useTtsPlayer.ts","../src/react/useStreamingTts.ts","../src/core/StreamingTtsClient.ts"],"sourcesContent":["/**\n * 科大讯飞语音识别和合成SDK\n * 支持Vue2/3和React，提供完整的语音处理功能\n *\n * @version 1.0.0\n * @author Singerw Team\n * @license MIT\n */\n\n// 工具函数导出\nexport {\n  toBase64,\n  int16ToFloat32,\n  bytesToInt16,\n  getSharedAudioContext,\n  releaseSharedAudioContext,\n  calculateRMS,\n  calculateLevel,\n  createAudioWorkletProcessor,\n  createScriptProcessor,\n  AUDIO_CONFIG,\n  AUDIO_PERFORMANCE\n} from \"./utils/audio\";\nexport type { AudioFramePayload } from \"./utils/audio\";\n\n// 错误处理导出\nexport {\n  mapXfyunError,\n  isRetryableError,\n  getErrorSeverity,\n  getErrorType,\n  createXfyunError,\n  calculateRetryDelay,\n  DEFAULT_RECOVERY_STRATEGY\n} from \"./utils/errorMap\";\nexport type { XfyunError, ErrorRecoveryStrategy } from \"./utils/errorMap\";\nexport { ErrorSeverity, ErrorType } from \"./utils/errorMap\";\n\n// React Hooks 导出\nexport * from './react/useIat';\nexport * from './react/useTts';\nexport * from './react/useRtasr';\nexport * from './react/useDts';\nexport * from './react/useBaseXfyun';\nexport * from './react/useIatRecorder';\nexport * from './react/useRtasrStream';\nexport * from './react/useTtsPlayer';\nexport * from './react/useStreamingTts';\n\n// 核心客户端导出\nexport * from \"./core/IatClient\";\nexport * from \"./core/TtsClient\";\nexport * from \"./core/StreamingTtsClient\";\nexport * from \"./core/RtasrClient\";\nexport * from \"./core/DtsClient\";\nexport * from \"./core/BaseXfyunClient\";\nexport * from \"./core/RtasrConnectionPool\";\n\n// 导出工具函数\nexport * from './utils/audio';\nexport * from './utils/errorMap';\n","/**\n * 音频帧数据类型\n */\nexport type AudioFramePayload = ArrayBuffer | Uint8Array | Int16Array;\n\n/**\n * 音频配置常量\n */\nexport const AUDIO_CONFIG = {\n    /** 默认采样率 */\n    DEFAULT_SAMPLE_RATE: 16000,\n    /** 默认声道数 */\n    DEFAULT_CHANNELS: 1,\n    /** 默认位深度 */\n    DEFAULT_BIT_DEPTH: 16,\n    /** 推荐帧大小（40ms） */\n    RECOMMENDED_FRAME_SIZE: 1280,\n    /** 缓冲区大小 */\n    BUFFER_SIZE: 512,\n    /** 重采样阈值 */\n    RESAMPLE_THRESHOLD: 0.1,\n} as const;\n\n/**\n * 音频处理性能优化配置\n */\nexport const AUDIO_PERFORMANCE = {\n    /** 是否启用Web Workers */\n    ENABLE_WORKER: typeof Worker !== 'undefined',\n    /** 批处理大小 */\n    BATCH_SIZE: 10,\n    /** 缓存大小 */\n    CACHE_SIZE: 100,\n    /** 是否启用音频压缩 */\n    ENABLE_COMPRESSION: true,\n} as const;\n\n/**\n * 校验音频规格是否符合 16kHz/单声道/16bit\n */\nexport function validateAudioSpec(params: {\n    sampleRate: number;\n    channels?: number;\n    bitDepth?: number;\n}): boolean {\n    const srOk = Math.abs(params.sampleRate - AUDIO_CONFIG.DEFAULT_SAMPLE_RATE) < 1e-6;\n    const chOk = (params.channels ?? AUDIO_CONFIG.DEFAULT_CHANNELS) === AUDIO_CONFIG.DEFAULT_CHANNELS;\n    const bdOk = (params.bitDepth ?? AUDIO_CONFIG.DEFAULT_BIT_DEPTH) === AUDIO_CONFIG.DEFAULT_BIT_DEPTH;\n    return srOk && chOk && bdOk;\n}\n\n/**\n * 将任意采样率/声道的 Float32 PCM 重采样到 16k 单声道，并返回 Int16 PCM\n * - 优先通过 OfflineAudioContext 高质量重采样\n * - 回退到简易线性插值重采样\n */\nexport async function resampleTo16kMono(\n    float32Input: Float32Array,\n    inputSampleRate: number,\n    channels: number = 1\n): Promise<Int16Array> {\n    try {\n        if (typeof OfflineAudioContext !== 'undefined') {\n            const targetSampleRate = AUDIO_CONFIG.DEFAULT_SAMPLE_RATE;\n            // 组装多声道为单声道（平均）\n            let mono: Float32Array;\n            if (channels === 1) {\n                mono = float32Input;\n            } else {\n                const frames = Math.floor(float32Input.length / channels);\n                mono = new Float32Array(frames);\n                for (let i = 0; i < frames; i++) {\n                    let sum = 0;\n                    for (let ch = 0; ch < channels; ch++) sum += float32Input[i * channels + ch] || 0;\n                    mono[i] = sum / channels;\n                }\n            }\n\n            const durationSeconds = mono.length / inputSampleRate;\n            const offline = new OfflineAudioContext(1, Math.ceil(durationSeconds * targetSampleRate), targetSampleRate);\n            const buffer = offline.createBuffer(1, mono.length, inputSampleRate);\n            // 避免某些环境下 Float32Array<ArrayBufferLike> 与 Float32Array<ArrayBuffer> 的类型不兼容\n            // 使用 getChannelData().set(...) 代替 copyToChannel\n            buffer.getChannelData(0).set(mono, 0);\n            const src = offline.createBufferSource();\n            src.buffer = buffer;\n            src.connect(offline.destination);\n            src.start(0);\n            const rendered = await offline.startRendering();\n            const renderedData = rendered.getChannelData(0);\n            return float32ToInt16(renderedData);\n        }\n    } catch {\n        // fallthrough to linear\n    }\n\n    // 线性插值回退\n    const targetSampleRate = AUDIO_CONFIG.DEFAULT_SAMPLE_RATE;\n    // 合并到单声道\n    let mono: Float32Array;\n    if (channels === 1) {\n        mono = float32Input;\n    } else {\n        const frames = Math.floor(float32Input.length / channels);\n        mono = new Float32Array(frames);\n        for (let i = 0; i < frames; i++) {\n            let sum = 0;\n            for (let ch = 0; ch < channels; ch++) sum += float32Input[i * channels + ch] || 0;\n            mono[i] = sum / channels;\n        }\n    }\n\n    const ratio = targetSampleRate / inputSampleRate;\n    const outLen = Math.floor(mono.length * ratio);\n    const out = new Float32Array(outLen);\n    for (let i = 0; i < outLen; i++) {\n        const pos = i / ratio;\n        const idx = Math.floor(pos);\n        const frac = pos - idx;\n        const s0 = mono[idx] || 0;\n        const s1 = mono[idx + 1] || 0;\n        out[i] = s0 + (s1 - s0) * frac;\n    }\n    return float32ToInt16(out);\n}\n\n/**\n * 音频处理缓存\n */\nclass AudioCache {\n    private cache = new Map<string, Float32Array>();\n    private maxSize = AUDIO_PERFORMANCE.CACHE_SIZE;\n\n    set(key: string, value: Float32Array): void {\n        if (this.cache.size >= this.maxSize) {\n            const firstKey = this.cache.keys().next().value;\n            if (firstKey) {\n                this.cache.delete(firstKey);\n            }\n        }\n        this.cache.set(key, value);\n    }\n\n    get(key: string): Float32Array | undefined {\n        return this.cache.get(key);\n    }\n\n    clear(): void {\n        this.cache.clear();\n    }\n}\n\nconst audioCache = new AudioCache();\n\n/**\n * 音频批处理器\n */\nclass AudioBatchProcessor {\n    private batch: Float32Array[] = [];\n    private batchSize = AUDIO_PERFORMANCE.BATCH_SIZE;\n    private callback: (data: Float32Array[]) => void;\n\n    constructor(callback: (data: Float32Array[]) => void) {\n        this.callback = callback;\n    }\n\n    add(data: Float32Array): void {\n        this.batch.push(data);\n        if (this.batch.length >= this.batchSize) {\n            this.flush();\n        }\n    }\n\n    flush(): void {\n        if (this.batch.length > 0) {\n            this.callback([...this.batch]);\n            this.batch = [];\n        }\n    }\n}\n\n/**\n * 获取音频缓存实例\n */\nexport function getAudioCache(): AudioCache {\n    return audioCache;\n}\n\n/**\n * 创建音频批处理器\n */\nexport function createAudioBatchProcessor(callback: (data: Float32Array[]) => void): AudioBatchProcessor {\n    return new AudioBatchProcessor(callback);\n}\n\n/**\n * 将音频帧转换为Base64编码\n *\n * @param buffer 音频帧数据\n * @returns Base64编码的字符串\n */\nexport function toBase64(buffer: AudioFramePayload): string {\n    let u8: Uint8Array;\n\n    if (buffer instanceof ArrayBuffer) {\n        u8 = new Uint8Array(buffer);\n    } else if (buffer instanceof Int16Array) {\n        u8 = new Uint8Array(buffer.buffer);\n    } else {\n        u8 = buffer;\n    }\n\n    let binary = \"\";\n    for (let i = 0; i < u8.byteLength; i++) {\n        binary += String.fromCharCode(u8[i]);\n    }\n\n    return btoa(binary);\n}\n\n/**\n * 将Int16数组转换为Float32数组\n *\n * @param int16 Int16数组\n * @returns Float32数组\n */\nexport function int16ToFloat32(int16: Int16Array): Float32Array {\n    const out = new Float32Array(int16.length);\n    for (let i = 0; i < int16.length; i++) {\n        out[i] = int16[i] / 0x8000;\n    }\n    return out;\n}\n\n/**\n * 将字节数组转换为Int16数组\n *\n * @param bytes 字节数组\n * @returns Int16数组\n */\nexport function bytesToInt16(bytes: Uint8Array): Int16Array {\n    return new Int16Array(bytes.buffer, bytes.byteOffset, Math.floor(bytes.byteLength / 2));\n}\n\n/**\n * 将Float32数组转换为Int16数组\n *\n * @param float32 Float32数组\n * @returns Int16数组\n */\nexport function float32ToInt16(float32: ArrayLike<number>): Int16Array {\n    const int16 = new Int16Array(float32.length);\n    for (let i = 0; i < float32.length; i++) {\n        const sample = Math.max(-1, Math.min(1, float32[i] as number));\n        int16[i] = sample < 0 ? sample * 0x8000 : sample * 0x7fff;\n    }\n    return int16;\n}\n\n/**\n * 计算音频RMS（均方根）值（优化版本）\n *\n * @param samples 音频样本数组\n * @returns RMS值\n */\nexport function calculateRMS(samples: ArrayLike<number>): number {\n    if (samples.length === 0) return 0;\n\n    let sum = 0;\n    const len = samples.length;\n\n    // 使用循环展开优化\n    for (let i = 0; i < len; i += 4) {\n        const s0 = (samples[i] as number) || 0;\n        const s1 = (samples[i + 1] as number) || 0;\n        const s2 = (samples[i + 2] as number) || 0;\n        const s3 = (samples[i + 3] as number) || 0;\n\n        sum += s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3;\n    }\n\n    return Math.sqrt(sum / len);\n}\n\n/**\n * 计算音频电平（0-100）\n *\n * @param samples 音频样本数组\n * @returns 电平值（0-100）\n */\nexport function calculateLevel(samples: ArrayLike<number>): number {\n    const rms = calculateRMS(samples);\n    // 对于16位音频，使用更大的系数来获得更准确的电平\n    return Math.min(100, Math.max(0, Math.round(rms * 1000)));\n}\n\n// 共享AudioContext实例\nlet sharedAudioCtx: AudioContext | null = null;\n// AudioContext引用计数\nlet audioContextRefCount = 0;\n\n/**\n * 获取共享的AudioContext实例\n *\n * @param sampleRate 采样率，默认16000\n * @returns AudioContext实例\n */\nexport function getSharedAudioContext(sampleRate: number = AUDIO_CONFIG.DEFAULT_SAMPLE_RATE): AudioContext {\n    // 若已有实例且采样率一致且未关闭，则复用\n    if (sharedAudioCtx && sharedAudioCtx.sampleRate === sampleRate && sharedAudioCtx.state !== 'closed') {\n        audioContextRefCount++;\n        return sharedAudioCtx;\n    }\n\n    // 若已有实例但已关闭或采样率不一致，则释放旧实例\n    if (sharedAudioCtx) {\n        try {\n            // 强制将引用计数归零以便真正关闭\n            audioContextRefCount = 1;\n            releaseSharedAudioContext();\n        } catch {\n            // ignore\n        }\n    }\n\n    // 创建新实例\n    sharedAudioCtx = new (window.AudioContext || (window as any).webkitAudioContext)({\n        sampleRate\n    });\n    audioContextRefCount = 1;\n\n    return sharedAudioCtx;\n}\n\n/**\n * 释放共享的AudioContext实例\n */\nexport function releaseSharedAudioContext(): void {\n    audioContextRefCount--;\n    \n    if (audioContextRefCount <= 0 && sharedAudioCtx) {\n        try {\n            // 更严格的状态检查\n            if (sharedAudioCtx.state === 'running' || sharedAudioCtx.state === 'suspended') {\n                sharedAudioCtx.close();\n            }\n        } catch (e) {\n            console.warn('AudioContext关闭时出错:', e);\n        } finally {\n            sharedAudioCtx = null;\n            audioContextRefCount = 0;\n        }\n    }\n}\n\n/**\n * 获取AudioContext引用计数\n */\nexport function getAudioContextRefCount(): number {\n    return audioContextRefCount;\n}\n\n/**\n * 暂停共享的AudioContext\n */\nexport async function suspendSharedAudioContext(): Promise<void> {\n    if (sharedAudioCtx && sharedAudioCtx.state !== 'suspended') {\n        try { await sharedAudioCtx.suspend(); } catch {}\n    }\n}\n\n/**\n * 恢复共享的AudioContext\n */\nexport async function resumeSharedAudioContext(): Promise<void> {\n    if (!sharedAudioCtx || sharedAudioCtx.state === 'closed') {\n        // 在需要时重建默认采样率的上下文\n        getSharedAudioContext(AUDIO_CONFIG.DEFAULT_SAMPLE_RATE);\n        return;\n    }\n    if (sharedAudioCtx.state !== 'running') {\n        try { await sharedAudioCtx.resume(); } catch {}\n    }\n}\n\n/**\n * 创建AudioWorkletNode处理器\n *\n * @param audioCtx AudioContext实例\n * @param onAudioData 音频数据回调函数\n * @returns Promise<AudioWorkletNode>\n */\nexport async function createAudioWorkletProcessor(\n    audioCtx: AudioContext, \n    onAudioData: (data: Float32Array) => void,\n    workletBaseUrl?: string\n): Promise<AudioWorkletNode> {\n    try {\n        // 检查AudioWorklet支持\n        if (!audioCtx.audioWorklet) {\n            throw new Error('AudioWorklet not supported');\n        }\n\n        // 加载AudioWorklet模块（支持自定义基址，默认 ./worklet 与 ../worklet）\n        const candidates = workletBaseUrl\n            ? [`${workletBaseUrl.replace(/\\/$/, '')}/audio-processor.js`]\n            : ['./worklet/audio-processor.js', '../worklet/audio-processor.js'];\n        let loaded = false\n        for (const rel of candidates) {\n            try {\n                const workletUrl = workletBaseUrl ? rel : new URL(rel, import.meta.url).toString();\n                await audioCtx.audioWorklet.addModule(workletUrl as any)\n                loaded = true\n                break\n            } catch (_) {\n                // try next\n            }\n        }\n        if (!loaded) {\n            throw new Error('Failed to load audio-processor worklet from candidates')\n        }\n\n        // 创建AudioWorkletNode\n        const processor = new AudioWorkletNode(audioCtx, 'audio-processor');\n\n        // 监听音频数据\n        processor.port.onmessage = (event: MessageEvent) => {\n            if (!event.data) return;\n            // 兼容两种消息格式：\n            // 1) { type: 'audioData', data: Float32Array }\n            // 2) { type: 'audio', samples: Float32Array, rms?: number }\n            if (event.data.type === 'audioData' && event.data.data) {\n                onAudioData(event.data.data);\n            } else if (event.data.type === 'audio' && event.data.samples) {\n                onAudioData(event.data.samples);\n            }\n        };\n\n        return processor;\n    } catch (error) {\n        console.warn('AudioWorklet不可用，回退到ScriptProcessor:', error);\n        throw error;\n    }\n}\n\n/**\n * 创建ScriptProcessorNode处理器（兼容性回退）\n *\n * @param audioCtx AudioContext实例\n * @param onAudioData 音频数据回调函数\n * @returns ScriptProcessorNode\n */\nexport function createScriptProcessor(\n    audioCtx: AudioContext,\n    onAudioData: (data: Float32Array) => void\n): ScriptProcessorNode {\n    // 根据RTASR API要求：每40ms发送1280字节\n    // 16kHz采样率，40ms = 640个样本，但ScriptProcessor需要2的幂次方\n    // 使用512作为缓冲区大小，然后进行重采样\n    const processor = audioCtx.createScriptProcessor(512, 1, 1);\n\n    processor.onaudioprocess = (e) => {\n        const input = e.inputBuffer.getChannelData(0);\n        onAudioData(new Float32Array(input));\n    };\n\n    return processor;\n}\n\n\n","/**\n * 讯飞错误码映射表\n */\nconst XFYUN_ERROR_MAP: Record<number, string> = {\n    0: '成功',\n    10105: '参数错误或鉴权失败',\n    10109: '访问频率超限',\n    10007: '服务不可用或超时',\n    10800: '连接数超限，请等待后重试',\n    11200: '音频格式不支持或数据异常',\n    11201: '音频过短或静音',\n    11202: '音频采样率不匹配（需16k单声道）',\n    11203: '音频通道数不匹配（需单声道）',\n    11204: '音频位深度不匹配（需16bit）',\n    11401: '文本编码不支持或内容异常',\n    11500: '服务端内部错误',\n    11999: '内部错误，请稍后重试',\n} as const;\n\n/**\n * 错误严重程度枚举\n */\nexport enum ErrorSeverity {\n    LOW = 'low',\n    MEDIUM = 'medium',\n    HIGH = 'high',\n    CRITICAL = 'critical',\n}\n\n/**\n * 错误类型枚举\n */\nexport enum ErrorType {\n    NETWORK = 'network',\n    AUTHENTICATION = 'authentication',\n    PARAMETER = 'parameter',\n    AUDIO = 'audio',\n    WEBSOCKET = 'websocket',\n    UNKNOWN = 'unknown',\n}\n\n/**\n * 增强的错误信息接口\n */\nexport interface XfyunError {\n    code: number;\n    message: string;\n    severity: ErrorSeverity;\n    type: ErrorType;\n    retryable: boolean;\n    timestamp: number;\n    context?: Record<string, any> | undefined;\n}\n\n/**\n * 映射讯飞错误码为友好的错误消息\n * \n * @param code 错误码\n * @param message 原始错误消息\n * @returns 友好的错误消息\n */\nexport function mapXfyunError(code?: number, message?: string): string {\n    // 如果没有错误码，返回原始消息或默认消息\n    if (code === undefined || code === null) {\n        return message || '未知错误';\n    }\n    \n    // 成功状态\n    if (code === 0) {\n        return '成功';\n    }\n    \n    // 查找映射的错误消息\n    const mappedMessage = XFYUN_ERROR_MAP[code];\n    if (mappedMessage) {\n        return mappedMessage;\n    }\n    \n    // 如果没有映射，返回原始消息或包含错误码的消息\n    return message || `错误码：${code}`;\n}\n\n/**\n * 检查是否为可重试的错误\n * \n * @param code 错误码\n * @returns 是否可重试\n */\nexport function isRetryableError(code?: number): boolean {\n    if (code === undefined || code === null) return false;\n    \n    const retryableCodes = [10007, 10109, 10800, 11500, 11999];\n    return retryableCodes.includes(code);\n}\n\n/**\n * 获取错误严重程度\n * \n * @param code 错误码\n * @returns 错误严重程度\n */\nexport function getErrorSeverity(code?: number): ErrorSeverity {\n    if (code === undefined || code === null) return ErrorSeverity.MEDIUM;\n    \n    const highSeverityCodes = [10105, 11200, 11201, 11202];\n    const lowSeverityCodes = [10109, 10800];\n    const criticalSeverityCodes = [11999];\n    \n    if (criticalSeverityCodes.includes(code)) return ErrorSeverity.CRITICAL;\n    if (highSeverityCodes.includes(code)) return ErrorSeverity.HIGH;\n    if (lowSeverityCodes.includes(code)) return ErrorSeverity.LOW;\n    return ErrorSeverity.MEDIUM;\n}\n\n/**\n * 获取错误类型\n * \n * @param code 错误码\n * @returns 错误类型\n */\nexport function getErrorType(code?: number): ErrorType {\n    if (code === undefined || code === null) return ErrorType.UNKNOWN;\n    \n    const authCodes = [10105, 10109, 10800];\n    const paramCodes = [11200, 11201, 11202, 11203, 11204, 11401];\n    const networkCodes = [10007];\n    \n    if (authCodes.includes(code)) return ErrorType.AUTHENTICATION;\n    if (paramCodes.includes(code)) return ErrorType.PARAMETER;\n    if (networkCodes.includes(code)) return ErrorType.NETWORK;\n    return ErrorType.UNKNOWN;\n}\n\n/**\n * 创建增强的错误对象\n * \n * @param code 错误码\n * @param message 原始错误消息\n * @param context 错误上下文\n * @returns 增强的错误对象\n */\nexport function createXfyunError(\n    code: number, \n    message?: string, \n    context?: Record<string, any>\n): XfyunError {\n    return {\n        code,\n        message: mapXfyunError(code, message),\n        severity: getErrorSeverity(code),\n        type: getErrorType(code),\n        retryable: isRetryableError(code),\n        timestamp: Date.now(),\n        context,\n    };\n}\n\n/**\n * 错误恢复策略\n */\nexport interface ErrorRecoveryStrategy {\n    maxRetries: number;\n    retryDelay: number;\n    backoffMultiplier: number;\n    maxRetryDelay: number;\n}\n\n/**\n * 默认错误恢复策略\n */\nexport const DEFAULT_RECOVERY_STRATEGY: ErrorRecoveryStrategy = {\n    maxRetries: 3,\n    retryDelay: 1000,\n    backoffMultiplier: 2,\n    maxRetryDelay: 10000,\n};\n\n/**\n * 计算重试延迟\n * \n * @param attempt 当前尝试次数\n * @param strategy 恢复策略\n * @returns 延迟时间（毫秒）\n */\nexport function calculateRetryDelay(\n    attempt: number, \n    strategy: ErrorRecoveryStrategy = DEFAULT_RECOVERY_STRATEGY\n): number {\n    const delay = strategy.retryDelay * Math.pow(strategy.backoffMultiplier, attempt - 1);\n    return Math.min(delay, strategy.maxRetryDelay);\n}\n\n/**\n * 生成可读的错误日志上下文\n */\nexport function formatErrorContext(ctx?: Record<string, any>): string {\n    if (!ctx) return '';\n    try {\n        const safe: Record<string, any> = {};\n        const keys = ['sid', 'type', 'code', 'message', 'lastEvent', 'wsReadyState'];\n        for (const k of keys) if (ctx[k] !== undefined) safe[k] = ctx[k];\n        return JSON.stringify(safe);\n    } catch {\n        return '';\n    }\n}\n\n\n","import { useEffect } from \"react\";\nimport { IatClient, IatClientOptions, IatBusiness } from \"../core/IatClient\";\nimport { BaseXfyunClientOptions } from \"../core/BaseXfyunClient\";\nimport { ErrorRecoveryStrategy } from \"../utils/errorMap\";\nimport { AudioFramePayload } from \"../utils/audio\";\nimport { useBaseXfyun } from \"./useBaseXfyun\";\n\n/**\n * IAT Hook选项\n */\nexport interface IatOptions extends BaseXfyunClientOptions {\n    /** IAT业务参数配置 */\n    business?: IatBusiness;\n    /** 识别增量文本回调 */\n    onResult?: (text: string, isFinal: boolean) => void;\n    /** 原始消息回调（调试用） */\n    onMessage?: (msg: any) => void;\n    /** 连接打开回调（包含 sid） */\n    onOpen?: (sid?: string) => void;\n    /** 连接关闭回调 */\n    onClose?: (code?: number, reason?: string) => void;\n    /** 心跳间隔（毫秒），0表示禁用 */\n    heartbeatMs?: number;\n    /** 最大重试次数（默认3） */\n    maxRetries?: number;\n    /** 重连退避策略（可选，不传使用默认） */\n    retryStrategy?: ErrorRecoveryStrategy;\n}\n\n/**\n * 科大讯飞语音听写(IAT) Hook\n * \n * 支持实时语音转文字功能，特点：\n * - WebSocket实时连接\n * - 支持动态修正\n * - 支持增量识别结果\n * - 自动断句处理\n * \n * 使用示例：\n * ```typescript\n * const { status, error, open, sendFrame, close, reset } = useIat({\n *   serverBase: 'http://localhost:8083',\n *   business: { language: 'zh_cn', vad_eos: 2000 },\n *   onResult: (text, isFinal) => console.log(text, isFinal)\n * });\n * \n * await open();\n * sendFrame(audioData, false);\n * ```\n */\nexport function useIat(options?: IatOptions) {\n    const { status, error, reset, close, ensureClient } = useBaseXfyun(\n        (opts) => new IatClient({\n            ...opts,\n            onResult: (text, isFinal) => options?.onResult?.(text, isFinal),\n            onMessage: (msg) => options?.onMessage?.(msg),\n            onOpen: (sid) => options?.onOpen?.(sid),\n            onClose: (code, reason) => options?.onClose?.(code, reason),\n            onError: (message, sid) => options?.onError?.(message, sid),\n            heartbeatMs: options?.heartbeatMs,\n            maxRetries: options?.maxRetries,\n            retryStrategy: options?.retryStrategy,\n        } as IatClientOptions),\n        options\n    );\n\n    /**\n     * 建立IAT WebSocket连接并发送首帧\n     * \n     * @throws Error 连接失败时抛出异常\n     */\n    async function open(): Promise<void> {\n        const client = ensureClient();\n        await client.open();\n    }\n\n    /**\n     * 发送音频帧\n     * \n     * @param frame 音频帧数据\n     * @param isLast 是否为最后一帧\n     */\n    function sendFrame(frame: AudioFramePayload, isLast: boolean): void {\n        const client = ensureClient();\n        client.sendFrame(frame, isLast);\n    }\n\n    // 当业务参数变更时，重建客户端实例\n    useEffect(() => {\n        ensureClient();\n    }, [JSON.stringify(options?.business)]);\n\n    return {\n        status,\n        error,\n        open,\n        sendFrame,\n        close,\n        reset\n    };\n}\n\n\n","import { mapXfyunError, formatErrorContext } from \"../utils/errorMap\";\n\n/**\n * 讯飞客户端基础配置接口\n */\nexport interface BaseXfyunClientOptions {\n    /** 后端服务基础地址 */\n    serverBase?: string;\n    /** 获取认证码的方法 */\n    getAuthCode?: () => string;\n    /** 错误回调 */\n    onError?: (message: string, sid?: string) => void;\n    /** 统一日志回调（可用于上报） */\n    onLog?: (level: 'info' | 'warn' | 'error', payload: Record<string, any>) => void;\n}\n\n/**\n * 讯飞客户端基础类\n *\n * 提供所有讯飞客户端的通用功能：\n * - 统一的错误处理\n * - 统一的签名获取\n * - 统一的状态管理\n *\n * @template T 具体的客户端选项类型\n */\nexport abstract class BaseXfyunClient<T extends BaseXfyunClientOptions = BaseXfyunClientOptions> {\n    protected readonly serverBase: string;\n    protected readonly options: T;\n    public error: string | null = null;\n    protected lastContext: Record<string, any> | null = null;\n    protected sessionId: string = `${Date.now()}-${Math.random().toString(36).slice(2,8)}`;\n\n    constructor(options?: T) {\n        this.options = options || ({} as T);\n        this.serverBase = this.options.serverBase || \"\";\n    }\n\n    /**\n     * 获取签名信息\n     *\n     * @param type 签名类型 (iat|tts|rtasr|dts/create|dts/query)\n     * @returns 签名响应数据\n     * @throws Error 获取签名失败时抛出异常\n     */\n    protected async getSignature(type: string): Promise<any> {\n        try {\n            const auth = this.options.getAuthCode?.() || \"\";\n            const response = await fetch(`${this.serverBase}/api/v1/xfyun/sign/${type}`, {\n                headers: { Authorization: `Bearer ${auth}` }\n            });\n\n            if (!response.ok) {\n                throw new Error(`获取${type}签名失败: ${response.status} ${response.statusText}`);\n            }\n\n            const result = await response.json();\n\n            if (result.errorCode !== 0) {\n                throw new Error(`获取${type}签名失败: ${result.message || '未知错误'}`);\n            }\n\n            return result.data;\n        } catch (error) {\n            const errorMessage = error instanceof Error ? error.message : `获取${type}签名失败`;\n            this.handleError(errorMessage);\n            throw error;\n        }\n    }\n\n    /**\n     * 统一错误处理\n     *\n     * @param message 错误消息\n     * @param sid 会话ID（可选）\n     */\n    protected handleError(message: string, sid?: string, context?: Record<string, any>): void {\n        this.error = message;\n        this.lastContext = { ...(context || {}), sid, message };\n        try {\n            const summary = formatErrorContext(this.lastContext);\n            if (summary) console.error('[XFYUN] ErrorContext:', summary);\n            this.options.onLog?.('error', {\n                sessionId: this.sessionId,\n                timestamp: Date.now(),\n                message,\n                ...this.lastContext,\n            });\n        } catch {}\n        this.options.onError?.(message, sid);\n    }\n\n    /**\n     * 处理讯飞API错误码\n     *\n     * @param code 错误码\n     * @param message 原始错误消息\n     * @param sid 会话ID（可选）\n     * @returns 处理后的错误消息\n     */\n    protected processXfyunError(code?: number, message?: string, sid?: string, extra?: Record<string, any>): string {\n        const errorMessage = mapXfyunError(code, message);\n        this.handleError(errorMessage, sid, { code, ...extra });\n        return errorMessage;\n    }\n\n    /**\n     * 重置客户端状态\n     */\n    public reset(): void {\n        this.error = null;\n        this.lastContext = null;\n        this.sessionId = `${Date.now()}-${Math.random().toString(36).slice(2,8)}`;\n    }\n\n    /**\n     * 关闭客户端连接\n     *\n     * 子类可以重写此方法来实现具体的关闭逻辑\n     */\n    public close(): void {\n        // 默认实现为空，子类可以重写\n        this.reset();\n    }\n\n}\n","import { BaseXfyunClient, BaseXfyunClientOptions } from \"./BaseXfyunClient\";\nimport { toBase64, AudioFramePayload, validateAudioSpec, int16ToFloat32 } from \"../utils/audio\";\nimport { calculateRetryDelay, ErrorRecoveryStrategy, DEFAULT_RECOVERY_STRATEGY } from \"../utils/errorMap\";\n\n/**\n * IAT业务参数配置\n */\nexport interface IatBusiness {\n    /** 语种，默认为 zh_cn */\n    language?: string;\n    /** 业务领域，固定为 iat */\n    domain?: string;\n    /** 方言/口音（中文场景），默认 mandarin */\n    accent?: string;\n    /** 静音断句阈值（毫秒），默认 2000 */\n    vad_eos?: number;\n    /** 动态修正开关，默认 \"wpgs\" */\n    dwa?: string;\n    /** 是否返回标点（1/0），默认 1 */\n    ptt?: 0 | 1;\n    /** 返回字级别信息 */\n    vinfo?: 0 | 1;\n    /** 返回结果格式（plain/json 等） */\n    rst?: string;\n    /** 返回结果语言 */\n    rlang?: string;\n    /** 产品类型 */\n    pd?: string;\n    /** 产品引擎 */\n    pd_engine?: string;\n    /** 候选结果数量 */\n    nbest?: number;\n    /** 候选词数量 */\n    wbest?: number;\n}\n\n/**\n * IAT客户端选项\n */\nexport interface IatClientOptions extends BaseXfyunClientOptions {\n    /** IAT业务参数配置 */\n    business?: IatBusiness;\n    /** 识别增量文本回调 */\n    onResult?: (text: string, isFinal: boolean) => void;\n    /** 原始消息回调（调试用） */\n    onMessage?: (msg: any) => void;\n    /** 连接打开回调（包含 sid） */\n    onOpen?: (sid?: string) => void;\n    /** 连接关闭回调 */\n    onClose?: (code?: number, reason?: string) => void;\n    /** 心跳间隔（毫秒），0表示禁用 */\n    heartbeatMs?: number;\n    /** 输入采样率（用于自动重采样判断） */\n    inputSampleRate?: number;\n    /** 输入声道数（默认1） */\n    inputChannels?: number;\n    /** 是否自动重采样到16k单声道（默认false） */\n    autoResample?: boolean;\n    /** 最大重试次数（默认3） */\n    maxRetries?: number;\n    /** 重连退避策略（可选，不传使用默认） */\n    retryStrategy?: ErrorRecoveryStrategy;\n    /** 是否启用语言/方言与URL匹配校验（默认true） */\n    enableLangCheck?: boolean;\n}\n\n/**\n * 科大讯飞语音听写(IAT)客户端\n *\n * 支持实时语音转文字功能，特点：\n * - WebSocket实时连接\n * - 支持动态修正\n * - 支持增量识别结果\n * - 自动断句处理\n *\n * 使用示例：\n * ```typescript\n * const client = new IatClient({\n *   serverBase: 'http://localhost:8083',\n *   business: { language: 'zh_cn', vad_eos: 2000 },\n *   onResult: (text, isFinal) => console.log(text, isFinal)\n * });\n * await client.open();\n * client.sendFrame(audioData, false);\n * ```\n */\nexport class IatClient extends BaseXfyunClient<IatClientOptions> {\n    private ws: WebSocket | null = null;\n    public status: \"idle\" | \"connecting\" | \"open\" | \"closing\" | \"closed\" = \"idle\";\n\n    private resultTemp = \"\";\n    private resultMap: Map<number, any> = new Map();\n    private maxResultWindow: number = 200; // 限制窗口，避免内存膨胀\n    private lastSnSeen: number = -1;\n    private appId = \"\";\n    private sid: string | undefined;\n    private heartbeatTimer: any = null;\n    private visibilityHandler?: () => void;\n    private pausedByPageHidden: boolean = false;\n    private retryCount: number = 0;\n\n    constructor(options?: IatClientOptions) {\n        super(options);\n    }\n\n    /**\n     * 建立IAT WebSocket连接并发送首帧\n     *\n     * 首帧内容：\n     * - common.app_id: 来自后端签名返回\n     * - business: 语言/断句/标点/动态修正等配置\n     * - data: { status:0, format:'audio/L16;rate=16000', encoding:'raw' }\n     *\n     * @throws Error 连接失败时抛出异常\n     */\n    async open(): Promise<void> {\n        this.reset();\n        this.status = \"connecting\";\n\n        try {\n            const signData = await this.getSignature(\"iat\");\n            const { url } = signData;\n            const appIdFromSign = signData.appId || signData.app_id;\n            this.appId = appIdFromSign || \"\";\n            if (!this.appId) {\n                this.handleError(\"签名返回缺少appId/app_id\");\n                throw new Error(\"签名返回缺少appId/app_id\");\n            }\n\n            const ws = new WebSocket(url);\n            this.ws = ws;\n\n            ws.onopen = () => {\n                this.status = \"open\";\n                this.options.onOpen?.(this.sid);\n\n                // 构建业务参数：仅发送用户显式配置的字段；始终包含 domain 默认为 iat\n                const business: any = { domain: this.options.business?.domain || \"iat\" };\n                const src = this.options.business || {};\n                const maybeAssign = (key: keyof IatBusiness) => {\n                    const value = (src as any)[key];\n                    if (value !== undefined && value !== null) {\n                        (business as any)[key] = value;\n                    }\n                };\n                maybeAssign(\"language\");\n                maybeAssign(\"accent\");\n                maybeAssign(\"vad_eos\");\n                maybeAssign(\"ptt\");\n                maybeAssign(\"dwa\");\n                maybeAssign(\"vinfo\");\n                maybeAssign(\"rst\");\n                maybeAssign(\"rlang\");\n                maybeAssign(\"pd\");\n                maybeAssign(\"pd_engine\");\n                maybeAssign(\"nbest\");\n                maybeAssign(\"wbest\");\n\n                // 语言/方言与URL匹配校验（提示级，不阻断）\n                if (this.options.enableLangCheck !== false) {\n                    try {\n                        const warns: string[] = [];\n                        const lang = business.language as string | undefined;\n                        const accent = business.accent as string | undefined;\n                        const urlHost = (() => {\n                            try { return new URL(signData.url).host; } catch { return ''; }\n                        })();\n                        const isChinese = !lang || lang === 'zh_cn';\n                        if (!isChinese) {\n                            // 小语种：不建议设置中文口音；URL 建议 niche 域名\n                            if (accent) {\n                                warns.push('小语种场景不应设置 accent，已检测到 accent=' + accent);\n                            }\n                            if (urlHost && !/iat-niche-api\\.xfyun\\.cn/i.test(urlHost)) {\n                                warns.push('当前 language=' + lang + '，建议使用 iat-niche-api.xfyun.cn 域名');\n                            }\n                        } else {\n                            // 中文：可设置 accent；如 URL 为 niche 域名，亦给出提示\n                            if (urlHost && /iat-niche-api\\.xfyun\\.cn/i.test(urlHost)) {\n                                warns.push('中文场景建议使用 iat-api.xfyun.cn 或 ws-api.xfyun.cn 域名');\n                            }\n                        }\n                        if (warns.length) {\n                            console.warn('[IAT] 语言/URL校验提示:', { warns, urlHost, lang, accent });\n                            this.options.onMessage?.({ type: 'warning', category: 'language-url-check', warns, urlHost, lang, accent });\n                        }\n                    } catch {}\n                }\n\n                // 发送首帧\n                ws.send(JSON.stringify({\n                    common: { app_id: this.appId },\n                    business,\n                    data: { status: 0, format: \"audio/L16;rate=16000\", encoding: \"raw\" },\n                }));\n\n                // 统一会话追踪日志\n                this.options.onLog?.('info', {\n                    event: 'iat.open',\n                    sessionId: this.sessionId,\n                    appId: this.appId,\n                    timestamp: Date.now(),\n                });\n\n                // 官方不鼓励发送空JSON心跳，这里不主动发送保活数据。\n\n                // 监听页面可见性，隐藏时暂停发送；可见时恢复\n                this.visibilityHandler = () => {\n                    if (typeof document === 'undefined') return;\n                    if (document.hidden) {\n                        this.pausedByPageHidden = true;\n                    } else {\n                        this.pausedByPageHidden = false;\n                    }\n                };\n                try { document.addEventListener('visibilitychange', this.visibilityHandler!, false); } catch {}\n            };\n\n            ws.onmessage = (evt) => {\n                try {\n                    const msg = JSON.parse(evt.data);\n                    if (msg?.sid) this.sid = msg.sid;\n                    this.options.onMessage?.(msg);\n\n                    // 处理识别结果\n                    if (msg?.data?.result) {\n                        this.processRecognitionResult(msg.data.result);\n                    }\n\n                    // 处理最终结果\n                    if (msg?.code === 0 && msg?.data?.status === 2) {\n                        this.options.onResult?.(this.resultTemp, true);\n                        this.status = \"closing\";\n                        ws.close();\n                    } else if (msg?.code !== 0) {\n                        this.processXfyunError(msg?.code, msg?.message, this.sid, {\n                            lastEvent: 'iat.onmessage',\n                            wsReadyState: this.ws?.readyState,\n                        });\n                        this.status = \"closed\";\n                        ws.close();\n                    }\n                } catch (error) {\n                    console.error(\"IAT消息解析错误:\", error);\n                    this.handleError(\"消息解析错误\", this.sid, { lastEvent: 'iat.onmessage.parseError' });\n                }\n            };\n\n            ws.onclose = (ev) => {\n                this.status = \"closed\";\n                if (this.heartbeatTimer) {\n                    clearInterval(this.heartbeatTimer);\n                    this.heartbeatTimer = null;\n                }\n                try { if (this.visibilityHandler) document.removeEventListener('visibilitychange', this.visibilityHandler, false); } catch {}\n                // 如果不是正常关闭，尝试重连（指数退避+抖动）\n                const maxRetries = this.options.maxRetries ?? DEFAULT_RECOVERY_STRATEGY.maxRetries;\n                if (!ev.wasClean && this.retryCount < maxRetries) {\n                    this.retryCount++;\n                    const strategy = this.options.retryStrategy ?? DEFAULT_RECOVERY_STRATEGY;\n                    const baseDelay = calculateRetryDelay(this.retryCount, strategy);\n                    const jitter = Math.floor(Math.random() * 300);\n                    const delay = baseDelay + jitter;\n                    setTimeout(() => {\n                        this.open().catch(error => {\n                            console.error(`IAT重连失败: ${error}`);\n                        });\n                    }, delay);\n                } else {\n                    this.retryCount = 0;\n                }\n                this.options.onClose?.(ev.code, ev.reason);\n            };\n\n            ws.onerror = () => {\n                this.handleError(\"WebSocket错误\", this.sid);\n            };\n        } catch (error) {\n            this.handleError(error instanceof Error ? error.message : \"连接失败\");\n            throw error;\n        }\n    }\n\n    /**\n     * 处理识别结果\n     *\n     * @param result 识别结果数据\n     */\n    private processRecognitionResult(result: any): void {\n        try {\n            const sn: number | undefined = result?.sn;\n            if (typeof sn !== 'number') {\n                return;\n            }\n\n            // 忽略重复结果（简单判定：同 sn 且 ws 长度未增长）\n            const prev = this.resultMap.get(sn);\n            if (prev && Array.isArray(prev.ws) && Array.isArray(result.ws) && result.ws.length <= prev.ws.length) {\n                // 但若为替换型 pgs=rpl 仍继续处理\n                if (result.pgs !== 'rpl') {\n                    return;\n                }\n            }\n\n            // 处理动态修正：pgs === 'rpl' 时，删去区间 [rg[0], rg[1]] 的历史，再写入当前 sn\n            if (result.pgs === 'rpl' && Array.isArray(result.rg)) {\n                const [start, end] = result.rg as [number, number];\n                for (let i = start; i <= end; i++) {\n                    if (i !== sn) this.resultMap.delete(i);\n                }\n            }\n\n            // 写入/覆盖当前 sn 结果\n            this.resultMap.set(sn, result);\n            this.lastSnSeen = Math.max(this.lastSnSeen, sn);\n\n            // 窗口裁剪：只保留最近 maxResultWindow 个片段\n            if (this.resultMap.size > this.maxResultWindow) {\n                const ordered = Array.from(this.resultMap.keys()).sort((a, b) => a - b);\n                const toDelete = ordered.length - this.maxResultWindow;\n                for (let i = 0; i < toDelete; i++) {\n                    this.resultMap.delete(ordered[i]);\n                }\n            }\n\n            // 按 sn 升序全量重建文本，兼容乱序/丢失\n            const orderedSn = Array.from(this.resultMap.keys()).sort((a, b) => a - b);\n            let merged = '';\n            for (const key of orderedSn) {\n                const seg = this.resultMap.get(key);\n                if (!seg) continue;\n                const wsArr = seg.ws || [];\n                for (const s of wsArr) {\n                    if (s.cw && s.cw[0]) {\n                        merged += s.cw[0].w || '';\n                    }\n                }\n            }\n            this.resultTemp = merged;\n            this.options.onResult?.(merged, false);\n        } catch {\n            // ignore parse errors for robustness\n        }\n    }\n\n    /**\n     * 调试/测试专用：注入一条识别结果并走内部重建逻辑\n     * 不建立网络连接即可验证动态修正与乱序容错\n     */\n    public debugProcessRecognitionResult(result: any): void {\n        this.processRecognitionResult(result);\n    }\n\n    /**\n     * 发送音频帧\n     *\n     * @param frame 音频帧数据\n     * @param isLast 是否为最后一帧\n     */\n    sendFrame(frame: AudioFramePayload, isLast: boolean): void {\n        if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n            console.warn('WebSocket未连接，无法发送音频帧');\n            return;\n        }\n        if (this.pausedByPageHidden) {\n            // 页面隐藏时暂停发送，避免被服务端判空闲\n            return;\n        }\n\n        // 可选：对非16k/单声道输入进行重采样\n        if (this.options.autoResample) {\n            const sr = this.options.inputSampleRate || 16000;\n            const ch = this.options.inputChannels || 1;\n            if (!validateAudioSpec({ sampleRate: sr, channels: ch, bitDepth: 16 })) {\n                try {\n                    let int16: Int16Array;\n                    if (frame instanceof Int16Array) {\n                        int16 = frame;\n                    } else if (frame instanceof ArrayBuffer) {\n                        int16 = new Int16Array(frame);\n                    } else {\n                        int16 = new Int16Array(frame.buffer);\n                    }\n                    const f32 = int16ToFloat32(int16);\n                    // 注意：异步重采样，这里无法直接 await，因此提示调用方改用异步管道更合适。\n                    // 为保持API同步性，仍然发送原始帧，但输出警告，建议调用方在喂帧前重采样。\n                    // 也可在后续版本新增 sendFrameAsync 以便真正替换帧数据。\n                    // void resampleTo16kMono(f32, sr, ch).then(() => {});\n                    console.warn('IAT: 输入音频非16k单声道，建议预先重采样后再传入，或未来使用异步接口');\n                } catch {}\n            }\n        }\n\n        const audioData = toBase64(frame);\n        const message = {\n            data: {\n                status: isLast ? 2 : 1,\n                format: \"audio/L16;rate=16000\",\n                encoding: \"raw\",\n                audio: audioData,\n            },\n        };\n\n        console.log('发送音频帧:', {\n            isLast,\n            frameSize: frame instanceof ArrayBuffer ? frame.byteLength : frame.length,\n            audioDataLength: audioData.length,\n            wsReadyState: this.ws.readyState\n        });\n\n        this.ws.send(JSON.stringify(message));\n\n        if (isLast) this.status = \"closing\";\n    }\n\n    /**\n     * 重置客户端状态\n     */\n    override reset(): void {\n        super.reset();\n        this.resultTemp = \"\";\n        this.resultMap = new Map();\n    }\n\n    /**\n     * 关闭WebSocket连接\n     */\n    override close(): void {\n        if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n            this.ws.close();\n        }\n        this.ws = null;\n    }\n}\n\n\n","import { useEffect, useRef, useState } from \"react\";\nimport { BaseXfyunClient, BaseXfyunClientOptions } from \"../core/BaseXfyunClient\";\n\n/**\n * 基础Hook状态类型\n */\nexport type BaseHookStatus = \"idle\" | \"connecting\" | \"open\" | \"closing\" | \"closed\" | \"error\";\n\n/**\n * 基础Hook选项\n */\nexport interface BaseHookOptions extends BaseXfyunClientOptions {\n    /** 是否自动清理资源 */\n    autoCleanup?: boolean;\n}\n\n/**\n * 基础讯飞Hook\n * \n * 提供所有讯飞Hook的通用功能：\n * - 统一的状态管理\n * - 统一的错误处理\n * - 统一的资源清理\n * \n * @template T 具体的客户端类型\n * @template O 具体的选项类型\n */\nexport function useBaseXfyun<T extends BaseXfyunClient<O>, O extends BaseHookOptions = BaseHookOptions>(\n    createClient: (options?: O) => T,\n    options?: O\n) {\n    const [status, setStatus] = useState<BaseHookStatus>(\"idle\");\n    const [error, setError] = useState<string | null>(null);\n    const clientRef = useRef<T | null>(null);\n\n    /**\n     * 确保客户端实例存在\n     */\n    function ensureClient(): T {\n        if (!clientRef.current) {\n            const client = createClient(options);\n            clientRef.current = client;\n        }\n        return clientRef.current;\n    }\n\n\n    /**\n     * 重置状态\n     */\n    function reset(): void {\n        setError(null);\n        setStatus(\"idle\");\n        ensureClient().reset();\n    }\n\n    /**\n     * 关闭客户端\n     */\n    function close(): void {\n        if (clientRef.current) {\n            clientRef.current.close();\n        }\n    }\n\n    // 自动清理资源\n    useEffect(() => {\n        if (options?.autoCleanup !== false) {\n            return () => {\n                close();\n            };\n        }\n        return undefined;\n    }, []);\n\n    // 当核心配置变更时，重建底层客户端实例\n    useEffect(() => {\n        clientRef.current = null;\n    }, [options?.serverBase, options?.getAuthCode]);\n\n    return {\n        status,\n        error,\n        reset,\n        close,\n        ensureClient,\n        clientRef,\n    };\n}\n","import { useEffect, useRef } from \"react\";\nimport { TtsClient, TtsClientOptions, TtsBusiness } from \"../core/TtsClient\";\nimport { BaseXfyunClientOptions } from \"../core/BaseXfyunClient\";\nimport { getSharedAudioContext } from \"../utils/audio\";\nimport { useBaseXfyun } from \"./useBaseXfyun\";\n\n/**\n * TTS Hook选项\n */\nexport interface TtsOptions extends BaseXfyunClientOptions {\n    /** TTS业务参数配置 */\n    business?: TtsBusiness;\n    /** 音量电平回调（0-100） */\n    onLevel?: (level: number) => void;\n    /** MP3音频块回调 */\n    onMp3Chunk?: (bytes: Uint8Array) => void;\n    /** 合成完成回调 */\n    onComplete?: () => void;\n}\n\n/**\n * 科大讯飞语音合成(TTS) Hook\n * \n * 支持文字转语音功能，特点：\n * - WebSocket实时连接\n * - 支持多种音频格式（PCM/MP3）\n * - 实时音频播放\n * - 音量电平监控\n * \n * 使用示例：\n * ```typescript\n * const { status, error, speak, stop } = useTts({\n *   serverBase: 'http://localhost:8083',\n *   business: { aue: 'raw', vcn: 'x4_yezi', speed: 50 },\n *   onLevel: (level) => console.log('音量:', level)\n * });\n * \n * await speak('你好世界');\n * ```\n */\nexport function useTts(options?: TtsOptions) {\n    // 创建一个动态参数获取函数\n    const getCurrentOptions = () => ({\n        ...options,\n        business: options?.business\n    });\n\n    const { status, error, reset, close, ensureClient, clientRef } = useBaseXfyun(\n        (opts) => {\n            const currentOptions = getCurrentOptions();\n            return new TtsClient({\n                ...opts,\n                // 动态获取最新的业务参数\n                business: currentOptions.business,\n                onLevel: (level) => currentOptions.onLevel?.(level),\n                onMp3Chunk: (bytes) => currentOptions.onMp3Chunk?.(bytes),\n                onComplete: () => currentOptions.onComplete?.(),\n            } as TtsClientOptions);\n        },\n        options\n    );\n\n    const audioCtxRef = useRef<AudioContext | null>(null);\n    const sourceRef = useRef<AudioBufferSourceNode | null>(null);\n    const pcmQueueRef = useRef<Float32Array[]>([]);\n    const processingRef = useRef<boolean>(false);\n\n    /**\n     * 播放PCM音频队列\n     */\n    async function playPcmQueue(): Promise<void> {\n        if (processingRef.current) return;\n        processingRef.current = true;\n        \n        try {\n            if (!audioCtxRef.current) {\n                audioCtxRef.current = getSharedAudioContext(16000);\n            }\n            \n            const ctx = audioCtxRef.current;\n            \n            // 改进：顺序播放音频块，避免重叠和回声\n            let currentTime = ctx.currentTime;\n            while (pcmQueueRef.current.length) {\n                const floatData = pcmQueueRef.current.shift()!;\n                const audioBuffer = ctx.createBuffer(1, floatData.length, 16000);\n                const channelData = audioBuffer.getChannelData(0);\n                channelData.set(floatData);\n                \n                const src = ctx.createBufferSource();\n                src.buffer = audioBuffer;\n                src.connect(ctx.destination);\n                \n                // 确保连续播放，避免重叠\n                const startTime = Math.max(currentTime, ctx.currentTime + 0.01);\n                src.start(startTime);\n                \n                // 更新下次播放时间\n                currentTime = startTime + audioBuffer.duration;\n                sourceRef.current = src;\n                \n                // 等待当前音频块播放完成再播放下一个\n                await new Promise<void>((resolve) => {\n                    src.onended = () => resolve();\n                });\n            }\n        } finally {\n            processingRef.current = false;\n        }\n    }\n\n    /**\n     * 发起TTS合成并实时播放\n     * \n     * @param text 待合成的文本\n     * @throws Error 合成失败时抛出异常\n     */\n    async function speak(text: string): Promise<void> {\n        // 每次speak时重新创建客户端，确保使用最新的参数\n        const client = ensureClient();\n        \n        // 获取最新的选项参数\n        const currentOptions = getCurrentOptions();\n        \n        // 清空之前的音频队列，避免重叠播放\n        pcmQueueRef.current = [];\n        \n        // 设置音频处理回调\n        client.onAudio = (bytes) => {\n            const samples = Math.floor(bytes.byteLength / 2);\n            const float32 = new Float32Array(samples);\n            const view = new DataView(bytes.buffer);\n            for (let i = 0; i < samples; i++) {\n                float32[i] = view.getInt16(i * 2, true) / 0x8000;\n            }\n            pcmQueueRef.current.push(float32);\n            playPcmQueue();\n        };\n        \n        await client.speak(text);\n    }\n\n    /**\n     * 停止播放并清空缓存\n     */\n    function stop(): void {\n        if (clientRef.current) {\n            clientRef.current.close();\n        }\n        sourceRef.current?.stop();\n        pcmQueueRef.current = [];\n    }\n\n    /**\n     * 强制重新创建客户端（用于参数更新）\n     */\n    function forceRecreate(): void {\n        if (clientRef.current) {\n            (clientRef.current as any).forceRecreate?.();\n        }\n        pcmQueueRef.current = [];\n        // 强制重新创建客户端实例，确保使用最新参数\n        reset();\n    }\n\n    // 当业务参数变更时，重建客户端实例\n    useEffect(() => {\n        ensureClient();\n    }, [JSON.stringify(options?.business)]);\n\n    return {\n        status,\n        error,\n        speak,\n        stop,\n        forceRecreate\n    };\n}\n\n\n","import { BaseXfyunClient, BaseXfyunClientOptions } from \"./BaseXfyunClient\";\nimport { getSharedAudioContext } from \"../utils/audio\";\n\n/**\n * TTS业务参数配置\n */\nexport interface TtsBusiness {\n    /** 音频编码，默认 \"raw\" */\n    aue?: string;\n    /** 发音人，默认 \"x4_yezi\" */\n    vcn?: string;\n    /** 语速（0-100），默认 50 */\n    speed?: number;\n    /** 音量（0-100），默认 50 */\n    volume?: number;\n    /** 音调（0-100），默认 50 */\n    pitch?: number;\n    /** 数字发音风格（按官方枚举/数值） */\n    rdn?: number | string;\n    /** 文本编码（默认 utf8，可覆盖） */\n    tte?: string;\n    /** 音频封装格式（默认 audio/L16;rate=16000，可覆盖） */\n    auf?: string;\n    /** 音库领域（如通用/教育等） */\n    ent?: string;\n}\n\n/**\n * TTS客户端选项\n */\nexport interface TtsClientOptions extends BaseXfyunClientOptions {\n    /** TTS业务参数配置 */\n    business?: TtsBusiness;\n    /** 音量电平回调（0-100） */\n    onLevel?: (level: number) => void;\n    /** MP3音频块回调 */\n    onMp3Chunk?: (bytes: Uint8Array) => void;\n    /** 合成完成回调 */\n    onComplete?: () => void;\n    /** 是否由SDK内置自动播放（PCM走WebAudio，MP3走MSE），默认 true */\n    autoplay?: boolean;\n    /** MP3 播放策略：\"mse\" | \"none\"，默认 \"mse\"（仅当 autoplay=true 且 aue=mp3 生效） */\n    mp3Playback?: \"mse\" | \"none\";\n    /** 自动播放被策略阻止时，是否绑定一次性手势触发以恢复播放（默认 true） */\n    autoplayGesture?: boolean;\n}\n\n/**\n * 科大讯飞语音合成(TTS)客户端\n *\n * 支持文字转语音功能，特点：\n * - WebSocket实时连接\n * - 支持多种音频格式（PCM/MP3）\n * - 实时音频播放\n * - 音量电平监控\n *\n * 使用示例：\n * ```typescript\n * const client = new TtsClient({\n *   serverBase: 'http://localhost:8083',\n *   business: { aue: 'raw', vcn: 'x4_yezi', speed: 50 },\n *   onLevel: (level) => console.log('音量:', level)\n * });\n * await client.speak('你好世界');\n * ```\n */\nexport class TtsClient extends BaseXfyunClient<TtsClientOptions> {\n    private ws: WebSocket | null = null;\n    public status: \"idle\" | \"connecting\" | \"open\" | \"playing\" | \"closed\" | \"error\" = \"idle\";\n\n    // 内置播放（PCM - WebAudio 队列）\n    private audioCtx: AudioContext | null = null;\n    private pcmQueue: Float32Array[] = [];\n    private pcmProcessing = false;\n    private pcmPaused = false;\n    private pcmCurrentSource: AudioBufferSourceNode | null = null;\n    private pcmScheduleAheadSec = 0.08; // 提前调度窗口\n    private pcmCursorTime = 0; // 相对于 ctx.currentTime 的累计播放时间\n    private pcmPlaybackComplete = false; // 标记PCM播放是否完成\n\n    // 内置播放（MP3 - MediaSource）\n    private mse: MediaSource | null = null;\n    private mseAudioEl: HTMLAudioElement | null = null;\n    private mseSourceBuffer: SourceBuffer | null = null;\n    private mseQueue: Uint8Array[] = [];\n    private mseAppending = false;\n\n    constructor(options?: TtsClientOptions) {\n        super(options);\n    }\n\n    /**\n     * 发起TTS合成并实时播放\n     *\n     * @param text 待合成的文本\n     * @throws Error 合成失败时抛出异常\n     */\n    async speak(text: string): Promise<void> {\n        this.reset();\n        this.status = \"connecting\";\n\n        try {\n            // 在用户手势触发的调用栈内尽早预热 MSE，提升自动播放成功率\n            const wantMp3Autoplay = (this.options.autoplay !== false) && ((this.options.mp3Playback ?? \"mse\") === \"mse\") && ((this.options.business?.aue || \"raw\") === \"mp3\");\n            if (wantMp3Autoplay) {\n                this.ensureMse();\n            }\n\n            const signData = await this.getSignature(\"tts\");\n            const { url, appId } = signData;\n\n            const ws = new WebSocket(url);\n            this.ws = ws;\n\n            ws.onopen = () => {\n                this.status = \"open\";\n\n                // 构建业务参数 - 动态读取最新的business参数\n                const currentBusiness = this.options.business || {};\n                const business: any = {\n                    aue: currentBusiness.aue || \"raw\",\n                    vcn: currentBusiness.vcn || \"x4_yezi\",\n                    speed: currentBusiness.speed ?? 50,\n                    volume: currentBusiness.volume ?? 50,\n                    pitch: currentBusiness.pitch ?? 50,\n                    tte: currentBusiness.tte || \"utf8\",\n                    auf: currentBusiness.auf || \"audio/L16;rate=16000\",\n                };\n\n                // 添加其他可选参数\n                if (this.options.business?.rdn !== undefined) business.rdn = this.options.business.rdn;\n                if (this.options.business?.ent !== undefined) business.ent = this.options.business.ent;\n\n                console.log('TTS业务参数:', business);\n                console.log('TTS发音人:', business.vcn, '音频格式:', business.aue);\n\n                // 触发日志回调\n                this.options.onLog?.('info', {\n                    event: 'tts.parameters',\n                    message: `TTS参数已设置: 发音人=${business.vcn}, 音频格式=${business.aue}, 语速=${business.speed}, 音量=${business.volume}, 音调=${business.pitch}`,\n                    parameters: business\n                });\n                // 再次确保MP3播放资源就绪\n                if ((this.options.autoplay !== false) && ((this.options.mp3Playback ?? \"mse\") === \"mse\") && (business.aue === \"mp3\")) {\n                    this.ensureMse();\n                }\n\n                // 发送合成请求\n                const payload = {\n                    common: { app_id: appId },\n                    business,\n                    data: {\n                        status: 2,\n                        text: btoa(unescape(encodeURIComponent(text))),\n                    },\n                };\n                ws.send(JSON.stringify(payload));\n\n                // 统一会话追踪日志\n                this.options.onError?.('', undefined); // no-op to satisfy optional chain, keep existing behavior\n                this.options.onLog?.('info', {\n                    event: 'tts.open',\n                    sessionId: this.sessionId,\n                    appId,\n                    timestamp: Date.now(),\n                });\n            };\n\n            ws.onmessage = (evt) => {\n                try {\n                    const msg = JSON.parse(evt.data);\n                    if (msg.code !== 0) {\n                        this.processXfyunError(msg.code, msg.message || \"TTS失败\");\n                        ws.close();\n                        return;\n                    }\n\n                    const audio = msg.data?.audio;\n                    if (audio) {\n                        this.processAudioData(audio);\n                        // 触发音频数据接收日志\n                        this.options.onLog?.('info', {\n                            event: 'tts.audio_received',\n                            message: `收到音频数据: ${audio.length} 字符`,\n                            audioLength: audio.length\n                        });\n                    }\n                    // 一旦收到音频，进入 playing 状态\n                    if (this.status === \"open\") {\n                        this.status = \"playing\";\n                        this.options.onLog?.('info', {\n                            event: 'tts.playing',\n                            message: 'TTS开始播放'\n                        });\n                    }\n                } catch (error) {\n                    console.error(\"TTS消息解析错误:\", error);\n                }\n            };\n\n            ws.onerror = () => {\n                this.status = \"error\";\n                this.handleError(\"TTS连接错误\");\n            };\n\n            ws.onclose = () => {\n                this.status = \"closed\";\n                // 触发连接关闭日志\n                this.options.onLog?.('info', {\n                    event: 'tts.closed',\n                    message: 'TTS连接已关闭'\n                });\n                // 对于PCM格式，需要等待音频播放完成\n                this.schedulePlaybackCompleteCheck();\n            };\n        } catch (error) {\n            this.handleError(error instanceof Error ? error.message : \"TTS合成失败\");\n            throw error;\n        }\n    }\n\n    /**\n     * 处理音频数据\n     *\n     * @param audio Base64编码的音频数据\n     */\n    private processAudioData(audio: string): void {\n        const binary = atob(audio);\n        const len = binary.length;\n        const bytes = new Uint8Array(len);\n        let sum = 0;\n\n        for (let i = 0; i < len; i++) {\n            bytes[i] = binary.charCodeAt(i);\n        }\n\n        const aue = this.options.business?.aue || \"raw\";\n        if (aue === \"mp3\") {\n            // MP3 直接透传给上层，由上层 MSE 播放\n            this.options.onMp3Chunk?.(bytes);\n\n            // 内置自动播放（无界面）\n            if (this.options.autoplay !== false && (this.options.mp3Playback ?? \"mse\") === \"mse\") {\n                this.enqueueMp3(bytes);\n            }\n        } else {\n            // 计算音量电平（基于 Int16 -> Float32）\n            const samples = Math.floor(len / 2);\n            const view = new DataView(bytes.buffer);\n            for (let i = 0; i < samples; i++) {\n                const s = view.getInt16(i * 2, true) / 0x8000;\n                sum += s * s;\n            }\n\n            if (this.options.onLevel) {\n                const rms = Math.sqrt(sum / Math.max(1, samples));\n                const level = Math.min(100, Math.max(0, Math.round(rms * 140)));\n                this.options.onLevel(level);\n            }\n\n            // 透传 PCM 由上层播放\n            this.onAudio?.(bytes);\n\n            // 内置自动播放（WebAudio）\n            if (this.options.autoplay !== false) {\n                this.enqueuePcm(bytes);\n            }\n        }\n    }\n\n    /**\n     * 停止TTS合成并关闭客户端\n     */\n    public override close(): void {\n        this.ws?.close();\n        super.close();\n        this.teardownPlayback();\n    }\n\n    /**\n     * 强制重新创建客户端（用于参数更新）\n     */\n    public forceRecreate(): void {\n        this.close();\n        this.reset();\n        console.log('TTS客户端已强制重新创建');\n    }\n\n    /**\n     * 重置客户端状态\n     */\n    public override reset(): void {\n        super.reset();\n        this.pcmPlaybackComplete = false; // 重置播放完成标记\n    }\n\n    /** 音频数据回调，由上层设置 */\n    onAudio?: (pcmBytes: Uint8Array) => void;\n\n    // ============== 内置 PCM(WebAudio) 播放 ==============\n    private enqueuePcm(pcmBytes: Uint8Array) {\n        try {\n            const samples = Math.floor(pcmBytes.byteLength / 2);\n            const float32 = new Float32Array(samples);\n            const view = new DataView(pcmBytes.buffer);\n            for (let i = 0; i < samples; i++) {\n                float32[i] = view.getInt16(i * 2, true) / 0x8000;\n            }\n            this.pcmQueue.push(float32);\n            if (!this.pcmProcessing) void this.playPcmQueue();\n        } catch {\n            // ignore\n        }\n    }\n\n    private async playPcmQueue() {\n        if (this.pcmProcessing) return;\n        this.pcmProcessing = true;\n        try {\n            if (!this.audioCtx) {\n                this.audioCtx = getSharedAudioContext(16000);\n            }\n            const ctx = this.audioCtx;\n            if (this.pcmCursorTime < ctx.currentTime) this.pcmCursorTime = ctx.currentTime;\n\n            // 改进：顺序播放音频块，避免重叠和回声\n            while (this.pcmQueue.length) {\n                if (this.pcmPaused) {\n                    await new Promise(r => setTimeout(r, 10));\n                    continue;\n                }\n\n                const floatData = this.pcmQueue.shift()!;\n                const audioBuffer = ctx.createBuffer(1, floatData.length, 16000);\n                audioBuffer.getChannelData(0).set(floatData);\n                const src = ctx.createBufferSource();\n                src.buffer = audioBuffer;\n                src.connect(ctx.destination);\n\n                // 计算播放时间，确保连续播放\n                const startAt = Math.max(\n                    this.pcmCursorTime,\n                    ctx.currentTime + 0.01\n                );\n\n                try {\n                    src.start(startAt);\n                } catch {\n                    src.start();\n                }\n\n                // 更新播放时间\n                const duration = audioBuffer.duration;\n                this.pcmCursorTime = startAt + duration;\n\n                // 等待当前音频块播放完成再播放下一个\n                await new Promise<void>((resolve) => {\n                    src.onended = () => resolve();\n                });\n            }\n\n            // 所有音频块播放完成，检查是否需要触发onComplete\n            this.checkPlaybackComplete();\n        } finally {\n            this.pcmProcessing = false;\n            // 处理完成后再次检查，确保没有遗漏\n            setTimeout(() => this.checkPlaybackComplete(), 50);\n        }\n    }\n\n    /**\n     * 调度播放完成检查（延迟检查确保音频播放完成）\n     */\n    private schedulePlaybackCompleteCheck(): void {\n        // 立即检查一次\n        this.checkPlaybackComplete();\n\n        // 如果还没有完成，设置定时器继续检查\n        if (!this.pcmPlaybackComplete) {\n            const checkInterval = setInterval(() => {\n                this.checkPlaybackComplete();\n                if (this.pcmPlaybackComplete || this.status !== \"closed\") {\n                    clearInterval(checkInterval);\n                }\n            }, 100); // 每100ms检查一次\n\n            // 设置最大等待时间（10秒）\n            setTimeout(() => {\n                clearInterval(checkInterval);\n                if (!this.pcmPlaybackComplete) {\n                    this.options.onLog?.('warn', {\n                        event: 'tts.playback_timeout',\n                        message: 'TTS播放完成检查超时，强制触发完成回调'\n                    });\n                    this.checkPlaybackComplete();\n                }\n            }, 10000);\n        }\n    }\n\n    /**\n     * 检查播放是否完成并触发onComplete回调\n     */\n    private checkPlaybackComplete(): void {\n        // 调试日志\n        this.options.onLog?.('info', {\n            event: 'tts.playback_check',\n            message: '检查播放完成状态',\n            details: {\n                status: this.status,\n                queueLength: this.pcmQueue.length,\n                processing: this.pcmProcessing,\n                completed: this.pcmPlaybackComplete\n            }\n        });\n\n        // 只有在连接已关闭且没有更多音频数据时才触发完成回调\n        if (this.status === \"closed\" && this.pcmQueue.length === 0 && !this.pcmProcessing) {\n            if (!this.pcmPlaybackComplete) {\n                this.pcmPlaybackComplete = true;\n                this.options.onLog?.('info', {\n                    event: 'tts.playback_complete',\n                    message: 'TTS音频播放完成'\n                });\n                this.options.onComplete?.();\n            }\n        }\n    }\n\n    // ============== 内置 MP3(MediaSource) 播放 ==============\n    private ensureMse() {\n        if (this.mse && this.mseSourceBuffer && this.mseAudioEl) return;\n        if (typeof window === 'undefined' || typeof MediaSource === 'undefined') return;\n        this.mse = new MediaSource();\n        const audioEl = document.createElement('audio');\n        audioEl.autoplay = true;\n        audioEl.controls = false; // 不挂载到DOM，无界面\n        this.mseAudioEl = audioEl;\n        audioEl.src = URL.createObjectURL(this.mse);\n        // 将隐藏播放器挂到DOM以提高自动播放成功率\n        try {\n            audioEl.style.display = 'none';\n            document.body && document.body.appendChild(audioEl);\n        } catch {}\n        this.mse.addEventListener('sourceopen', () => {\n            if (!this.mse) return;\n            if (!this.mseSourceBuffer) {\n                this.mseSourceBuffer = this.mse.addSourceBuffer('audio/mpeg');\n                this.mseSourceBuffer.mode = 'sequence';\n                this.mseSourceBuffer.addEventListener('updateend', () => this.flushMseQueue());\n                this.flushMseQueue();\n            }\n        });\n        // 添加播放完成监听\n        audioEl.addEventListener('ended', () => {\n            this.options.onLog?.('info', {\n                event: 'tts.mp3_playback_complete',\n                message: 'TTS MP3播放完成'\n            });\n            this.options.onComplete?.();\n        });\n\n        // 为MP3播放添加超时保护\n        audioEl.addEventListener('loadstart', () => {\n            // 设置MP3播放超时（15秒）\n            setTimeout(() => {\n                if (this.status === \"closed\" && !this.pcmPlaybackComplete) {\n                    this.options.onLog?.('warn', {\n                        event: 'tts.mp3_playback_timeout',\n                        message: 'TTS MP3播放超时，强制触发完成回调'\n                    });\n                    this.options.onComplete?.();\n                }\n            }, 15000);\n        });\n\n        // 开始播放\n        void audioEl.play().catch(() => {\n            // autoplay might be blocked; optionally bind one-time gesture to resume\n            if (this.options.autoplayGesture === false) return;\n            const resume = () => {\n                try { void audioEl.play(); } catch {}\n                off();\n            };\n            const off = () => {\n                try { window.removeEventListener('click', resume, true); } catch {}\n                try { window.removeEventListener('touchstart', resume, true); } catch {}\n                try { window.removeEventListener('keydown', resume, true); } catch {}\n            };\n            try {\n                window.addEventListener('click', resume, true);\n                window.addEventListener('touchstart', resume, true);\n                window.addEventListener('keydown', resume, true);\n            } catch {}\n        });\n    }\n\n    private enqueueMp3(chunk: Uint8Array) {\n        this.ensureMse();\n        if (!this.mseSourceBuffer) {\n            this.mseQueue.push(chunk);\n            return;\n        }\n        this.mseQueue.push(chunk);\n        this.flushMseQueue();\n    }\n\n    private flushMseQueue() {\n        if (!this.mseSourceBuffer || this.mseSourceBuffer.updating) return;\n        const next = this.mseQueue.shift();\n        if (!next) return;\n        try {\n            // 始终复制成新的 ArrayBuffer，避免 SharedArrayBuffer/偏移与类型不兼容\n            const copied = new Uint8Array(next); // copy\n            const ab: ArrayBuffer = copied.buffer;\n            this.mseSourceBuffer.appendBuffer(ab);\n        } catch {\n            // 如果 append 异常，丢弃本帧并继续\n            this.flushMseQueue();\n        }\n    }\n\n    private teardownPlayback() {\n        // PCM\n        this.pcmQueue = [];\n        this.pcmCursorTime = 0;\n        this.pcmPaused = false;\n        try { this.pcmCurrentSource?.stop(); } catch {}\n        this.pcmCurrentSource = null;\n        if (this.audioCtx) {\n            try {\n                if (this.audioCtx.state !== 'closed') {\n                    this.audioCtx.close();\n                }\n            } catch {}\n            this.audioCtx = null;\n        }\n        this.pcmProcessing = false;\n\n        // MP3 MSE\n        this.mseQueue = [];\n        if (this.mseAudioEl) {\n            try { this.mseAudioEl.pause(); } catch {}\n            try { this.mseAudioEl.src = ''; } catch {}\n            this.mseAudioEl = null;\n        }\n        if (this.mseSourceBuffer) {\n            try {\n                if (this.mseSourceBuffer.updating) {\n                    this.mseSourceBuffer.abort();\n                }\n            } catch {}\n            this.mseSourceBuffer = null;\n        }\n        if (this.mse) {\n            try { if (this.mse.readyState === 'open') this.mse.endOfStream(); } catch {}\n            this.mse = null;\n        }\n    }\n\n    /**\n     * 主动请求触发一次自动播放（适用于外部在用户手势中调用）\n     */\n    public requestAutoplay(): void {\n        try { this.mseAudioEl && void this.mseAudioEl.play(); } catch {}\n    }\n\n    /** 暂停PCM播放（仅影响内置PCM播放） */\n    public pause(): void {\n        this.pcmPaused = true;\n        try { this.pcmCurrentSource?.stop(); } catch {}\n        this.pcmCurrentSource = null;\n    }\n\n    /** 恢复PCM播放 */\n    public resume(): void {\n        this.pcmPaused = false;\n        if (!this.pcmProcessing) void this.playPcmQueue();\n    }\n\n    /** 停止播放并清空队列 */\n    public stop(): void {\n        this.pcmPaused = false;\n        this.pcmQueue = [];\n        this.pcmCursorTime = 0;\n        try { this.pcmCurrentSource?.stop(); } catch {}\n        this.pcmCurrentSource = null;\n    }\n}\n\n\n","import { useEffect } from \"react\";\nimport { RtasrClient, RtasrClientOptions, RtasrBusiness } from \"../core/RtasrClient\";\nimport { BaseXfyunClientOptions } from \"../core/BaseXfyunClient\";\nimport { ErrorRecoveryStrategy } from \"../utils/errorMap\";\nimport { useBaseXfyun } from \"./useBaseXfyun\";\nimport { getRtasrConnectionPool } from \"../core/RtasrConnectionPool\";\n\n/**\n * RTASR Hook选项\n */\nexport interface RtasrOptions extends BaseXfyunClientOptions {\n    /** RTASR业务参数配置 */\n    business?: RtasrBusiness;\n    /** 识别增量文本回调 */\n    onResult?: (text: string, isFinal: boolean) => void;\n    /** 原始消息回调（调试用） */\n    onMessage?: (msg: any) => void;\n    /** 连接打开回调（包含 sid） */\n    onOpen?: (sid?: string) => void;\n    /** 连接关闭回调 */\n    onClose?: (code?: number, reason?: string) => void;\n    /** 心跳间隔（毫秒），0表示禁用 */\n    heartbeatMs?: number;\n    /** 最大重试次数（默认3） */\n    maxRetries?: number;\n    /** 重连退避策略（可选，不传使用默认） */\n    retryStrategy?: ErrorRecoveryStrategy;\n}\n\n/**\n * 科大讯飞实时语音转写(RTASR) Hook\n * \n * 支持长时间语音转文字功能，特点：\n * - WebSocket实时连接\n * - 支持连续音频流识别\n * - 自动重连机制\n * - 支持动态修正\n * \n * 使用示例：\n * ```typescript\n * const { status, error, open, sendFrame, close, reset } = useRtasr({\n *   serverBase: 'http://localhost:8083',\n *   business: { language: 'zh_cn', domain: 'rtasr' },\n *   onResult: (text, isFinal) => console.log(text, isFinal)\n * });\n * \n * await open();\n * sendFrame(audioData, false);\n * ```\n */\nexport function useRtasr(options?: RtasrOptions) {\n    const { status, error, reset, close: baseClose, ensureClient, clientRef } = useBaseXfyun(\n        (opts) => new RtasrClient({\n            ...opts,\n            onResult: (text, isFinal) => options?.onResult?.(text, isFinal),\n            onMessage: (msg) => options?.onMessage?.(msg),\n            onOpen: (sid) => options?.onOpen?.(sid),\n            onClose: (code, reason) => options?.onClose?.(code, reason),\n            onError: (message, sid) => options?.onError?.(message, sid),\n            heartbeatMs: options?.heartbeatMs,\n            maxRetries: options?.maxRetries,\n            retryStrategy: options?.retryStrategy,\n        } as RtasrClientOptions),\n        options\n    );\n\n    /**\n     * 建立RTASR WebSocket连接并发送首帧\n     * \n     * @throws Error 连接失败时抛出异常\n     */\n    async function open(): Promise<void> {\n        try {\n            // 使用连接池获取连接\n            const pool = getRtasrConnectionPool();\n            const client = await pool.getConnection(options || {});\n            \n            // 更新客户端引用\n            clientRef.current = client;\n        } catch (error) {\n            throw error;\n        }\n    }\n\n    /**\n     * 发送音频帧\n     * \n     * @param frame 音频帧数据\n     * @param isLast 是否为最后一帧\n     */\n    function sendFrame(frame: ArrayBuffer, isLast: boolean): void {\n        const client = ensureClient();\n        client.sendFrame(frame, isLast);\n    }\n\n    /**\n     * 关闭连接\n     */\n    function close(): void {\n        if (clientRef.current && options) {\n            const pool = getRtasrConnectionPool();\n            pool.closeConnection(options);\n        }\n        clientRef.current = null;\n        baseClose();\n    }\n\n    // 当业务参数变更时，重建客户端实例\n    useEffect(() => {\n        ensureClient();\n    }, [JSON.stringify(options?.business)]);\n\n    return {\n        status,\n        error,\n        open,\n        sendFrame,\n        close,\n        reset,\n        client: clientRef.current\n    };\n}\n\n\n","import { BaseXfyunClient, BaseXfyunClientOptions } from \"./BaseXfyunClient\";\nimport { validateAudioSpec, int16ToFloat32 } from \"../utils/audio\";\nimport { calculateRetryDelay, ErrorRecoveryStrategy, DEFAULT_RECOVERY_STRATEGY } from \"../utils/errorMap\";\n\n/**\n * RTASR业务参数配置\n */\nexport interface RtasrBusiness {\n    /** 语种，默认为 zh_cn */\n    language?: string;\n    /** 业务领域，固定为 rtasr */\n    domain?: string;\n    /** 方言/口音（中文场景），默认 mandarin */\n    accent?: string;\n    /** 静音断句阈值（毫秒），默认 2000 */\n    vad_eos?: number;\n    /** 动态修正开关，默认 \"wpgs\" */\n    dwa?: string;\n    /** 是否返回标点（1/0），默认 1 */\n    ptt?: 0 | 1;\n    /** 产品类型，默认 \"edu\" */\n    pd?: string;\n    /** 产品引擎 */\n    pd_engine?: string;\n    /** 结果语言 */\n    rlang?: string;\n    /** 候选结果数量 */\n    nbest?: number;\n    /** 候选词数量 */\n    wbest?: number;\n}\n\n/**\n * RTASR客户端选项\n */\nexport interface RtasrClientOptions extends BaseXfyunClientOptions {\n    /** RTASR业务参数配置 */\n    business?: RtasrBusiness;\n    /** 识别增量文本回调 */\n    onResult?: (text: string, isFinal: boolean) => void;\n    /** 原始消息回调（调试用） */\n    onMessage?: (msg: any) => void;\n    /** 连接打开回调（包含 sid） */\n    onOpen?: (sid?: string) => void;\n    /** 连接关闭回调 */\n    onClose?: (code?: number, reason?: string) => void;\n    /** 心跳间隔（毫秒），0表示禁用 */\n    heartbeatMs?: number;\n    /** 最大重试次数（默认3） */\n    maxRetries?: number;\n    /** 重连退避策略（可选，不传使用默认） */\n    retryStrategy?: ErrorRecoveryStrategy;\n    /** 输入采样率（用于自动重采样判断） */\n    inputSampleRate?: number;\n    /** 输入声道数（默认1） */\n    inputChannels?: number;\n    /** 是否自动重采样到16k单声道（默认false） */\n    autoResample?: boolean;\n}\n\n/**\n * 科大讯飞实时语音转写(RTASR)客户端\n *\n * 支持长时间语音转文字功能，特点：\n * - WebSocket实时连接\n * - 支持连续音频流识别\n * - 自动重连机制\n * - 支持动态修正\n *\n * 使用示例：\n * ```typescript\n * const client = new RtasrClient({\n *   serverBase: 'http://localhost:8083',\n *   business: { language: 'zh_cn', domain: 'rtasr' },\n *   onResult: (text, isFinal) => console.log(text, isFinal)\n * });\n * await client.open();\n * client.sendFrame(audioData, false);\n * ```\n */\nexport class RtasrClient extends BaseXfyunClient<RtasrClientOptions> {\n    private ws: WebSocket | null = null;\n    public status: \"idle\" | \"connecting\" | \"open\" | \"closing\" | \"closed\" = \"idle\";\n\n    private resultTemp = \"\";\n    private resultArray: Array<any | null> = [];\n    private appId = \"\";\n    private sid: string | undefined;\n    private started: boolean = false;\n    private pendingFrames: Array<{ frame: ArrayBuffer; isLast: boolean }> = [];\n    private lastMessageTime = 0;\n    private lastAudioTime = 0;\n    private messageCheckTimer: NodeJS.Timeout | null = null;\n    private audioTimeoutTimer: NodeJS.Timeout | null = null;\n    private heartbeatTimer: any = null;\n    private retryCount: number = 0;\n    private ended: boolean = false;\n    private sentEnd: boolean = false;\n    private visibilityHandler?: () => void;\n    private pausedByPageHidden: boolean = false;\n\n    constructor(options?: RtasrClientOptions) {\n        super(options);\n    }\n\n    /**\n     * 清理现有连接，确保完全关闭\n     */\n    private async cleanupExistingConnection(): Promise<void> {\n        if (this.ws) {\n            const ws = this.ws;\n            this.ws = null;\n            \n            // 等待WebSocket完全关闭\n            if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {\n                return new Promise<void>((resolve) => {\n                    const timeout = setTimeout(() => {\n                        resolve();\n                    }, 5000); // 5秒超时\n                    \n                    ws.onclose = () => {\n                        clearTimeout(timeout);\n                        resolve();\n                    };\n                    \n                    ws.onerror = () => {\n                        clearTimeout(timeout);\n                        resolve();\n                    };\n                    \n                    try {\n                        ws.close();\n                    } catch (e) {\n                        clearTimeout(timeout);\n                        resolve();\n                    }\n                });\n            }\n        }\n        \n        // 清理定时器\n        if (this.heartbeatTimer) {\n            clearInterval(this.heartbeatTimer);\n            this.heartbeatTimer = null;\n        }\n        if (this.messageCheckTimer) {\n            clearInterval(this.messageCheckTimer);\n            this.messageCheckTimer = null;\n        }\n        if (this.audioTimeoutTimer) {\n            clearInterval(this.audioTimeoutTimer);\n            this.audioTimeoutTimer = null;\n        }\n        \n        // 清理事件监听器\n        if (this.visibilityHandler) {\n            try {\n                document.removeEventListener('visibilitychange', this.visibilityHandler, false);\n            } catch {}\n            this.visibilityHandler = undefined as any;\n        }\n        \n        // 重置状态\n        this.started = false;\n        this.ended = false;\n        this.sentEnd = false;\n        this.pendingFrames = [];\n        this.retryCount = 0;\n    }\n\n    /**\n     * 建立RTASR WebSocket连接并发送首帧\n     *\n     * @throws Error 连接失败时抛出异常\n     */\n    async open(): Promise<void> {\n        // 检查当前状态，防止重复连接\n        if (this.status === \"connecting\") {\n            throw new Error(\"RTASR正在连接中，请等待连接完成\");\n        }\n        if (this.status === \"open\") {\n            throw new Error(\"RTASR连接已存在，请先关闭现有连接\");\n        }\n\n        // 先完全清理现有连接\n        await this.cleanupExistingConnection();\n\n        // 重置所有状态\n        this.reset();\n        this.status = \"connecting\";\n        this.ended = false;\n        this.sentEnd = false;\n        this.started = false;\n\n        try {\n            const signData = await this.getSignature(\"rtasr\");\n            const { url } = signData;\n            const appIdFromSign = signData.appId || signData.app_id;\n            this.appId = appIdFromSign || \"\";\n            if (!this.appId) {\n                const errorMsg = \"签名返回缺少appId/app_id，请检查后端签名服务配置\";\n                this.handleError(errorMsg);\n                throw new Error(errorMsg);\n            }\n\n            const ws = new WebSocket(url);\n            this.ws = ws;\n\n            // 等待底层连接建立（TCP/WS open）\n            await new Promise<void>((resolve, reject) => {\n                const timeout = setTimeout(() => {\n                    reject(new Error('WebSocket连接超时，请检查网络连接'));\n                }, 10000); // 10秒超时\n                \n                ws.onopen = () => {\n                    clearTimeout(timeout);\n                    resolve();\n                };\n                ws.onerror = (error) => {\n                    clearTimeout(timeout);\n                    reject(new Error(`WebSocket连接失败: ${error}`));\n                };\n            });\n\n            // 按官方文档，RTASR握手参数在URL上携带。建立连接后无需发送任何首帧JSON。\n            // 等待服务端返回 { action: 'started' } 后再发送二进制音频数据。\n\n            // 等待服务端 started 再认为就绪\n            await new Promise<void>((resolve, reject) => {\n                const startedTimeout = setTimeout(() => {\n                    reject(new Error('RTASR启动超时，未收到started消息，请检查服务端状态'));\n                }, 15000);\n\n                const prevOnMessage = ws.onmessage;\n                ws.onmessage = (evt) => {\n                    try {\n                        this.lastMessageTime = Date.now();\n                        if (!(evt.data instanceof ArrayBuffer)) {\n                            const msg = JSON.parse(evt.data);\n                            if (msg?.sid) this.sid = msg.sid;\n                            this.options.onMessage?.(msg);\n                            if (msg?.action === 'started' && (msg?.code === 0 || msg?.code === '0')) {\n                                clearTimeout(startedTimeout);\n                                this.started = true;\n                                this.status = 'open';\n                                this.retryCount = 0;\n                                this.options.onOpen?.(this.sid);\n                                console.log('RTASR连接建立成功，SID:', this.sid);\n                                // 冲刷队列\n                                this.flushPendingFrames();\n                                // 恢复onmessage链\n                                ws.onmessage = prevOnMessage as any;\n                                // 交给原有处理继续处理当前消息（如果需要）\n                                if (prevOnMessage) {\n                                    prevOnMessage.call(ws, evt as any);\n                                }\n                                resolve();\n                                return;\n                            }\n                        }\n                    } catch {}\n                    // 非 started 的消息，交由后续 onmessage 正常流程\n                    if (prevOnMessage) {\n                        prevOnMessage.call(ws, evt as any);\n                    }\n                };\n            });\n\n            // 官方不鼓励发送空JSON心跳，这里禁用默认心跳；若需保活，应由后端签名/网关层处理。\n            // 监听页面可见性，隐藏时暂停发送；可见时恢复\n            this.visibilityHandler = () => {\n                if (typeof document === 'undefined') return;\n                if (document.hidden) {\n                    this.pausedByPageHidden = true;\n                } else {\n                    this.pausedByPageHidden = false;\n                }\n            };\n            try { document.addEventListener('visibilitychange', this.visibilityHandler!, false); } catch {}\n\n            // 启动消息检查定时器\n            this.messageCheckTimer = setInterval(() => {\n                const now = Date.now();\n                const timeSinceLastMessage = now - this.lastMessageTime;\n                if (timeSinceLastMessage > 10000 && this.lastMessageTime > 0) {\n                    console.warn('RTASR: 已超过10秒未收到服务器消息');\n                }\n            }, 5000);\n\n            // 启动音频发送超时检测（根据API文档：音频发送间隔超时时间为15秒）\n            // 注意：只有在连接建立后才启用超时检测，避免在静音期间误关闭\n            this.audioTimeoutTimer = setInterval(() => {\n                const now = Date.now();\n                const timeSinceLastAudio = now - this.lastAudioTime;\n                // 只有在已经发送过音频数据且超过30秒未发送时才关闭（给用户更多缓冲时间）\n                if (timeSinceLastAudio > 30000 && this.lastAudioTime > 0 && this.status === 'open') {\n                    console.error('RTASR: 超过30秒未发送音频数据，连接将被关闭');\n                    this.handleError('音频发送超时');\n                    ws.close();\n                }\n            }, 10000); // 每10秒检查一次，减少检查频率\n\n            ws.onmessage = (evt) => {\n                try {\n                    this.lastMessageTime = Date.now();\n\n                    // 检查消息类型\n                    if (evt.data instanceof ArrayBuffer) {\n                        console.log('RTASR收到二进制消息，长度:', evt.data.byteLength);\n                        return;\n                    }\n\n                    // 处理文本消息（JSON格式）\n                    const msg = JSON.parse(evt.data);\n\n                    console.log('RTASR收到服务器消息:', {\n                        action: msg.action,\n                        code: msg.code,\n                        desc: msg.desc,\n                        sid: msg.sid,\n                        hasData: !!msg.data,\n                        dataLength: msg.data ? msg.data.length : 0\n                    });\n\n                    if (msg?.sid) {\n                        this.sid = msg.sid;\n                    }\n\n                    this.options.onMessage?.(msg);\n\n                    // 处理连接建立消息（冗余保护）\n                    if (msg?.action === 'started' && (msg?.code === 0 || msg?.code === '0')) {\n                        if (!this.started) {\n                            this.started = true;\n                            this.status = 'open';\n                            this.retryCount = 0;\n                            this.options.onOpen?.(this.sid);\n                            console.log('RTASR连接建立成功，SID:', this.sid);\n                            this.flushPendingFrames();\n                        }\n                    }\n\n                    // 处理识别结果\n                    if (msg?.action === 'result' && (msg?.code === '0' || msg?.code === 0)) {\n                        console.log('RTASR收到识别结果:', {\n                            action: msg.action,\n                            code: msg.code,\n                            data: msg.data,\n                            desc: msg.desc,\n                            sid: msg.sid\n                        });\n                        this.processRecognitionResult(msg);\n                    }\n\n                    // 处理错误消息\n                    else if (msg?.code !== 0 && msg?.code !== '0') {\n                        console.error('RTASR收到错误消息:', {\n                            action: msg.action,\n                            code: msg.code,\n                            desc: msg.desc,\n                            sid: msg.sid\n                        });\n                        this.processXfyunError(msg?.code, msg?.message, this.sid, {\n                            lastEvent: 'rtasr.onmessage',\n                            wsReadyState: this.ws?.readyState,\n                        });\n                        ws.close();\n                    }\n                } catch (error) {\n                    console.error(\"RTASR消息解析错误:\", error);\n                    this.handleError('消息解析错误', this.sid, { lastEvent: 'rtasr.onmessage.parseError' });\n                }\n            };\n\n            ws.onclose = (ev) => {\n                this.status = \"closed\";\n                this.ended = false;\n                if (this.heartbeatTimer) {\n                    clearInterval(this.heartbeatTimer);\n                    this.heartbeatTimer = null;\n                }\n                if (this.messageCheckTimer) {\n                    clearInterval(this.messageCheckTimer);\n                    this.messageCheckTimer = null;\n                }\n                if (this.audioTimeoutTimer) {\n                    clearInterval(this.audioTimeoutTimer);\n                    this.audioTimeoutTimer = null;\n                }\n                try { if (this.visibilityHandler) document.removeEventListener('visibilitychange', this.visibilityHandler, false); } catch {}\n\n                // 如果不是正常关闭，尝试重连（指数退避+抖动）\n                const maxRetries = this.options.maxRetries ?? DEFAULT_RECOVERY_STRATEGY.maxRetries;\n                if (!ev.wasClean && this.retryCount < maxRetries) {\n                    this.retryCount++;\n                    const strategy = this.options.retryStrategy ?? DEFAULT_RECOVERY_STRATEGY;\n                    const baseDelay = calculateRetryDelay(this.retryCount, strategy);\n                    const jitter = Math.floor(Math.random() * 300); // 0-300ms 抖动\n                    const delay = baseDelay + jitter;\n                    setTimeout(() => {\n                        this.open().catch(error => {\n                            console.error(`重连失败: ${error}`);\n                        });\n                    }, delay);\n                }\n\n                this.options.onClose?.(ev.code, ev.reason);\n            };\n\n            ws.onerror = (error) => {\n                this.handleError(\"WebSocket错误\", this.sid);\n            };\n        } catch (error) {\n            this.handleError(error instanceof Error ? error.message : \"连接失败\");\n            throw error;\n        }\n    }\n\n    /**\n     * 处理识别结果\n     *\n     * @param msg 消息数据\n     */\n    private processRecognitionResult(msg: any): void {\n        try {\n            const resultData = JSON.parse(msg.data);\n            let recognizedText = '';\n\n            // 处理普通识别结果\n            if (resultData.cn?.st?.rt) {\n                const rt = resultData.cn.st.rt;\n                for (const segment of rt) {\n                    if (segment.ws) {\n                        for (const word of segment.ws) {\n                            if (word.cw) {\n                                for (const char of word.cw) {\n                                    if (char.w) {\n                                        recognizedText += char.w;\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n            // 处理翻译结果\n            if (resultData.biz === 'trans') {\n                recognizedText = resultData.src || '';\n            }\n\n            if (recognizedText) {\n                this.resultTemp = recognizedText;\n                this.options.onResult?.(recognizedText, false);\n            }\n\n            // 检查是否为最终结果\n            const isFinal = resultData.cn?.st?.type === '0' || resultData.isEnd === true;\n            if (isFinal) {\n                this.options.onResult?.(recognizedText, true);\n            }\n        } catch (error) {\n            console.error('解析识别结果失败:', error);\n        }\n    }\n\n    /**\n     * 发送音频帧\n     *\n     * @param frame 音频帧数据\n     * @param isLast 是否为最后一帧\n     */\n    sendFrame(frame: ArrayBuffer, isLast: boolean): void {\n        // 结束后禁止继续入队/发送\n        if (this.ended || this.sentEnd) {\n            return;\n        }\n        // 页面隐藏时暂停发送\n        if (this.pausedByPageHidden) {\n            return;\n        }\n        // 握手未完成：统一入队，待 started 后冲刷\n        if (!this.started) {\n            this.pendingFrames.push({ frame, isLast });\n            return;\n        }\n        // 连接未就绪：不发送，但保守入队（避免数据丢失）\n        if (!this.ws || this.ws.readyState !== WebSocket.OPEN || this.status !== 'open') {\n            this.pendingFrames.push({ frame, isLast });\n            return;\n        }\n\n        // 调试日志：发送音频帧信息\n        console.log('RTASR发送音频帧:', {\n            isLast,\n            frameSize: frame.byteLength,\n            wsReadyState: this.ws.readyState,\n            status: this.status\n        });\n\n        // 如果是结束帧，发送结束标识（JSON格式）\n        if (isLast) {\n            const endMessage = JSON.stringify({end: true});\n            try {\n                this.ws.send(endMessage);\n            } catch {}\n            console.log('RTASR发送结束帧:', endMessage);\n            this.status = \"closing\";\n            this.ended = true;\n            this.sentEnd = true;\n            // 结束帧不更新音频时间，避免触发超时\n            return;\n        }\n\n        // 可选：对非16k/单声道输入进行重采样（同步接口仅告警，建议调用方预处理）\n        if (this.options.autoResample) {\n            const sr = this.options.inputSampleRate || 16000;\n            const ch = this.options.inputChannels || 1;\n            if (!validateAudioSpec({ sampleRate: sr, channels: ch, bitDepth: 16 })) {\n                try {\n                    const int16 = new Int16Array(frame);\n                    const f32 = int16ToFloat32(int16);\n                    // 同 IAT，暂不同步替换，给出提示\n                    // void resampleTo16kMono(f32, sr, ch).then(() => {});\n                    console.warn('RTASR: 输入音频非16k单声道，建议预先重采样后再传入，或未来使用异步接口');\n                } catch {}\n            }\n        }\n\n        // 检查音频数据是否有效\n        const int16Array = new Int16Array(frame);\n        const hasNonZeroData = int16Array.some(value => value !== 0);\n        const maxValue = Math.max(...Array.from(int16Array));\n        const minValue = Math.min(...Array.from(int16Array));\n\n        console.log('RTASR音频数据检查:', {\n            frameSize: frame.byteLength,\n            hasNonZeroData: hasNonZeroData,\n            maxValue: maxValue,\n            minValue: minValue\n        });\n\n        // 根据API文档，RTASR应该发送binary message（音频的二进制数据）\n        // 不是JSON格式，而是直接的音频二进制数据\n        console.log('RTASR发送二进制音频数据:', {\n            frameSize: frame.byteLength,\n            hasNonZeroData: hasNonZeroData,\n            maxValue: maxValue,\n            minValue: minValue\n        });\n\n        // 更新最后音频发送时间\n        this.lastAudioTime = Date.now();\n\n        // 发送二进制音频数据\n        this.ws.send(frame);\n    }\n\n    /**\n     * 冲刷等待队列\n     */\n    private flushPendingFrames(): void {\n        if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return;\n        const queue = this.pendingFrames;\n        this.pendingFrames = [];\n        for (const item of queue) {\n            if (this.ended || this.sentEnd) continue;\n            if (item.isLast) {\n                const endMessage = JSON.stringify({ end: true });\n                try { this.ws.send(endMessage); } catch {}\n                this.status = \"closing\";\n                this.ended = true;\n                this.sentEnd = true;\n            } else {\n                try { this.ws.send(item.frame); } catch {}\n                this.lastAudioTime = Date.now();\n            }\n        }\n    }\n\n    /**\n     * 重置客户端状态\n     */\n    override reset(): void {\n        super.reset();\n        this.resultTemp = \"\";\n        this.resultArray = [];\n        this.ended = false;\n    }\n\n    /**\n     * 关闭WebSocket连接\n     */\n    override close(): void {\n        // 使用异步清理，但不等待完成\n        this.cleanupExistingConnection().catch(() => {\n            // 忽略清理过程中的错误\n        });\n        this.status = \"closed\";\n    }\n}\n","import { RtasrClient, RtasrClientOptions } from './RtasrClient';\n\n/**\n * RTASR连接池管理器\n * \n * 提供连接复用和管理功能，支持多次调用\n */\nexport class RtasrConnectionPool {\n    private static instance: RtasrConnectionPool | null = null;\n    private connections: Map<string, RtasrClient> = new Map();\n    private connectionOptions: Map<string, RtasrClientOptions> = new Map();\n\n    private constructor() {}\n\n    /**\n     * 获取单例实例\n     */\n    static getInstance(): RtasrConnectionPool {\n        if (!RtasrConnectionPool.instance) {\n            RtasrConnectionPool.instance = new RtasrConnectionPool();\n        }\n        return RtasrConnectionPool.instance;\n    }\n\n    /**\n     * 生成连接键\n     */\n    private generateKey(options: RtasrClientOptions): string {\n        const business = options.business || {};\n        return JSON.stringify({\n            serverBase: options.serverBase,\n            language: business.language || 'zh_cn',\n            accent: business.accent || 'mandarin',\n            domain: business.domain || 'rtasr'\n        });\n    }\n\n    /**\n     * 获取或创建连接\n     */\n    async getConnection(options: RtasrClientOptions): Promise<RtasrClient> {\n        const key = this.generateKey(options);\n        \n        // 检查是否已有可用连接\n        let client = this.connections.get(key);\n        if (client && client.status === 'open') {\n            return client;\n        }\n\n        // 清理无效连接\n        if (client && (client.status === 'closed' || client.status === 'closing')) {\n            this.connections.delete(key);\n            this.connectionOptions.delete(key);\n        }\n\n        // 创建新连接\n        client = new RtasrClient(options);\n        this.connections.set(key, client);\n        this.connectionOptions.set(key, options);\n\n        try {\n            await client.open();\n            return client;\n        } catch (error) {\n            // 连接失败时清理\n            this.connections.delete(key);\n            this.connectionOptions.delete(key);\n            \n            // 提供更详细的错误信息\n            const errorMessage = error instanceof Error ? error.message : '未知错误';\n            throw new Error(`RTASR连接失败: ${errorMessage}。请检查网络连接和服务端状态。`);\n        }\n    }\n\n    /**\n     * 关闭指定连接\n     */\n    closeConnection(options: RtasrClientOptions): void {\n        const key = this.generateKey(options);\n        const client = this.connections.get(key);\n        \n        if (client) {\n            client.close();\n            this.connections.delete(key);\n            this.connectionOptions.delete(key);\n        }\n    }\n\n    /**\n     * 关闭所有连接\n     */\n    closeAllConnections(): void {\n        for (const [key, client] of this.connections) {\n            try {\n                client.close();\n            } catch (e) {\n                console.warn(`关闭连接 ${key} 时出错:`, e);\n            }\n        }\n        this.connections.clear();\n        this.connectionOptions.clear();\n    }\n\n    /**\n     * 获取连接状态\n     */\n    getConnectionStatus(options: RtasrClientOptions): 'none' | 'connecting' | 'open' | 'closed' | 'closing' | 'idle' {\n        const key = this.generateKey(options);\n        const client = this.connections.get(key);\n        \n        if (!client) {\n            return 'none';\n        }\n        \n        return client.status;\n    }\n\n    /**\n     * 获取连接数量\n     */\n    getConnectionCount(): number {\n        return this.connections.size;\n    }\n\n    /**\n     * 清理无效连接\n     */\n    cleanupInvalidConnections(): void {\n        for (const [key, client] of this.connections) {\n            if (client.status === 'closed' || client.status === 'closing') {\n                this.connections.delete(key);\n                this.connectionOptions.delete(key);\n            }\n        }\n    }\n}\n\n/**\n * 获取RTASR连接池实例\n */\nexport function getRtasrConnectionPool(): RtasrConnectionPool {\n    return RtasrConnectionPool.getInstance();\n}\n","import { useEffect, useState } from \"react\";\nimport { DtsClient, DtsClientOptions, DtsBusiness } from \"../core/DtsClient\";\nimport { BaseXfyunClientOptions } from \"../core/BaseXfyunClient\";\nimport { useBaseXfyun } from \"./useBaseXfyun\";\n\n/**\n * DTS Hook选项\n */\nexport interface DtsOptions extends DtsClientOptions {\n    // 继承 DtsClientOptions 的所有属性\n}\n\n/**\n * DTS Hook状态类型\n */\nexport type DtsStatus = \"idle\" | \"creating\" | \"querying\" | \"completed\" | \"error\";\n\n/**\n * 科大讯飞长文本语音合成(DTS) Hook\n *\n * 支持长文本语音合成功能，特点：\n * - HTTP API调用\n * - 支持10万字左右的长文本\n * - 异步任务处理\n * - 任务状态查询\n *\n * 使用示例：\n * ```typescript\n * const { status, error, taskId, result, createTask, waitForTask } = useDts({\n *   serverBase: 'http://localhost:8083',\n *   business: { aue: 'raw', vcn: 'x4_mingge', speed: 50 },\n *   onTaskCreated: (taskId) => console.log('任务ID:', taskId)\n * });\n *\n * const taskId = await createTask('很长的文本...');\n * const result = await waitForTask(taskId);\n * ```\n */\nexport function useDts(options?: DtsOptions) {\n    const { status: baseStatus, error, reset, ensureClient } = useBaseXfyun<DtsClient, DtsClientOptions>(\n        (opts) => new DtsClient({\n            serverBase: opts?.serverBase || '',\n            getAuthCode: opts?.getAuthCode || (() => ''),\n            ...opts,\n            onTaskCreated: (taskId) => {\n                setTaskId(taskId);\n                options?.onTaskCreated?.(taskId);\n            },\n            onTaskCompleted: (result) => {\n                setResult(result);\n                options?.onTaskCompleted?.(result);\n            },\n        }),\n        options\n    );\n\n    const [taskId, setTaskId] = useState<string | null>(null);\n    const [result, setResult] = useState<any>(null);\n\n    // 转换基础状态为DTS状态\n    const status: DtsStatus = baseStatus === \"open\" ? \"idle\" : baseStatus as DtsStatus;\n\n    /**\n     * 创建DTS任务\n     *\n     * @param text 待合成的文本\n     * @param business 业务参数（可选）\n     * @returns 任务ID\n     * @throws Error 创建失败时抛出异常\n     */\n    async function createTask(text: string, business?: DtsBusiness): Promise<string> {\n        const client = ensureClient();\n        const taskId = await client.createTask(text, business);\n        setTaskId(taskId);\n        return taskId;\n    }\n\n    /**\n     * 查询DTS任务状态\n     *\n     * @param taskId 任务ID\n     * @returns 任务状态数据\n     * @throws Error 查询失败时抛出异常\n     */\n    async function queryTask(taskId: string): Promise<any> {\n        const client = ensureClient();\n        const result = await client.queryTask(taskId);\n        if (result.status === 4) {\n            setResult(result);\n        }\n        return result;\n    }\n\n    /**\n     * 轮询查询任务直到完成\n     *\n     * @param taskId 任务ID\n     * @param intervalMs 轮询间隔（毫秒），默认2000\n     * @returns 任务完成后的结果数据\n     * @throws Error 任务失败或查询异常时抛出异常\n     */\n    async function waitForTask(taskId: string, intervalMs: number = 2000): Promise<any> {\n        const client = ensureClient();\n        const result = await client.waitForTask(taskId, intervalMs);\n        setResult(result);\n        return result;\n    }\n\n    /**\n     * 重置Hook状态\n     */\n    function resetDts(): void {\n        reset();\n        setTaskId(null);\n        setResult(null);\n    }\n\n    // 当业务参数变更时，重建客户端实例\n    useEffect(() => {\n        ensureClient();\n    }, [JSON.stringify(options?.business)]);\n\n    return {\n        status,\n        error,\n        taskId,\n        result,\n        createTask,\n        queryTask,\n        waitForTask,\n        reset: resetDts\n    };\n}\n","import { BaseXfyunClient, BaseXfyunClientOptions } from \"./BaseXfyunClient\";\n\n/**\n * DTS发音人配置\n */\nexport const DTS_VOICES = {\n  // 中文发音人\n  'x4_yeting': { name: '希涵', gender: '女', language: '中文/普通话', style: '游戏影视解说' },\n  'x4_guanyijie': { name: '关山-专题', gender: '男', language: '中文/普通话', style: '专题片纪录片' },\n  'x4_pengfei': { name: '小鹏', gender: '男', language: '中文/普通话', style: '新闻播报' },\n  'x4_qianxue': { name: '千雪', gender: '女', language: '中文/普通话', style: '阅读听书' },\n  'x4_lingbosong': { name: '聆伯松-老年男声', gender: '男', language: '中文/普通话', style: '阅读听书' },\n  'x4_xiuying': { name: '秀英-老年女声', gender: '女', language: '中文/普通话', style: '阅读听书' },\n  'x4_mingge': { name: '明哥', gender: '男', language: '中文/普通话', style: '阅读听书' },\n  'x4_doudou': { name: '豆豆', gender: '男', language: '中文/男童', style: '阅读听书' },\n  'x4_lingxiaoshan_profnews': { name: '聆小珊', gender: '女', language: '中文/普通话', style: '新闻播报' },\n  'x4_xiaoguo': { name: '小果', gender: '女', language: '中文/普通话', style: '新闻播报' },\n  'x4_xiaozhong': { name: '小忠', gender: '男', language: '中文/普通话', style: '新闻播报' },\n  'x4_yezi': { name: '小露', gender: '女', language: '中文/普通话', style: '通用场景' },\n  'x4_chaoge': { name: '超哥', gender: '男', language: '中文/普通话', style: '新闻播报' },\n  'x4_feidie': { name: '飞碟哥', gender: '男', language: '中文/普通话', style: '游戏影视解说' },\n  'x4_lingfeihao_upbeatads': { name: '聆飞皓-广告', gender: '男', language: '中文/普通话', style: '直播广告' },\n  'x4_wangqianqian': { name: '嘉欣', gender: '女', language: '中文/普通话', style: '直播广告' },\n  'x4_lingxiaozhen_eclives': { name: '聆小臻', gender: '女', language: '中文/普通话', style: '直播广告' },\n  // 其他发音人\n  'x4_EnUs_Catherine_profnews': { name: 'Catherine', gender: '女', language: '英语', style: '专业新闻' },\n  'x5_lingfeizhe': { name: '灵飞哲', gender: '男', language: '中文/普通话', style: '通用场景' },\n  'x5_lingxiaoxue': { name: '灵小雪', gender: '女', language: '中文/普通话', style: '通用场景' },\n  'x4_lingfeihong_document': { name: '聆飞红-文档', gender: '女', language: '中文/普通话', style: '文档阅读' },\n  'x4_lingfeichen_assist': { name: '聆飞晨-助手', gender: '男', language: '中文/普通话', style: '智能助手' },\n  'x4_lingxiaoqi_assist': { name: '聆小七-助手', gender: '女', language: '中文/普通话', style: '智能助手' },\n  'x4_lingfeihong_document_n': { name: '聆飞红-文档N', gender: '女', language: '中文/普通话', style: '文档阅读' }\n} as const;\n\n/**\n * DTS业务参数配置\n */\nexport interface DtsBusiness {\n    /** 音频编码，默认 \"raw\" */\n    aue?: string;\n    /** 发音人，默认 \"x4_mingge\" */\n    vcn?: 'x4_yeting' | 'x4_guanyijie' | 'x4_pengfei' | 'x4_qianxue' | 'x4_lingbosong' | 'x4_xiuying' | 'x4_mingge' | 'x4_doudou' | 'x4_lingxiaoshan_profnews' | 'x4_xiaoguo' | 'x4_xiaozhong' | 'x4_yezi' | 'x4_chaoge' | 'x4_feidie' | 'x4_lingfeihao_upbeatads' | 'x4_wangqianqian' | 'x4_lingxiaozhen_eclives' | 'x4_EnUs_Catherine_profnews' | 'x5_lingfeizhe' | 'x5_lingxiaoxue' | 'x4_lingfeihong_document' | 'x4_lingfeichen_assist' | 'x4_lingxiaoqi_assist' | 'x4_lingfeihong_document_n';\n    /** 语速（0-100），默认 50 */\n    speed?: number;\n    /** 音量（0-100），默认 50 */\n    volume?: number;\n    /** 音调（0-100），默认 50 */\n    pitch?: number;\n    /** 背景音（0-100），默认 0 */\n    bgs?: number;\n    /** 文本处理类型，默认 0 */\n    ttp?: number;\n}\n\n/**\n * DTS客户端选项\n */\nexport interface DtsClientOptions extends BaseXfyunClientOptions {\n    /** 后端服务基础地址（必需） */\n    serverBase: string;\n    /** 获取认证码的方法（必需） */\n    getAuthCode: () => string;\n    /** DTS业务参数配置 */\n    business?: DtsBusiness;\n    /** 任务创建回调 */\n    onTaskCreated?: (taskId: string) => void;\n    /** 任务完成回调 */\n    onTaskCompleted?: (result: any) => void;\n    /** 任务轮询超时时间（毫秒，默认 10 分钟） */\n    pollTimeoutMs?: number;\n    /** 任务轮询最大次数（默认 300 次） */\n    maxPollTimes?: number;\n}\n\n/**\n * 科大讯飞长文本语音合成(DTS)客户端\n * \n * 支持长文本语音合成功能，特点：\n * - HTTP API调用\n * - 支持10万字左右的长文本\n * - 异步任务处理\n * - 任务状态查询\n * \n * 使用示例：\n * ```typescript\n * const client = new DtsClient({\n *   serverBase: 'http://localhost:8083',\n *   business: { aue: 'raw', vcn: 'x4_mingge', speed: 50 },\n *   onTaskCreated: (taskId) => console.log('任务ID:', taskId)\n * });\n * const taskId = await client.createTask('很长的文本...');\n * const result = await client.waitForTask(taskId);\n * ```\n */\nexport class DtsClient extends BaseXfyunClient<DtsClientOptions> {\n    constructor(options?: DtsClientOptions) {\n        super(options);\n    }\n\n    /**\n     * 创建DTS任务\n     * \n     * @param text 待合成的文本\n     * @param business 业务参数（可选，会覆盖默认配置）\n     * @returns 任务ID\n     * @throws Error 创建失败时抛出异常\n     */\n    async createTask(text: string, business?: DtsBusiness): Promise<string> {\n        try {\n            this.reset();\n\n            // 1. 获取签名信息\n            const signData = await this.getSignature(\"dts/create\");\n            const { url, appId, host, date, authorization } = signData;\n            \n            // 2. 构建业务参数\n            const businessParams = {\n                aue: business?.aue || this.options.business?.aue || \"raw\",\n                vcn: business?.vcn || this.options.business?.vcn || \"x4_mingge\", // 使用当前API支持的发音人\n                speed: business?.speed ?? this.options.business?.speed ?? 50,\n                volume: business?.volume ?? this.options.business?.volume ?? 50,\n                pitch: business?.pitch ?? this.options.business?.pitch ?? 50,\n                bgs: business?.bgs ?? this.options.business?.bgs ?? 0,\n                ttp: business?.ttp ?? this.options.business?.ttp ?? 0,\n            };\n\n            // 3. 构建讯飞API请求体（使用官方示例格式）\n            const payload = {\n                header: {\n                    app_id: appId\n                },\n                parameter: {\n                    dts: {\n                        vcn: businessParams.vcn,\n                        language: \"zh\",\n                        speed: businessParams.speed,\n                        volume: businessParams.volume,\n                        pitch: businessParams.pitch,\n                        rhy: 1,\n                        audio: {\n                            encoding: \"lame\",\n                            sample_rate: 16000\n                        },\n                        pybuf: {\n                            encoding: \"utf8\",\n                            compress: \"raw\",\n                            format: \"plain\"\n                        }\n                    }\n                },\n                payload: {\n                    text: {\n                        encoding: \"utf8\",\n                        compress: \"raw\",\n                        format: \"plain\",\n                        text: btoa(unescape(encodeURIComponent(text)))\n                    }\n                }\n            };\n\n            // 4. 通过代理调用讯飞API（解决CORS问题）\n            // 将完整的讯飞API URL转换为代理路径\n            const proxyUrl = url.replace('https://api-dx.xf-yun.com', '');\n            \n            console.log('DTS请求URL:', url);\n            console.log('DTS代理URL:', proxyUrl);\n            console.log('DTS请求Host:', host);\n            console.log('DTS请求Date:', date);\n            console.log('DTS请求Authorization:', authorization);\n            \n            const response = await fetch(proxyUrl, {\n                method: 'POST',\n                headers: {\n                    'Content-Type': 'application/json'\n                },\n                body: JSON.stringify(payload)\n            });\n\n            if (!response.ok) {\n                throw new Error(`DTS创建任务失败: ${response.status} ${response.statusText}`);\n            }\n\n            const result = await response.json();\n            \n            console.log('DTS创建任务响应:', JSON.stringify(result, null, 2));\n\n            if (result.header?.code !== 0) {\n                throw new Error(`DTS创建任务失败: ${result.header?.message || '未知错误'}`);\n            }\n\n            const taskId = result.header?.task_id;\n            if (!taskId) {\n                throw new Error('DTS创建任务失败: 未返回task_id');\n            }\n\n            this.options.onTaskCreated?.(taskId);\n            this.options.onLog?.('info', {\n                event: 'dts.create',\n                sessionId: this.sessionId,\n                appId,\n                taskId,\n                timestamp: Date.now(),\n            });\n            return taskId;\n\n        } catch (error) {\n            this.handleError(error instanceof Error ? error.message : 'DTS创建任务失败');\n            throw error;\n        }\n    }\n\n    /**\n     * 查询DTS任务状态\n     * \n     * @param taskId 任务ID\n     * @returns 任务状态数据\n     * @throws Error 查询失败时抛出异常\n     */\n    async queryTask(taskId: string): Promise<any> {\n        try {\n            this.reset();\n\n            // 1. 获取签名信息\n            const signData = await this.getSignature(\"dts/query\");\n            const { url, appId, host, date, authorization } = signData;\n            \n            // 2. 构建讯飞API请求体（使用官方示例格式）\n            const payload = {\n                header: {\n                    app_id: appId,\n                    task_id: taskId\n                }\n            };\n\n            // 3. 通过代理调用讯飞API（解决CORS问题）\n            // 将完整的讯飞API URL转换为代理路径\n            const proxyUrl = url.replace('https://api-dx.xf-yun.com', '');\n            \n            console.log('DTS查询请求URL:', url);\n            console.log('DTS查询代理URL:', proxyUrl);\n            console.log('DTS查询请求Host:', host);\n            console.log('DTS查询请求Date:', date);\n            console.log('DTS查询请求Authorization:', authorization);\n            \n            const response = await fetch(proxyUrl, {\n                method: 'POST',\n                headers: {\n                    'Content-Type': 'application/json'\n                },\n                body: JSON.stringify(payload)\n            });\n\n            if (!response.ok) {\n                throw new Error(`DTS查询任务失败: ${response.status} ${response.statusText}`);\n            }\n\n            const result = await response.json();\n            \n            console.log('DTS查询任务响应:', JSON.stringify(result, null, 2));\n\n            if (result.header?.code !== 0) {\n                throw new Error(`DTS查询任务失败: ${result.header?.message || '未知错误'}`);\n            }\n\n            const data = result.payload;\n\n            // 如果任务完成，触发回调\n            if (result.header?.task_status === \"5\") { // 5表示任务处理成功\n                this.options.onTaskCompleted?.(data);\n            }\n\n            return {\n                status: result.header?.task_status,\n                data: data\n            };\n\n        } catch (error) {\n            this.handleError(error instanceof Error ? error.message : 'DTS查询任务失败');\n            throw error;\n        }\n    }\n\n    /**\n     * 轮询查询任务直到完成\n     * \n     * @param taskId 任务ID\n     * @param intervalMs 轮询间隔（毫秒），默认2000\n     * @returns 任务完成后的结果数据\n     * @throws Error 任务失败或查询异常时抛出异常\n     */\n    async waitForTask(taskId: string, intervalMs: number = 2000): Promise<any> {\n        const timeoutMs = this.options.pollTimeoutMs ?? 10 * 60 * 1000;\n        const maxTimes = this.options.maxPollTimes ?? 300;\n        const start = Date.now();\n        let times = 0;\n        return new Promise((resolve, reject) => {\n            const timer = setInterval(async () => {\n                try {\n                    times++;\n                    if (Date.now() - start > timeoutMs || times > maxTimes) {\n                        clearInterval(timer);\n                        reject(new Error('DTS任务轮询超时'));\n                        return;\n                    }\n                    const result = await this.queryTask(taskId);\n                    if (result.status === \"5\") { // 任务处理成功\n                        clearInterval(timer);\n                        this.options.onTaskCompleted?.(result.data);\n                        resolve(result.data);\n                    } else if (result.status === \"2\" || result.status === \"4\") { // 任务派发失败或处理失败\n                        clearInterval(timer);\n                        reject(new Error('DTS任务执行失败'));\n                    }\n                } catch (error) {\n                    clearInterval(timer);\n                    reject(error);\n                }\n            }, intervalMs);\n        });\n    }\n\n    /**\n     * 下载任务结果产物\n     * - 支持片段数组或单一直链\n     */\n    public async downloadResult(taskId: string, format?: string): Promise<Blob | null> {\n        try {\n            const result = await this.queryTask(taskId);\n            const data = result.data;\n            \n            // 检查是否有音频数据\n            if (!data?.audio?.audio) {\n                console.log('DTS下载: 没有找到音频数据', data);\n                return null;\n            }\n            \n            // 解码Base64编码的音频URL\n            const audioUrl = atob(data.audio.audio);\n            console.log('DTS下载: 音频URL', audioUrl);\n            \n            // 下载音频文件\n            const response = await fetch(audioUrl);\n            if (!response.ok) {\n                console.log('DTS下载: 音频下载失败', response.status, response.statusText);\n                return null;\n            }\n            \n            const blob = await response.blob();\n            console.log('DTS下载: 音频下载成功', blob.size, 'bytes');\n            \n            // 根据格式设置MIME类型\n            const mime = format === 'mp3' ? 'audio/mpeg' : \n                        (format === 'wav' ? 'audio/wav' : \n                        (format === 'pcm' ? 'audio/pcm' : 'application/octet-stream'));\n            \n            return new Blob([blob], { type: mime });\n        } catch (error) {\n            console.log('DTS下载: 下载失败', error);\n            return null;\n        }\n    }\n\n    /**\n     * 关闭DTS客户端\n     * \n     * DTS客户端使用HTTP API，无需特殊关闭逻辑\n     */\n    public override close(): void {\n        super.close();\n    }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { IatClient } from '../core/IatClient';\nimport { AUDIO_CONFIG, createScriptProcessor, getSharedAudioContext, calculateLevel, float32ToInt16 } from '../utils/audio';\n\n/**\n * useIatRecorder 选项\n * - client: IatClient 实例（需外部创建与配置）\n * - vadThreshold: 本地音量阈值（0-100），用于粗略静音门限显示/控制\n * - frameMs: 发送给服务端的帧长（毫秒），默认 40ms（约 640 samples @16kHz）\n */\nexport interface UseIatRecorderOptions {\n    client: IatClient;\n    vadThreshold?: number; // 0-100, 静音阈值（保留参数，当前用于电平显示）\n    frameMs?: number; // 帧长，默认40ms\n}\n\n/**\n * 基于浏览器麦克风的 IAT 录音 Hook。\n * - 内部通过 WebAudio 的 ScriptProcessor 聚合帧，并以 16bit PCM 发送给 IatClient\n * - 提供 recording/level 状态与 start/stop 控制方法\n */\nexport function useIatRecorder(options: UseIatRecorderOptions) {\n    const { client, vadThreshold = 3, frameMs = 40 } = options;\n    const [recording, setRecording] = useState(false);\n    const [level, setLevel] = useState(0);\n    const mediaStreamRef = useRef<MediaStream | null>(null);\n    const audioCtxRef = useRef<AudioContext | null>(null);\n    const processorRef = useRef<ScriptProcessorNode | null>(null);\n    const bufferRef = useRef<Float32Array[]>([]);\n    const lastSendTimeRef = useRef<number>(0);\n\n    // 清理 WebAudio 节点与麦克风流，防止资源泄漏\n    const cleanup = useCallback(() => {\n        try { processorRef.current && processorRef.current.disconnect(); } catch {}\n        try { audioCtxRef.current && audioCtxRef.current.destination.disconnect(); } catch {}\n        try { mediaStreamRef.current && mediaStreamRef.current.getTracks().forEach(t => t.stop()); } catch {}\n        processorRef.current = null;\n        audioCtxRef.current = null;\n        mediaStreamRef.current = null;\n        bufferRef.current = [];\n    }, []);\n\n    useEffect(() => () => { cleanup(); }, [cleanup]);\n\n    /**\n     * 开始录音并建立 IAT 连接\n     * - 申请麦克风权限，创建 AudioContext 与 ScriptProcessor\n     * - 按 frameMs 聚合样本并转换为 Int16 发送\n     */\n    const start = useCallback(async () => {\n        if (recording) return;\n        const stream = await navigator.mediaDevices.getUserMedia({ audio: { channelCount: 1, sampleRate: 16000 }, video: false });\n        mediaStreamRef.current = stream;\n        const audioCtx = getSharedAudioContext(AUDIO_CONFIG.DEFAULT_SAMPLE_RATE); // 统一的共享 AudioContext\n        audioCtxRef.current = audioCtx;\n        const source = audioCtx.createMediaStreamSource(stream);\n        const processor = createScriptProcessor(audioCtx, (data) => {\n            // 计算声级用于 UI 显示（0-100）\n            setLevel(calculateLevel(data));\n            // push 原始采样至缓冲\n            bufferRef.current.push(new Float32Array(data));\n            const now = Date.now();\n            const needBytes = Math.floor((AUDIO_CONFIG.DEFAULT_SAMPLE_RATE * (frameMs / 1000)) /* samples */);\n            // 尝试聚合足够样本后发送一帧\n            let total = 0;\n            for (const buf of bufferRef.current) total += buf.length;\n            if (total >= needBytes) {\n                const merged = new Float32Array(total);\n                let off = 0;\n                for (const buf of bufferRef.current) { merged.set(buf, off); off += buf.length; }\n                bufferRef.current = [];\n                const cut = merged.subarray(0, needBytes);\n                const int16 = float32ToInt16(cut); // Float32 -> Int16 PCM\n                client.sendFrame(int16, false); // 发送非最后一帧\n                lastSendTimeRef.current = now;\n            }\n        });\n        processorRef.current = processor;\n        source.connect(processor);\n        processor.connect(audioCtx.destination); // 挂到输出，部分浏览器需要连接到 destination 才会回调\n        if (client.status !== 'open') await client.open();\n        setRecording(true);\n    }, [client, frameMs, recording]);\n\n    /**\n     * 停止录音并发送结束帧\n     */\n    const stop = useCallback(() => {\n        if (!recording) return;\n        try { client.sendFrame(new Int16Array(0), true); } catch {}\n        cleanup();\n        setRecording(false);\n    }, [client, cleanup, recording]);\n\n    return { recording, level, start, stop };\n}\n\n\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { RtasrClient } from '../core/RtasrClient';\nimport { AUDIO_CONFIG, createScriptProcessor, getSharedAudioContext, float32ToInt16, releaseSharedAudioContext } from '../utils/audio';\n\n/**\n * useRtasrStream 选项\n * - client: RtasrClient 实例\n * - frameMs: 帧长（毫秒），默认 40ms\n */\nexport interface UseRtasrStreamOptions {\n    client: RtasrClient;\n    frameMs?: number; // 默认40ms\n}\n\n/**\n * 使用浏览器麦克风流向 RTASR 发送音频数据的 Hook。\n * - 内部以 ScriptProcessor 聚合帧并转换为 Int16 PCM，通过 WebSocket 发送\n * - 提供 streaming 状态与 start/stop 控制\n */\nexport function useRtasrStream(options: UseRtasrStreamOptions) {\n    const { client, frameMs = 40 } = options;\n    const [streaming, setStreaming] = useState(false);\n    const mediaStreamRef = useRef<MediaStream | null>(null);\n    const audioCtxRef = useRef<AudioContext | null>(null);\n    const processorRef = useRef<ScriptProcessorNode | null>(null);\n    const bufferRef = useRef<Float32Array[]>([]);\n\n    // 释放资源，断开节点与停止轨道\n    const cleanup = useCallback(() => {\n        try { \n            if (processorRef.current) {\n                processorRef.current.disconnect();\n                processorRef.current = null;\n            }\n        } catch (e) {\n            console.warn('断开ScriptProcessor时出错:', e);\n        }\n        \n        try { \n            if (mediaStreamRef.current) {\n                mediaStreamRef.current.getTracks().forEach(t => t.stop());\n                mediaStreamRef.current = null;\n            }\n        } catch (e) {\n            console.warn('停止媒体轨道时出错:', e);\n        }\n        \n        // 不直接关闭AudioContext，而是释放引用\n        try {\n            if (audioCtxRef.current) {\n                // 使用引用计数管理，避免重复关闭\n                releaseSharedAudioContext();\n                audioCtxRef.current = null;\n            }\n        } catch (e) {\n            console.warn('释放AudioContext时出错:', e);\n        }\n        \n        bufferRef.current = [];\n    }, []);\n\n    useEffect(() => () => { cleanup(); }, [cleanup]);\n\n    /**\n     * 开始采集与推流\n     */\n    const start = useCallback(async () => {\n        if (streaming) return;\n        const stream = await navigator.mediaDevices.getUserMedia({ audio: { channelCount: 1, sampleRate: 16000 }, video: false });\n        mediaStreamRef.current = stream;\n        const audioCtx = getSharedAudioContext(AUDIO_CONFIG.DEFAULT_SAMPLE_RATE);\n        audioCtxRef.current = audioCtx;\n        const source = audioCtx.createMediaStreamSource(stream);\n        const processor = createScriptProcessor(audioCtx, (data) => {\n            bufferRef.current.push(new Float32Array(data));\n            const needBytes = Math.floor((AUDIO_CONFIG.DEFAULT_SAMPLE_RATE * (frameMs / 1000)) /* samples */);\n            let total = 0;\n            for (const buf of bufferRef.current) total += buf.length;\n            if (total >= needBytes) {\n                const merged = new Float32Array(total);\n                let off = 0;\n                for (const buf of bufferRef.current) { merged.set(buf, off); off += buf.length; }\n                bufferRef.current = [];\n                const cut = merged.subarray(0, needBytes);\n                const int16 = float32ToInt16(cut);\n                // 显式拷贝为 ArrayBuffer，规避 SharedArrayBuffer 等兼容性\n                const ab = new Uint8Array(int16.buffer.slice(0)).buffer as ArrayBuffer;\n                client.sendFrame(ab, false);\n            }\n        });\n        processorRef.current = processor;\n        source.connect(processor);\n        processor.connect(audioCtx.destination); // 连接到输出，确保音频处理回调被触发\n        if (client.status !== 'open') await client.open();\n        setStreaming(true);\n    }, [client, frameMs, streaming]);\n\n    /**\n     * 停止推流，发送结束帧\n     */\n    const stop = useCallback(() => {\n        if (!streaming) return;\n        try { client.sendFrame(new ArrayBuffer(0), true); } catch {}\n        cleanup();\n        setStreaming(false);\n    }, [client, cleanup, streaming]);\n\n    return { streaming, start, stop };\n}\n\n\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { TtsClient } from '../core/TtsClient';\n\n/**\n * useTtsPlayer 选项\n * - client: TtsClient 实例\n */\nexport interface UseTtsPlayerOptions {\n    client: TtsClient;\n}\n\n/**\n * TTS 播放控制 Hook。\n * - 封装 speak/pause/resume/stop 控制\n * - 暴露播放状态与音量电平 level（0-100）\n */\nexport function useTtsPlayer({ client }: UseTtsPlayerOptions) {\n    const [status, setStatus] = useState<'idle' | 'connecting' | 'open' | 'playing' | 'closed' | 'error'>('idle');\n    const [level, setLevel] = useState(0);\n\n    useEffect(() => {\n        // 订阅音量电平回调\n        const onLevel = (lv: number) => setLevel(lv);\n        const orig = (client as any).onAudio;\n        (client as any).onLevel = onLevel;\n        return () => { (client as any).onLevel = undefined; (client as any).onAudio = orig; };\n    }, [client]);\n\n    useEffect(() => {\n        // 轮询同步客户端状态\n        const id = setInterval(() => setStatus(client.status as any), 100);\n        return () => clearInterval(id);\n    }, [client]);\n\n    /**\n     * 触发合成与播放。如果尚未连接，将在内部建立连接。\n     */\n    const speak = useCallback(async (text: string) => {\n        await client.speak(text);\n        setStatus(client.status as any);\n    }, [client]);\n\n    /** 暂停播放 */\n    const pause = useCallback(() => client.pause(), [client]);\n    /** 恢复播放 */\n    const resume = useCallback(() => client.resume(), [client]);\n    /** 停止播放并清空队列 */\n    const stop = useCallback(() => client.stop(), [client]);\n\n    return { status, level, speak, pause, resume, stop, requestAutoplay: () => client.requestAutoplay() };\n}\n\n\n","import { useRef, useCallback, useEffect, useState } from 'react';\nimport { StreamingTtsClient, StreamingTtsOptions } from '../core/StreamingTtsClient';\n\n/**\n * useStreamingTts 选项\n * 继承底层客户端选项（屏蔽底层回调以便由 Hook 转发）。\n */\nexport interface UseStreamingTtsOptions extends Omit<StreamingTtsOptions, 'onTextReceived' | 'onAudioReceived' | 'onPlaying' | 'onComplete' | 'onError' | 'onLog'> {\n    onTextReceived?: (text: string) => void;\n    onAudioReceived?: (audio: Uint8Array) => void;\n    onPlaying?: (isPlaying: boolean) => void;\n    onComplete?: () => void;\n    onError?: (error: string) => void;\n    onLog?: (level: 'info' | 'warn' | 'error', payload: any) => void;\n}\n\n/**\n * useStreamingTts 返回结果\n */\nexport interface UseStreamingTtsResult {\n    // 状态\n    status: 'idle' | 'connecting' | 'open' | 'synthesizing' | 'playing' | 'paused' | 'closed' | 'error';\n    isConnected: boolean;\n    isPlaying: boolean;\n    error: string | null;\n\n    // 控制方法\n    start: () => Promise<void>;\n    appendText: (text: string) => void;\n    endText: () => void;\n    pause: () => void;\n    resume: () => void;\n    stop: () => void;\n    close: () => void;\n    setLocalVolume: (v: number) => void;\n\n    // 文本管理\n    currentText: string;\n    totalTextLength: number;\n}\n\n/**\n * React Hook：流式语音合成\n * - 负责实例化 `StreamingTtsClient` 并通过回调事件驱动 React 状态\n * - 暴露便捷控制方法与本地音量控制\n * @param options Hook 配置，可覆盖客户端选项并接收 Hook 级别回调\n * @returns Hook 返回的状态、控制方法与文本统计\n */\nexport function useStreamingTts(options?: UseStreamingTtsOptions): UseStreamingTtsResult {\n    const clientRef = useRef<StreamingTtsClient | null>(null);\n    const [status, setStatus] = useState<'idle' | 'connecting' | 'open' | 'synthesizing' | 'playing' | 'paused' | 'closed' | 'error'>('idle');\n    const [isConnected, setIsConnected] = useState(false);\n    const [isPlaying, setIsPlaying] = useState(false);\n    const [error, setError] = useState<string | null>(null);\n    const [currentText, setCurrentText] = useState('');\n    const [totalTextLength, setTotalTextLength] = useState(0);\n\n    // 单例化客户端并桥接回调 → React 状态\n    const ensureClient = useCallback(() => {\n        if (!clientRef.current) {\n            clientRef.current = new StreamingTtsClient({\n                ...options,\n                business: options?.business || { aue: 'raw', vcn: 'x4_yezi', speed: 50, volume: 50, pitch: 50, tte: 'utf8', auf: 'audio/L16;rate=16000' },\n                onTextReceived: (text) => {\n                    setCurrentText(prev => prev + text);\n                    setTotalTextLength(prev => prev + text.length);\n                    options?.onTextReceived?.(text);\n                },\n                onAudioReceived: (audio) => {\n                    options?.onAudioReceived?.(audio);\n                },\n                onPlaying: (playing) => {\n                    setIsPlaying(playing);\n                    options?.onPlaying?.(playing);\n                },\n                onComplete: () => {\n                    setStatus('closed');\n                    setIsPlaying(false);\n                    options?.onComplete?.();\n                },\n                onError: (err) => {\n                    setError(err);\n                    setStatus('error');\n                    options?.onError?.(err);\n                },\n                onLog: (level, payload) => {\n                    options?.onLog?.(level, payload);\n                },\n                onOpen: () => {\n                    setIsConnected(true);\n                    setStatus('open');\n                },\n                onClose: () => {\n                    setIsConnected(false);\n                    setStatus('closed');\n                },\n                onStatusChange: (s) => {\n                    setStatus(s);\n                    setIsConnected(s === 'open' || s === 'synthesizing' || s === 'playing' || s === 'paused');\n                }\n            });\n        }\n        return clientRef.current;\n    }, [options]);\n\n    /** 开始流式合成：重置 Hook 状态并调用客户端 start */\n    const start = useCallback(async () => {\n        try {\n            setError(null);\n            setCurrentText('');\n            setTotalTextLength(0);\n\n            const client = ensureClient();\n            await client.start();\n            setStatus(client.getStatus());\n            setIsConnected(client.isConnected());\n        } catch (err) {\n            const errorMsg = err instanceof Error ? err.message : '启动流式TTS失败';\n            setError(errorMsg);\n            setStatus('error');\n            throw err;\n        }\n    }, [ensureClient]);\n\n    /** 追加文本（分片） */\n    const appendText = useCallback((text: string) => {\n        const client = clientRef.current;\n        if (!client) {\n            throw new Error('StreamingTtsClient not initialized');\n        }\n        client.appendText(text);\n    }, []);\n\n    /** 结束文本输入 */\n    const endText = useCallback(() => {\n        const client = clientRef.current;\n        if (!client) {\n            throw new Error('StreamingTtsClient not initialized');\n        }\n        client.endText();\n    }, []);\n\n    /** 暂停播放 */\n    const pause = useCallback(() => {\n        const client = clientRef.current;\n        if (!client) {\n            throw new Error('StreamingTtsClient not initialized');\n        }\n        client.pause();\n    }, []);\n\n    /** 恢复播放 */\n    const resume = useCallback(() => {\n        const client = clientRef.current;\n        if (!client) {\n            throw new Error('StreamingTtsClient not initialized');\n        }\n        client.resume();\n    }, []);\n\n    /** 停止合成并复位 Hook 状态 */\n    const stop = useCallback(() => {\n        const client = clientRef.current;\n        if (client) {\n            client.stop();\n            setStatus('idle');\n            setIsConnected(false);\n            setIsPlaying(false);\n            setCurrentText('');\n            setTotalTextLength(0);\n        }\n    }, []);\n\n    /** 关闭连接并释放资源 */\n    const close = useCallback(() => {\n        const client = clientRef.current;\n        if (client) {\n            client.close();\n            clientRef.current = null;\n            setStatus('idle');\n            setIsConnected(false);\n            setIsPlaying(false);\n            setCurrentText('');\n            setTotalTextLength(0);\n        }\n    }, []);\n\n    /** 设置本地音量（0..1） */\n    const setLocalVolume = useCallback((v: number) => {\n        const client = clientRef.current;\n        if (!client) {\n            throw new Error('StreamingTtsClient not initialized');\n        }\n        client.setLocalVolume(v);\n    }, []);\n\n    // 组件卸载时确保关闭连接\n    useEffect(() => {\n        return () => {\n            const client = clientRef.current;\n            if (client) {\n                client.close();\n            }\n        };\n    }, []);\n\n    return {\n        status,\n        isConnected,\n        isPlaying,\n        error,\n        start,\n        appendText,\n        endText,\n        pause,\n        resume,\n        stop,\n        close,\n        setLocalVolume,\n        currentText,\n        totalTextLength\n    };\n}\n","import { BaseXfyunClient, BaseXfyunClientOptions } from './BaseXfyunClient';\nimport { getSharedAudioContext, releaseSharedAudioContext } from '../utils/audio';\n\nexport type StreamingTtsStatus = \"idle\" | \"connecting\" | \"open\" | \"synthesizing\" | \"playing\" | \"paused\" | \"closed\" | \"error\";\n\n/**\n * StreamingTts 客户端配置\n */\nexport interface StreamingTtsOptions extends BaseXfyunClientOptions {\n    /**\n     * 业务参数（发送到服务端的合成参数）\n     */\n    business: {\n        /** 音频编码格式，例如 'raw'（PCM）或 'mp3' */\n        aue?: string;\n        /** 发音人，示例：'x4_yezi' */\n        vcn?: string;\n        /** 语速，0-100，默认 50 */\n        speed?: number;\n        /** 音量，0-100，默认 50（服务端合成音量） */\n        volume?: number;\n        /** 音调，0-100，默认 50 */\n        pitch?: number;\n        /** 文本编码，通常为 'utf8' */\n        tte?: string;\n        /** 采样率及格式，示例：'audio/L16;rate=16000' */\n        auf?: string;\n        /** 随机数（部分场景使用） */\n        rdn?: number;\n        /** 引擎类型（部分场景使用） */\n        ent?: string;\n    };\n    \n    // 回调函数\n    /**\n     * 文本接收回调\n     * @param text 已追加的原始文本片段\n     */\n    onTextReceived?: (text: string) => void;\n    /**\n     * 音频接收回调\n     * @param audio 原始音频字节（PCM: 16bit 小端，MP3: 二进制分片）\n     */\n    onAudioReceived?: (audio: Uint8Array) => void;\n    /**\n     * 播放状态回调\n     * @param isPlaying 是否处于播放中\n     */\n    onPlaying?: (isPlaying: boolean) => void;\n    /** 合成与播放整体完成回调（连接关闭且缓冲播放完毕后触发） */\n    onComplete?: () => void;\n    /**\n     * 错误回调\n     * @param error 具有人类可读信息的错误字符串\n     */\n    onError?: (error: string) => void;\n    /**\n     * 日志回调\n     * @param level 日志级别：'info' | 'warn' | 'error'\n     * @param payload 任意结构化日志载荷\n     */\n    onLog?: (level: 'info' | 'warn' | 'error', payload: any) => void;\n    /** WebSocket 连接建立回调（readyState=OPEN） */\n    onOpen?: () => void;\n    /** WebSocket 连接关闭回调（包括正常关闭与异常关闭） */\n    onClose?: () => void;\n    /**\n     * 客户端状态变化回调\n     * @param status 当前状态\n     */\n    onStatusChange?: (status: StreamingTtsStatus) => void;\n    \n    // 播放/连接控制\n    /** 是否自动播放（MP3/MSE 需在可用时尝试自动播放） */\n    autoplay?: boolean;\n    /** MP3 播放方式：'mse' 优先 MediaSource，'blob' 走 URL.createObjectURL */\n    mp3Playback?: 'mse' | 'blob';\n    /** 保活间隔毫秒，默认 30000 */\n    keepAliveIntervalMs?: number;\n    /** 空闲时（无文本/未结束）也发送保活，默认 false */\n    keepAliveWhenIdle?: boolean;\n    /** PCM 播放前瞻秒数，默认 0.08 */\n    audioScheduleAheadSec?: number;\n    /** 在最后一次 appendText 之后，若无新输入则在该毫秒后自动 endText */\n    autoEndAfterMs?: number;\n    /** 最小日志级别过滤，默认 'info' */\n    logLevel?: 'info' | 'warn' | 'error';\n    /**\n     * 启动重试策略\n     * - maxRetries: 最大重试次数（默认 0）\n     * - initialDelayMs: 初始延迟（默认 500）\n     * - factor: 退避乘数（默认 1.8）\n     */\n    retry?: { maxRetries?: number; initialDelayMs?: number; factor?: number };\n}\n\n/**\n * 流式语音合成客户端\n *\n * - 支持流式文本输入与实时音频播放（PCM/MP3）\n * - 单连接复用，提供暂停、恢复、停止控制\n * - 事件与日志回调丰富，便于生产观测\n */\nexport class StreamingTtsClient extends BaseXfyunClient<StreamingTtsOptions> {\n    private ws: WebSocket | null = null;\n    public status: StreamingTtsStatus = \"idle\";\n    \n    // 文本管理\n    private textBuffer: string = '';\n    private textEnded: boolean = false;\n    public override sessionId: string = '';\n    private appId: string = '';\n    private keepAliveInterval: NodeJS.Timeout | null = null;\n    private closing: boolean = false;\n    private inactivityTimer: ReturnType<typeof setTimeout> | null = null;\n    \n    // 音频播放管理\n    private audioCtx: AudioContext | null = null;\n    private pcmQueue: Float32Array[] = [];\n    private pcmProcessing = false;\n    private pcmPaused = false;\n    private pcmCurrentSource: AudioBufferSourceNode | null = null;\n    private pcmScheduleAheadSec = 0.08;\n    private pcmCursorTime = 0;\n    private pcmPlaybackComplete = false;\n    private gainNode: GainNode | null = null;\n    \n    // MP3播放管理\n    private mse: MediaSource | null = null;\n    private mseAudioEl: HTMLAudioElement | null = null;\n    private mseSourceBuffer: SourceBuffer | null = null;\n    private mseQueue: Uint8Array[] = [];\n    private mseAppending = false;\n    // blob 回退\n    private blobAudioEl: HTMLAudioElement | null = null;\n    private blobChunks: Uint8Array[] = [];\n    \n    constructor(options: StreamingTtsOptions) {\n        super(options);\n        if (typeof options.audioScheduleAheadSec === 'number') {\n            this.pcmScheduleAheadSec = Math.max(0, options.audioScheduleAheadSec);\n        }\n    }\n    \n    /**\n     * 写日志，遵循 logLevel 最小级别过滤\n     * @param level 日志级别\n     * @param payload 结构化日志内容\n     */\n    private log(level: 'info' | 'warn' | 'error', payload: any): void {\n        const order = { info: 0, warn: 1, error: 2 } as const;\n        const min = this.options.logLevel ?? 'info';\n        if (order[level] >= order[min]) {\n            this.options.onLog?.(level, payload);\n        }\n    }\n\n    /**\n     * 统一更新状态并派发 onStatusChange 回调\n     * @param next 下一个状态\n     */\n    private updateStatus(next: StreamingTtsStatus): void {\n        if (this.status === next) return;\n        this.status = next;\n        this.options.onStatusChange?.(next);\n    }\n\n    /**\n     * UTF-8 安全的 Base64 编码\n     * @param text 原始字符串\n     * @returns Base64 字符串\n     */\n    private encodeBase64Utf8(text: string): string {\n        const encoder = new TextEncoder();\n        const bytes = encoder.encode(text);\n        let binary = '';\n        for (let i = 0; i < bytes.length; i++) {\n            binary += String.fromCharCode(bytes[i]);\n        }\n        return btoa(binary);\n    }\n\n    /**\n     * 设置本地播放音量（0.0 - 1.0）\n     * @param volume 音量值\n     */\n    public setLocalVolume(volume: number): void {\n        if (!this.audioCtx) {\n            this.audioCtx = getSharedAudioContext(16000);\n        }\n        if (!this.gainNode) {\n            this.gainNode = this.audioCtx.createGain();\n            this.gainNode.connect(this.audioCtx.destination);\n        }\n        this.gainNode.gain.value = Math.max(0, Math.min(1, volume));\n    }\n\n    /**\n     * 重置自动结束计时器（用于 autoEndAfterMs）\n     */\n    private resetInactivityTimer(): void {\n        if (!this.options.autoEndAfterMs) return;\n        if (this.inactivityTimer) clearTimeout(this.inactivityTimer);\n        const delay = Math.max(1000, this.options.autoEndAfterMs);\n        this.inactivityTimer = setTimeout(() => {\n            try {\n                if ((this.status === 'open' || this.status === 'synthesizing') && !this.textEnded) {\n                    this.endText();\n                    this.log('info', { event: 'streaming_tts.auto_end', message: '自动结束文本输入' });\n                }\n            } catch {}\n        }, delay);\n    }\n    \n    /**\n     * 开始流式合成，建立 WebSocket 连接并预热播放资源\n     * @returns Promise，在连接建立或失败后决议\n     */\n    async start(): Promise<void> {\n        if (this.status !== 'idle') {\n            throw new Error('StreamingTtsClient is not in idle state');\n        }\n        \n        this.reset();\n        this.updateStatus('connecting');\n        this.closing = false;\n        \n        // 简单的初始连接重试策略\n        const maxRetries = this.options.retry?.maxRetries ?? 0;\n        const factor = this.options.retry?.factor ?? 1.8;\n        let delay = this.options.retry?.initialDelayMs ?? 500;\n\n        for (let attempt = 0; attempt <= maxRetries; attempt++) {\n            try {\n                await this.openWebSocket();\n                return;\n            } catch (e) {\n                if (attempt === maxRetries) {\n                    this.handleError(e instanceof Error ? e.message : '启动连接失败');\n                    throw e;\n                }\n                await new Promise(r => setTimeout(r, delay));\n                delay = Math.min(10000, Math.floor(delay * factor));\n                this.log('warn', { event: 'streaming_tts.retrying', attempt: attempt + 1, nextDelay: delay });\n            }\n        }\n    }\n\n    /**\n     * 建立 WebSocket 并绑定事件\n     * @returns Promise，在 onopen 时 resolve，若连接未能打开则 reject\n     */\n    private async openWebSocket(): Promise<void> {\n        const signData = await this.getSignature(\"tts\");\n        const { url, appId } = signData;\n        const ws = new WebSocket(url);\n        this.ws = ws;\n\n        return new Promise<void>((resolve, reject) => {\n            let opened = false;\n\n            ws.onopen = () => {\n                opened = true;\n                this.updateStatus('open');\n                this.sessionId = `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n                this.appId = appId;\n                \n                // 生成业务参数（一次，后续发送时复用构造器）\n                const business: any = this.buildBusinessParams();\n                \n                this.log('info', {\n                    event: 'streaming_tts.open',\n                    sessionId: this.sessionId,\n                    appId,\n                    timestamp: Date.now(),\n                    message: '流式TTS连接已建立'\n                });\n                \n                // 如果是 MP3 并选择 MSE，预先初始化播放器\n                if (this.options.autoplay !== false && \n                    (this.options.mp3Playback ?? \"mse\") === \"mse\" && \n                    business.aue === \"mp3\") {\n                    this.ensureMse();\n                } else if ((this.options.mp3Playback ?? 'mse') === 'blob' && business.aue === 'mp3') {\n                    this.ensureBlobAudio();\n                }\n                \n                // 启动连接保活机制\n                this.startKeepAlive();\n                \n                this.options.onOpen?.();\n                resolve();\n            };\n\n            ws.onmessage = (evt) => {\n                try {\n                    const msg = JSON.parse(evt.data);\n                    \n                    this.log('info', {\n                        event: 'streaming_tts.message',\n                        message: '收到WebSocket消息',\n                        data: msg\n                    });\n                    \n                    if (msg.code !== 0) {\n                        this.processXfyunError(msg.code, msg.message || \"流式TTS失败\");\n                        ws.close();\n                        return;\n                    }\n                    \n                    const audio = msg.data?.audio;\n                    if (audio) {\n                        this.processAudioData(audio);\n                        this.log('info', {\n                            event: 'streaming_tts.audio_received',\n                            message: `收到音频数据: ${audio.length} 字符`,\n                            audioLength: audio.length\n                        });\n                        \n                        // 首包音频到达时，标记进入合成中\n                        if (this.status === 'open') {\n                            this.updateStatus('synthesizing');\n                        }\n                    } else {\n                        this.log('info', {\n                            event: 'streaming_tts.non_audio_message',\n                            message: '收到非音频消息',\n                            data: msg.data\n                        });\n                    }\n                } catch (error) {\n                    this.handleError(`流式TTS消息解析失败: ${error instanceof Error ? error.message : '未知错误'}`);\n                }\n            };\n            \n            ws.onclose = (event) => {\n                if (this.closing && this.status === 'idle') {\n                    // stop/close 已优先将状态置为 idle\n                } else {\n                    this.updateStatus('closed');\n                }\n                this.stopKeepAlive();\n                this.log('info', {\n                    event: 'streaming_tts.closed',\n                    message: `流式TTS连接已关闭: ${event.code} ${event.reason || ''}`,\n                    code: event.code,\n                    reason: event.reason\n                });\n                this.schedulePlaybackCompleteCheck();\n                \n                this.options.onClose?.();\n                this.closing = false;\n                if (!opened) {\n                    reject(new Error('WebSocket closed before open'));\n                }\n            };\n            \n            ws.onerror = () => {\n                this.updateStatus('error');\n                this.handleError(\"流式TTS连接错误\");\n                if (!opened) {\n                    try { ws.close(); } catch {}\n                    reject(new Error('WebSocket error'));\n                }\n            };\n        });\n    }\n    \n    /**\n     * 追加文本片段（status=1）\n     * @param text 文本片段\n     */\n    appendText(text: string): void {\n        if (this.status !== 'open' && this.status !== 'synthesizing' && this.status !== 'playing' && this.status !== 'paused') {\n            throw new Error('StreamingTtsClient is not ready for text input');\n        }\n        if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n            throw new Error('WebSocket connection is not established');\n        }\n        \n        this.textBuffer += text;\n        this.resetInactivityTimer();\n        \n        const payload = {\n            common: { app_id: this.appId },\n            business: this.buildBusinessParams(),\n            data: {\n                status: 1,\n                text: this.encodeBase64Utf8(text),\n            },\n        };\n        \n        this.ws.send(JSON.stringify(payload));\n        \n        this.log('info', {\n            event: 'streaming_tts.text_sent',\n            message: '发送文本数据',\n            payload: payload\n        });\n        \n        this.options.onTextReceived?.(text);\n        this.log('info', {\n            event: 'streaming_tts.text_appended',\n            message: `追加文本: ${text.substring(0, 50)}${text.length > 50 ? '...' : ''}`,\n            textLength: text.length\n        });\n    }\n    \n    /**\n     * 结束文本输入（status=2）\n     */\n    endText(): void {\n        if (this.status !== 'open' && this.status !== 'synthesizing') {\n            throw new Error('StreamingTtsClient is not ready for text input');\n        }\n        if (!this.ws) {\n            throw new Error('WebSocket connection is not established');\n        }\n        \n        this.textEnded = true;\n        if (this.inactivityTimer) {\n            clearTimeout(this.inactivityTimer);\n            this.inactivityTimer = null;\n        }\n        \n        const payload = {\n            common: { app_id: this.appId },\n            business: this.buildBusinessParams(),\n            data: {\n                status: 2,\n                text: this.encodeBase64Utf8(''),\n            },\n        };\n        \n        this.ws.send(JSON.stringify(payload));\n        \n        this.log('info', {\n            event: 'streaming_tts.text_ended',\n            message: '文本输入已结束',\n            totalTextLength: this.textBuffer.length\n        });\n    }\n    \n    /**\n     * 暂停播放（仅在 playing 状态有效）\n     */\n    pause(): void {\n        if (this.status === 'playing') {\n            this.pcmPaused = true;\n            this.updateStatus('paused');\n            \n            if (this.pcmCurrentSource) {\n                this.pcmCurrentSource.stop();\n                this.pcmCurrentSource = null;\n            }\n            \n            this.options.onPlaying?.(false);\n            this.log('info', {\n                event: 'streaming_tts.paused',\n                message: '播放已暂停'\n            });\n        }\n    }\n    \n    /**\n     * 恢复播放（仅在 paused 状态有效）\n     */\n    resume(): void {\n        if (this.status === 'paused') {\n            this.pcmPaused = false;\n            this.updateStatus('playing');\n            \n            // 继续处理音频队列\n            void this.playPcmQueue();\n            \n            this.options.onPlaying?.(true);\n            this.log('info', {\n                event: 'streaming_tts.resumed',\n                message: '播放已恢复'\n            });\n        }\n    }\n    \n    /**\n     * 停止合成与播放，复位到 idle\n     */\n    stop(): void {\n        this.stopKeepAlive();\n        this.closing = true;\n        \n        if (this.ws) {\n            try { this.ws.close(); } catch {}\n            this.ws = null;\n        }\n        \n        this.pcmPaused = true;\n        this.pcmQueue = [];\n        this.textBuffer = '';\n        this.textEnded = false;\n        if (this.inactivityTimer) {\n            clearTimeout(this.inactivityTimer);\n            this.inactivityTimer = null;\n        }\n        \n        if (this.pcmCurrentSource) {\n            try { this.pcmCurrentSource.stop(); } catch {}\n            this.pcmCurrentSource = null;\n        }\n        \n        this.updateStatus('idle');\n        this.options.onPlaying?.(false);\n        this.log('info', {\n            event: 'streaming_tts.stopped',\n            message: '流式TTS已停止'\n        });\n    }\n    \n    /**\n     * 关闭连接并释放音频相关资源\n     */\n    public override close(): void {\n        this.stop();\n        // 释放MSE与audio元素资源\n        if (this.mseAudioEl) {\n            try { this.mseAudioEl.pause(); } catch {}\n            try { URL.revokeObjectURL(this.mseAudioEl.src); } catch {}\n            try { this.mseAudioEl.remove(); } catch {}\n        }\n        if (this.mseSourceBuffer) {\n            try { this.mseSourceBuffer.abort(); } catch {}\n        }\n        this.mseQueue = [];\n        this.mseAppending = false;\n        this.mseSourceBuffer = null;\n        this.mse = null;\n        this.mseAudioEl = null;\n        // 断开GainNode\n        if (this.gainNode) {\n            try { this.gainNode.disconnect(); } catch {}\n            this.gainNode = null;\n        }\n        // 释放blob音频资源\n        if (this.blobAudioEl) {\n            try { this.blobAudioEl.pause(); } catch {}\n            try { URL.revokeObjectURL(this.blobAudioEl.src); } catch {}\n            try { this.blobAudioEl.remove(); } catch {}\n            this.blobAudioEl = null;\n        }\n        this.blobChunks = [];\n        \n        releaseSharedAudioContext();\n    }\n    \n    /** 获取当前状态 */\n    getStatus(): StreamingTtsStatus {\n        return this.status;\n    }\n    \n    /** 是否处于连接态（open/synthesizing/playing/paused） */\n    isConnected(): boolean {\n        return this.status === 'open' || this.status === 'synthesizing' || this.status === 'playing' || this.status === 'paused';\n    }\n    \n    /** 是否处于播放态 */\n    isPlaying(): boolean {\n        return this.status === 'playing';\n    }\n    \n    /**\n     * 启动连接保活机制\n     */\n    private startKeepAlive(): void {\n        this.stopKeepAlive(); // 先停止现有的保活\n        const interval = typeof this.options.keepAliveIntervalMs === 'number' ? this.options.keepAliveIntervalMs : 30000;\n        const allowWhenIdle = !!this.options.keepAliveWhenIdle;\n        \n        this.keepAliveInterval = setInterval(() => {\n            // 空闲时根据配置决定是否发送心跳\n            if (allowWhenIdle || this.textBuffer.length > 0 || this.textEnded) {\n                this.sendKeepAliveData();\n            }\n        }, Math.max(1000, interval));\n    }\n    \n    /** 停止连接保活 */\n    private stopKeepAlive(): void {\n        if (this.keepAliveInterval) {\n            clearInterval(this.keepAliveInterval);\n            this.keepAliveInterval = null;\n        }\n    }\n    \n    /**\n     * 发送保活数据（status=0）\n     */\n    private sendKeepAliveData(): void {\n        if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n            const payload = {\n                common: { app_id: this.appId },\n                business: this.buildBusinessParams(),\n                data: { \n                    status: 0,\n                    text: this.encodeBase64Utf8('') // 空文本，但字段必需\n                }\n            };\n            \n            this.ws.send(JSON.stringify(payload));\n            \n            this.log('info', {\n                event: 'streaming_tts.keepalive_data',\n                message: '发送保活数据'\n            });\n        }\n    }\n    \n    /**\n     * 构建业务参数（含默认值与可选项）\n     * @returns 业务参数对象\n     */\n    private buildBusinessParams(): any {\n        const currentBusiness = this.options.business || {};\n        return {\n            aue: currentBusiness.aue || \"raw\",\n            vcn: currentBusiness.vcn || \"x4_yezi\",\n            speed: currentBusiness.speed ?? 50,\n            volume: currentBusiness.volume ?? 50,\n            pitch: currentBusiness.pitch ?? 50,\n            tte: currentBusiness.tte || \"utf8\",\n            auf: currentBusiness.auf || \"audio/L16;rate=16000\",\n            ...(currentBusiness.rdn !== undefined && { rdn: currentBusiness.rdn }),\n            ...(currentBusiness.ent !== undefined && { ent: currentBusiness.ent }),\n        };\n    }\n    \n    /** 根据业务配置将音频交给对应处理器 */\n    private processAudioData(audio: string): void {\n        const currentBusiness = this.options.business || {};\n        const aue = currentBusiness.aue || \"raw\";\n        \n        if (aue === \"raw\") {\n            this.processPcmAudio(audio);\n        } else if (aue === \"mp3\") {\n            this.processMp3Audio(audio);\n        }\n    }\n    \n    /**\n     * 处理 PCM 音频（16-bit 小端）并推入播放队列\n     * @param audio Base64 字符串形式的音频数据\n     */\n    private processPcmAudio(audio: string): void {\n        try {\n            const audioBytes = Uint8Array.from(atob(audio), c => c.charCodeAt(0));\n            const samples = Math.floor(audioBytes.length / 2);\n            const float32 = new Float32Array(samples);\n            const view = new DataView(audioBytes.buffer);\n            \n            for (let i = 0; i < samples; i++) {\n                // 16-bit PCM → Float32 [-1, 1]\n                float32[i] = view.getInt16(i * 2, true) / 0x8000;\n            }\n            \n            this.pcmQueue.push(float32);\n            void this.playPcmQueue();\n            \n            this.options.onAudioReceived?.(audioBytes);\n        } catch (error) {\n            this.handleError(`PCM音频处理失败: ${error instanceof Error ? error.message : '未知错误'}`);\n        }\n    }\n    \n    /**\n     * 处理 MP3 音频：优先 MSE，失败则 blob 兜底\n     * @param audio Base64 字符串形式的 MP3 数据分片\n     */\n    private processMp3Audio(audio: string): void {\n        try {\n            const audioBytes = Uint8Array.from(atob(audio), c => c.charCodeAt(0));\n            if ((this.options.mp3Playback ?? 'mse') === 'mse' && typeof MediaSource !== 'undefined') {\n                this.mseQueue.push(audioBytes);\n                this.flushMseQueue();\n            } else {\n                // blob 兜底：收集分片，结束后统一播放\n                this.blobChunks.push(audioBytes);\n            }\n            \n            this.options.onAudioReceived?.(audioBytes);\n        } catch (error) {\n            this.handleError(`MP3音频处理失败: ${error instanceof Error ? error.message : '未知错误'}`);\n        }\n    }\n    \n    /**\n     * 批量调度 PCM 队列，提高连贯性并降低卡顿\n     */\n    private async playPcmQueue(): Promise<void> {\n        if (this.pcmProcessing) return;\n        this.pcmProcessing = true;\n        \n        try {\n            if (!this.audioCtx) {\n                this.audioCtx = getSharedAudioContext(16000);\n            }\n            if (!this.gainNode) {\n                this.gainNode = this.audioCtx.createGain();\n                this.gainNode.connect(this.audioCtx.destination);\n            }\n            \n            const ctx = this.audioCtx;\n            if (this.pcmCursorTime < ctx.currentTime) {\n                this.pcmCursorTime = ctx.currentTime;\n            }\n            \n            const batchSize = 3;\n            while (this.pcmQueue.length) {\n                if (this.pcmPaused) {\n                    await new Promise(r => setTimeout(r, 10));\n                    continue;\n                }\n                \n                const batch = this.pcmQueue.splice(0, batchSize);\n                const promises = batch.map((floatData, index) => {\n                    return new Promise<void>((resolve) => {\n                        const audioBuffer = ctx.createBuffer(1, floatData.length, 16000);\n                        audioBuffer.getChannelData(0).set(floatData);\n                        const src = ctx.createBufferSource();\n                        src.buffer = audioBuffer;\n                        src.connect(this.gainNode!);\n                        \n                        // 使用可配置的前瞻时间，降低调度抖动\n                        const startAt = Math.max(\n                            this.pcmCursorTime + (index * 0.01),\n                            ctx.currentTime + (this.pcmScheduleAheadSec || 0.002)\n                        );\n                        \n                        try {\n                            src.start(startAt);\n                        } catch {\n                            src.start();\n                        }\n                        \n                        this.pcmCurrentSource = src;\n                        const duration = audioBuffer.duration;\n                        this.pcmCursorTime = Math.max(this.pcmCursorTime, startAt + duration);\n                        \n                        src.onended = () => resolve();\n                    });\n                });\n                \n                await Promise.all(promises);\n                \n                if (this.status === 'synthesizing') {\n                    this.updateStatus('playing');\n                    this.options.onPlaying?.(true);\n                }\n            }\n            \n            this.checkPlaybackComplete();\n        } finally {\n            this.pcmProcessing = false;\n            setTimeout(() => this.checkPlaybackComplete(), 50);\n        }\n    }\n    \n    /** 触发播放完成检查的定时流程 */\n    private schedulePlaybackCompleteCheck(): void {\n        this.checkPlaybackComplete();\n        \n        if (!this.pcmPlaybackComplete) {\n            const checkInterval = setInterval(() => {\n                this.checkPlaybackComplete();\n                if (this.pcmPlaybackComplete || this.status !== \"closed\") {\n                    clearInterval(checkInterval);\n                }\n            }, 100);\n            \n            setTimeout(() => {\n                clearInterval(checkInterval);\n                if (!this.pcmPlaybackComplete) {\n                    this.log('warn', {\n                        event: 'streaming_tts.playback_timeout',\n                        message: '流式TTS播放完成检查超时，强制触发完成回调'\n                    });\n                    this.checkPlaybackComplete();\n                }\n            }, 10000);\n        }\n    }\n    \n    /**\n     * 在连接 closed 且缓冲播放完毕时触发完成回调\n     */\n    private checkPlaybackComplete(): void {\n        if (this.status === \"closed\" && this.pcmQueue.length === 0 && !this.pcmProcessing && this.textEnded) {\n            if (!this.pcmPlaybackComplete) {\n                this.pcmPlaybackComplete = true;\n                // 如果是blob播放，关闭后开始一次性播放\n                if (this.blobChunks.length && !this.mseAudioEl) {\n                    // 合并所有 Uint8Array 分片为一个连续的 ArrayBuffer，避免 SharedArrayBuffer 类型问题\n                    const totalLen = this.blobChunks.reduce((n, u) => n + u.byteLength, 0);\n                    const merged = new Uint8Array(totalLen);\n                    let offsetPos = 0;\n                    for (const u of this.blobChunks) {\n                        merged.set(u, offsetPos);\n                        offsetPos += u.byteLength;\n                    }\n                    const all = new Blob([merged.buffer], { type: 'audio/mpeg' });\n                    this.ensureBlobAudio();\n                    if (this.blobAudioEl) {\n                        try { URL.revokeObjectURL(this.blobAudioEl.src); } catch {}\n                        this.blobAudioEl.src = URL.createObjectURL(all);\n                        void this.blobAudioEl.play().catch(() => {});\n                    }\n                }\n                this.log('info', {\n                    event: 'streaming_tts.playback_complete',\n                    message: '流式TTS音频播放完成'\n                });\n                this.options.onComplete?.();\n            }\n        }\n    }\n    \n    /**\n     * 初始化 MSE 播放器，不支持时自动降级为 blob\n     */\n    private ensureMse(): void {\n        if (this.mse && this.mseSourceBuffer && this.mseAudioEl) return;\n        if (typeof window === 'undefined' || typeof MediaSource === 'undefined') {\n            this.ensureBlobAudio();\n            return;\n        }\n        \n        const audioEl = document.createElement('audio');\n        audioEl.style.display = 'none';\n        document.body.appendChild(audioEl);\n        \n        this.mseAudioEl = audioEl;\n        this.mse = new MediaSource();\n        audioEl.src = URL.createObjectURL(this.mse);\n        \n        this.mse.addEventListener('sourceopen', () => {\n            if (!this.mse) return;\n            if (!this.mseSourceBuffer) {\n                this.mseSourceBuffer = this.mse.addSourceBuffer('audio/mpeg');\n                this.mseSourceBuffer.mode = 'sequence';\n                this.flushMseQueue();\n            }\n        });\n        \n        audioEl.addEventListener('ended', () => {\n            this.log('info', {\n                event: 'streaming_tts.mp3_playback_complete',\n                message: '流式TTS MP3播放完成'\n            });\n            this.options.onComplete?.();\n        });\n        \n        void audioEl.play().catch(() => {\n            // autoplay 可能被阻止\n        });\n    }\n\n    /**\n     * 初始化 blob 播放器\n     */\n    private ensureBlobAudio(): void {\n        if (this.blobAudioEl) return;\n        const audioEl = document.createElement('audio');\n        audioEl.style.display = 'none';\n        document.body.appendChild(audioEl);\n        this.blobAudioEl = audioEl;\n    }\n    \n    /**\n     * 刷新 MSE 队列，采用一次性 updateend 监听避免重复注册\n     */\n    private flushMseQueue(): void {\n        if (!this.mseSourceBuffer || this.mseAppending || this.mseQueue.length === 0) return;\n        \n        this.mseAppending = true;\n        const chunk = this.mseQueue.shift()!;\n        this.mseSourceBuffer.appendBuffer(chunk as BufferSource);\n        \n        this.mseSourceBuffer.addEventListener('updateend', () => {\n            this.mseAppending = false;\n            this.flushMseQueue();\n        }, { once: true });\n    }\n    \n    /**\n     * 统一处理讯飞错误\n     */\n    protected override processXfyunError(code?: number, message?: string, _sid?: string, _extra?: Record<string, any>): string {\n        const errorMsg = `讯飞TTS错误 ${code}: ${message}`;\n        this.handleError(errorMsg);\n        return errorMsg;\n    }\n    \n    /**\n     * 设置错误状态并分发错误回调与日志\n     * @param message 错误详情\n     */\n    protected override handleError(message: string): void {\n        this.updateStatus('error');\n        this.options.onError?.(message);\n        this.log('error', {\n            event: 'streaming_tts.error',\n            message\n        });\n    }\n    \n    /**\n     * 重置内部状态与资源，供 start 前或 stop/close 使用\n     */\n    public override reset(): void {\n        this.stopKeepAlive();\n        this.status = 'idle';\n        this.textBuffer = '';\n        this.textEnded = false;\n        this.pcmQueue = [];\n        this.pcmProcessing = false;\n        this.pcmPaused = false;\n        this.pcmPlaybackComplete = false;\n        this.pcmCurrentSource = null;\n        this.pcmCursorTime = 0;\n        if (this.gainNode) {\n            try { this.gainNode.disconnect(); } catch {}\n            this.gainNode = null;\n        }\n        this.mseQueue = [];\n        this.mseAppending = false;\n        if (this.mseAudioEl) {\n            try { this.mseAudioEl.pause(); } catch {}\n            try { URL.revokeObjectURL(this.mseAudioEl.src); } catch {}\n            try { this.mseAudioEl.remove(); } catch {}\n        }\n        if (this.mseSourceBuffer) {\n            try { this.mseSourceBuffer.abort(); } catch {}\n        }\n        this.mseSourceBuffer = null;\n        this.mse = null;\n        this.mseAudioEl = null;\n        if (this.blobAudioEl) {\n            try { this.blobAudioEl.pause(); } catch {}\n            try { URL.revokeObjectURL(this.blobAudioEl.src); } catch {}\n            try { this.blobAudioEl.remove(); } catch {}\n            this.blobAudioEl = null;\n        }\n        this.blobChunks = [];\n        if (this.inactivityTimer) {\n            clearTimeout(this.inactivityTimer);\n            this.inactivityTimer = null;\n        }\n        this.closing = false;\n    }\n}\n"],"mappings":"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","names":["targetSampleRate","mono","ErrorSeverity","ErrorType","import_react","import_react","import_react","error","import_react","taskId","result","import_react","import_react","import_react","import_react"]}