From 17ce93d5bdf781d2defff402b9938476658e07bf Mon Sep 17 00:00:00 2001 From: abearxiong Date: Sun, 20 Apr 2025 01:32:28 +0800 Subject: [PATCH] temp --- src/asr/index.ts | 0 .../volcengine/asr-ws-big-model-client.ts | 17 ++++++++++++--- src/asr/provider/volcengine/base.ts | 1 + src/asr/provider/ws-server.ts | 21 +++++++++++++++++++ src/utils/convert.ts | 13 ++++++++++++ 5 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 src/asr/index.ts diff --git a/src/asr/index.ts b/src/asr/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/asr/provider/volcengine/asr-ws-big-model-client.ts b/src/asr/provider/volcengine/asr-ws-big-model-client.ts index 1f32bcf..dacd499 100644 --- a/src/asr/provider/volcengine/asr-ws-big-model-client.ts +++ b/src/asr/provider/volcengine/asr-ws-big-model-client.ts @@ -315,7 +315,7 @@ export class AsrWsClient extends VolcEngineBase { }, }; } - private async sendFullClientRequest() { + async sendFullClientRequest() { if (this.hasSendFullClientRequest) { return; } @@ -353,6 +353,7 @@ export class AsrWsClient extends VolcEngineBase { for (const [chunk, last] of sliceData(audioData, segmentSize)) { that.seq += 1; const isEnd = that.isEnd && last; // 结束了,而且是语音的最后一包 + console.log('chunkSize', Buffer.byteLength(chunk), segmentSize, 'last', last); if (isEnd) { that.seq = -that.seq; } @@ -391,9 +392,14 @@ export class AsrWsClient extends VolcEngineBase { try { const parsed = parseResponse(Buffer.from(event.data as ArrayBuffer)); console.log(`Seq ${parsed.payloadSequence} response:`, parsed); + if (typeof event.data === 'string') { + throw new Error('event.data is string: ' + event.data); + } // console.log('parsed', parsed.payloadSequence, parsed.payloadMsg.result.text); if (parsed.isLastPackage) { this.emitter.emit('end', parsed); + } else { + this.emitter.emit('message', parsed); } } catch (error) { console.error('Error processing response:', error); @@ -425,9 +431,14 @@ export class AsrWsClient extends VolcEngineBase { throw error; } } + /** + * 发送语音流, 最小10000 + * @param data + * @returns + */ public async sendVoiceStream(data: Buffer) { - const segmentSize = Buffer.byteLength(data); - console.log('segmentSize', segmentSize); + let segmentSize = Buffer.byteLength(data); + return await this.segmentDataProcessor(data, segmentSize); } } diff --git a/src/asr/provider/volcengine/base.ts b/src/asr/provider/volcengine/base.ts index 62fb12a..6adb66e 100644 --- a/src/asr/provider/volcengine/base.ts +++ b/src/asr/provider/volcengine/base.ts @@ -33,6 +33,7 @@ export class VolcEngineBase extends WSServer { async onOpen() { console.log('VolcEngineBase onOpen'); // 发送认证信息 + this.emitter.emit('open'); } async isCanSend() { if (this.canSend) { diff --git a/src/asr/provider/ws-server.ts b/src/asr/provider/ws-server.ts index 292c040..f3fd385 100644 --- a/src/asr/provider/ws-server.ts +++ b/src/asr/provider/ws-server.ts @@ -13,7 +13,12 @@ export class WSServer { onConnect?: () => void; connected: boolean; emitter: EventEmitter; + url: string; + wsOptions?: ClientOptions; constructor(opts: WSSOptions) { + this.connected = false; + this.url = opts.url; + this.wsOptions = opts.wsOptions; this.initWs(opts); } async initWs(opts: WSSOptions) { @@ -28,6 +33,13 @@ export class WSServer { this.ws.onerror = this.onError.bind(this); this.ws.onclose = this.onClose.bind(this); } + async reconnect() { + this.ws = await initWs(this.url, this.wsOptions); + this.ws.onopen = this.onOpen.bind(this); + this.ws.onmessage = this.onMessage.bind(this); + this.ws.onerror = this.onError.bind(this); + this.ws.onclose = this.onClose.bind(this); + } /** * 连接成功 ws 事件 */ @@ -73,5 +85,14 @@ export class WSServer { async onClose(event: CloseEvent) { console.error('WSS onClose'); this.emitter.emit('close', event); + this.connected = false; + } + /** + * 关闭 ws 连接 + */ + async close() { + if (this.ws.readyState === WebSocket.OPEN) { + this.ws.close(); + } } } diff --git a/src/utils/convert.ts b/src/utils/convert.ts index aeaa3d4..7ef7f04 100644 --- a/src/utils/convert.ts +++ b/src/utils/convert.ts @@ -67,3 +67,16 @@ export const converter = { encodeWav, decodeWav, }; + +/** + * 生成无声音频 + * @param duration 音频时长(秒) + * @param sampleRate 采样率 + * @param channels 声道数 + * @returns 无声音频 + */ +export const generateSilent = (duration: number = 2, sampleRate: number = 16000, channels: number = 1) => { + const bufferSize = Math.floor(duration * sampleRate * channels * 2); // 2 bytes per sample + const silent = Buffer.alloc(bufferSize); + return silent; +};