// Generic AudioWorkletProcessor for low-latency raw PCM playback over a // WebSocket (paired with pcm_ws_bridge.py on the server side). Expects // interleaved 16-bit signed little-endian stereo frames delivered via // postMessage as ArrayBuffers; converts to Float32 and plays them back // through a small ring buffer that absorbs network jitter. class PCMWorkletProcessor extends AudioWorkletProcessor { constructor() { super(); this.queue = []; this.readOffset = 0; this.port.onmessage = (event) => { const int16 = new Int16Array(event.data); const float32 = new Float32Array(int16.length); for (let i = 0; i < int16.length; i++) { float32[i] = int16[i] / 32768; } this.queue.push(float32); }; } process(inputs, outputs) { const output = outputs[0]; const numChannels = output.length; const numFrames = output[0].length; for (let frame = 0; frame < numFrames; frame++) { if (this.queue.length === 0) { for (let ch = 0; ch < numChannels; ch++) output[ch][frame] = 0; continue; } const current = this.queue[0]; for (let ch = 0; ch < numChannels; ch++) { const idx = this.readOffset * numChannels + ch; output[ch][frame] = idx < current.length ? current[idx] : 0; } this.readOffset++; if (this.readOffset * numChannels >= current.length) { this.queue.shift(); this.readOffset = 0; } } return true; } } registerProcessor('pcm-worklet-processor', PCMWorkletProcessor);