Skip to content

Commit f4cac68

Browse files
jackshen310shenxiaojie.316
andauthored
perf: Use transferable objects when posting audio buffers to avoid data copying (#264)
* feat(ws-tools): add sentence-level audio streaming support * chore: Publish feat/sentence * feat(coze-api): Use transferable objects when posting audio buffers to avoid data copying --------- Co-authored-by: shenxiaojie.316 <shenxiaojie.316@bytedance.com>
1 parent 15fc74c commit f4cac68

4 files changed

Lines changed: 22 additions & 9 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@coze/api",
5+
"comment": "Use transferable objects when posting audio buffers to avoid data copying",
6+
"type": "minor"
7+
}
8+
],
9+
"packageName": "@coze/api",
10+
"email": "shenxiaojie.316@bytedance.com"
11+
}

packages/coze-js/src/ws-tools/chat/base.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
WebsocketsEventType,
2424
} from '../../index';
2525

26-
class BaseWsChatClient {
26+
abstract class BaseWsChatClient {
2727
public ws: WebSocketAPI<CreateChatWsReq, CreateChatWsRes> | null = null;
2828
protected listeners: Map<string, Set<WsChatCallbackHandler>> = new Map();
2929
protected wavStreamPlayer?: WavStreamPlayer;
@@ -170,6 +170,7 @@ class BaseWsChatClient {
170170
}
171171

172172
sendTextMessage(text: string) {
173+
this.clear();
173174
this.sendMessage({
174175
id: uuid(),
175176
event_type: WebsocketsEventType.CONVERSATION_MESSAGE_CREATE,

packages/coze-js/src/ws-tools/chat/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ class WsChatClient extends BaseWsChatClient {
8686
// init stream player
8787
await this.wavStreamPlayer?.add16BitPCM(new ArrayBuffer(0), this.trackId);
8888

89-
// let startTime = performance.now();
9089
// 2. recording
9190
await this.recorder.record({
9291
pcmAudioCallback: data => {

packages/coze-js/src/ws-tools/wavtools/lib/wav_stream_player.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,17 @@ export class WavStreamPlayer {
3131
defaultFormat: AudioFormat;
3232
localLoopbackStream: MediaStream | undefined;
3333
private volume: number = 1.0;
34-
private firstFrameCallback?: (timestamp: number) => void;
3534

3635
/**
3736
* Creates a new WavStreamPlayer instance
3837
* @param {{sampleRate?: number, enableLocalLoopback?: boolean, defaultFormat?: AudioFormat, volume?: number}} options
3938
* @returns {WavStreamPlayer}
4039
*/
41-
constructor({ sampleRate = 44100, enableLocalLoopback = false, defaultFormat = 'pcm', volume = 1.0, firstFrameCallback }: {
40+
constructor({ sampleRate = 44100, enableLocalLoopback = false, defaultFormat = 'pcm', volume = 1.0 }: {
4241
sampleRate?: number,
4342
enableLocalLoopback?: boolean,
4443
defaultFormat?: AudioFormat,
4544
volume?: number,
46-
firstFrameCallback?: (timestamp: number) => void
4745
} = {}) {
4846
this.scriptSrc = StreamProcessorSrc;
4947
this.sampleRate = sampleRate;
@@ -59,7 +57,6 @@ export class WavStreamPlayer {
5957
this.localLoopback = new LocalLoopback(true);
6058
}
6159

62-
this.firstFrameCallback = firstFrameCallback;
6360

6461
// Initialize volume (0 = muted, 1 = full volume)
6562
this.volume = volume;
@@ -153,8 +150,6 @@ export class WavStreamPlayer {
153150
const { requestId, trackId, offset } = e.data;
154151
const currentTime = offset / this.sampleRate;
155152
this.trackSampleOffsets[requestId] = { trackId, offset, currentTime };
156-
} else if (event === 'first_frame') {
157-
this.firstFrameCallback?.(Date.now());
158153
}
159154
};
160155

@@ -214,7 +209,14 @@ export class WavStreamPlayer {
214209
} else {
215210
throw new Error(`argument must be Int16Array, Uint8Array, or ArrayBuffer`);
216211
}
217-
this.streamNode!.port.postMessage({ event: 'write', buffer, trackId });
212+
// 使用 Transferable 对象传递 ArrayBuffer,避免数据复制
213+
// 注意:只能传递 buffer.buffer,因为 buffer 是 Int16Array
214+
const transferableBuffer = buffer.buffer;
215+
this.streamNode!.port.postMessage({
216+
event: 'write',
217+
buffer,
218+
trackId
219+
}, [transferableBuffer]);
218220
return buffer;
219221
}
220222

0 commit comments

Comments
 (0)