const SAMPLE_RATE = 48000; const PACKET_SAMPLES = 960; class RustMicWorklet extends AudioWorkletProcessor { constructor(options) { super(); this.module = options.processorOptions; this.timestamp = null; this.buffer = new Float32Array(PACKET_SAMPLES * 2); this.buffer_offset = 0; if (sampleRate != SAMPLE_RATE) { throw Error(`sample rate ${sampleRate} should be ${SAMPLE_RATE}`); } console.log('RustWorklet:', this); } do_send() { const data = { format: 'f32', sampleRate: SAMPLE_RATE, numberOfFrames: PACKET_SAMPLES, numberOfChannels: 1, timestamp: this.timestamp, data: this.buffer.slice(0, PACKET_SAMPLES), }; this.port.postMessage(data); if (this.buffer_offset > PACKET_SAMPLES) { this.buffer.copyWithin(0, PACKET_SAMPLES, this.buffer_offset); } this.buffer_offset -= PACKET_SAMPLES; this.timestamp = null; } process(inputs) { //console.log(inputs); if (inputs.length != 1) { console.log("We got " + inputs.length + " heads?") } const input = inputs[0]; if (input.length == 0) { console.log("We got no ears?") return true } if (this.timestamp == null) { this.timestamp = currentFrame / SAMPLE_RATE * 1e6; } const frames = input[0]; this.buffer.set(frames, this.buffer_offset); this.buffer_offset += frames.length; if (this.buffer_offset >= PACKET_SAMPLES) { this.do_send(); } return true; } }; class RustSpeakerWorklet extends AudioWorkletProcessor { constructor() { super(); this.queue = []; this.readIndex = 0; this.port.onmessage = (event) => { this.queue.push(event.data) }; } process(inputs, outputs) { if (this.queue.length) { console.log(this.queue[0].samples.length, outputs[0][0].length); } const output = outputs[0]; for (let i = 0; i < output[0].length; i++) { if (!this.queue.length) { return true; } const current = this.queue[0]; for (let ch = 0; ch < output.length; ch++) { output[ch][i] = current.samples[this.readIndex]; } this.readIndex++; if (this.readIndex >= current.samples.length) { this.queue.shift(); this.readIndex = 0; } } return true; } }; registerProcessor("rust_mic_worklet", RustMicWorklet); registerProcessor("rust_speaker_worklet", RustSpeakerWorklet);