(audioChunk: Buffer)
| 214 | // to onReady when the WebSocket opens. |
| 215 | const connection: VoiceStreamConnection = { |
| 216 | send(audioChunk: Buffer): void { |
| 217 | if (ws.readyState !== WebSocket.OPEN) { |
| 218 | return |
| 219 | } |
| 220 | if (finalized) { |
| 221 | // After CloseStream has been sent, the server rejects further audio. |
| 222 | // Drop the chunk to avoid a protocol error. |
| 223 | logForDebugging( |
| 224 | `[voice_stream] Dropping audio chunk after CloseStream: ${String(audioChunk.length)} bytes`, |
| 225 | ) |
| 226 | return |
| 227 | } |
| 228 | logForDebugging( |
| 229 | `[voice_stream] Sending audio chunk: ${String(audioChunk.length)} bytes`, |
| 230 | ) |
| 231 | // Copy the buffer before sending: NAPI Buffer objects from native |
| 232 | // modules may share a pooled ArrayBuffer. Creating a view with |
| 233 | // `new Uint8Array(buf.buffer, offset, len)` can reference stale or |
| 234 | // overlapping memory by the time the ws library reads it. |
| 235 | // `Buffer.from()` makes an owned copy that the ws library can safely |
| 236 | // consume as a binary WebSocket frame. |
| 237 | ws.send(Buffer.from(audioChunk)) |
| 238 | }, |
| 239 | finalize(): Promise<FinalizeSource> { |
| 240 | if (finalizing || finalized) { |
| 241 | // Already finalized or WebSocket already closed — resolve immediately. |
nothing calls this directly
no test coverage detected