/** * AudioWorkletProcessor that collects 512-sample chunks of PCM audio * and posts them to the main thread for WebSocket transmission. */ class PCMProcessor extends AudioWorkletProcessor { constructor() { super(); this.buffer = new Float32Array(0); this.chunkSize = 512; // 512 samples at 16kHz = 32ms } process(inputs) { const input = inputs[0]; if (!input || !input[0]) return true; const channelData = input[0]; // mono // Append to buffer const newBuffer = new Float32Array(this.buffer.length + channelData.length); newBuffer.set(this.buffer); newBuffer.set(channelData, this.buffer.length); this.buffer = newBuffer; // Send complete chunks while (this.buffer.length >= this.chunkSize) { const chunk = this.buffer.slice(0, this.chunkSize); this.buffer = this.buffer.slice(this.chunkSize); // Convert float32 to int16 for transmission const int16 = new Int16Array(chunk.length); for (let i = 0; i < chunk.length; i++) { const s = Math.max(-1, Math.min(1, chunk[i])); int16[i] = s < 0 ? s * 0x8000 : s * 0x7fff; } this.port.postMessage(int16.buffer, [int16.buffer]); } return true; } } registerProcessor("pcm-processor", PCMProcessor);