feat: 添加流获取音频的事件

This commit is contained in:
熊潇 2025-04-23 15:41:52 +08:00
parent ad5bcd5be8
commit 3ecc9353c7

View File

@ -1,7 +1,7 @@
// https://www.volcengine.com/docs/6561/1329505#%E7%A4%BA%E4%BE%8Bsamples // https://www.volcengine.com/docs/6561/1329505#%E7%A4%BA%E4%BE%8Bsamples
import { WebSocket } from 'ws'; import { WebSocket } from 'ws';
import { EventEmitter } from 'eventemitter3';
import fs from 'fs/promises'; import fs from 'fs/promises';
import { nanoid } from 'nanoid'; import { nanoid } from 'nanoid';
const uuidv4 = nanoid; const uuidv4 = nanoid;
@ -308,7 +308,7 @@ async function finishConnection(ws: WebSocket): Promise<void> {
return await sendEvent(ws, header, optional, payload); return await sendEvent(ws, header, optional, payload);
} }
export async function runDemo(appId: string, token: string, speaker: string, text: string, outputPath: string): Promise<void> { export async function runDemo(appId: string, token: string, speaker: string, text: string, outputPath: string, emitter?: EventEmitter): Promise<void> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const wsHeader = { const wsHeader = {
'X-Api-App-Key': appId, 'X-Api-App-Key': appId,
@ -319,13 +319,36 @@ export async function runDemo(appId: string, token: string, speaker: string, tex
const url = 'wss://openspeech.bytedance.com/api/v3/tts/bidirection'; const url = 'wss://openspeech.bytedance.com/api/v3/tts/bidirection';
const ws = new WebSocket(url, { headers: wsHeader }); const ws = new WebSocket(url, { headers: wsHeader });
const filename = outputPath.split('/').pop() || '';
let isBegin = true;
const writeFileEmitter = (data: Buffer) => {
const value: TTSWriteType = {
type: 'tts-mix',
filename,
data,
};
if (isBegin) {
value.isBegin = true;
isBegin = false;
}
emitter?.emit?.('writeFile', value);
};
const finishEmitter = () => {
emitter?.emit?.('writeFile', {
type: 'tts-mix',
isEnd: true,
data: Buffer.from(''),
filename,
});
};
ws.on('open', async () => { ws.on('open', async () => {
try { try {
await startConnection(ws); await startConnection(ws);
let isFirstResponse = true;
let fileHandle: fs.FileHandle | null = null; let fileHandle: fs.FileHandle | null = null;
let sessionId: string = ''; let sessionId: string = '';
let isFirstResponse = true;
ws.on('message', async (data) => { ws.on('message', async (data) => {
try { try {
const res = parserResponse(data as Buffer); const res = parserResponse(data as Buffer);
@ -347,14 +370,17 @@ export async function runDemo(appId: string, token: string, speaker: string, tex
} else if (!isFirstResponse) { } else if (!isFirstResponse) {
if (res.optional.event === EVENT_TTSResponse && res.header.messageType === AUDIO_ONLY_RESPONSE && res.payload && fileHandle) { if (res.optional.event === EVENT_TTSResponse && res.header.messageType === AUDIO_ONLY_RESPONSE && res.payload && fileHandle) {
await fileHandle.write(res.payload); await fileHandle.write(res.payload);
writeFileEmitter(res.payload);
} else if (res.optional.event === EVENT_TTSSentenceStart || res.optional.event === EVENT_TTSSentenceEnd) { } else if (res.optional.event === EVENT_TTSSentenceStart || res.optional.event === EVENT_TTSSentenceEnd) {
// continue // continue
} else { } else {
// 152
if (fileHandle) { if (fileHandle) {
await fileHandle.close(); await fileHandle.close();
fileHandle = null; fileHandle = null;
} }
await finishConnection(ws); await finishConnection(ws);
finishEmitter();
} }
} }
} catch (err) { } catch (err) {
@ -374,12 +400,22 @@ export async function runDemo(appId: string, token: string, speaker: string, tex
}); });
} }
type TTSWriteType = {
type: 'tts-mix';
filename: string;
data?: Buffer;
isBegin?: boolean;
isEnd?: boolean;
};
export class TtsMix { export class TtsMix {
appId: string; appId: string;
token: string; token: string;
emitter: EventEmitter;
constructor(appId: string, token: string) { constructor(appId: string, token: string) {
this.appId = appId; this.appId = appId;
this.token = token; this.token = token;
this.emitter = new EventEmitter();
} }
/** /**
* *
@ -389,6 +425,12 @@ export class TtsMix {
* @returns * @returns
*/ */
async getVoiceDemo(speaker: string, text: string, outputPath: string): Promise<void> { async getVoiceDemo(speaker: string, text: string, outputPath: string): Promise<void> {
return runDemo(this.appId, this.token, speaker, text, outputPath); return runDemo(this.appId, this.token, speaker, text, outputPath, this.emitter);
}
onWriteFile(callback: (data: TTSWriteType) => void) {
this.emitter.on('writeFile', callback);
return () => {
this.emitter.off?.('writeFile', callback);
};
} }
} }