mstf-kit
Version:
一个现代化的 JavaScript/TypeScript 工具库,提供了丰富的常用工具函数
620 lines (619 loc) • 18.4 kB
TypeScript
/**
* 流式音频处理工具
* 用于处理从服务器实时流式接收的音频数据
*/
/**
* 音频处理器配置选项
*/
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;
}>;
};