UNPKG

mstf-kit

Version:

一个现代化的 JavaScript/TypeScript 工具库,提供了丰富的常用工具函数

620 lines (619 loc) 18.4 kB
/** * 流式音频处理工具 * 用于处理从服务器实时流式接收的音频数据 */ /** * 音频处理器配置选项 */ export interface AudioProcessorOptions { /** 音频 MIME 类型 */ mimeType?: string; /** 自动播放提取的音频 */ autoPlay?: boolean; /** * 从响应数据中提取音频数据的字段路径 * 例如:'data.audio',将从 { data: { audio: binaryData } } 中提取 binaryData */ audioDataField?: string; /** * 从响应数据中提取文本数据的字段路径 * 例如:'data.text',将从 { data: { text: "文本内容" } } 中提取文本 */ textDataField?: string; /** 是否直接处理原始数据(不进行JSON解析) */ processRawData?: boolean; /** 是否将响应视为直接的二进制音频文件 */ directAudioResponse?: boolean; /** 延迟一定数量的块后再开始播放,提高播放流畅性 */ playbackDelayChunks?: number; /** 是否立即播放第一个接收到的音频片段(即使队列中有多个音频) */ playFirstChunkImmediately?: boolean; /** 是否按照接收顺序播放音频(FIFO先进先出,默认为true) */ playInSequentialOrder?: boolean; /** 调试器 */ debugger?: AudioDebugger; /** 是否启用调试日志 */ debug?: boolean; } /** * 音频处理器回调函数 */ export interface AudioProcessorCallbacks { /** 当接收到新的音频数据时触发 */ onAudioData?: (audioBlob: Blob) => void; /** 当接收到新的文本数据时触发 */ onTextData?: (text: string) => void; /** 当发生错误时触发 */ onError?: (error: Error) => void; /** 接收原始数据块回调 - 用于调试 */ onRawChunk?: (chunk: string) => void; } /** * 调试器类,用于控制日志输出 */ export declare class AudioDebugger { private _enabled; private _prefix; private _level; /** * 创建调试器 * @param options 调试器选项 */ constructor(options?: { enabled?: boolean; prefix?: string; level?: 'info' | 'warn' | 'error' | 'all'; }); /** * 启用调试 */ enable(): void; /** * 禁用调试 */ disable(): void; /** * 设置调试级别 * @param level 调试级别 */ setLevel(level: 'info' | 'warn' | 'error' | 'all'): void; /** * 设置日志前缀 * @param prefix 日志前缀 */ setPrefix(prefix: string): void; /** * 输出信息日志 * @param message 日志消息 * @param data 附加数据 */ log(message: string, ...data: any[]): void; /** * 输出警告日志 * @param message 日志消息 * @param data 附加数据 */ warn(message: string, ...data: any[]): void; /** * 输出错误日志 * @param message 日志消息 * @param data 附加数据 */ error(message: string, ...data: any[]): void; /** * 获取当前是否启用 */ get enabled(): boolean; /** * 获取当前日志级别 */ get level(): string; } /** * 创建一个音频调试器 * @param options 调试器选项 */ export declare function createAudioDebugger(options?: { enabled?: boolean; prefix?: string; level?: 'info' | 'warn' | 'error' | 'all'; }): AudioDebugger; export declare const globalAudioDebugger: AudioDebugger; /** * 流式音频处理器 * 用于处理服务器返回的流式音频数据 */ export declare class StreamAudioProcessor { _options: Required<AudioProcessorOptions>; private _callbacks; private _isProcessing; private _isPlaying; private _currentAudio; private _buffer; private _audioChunks; private _audioQueue; private _isPlayingQueue; private _shouldContinueQueue; private _decoder; private _isFirstChunk; private _pendingFirstChunk; private _accumulatedChunks; private _playbackDelayCount; private _isProcessingQueue; private _playLock; private _processedAudioHashes; private _lastResponseSize; private _debugger; /** * 创建流式音频处理器 * @param options 处理器配置 * @param callbacks 回调函数 */ constructor(options?: AudioProcessorOptions, callbacks?: AudioProcessorCallbacks); /** * 处理下载进度回调 * @param progressEvent 进度事件 */ onDownloadProgress(progressEvent: any): void; /** * 处理流式数据 * @param stream ReadableStream */ private _handleStream; /** * 处理直接的二进制音频响应 * @param progressEvent 进度事件 */ private _processDirectAudioResponse; /** * 处理新收到的数据 */ private _processNewData; /** * 处理单行数据 * @param line 数据行 */ private _processLine; /** * 从数据行中提取音频数据 * @param line 数据行 * @returns 提取的音频数据 */ private _extractAudioDataFromLine; /** * 从对象中提取音频数据 * @param data JSON对象 * @returns 提取的音频数据字符串 */ private _extractAudioData; /** * 递归搜索对象中的音频数据 * @param data 要搜索的对象 * @returns 找到的音频数据字符串 */ private _recursiveExtractAudioData; /** * 从数据行中提取文本数据 * @param line 数据行 * @returns 提取的文本数据 */ private _extractTextDataFromLine; /** * 从对象中提取文本数据 * @param data JSON对象 * @returns 提取的文本数据字符串 */ private _extractTextData; /** * 处理文本数据 * @param textData 文本数据 */ private _processTextData; /** * 处理音频数据 * @param base64Data Base64编码的音频数据 */ private _processAudioData; /** * 确保音频队列正在被处理 * 该方法在收到新的音频数据块时调用,确保音频开始播放 */ private _ensureQueueIsProcessing; /** * 处理音频队列 * 只有在没有正在播放的音频时,才会播放下一个 */ private _processAudioQueue; /** * 清理音频队列,去除重复或相似的音频块 */ private _cleanupAudioQueue; /** * 播放队列中的下一个音频 */ private _playNextInQueue; /** * 从队列中播放音频 * @param blob 音频Blob */ private _playAudioFromQueue; /** * 将音频块添加到播放队列 * @param blob 音频Blob */ private _addToPlayQueue; /** * 开始播放 */ play(): void; /** * 停止播放 */ stop(): void; /** * 开始处理 */ startProcessing(): void; /** * 停止处理 * 这将停止接收和处理新数据 */ stopProcessing(): void; /** * 获取播放状态 */ get isPlaying(): boolean; /** * 获取处理状态 */ get isProcessing(): boolean; /** * 获取所有处理过的音频块 * @returns 所有音频块的数组 */ get audioChunks(): Blob[]; /** * 获取合并后的完整音频 * @returns 合并后的音频Blob */ get completeAudio(): Blob; /** * 清空已处理的音频数据 */ clearAudio(): void; /** * 播放音频 * @param blob 音频Blob * @deprecated 使用_addToPlayQueue代替 */ private _playAudio; /** * 处理原始音频数据 * @param data 原始数据 */ private _processRawAudio; /** * 停止播放当前音频 * 仅停止播放,但继续处理数据 */ stopPlayback(): void; /** * 恢复播放 */ resumePlayback(): void; /** * 将音频添加到播放队列 * 用户可以在onAudioData回调中使用此方法将音频添加到无缝播放队列 * @param blob 音频Blob对象 */ addAudioToQueue(blob: Blob): void; /** * 立即播放音频Blob * 注意:这会打断当前的播放队列,可能导致不连贯的体验 * 建议使用addAudioToQueue实现无缝播放 * @param blob 音频Blob对象 */ playAudioBlob(blob: Blob): void; /** * 创建一个已准备好直接播放的音频元素 * 用户可以使用此方法获取准备好的音频元素,自行控制播放时机 * @param blob 音频Blob对象 * @returns 准备好的Audio元素 */ createAudioElement(blob: Blob): HTMLAudioElement; /** * 获取当前缓冲的音频数量 * 用户可以基于此信息决定何时开始播放 */ get bufferedChunksCount(): number; /** * 获取第一段音频数据 * 如果第一段音频还未收到,则返回null */ get firstAudioChunk(): Blob | null; /** * 完成处理,处理剩余的缓冲数据 * 用于确保处理一次性响应或流结束时的剩余数据 */ finalizeProcessing(): void; /** * 对字符串进行简单哈希处理 * @param str 要哈希的字符串 * @returns 哈希字符串 */ private _hashString; } /** * Fetch API流式请求选项 */ export interface FetchStreamOptions { /** 请求URL */ url: string; /** 请求方法 */ method?: 'GET' | 'POST' | 'PUT' | 'DELETE'; /** 请求头 */ headers?: Record<string, string>; /** 请求体 */ body?: any; /** 请求超时时间(ms) */ timeout?: number; /** 是否使用直接二进制处理模式 */ directAudioResponse?: boolean; /** 重试次数 */ retries?: number; /** 重试延迟时间(ms) */ retryDelay?: number; /** 音频处理器 */ processor?: StreamAudioProcessor; /** 进度回调 */ onProgress?: (event: any) => void; /** 成功回调 */ onSuccess?: (response: any) => void; /** 错误回调 */ onError?: (error: Error) => void; /** 完成回调(无论成功失败) */ onComplete?: () => void; } /** * 使用Fetch API进行流式音频请求 * 支持流式处理并与StreamAudioProcessor无缝集成 * @param options 请求选项 * @returns 包含abort方法的控制器对象,可用于取消请求 */ export declare function fetchAudioStream(options: FetchStreamOptions): { abort: () => void; }; /** * 创建流式音频处理器并发起fetch请求 * 简化版的一站式音频流处理方案 * @param fetchOptions fetch请求选项 * @param processorOptions 音频处理器选项 * @param callbacks 音频处理回调 * @returns {processor, controller} - 处理器和请求控制器 */ export declare function createAudioStream(fetchOptions: Omit<FetchStreamOptions, 'processor' | 'onProgress'>, processorOptions?: AudioProcessorOptions, callbacks?: AudioProcessorCallbacks): { processor: StreamAudioProcessor; controller: { abort: () => void; }; }; /** * 创建流式音频处理器 * @param options 处理器配置 * @param callbacks 回调函数 * @returns 流式音频处理器 */ export declare function createStreamAudioProcessor(options?: AudioProcessorOptions, callbacks?: AudioProcessorCallbacks): StreamAudioProcessor; /** * 音频请求配置对象(类似Axios的配置) */ export interface AudioRequestConfig extends Omit<FetchStreamOptions, 'url' | 'method'> { /** 请求URL */ url?: string; /** 请求方法 */ method?: 'GET' | 'POST' | 'PUT' | 'DELETE'; /** 请求参数(会转换为query string) */ params?: Record<string, any>; /** 请求数据(相当于body) */ data?: any; /** 响应类型 */ responseType?: 'json' | 'text' | 'arraybuffer' | 'blob' | 'stream'; /** 下载进度回调 */ onDownloadProgress?: (progressEvent: any) => void; /** 音频处理器选项(如果未提供processor) */ processorOptions?: AudioProcessorOptions; /** 音频处理回调(如果未提供processor) */ processorCallbacks?: AudioProcessorCallbacks; } /** * 音频请求的响应对象 */ export interface AudioResponse<T = any> { /** 响应数据 */ data: T; /** 状态码 */ status: number; /** 状态文本 */ statusText: string; /** 响应头 */ headers: Record<string, string>; /** 配置对象 */ config: AudioRequestConfig; /** 原始响应对象 */ request?: any; /** 音频处理器(如果有) */ processor?: StreamAudioProcessor; } /** * 取消控制器 */ export interface CancelController { /** 取消请求方法 */ abort: () => void; } /** * 音频请求实例接口 */ export interface AudioRequestInstance { /** 默认配置 */ defaults: AudioRequestConfig; /** 发起请求的主函数 */ (config: AudioRequestConfig): Promise<AudioResponse>; /** 发起GET请求 */ get(url: string, config?: Omit<AudioRequestConfig, 'url' | 'method'>): Promise<AudioResponse>; /** 发起POST请求 */ post(url: string, data?: any, config?: Omit<AudioRequestConfig, 'url' | 'method' | 'data'>): Promise<AudioResponse>; /** 创建一个新的音频处理器 */ createProcessor(options?: AudioProcessorOptions, callbacks?: AudioProcessorCallbacks): StreamAudioProcessor; } /** * 创建并导出默认的音频请求实例 */ export declare const msAudio: AudioRequestInstance; /** * 创建自定义音频请求实例 */ export declare function createAudioInstance(config?: AudioRequestConfig): AudioRequestInstance; /** * 处理流式响应 * 允许用户将从fetch API或其他来源获取的响应流传递给音频处理器 * @param response 响应对象(可以是fetch API的Response或类似对象) * @param processor 音频处理器实例 * @param options 额外选项 * @returns 控制器对象,可用于取消流处理 */ export declare function handleStreamResponse(response: Response | { body?: ReadableStream | null; blob?: () => Promise<Blob>; }, processor: StreamAudioProcessor, options?: { directAudioResponse?: boolean; mimeType?: string; onProgress?: (loaded: number) => void; onComplete?: () => void; onError?: (error: Error) => void; }): Promise<{ abort: () => void; }>; /** * 将从外部获取的响应转换为音频数据 * 简化版的处理外部响应的方法 * @param response 响应对象(通常是fetch的返回值) * @param options 处理器选项 * @param callbacks 回调函数 * @returns {processor, controller} - 处理器和控制器 */ export declare function processExternalResponse(response: Response, options?: AudioProcessorOptions, callbacks?: AudioProcessorCallbacks): Promise<{ processor: StreamAudioProcessor; controller: { abort: () => void; }; }>; /** * 处理 Axios 返回的响应 * 支持直接响应和流式响应 * @param axiosResponse Axios 响应对象 * @param options 音频处理器选项 * @param callbacks 回调函数 * @returns {processor, controller} - 处理器和控制器 */ export declare function processAxiosResponse(axiosResponse: any, // 使用 any 类型以适应各种 axios 响应格式 options?: AudioProcessorOptions, callbacks?: AudioProcessorCallbacks): Promise<{ processor: StreamAudioProcessor; controller: { abort: () => void; }; }>; /** * 示例:直接处理 axios 响应中的音频数据 * 这个示例函数展示了如何使用 processAxiosResponse 处理不同类型的响应 * @param response Axios 响应对象 */ export declare function handleAudioResponse(response: any, options?: AudioProcessorOptions): Promise<Blob[]>; /** * 使用示例: * * // 导入必要的函数 * import axios from 'axios'; * import { processAxiosResponse } from './audioStream'; * * async function fetchAudio() { * try { * // 发起请求 * const response = await axios.get('https://your-api.com/audio', { * responseType: 'arraybuffer', // 根据API选择合适的类型 * }); * * // 处理响应 * const { processor } = await processAxiosResponse( * response, * { * mimeType: 'audio/mpeg', * autoPlay: true * }, * { * onAudioData: (blob) => { * console.log('收到音频数据', blob.size); * // 可以在这里更新UI或存储音频 * } * } * ); * * // 现在可以使用 processor 的方法操作音频 * } catch (error) { * console.error('获取音频失败:', error); * } * } */ /** * 处理一次性音频响应(非流式),适用于已完成的Axios响应 * 与 processAxiosResponse 不同,此函数不需要 onDownloadProgress * * @param response Axios 响应对象 * @param options 音频处理器选项 * @param callbacks 回调函数 * @returns Promise<{processor: StreamAudioProcessor, audioBlob: Blob}> */ export declare function processCompleteAudioResponse(response: any, options?: AudioProcessorOptions, callbacks?: AudioProcessorCallbacks): Promise<{ processor: StreamAudioProcessor; audioBlob: Blob; }>; /** * 简化版音频响应处理函数,更适合一次性调用 * 返回音频 Blob,不需要额外事件处理 * * @param response Axios 响应对象 * @param options 处理选项 * @returns Promise<Blob> 音频数据的 Blob 对象 */ export declare function getAudioFromResponse(response: any, options?: { mimeType?: string; debug?: boolean; audioDataField?: string; }): Promise<Blob>; /** * 使用示例:如何处理不同场景的音频响应 * * 注意:这些只是示例代码,展示如何使用函数。 * 实际使用时请替换为您的实际 API 调用方式。 */ export declare const AudioResponseExamples: { /** * 示例1: 流式处理音频响应(适用于需要实时处理的场景) */ streamingExample(): Promise<{ processor: StreamAudioProcessor; }>; /** * 示例2: 一次性处理完整响应(适用于较小的音频文件) */ completeResponseExample(): Promise<{ processor: StreamAudioProcessor; audioBlob: Blob; }>; /** * 示例3: 简化版 - 只获取音频数据不进行其他处理 */ simpleExample(): Promise<{ audioBlob: Blob; }>; };