feat: room-based calls + AudioWorklet for capture and playback
Rooms: - URL-based: open /myroom to join a room - Two clients in same room get bridged through relay - Input field for room name, also supports URL path and hash - Each room creates independent relay connections AudioWorklet (replaces deprecated ScriptProcessorNode): - capture-processor.js: accumulates mic samples, sends 960-sample frames - playback-processor.js: pull-based output with 200ms buffer cap - Falls back to ScriptProcessor if AudioWorklet unavailable - Eliminates drift: worklet runs on audio thread, not main thread Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
45
crates/wzp-web/static/playback-processor.js
Normal file
45
crates/wzp-web/static/playback-processor.js
Normal file
@@ -0,0 +1,45 @@
|
||||
// AudioWorklet processor for playing received audio.
|
||||
// Receives PCM samples from the main thread and outputs them.
|
||||
|
||||
class PlaybackProcessor extends AudioWorkletProcessor {
|
||||
constructor() {
|
||||
super();
|
||||
this.buffer = new Float32Array(0);
|
||||
this.maxBuffered = 48000 / 5; // 200ms max
|
||||
this.port.onmessage = (e) => {
|
||||
const incoming = new Float32Array(e.data);
|
||||
// Append
|
||||
const newBuf = new Float32Array(this.buffer.length + incoming.length);
|
||||
newBuf.set(this.buffer);
|
||||
newBuf.set(incoming, this.buffer.length);
|
||||
this.buffer = newBuf;
|
||||
|
||||
// Cap buffer to prevent drift
|
||||
if (this.buffer.length > this.maxBuffered) {
|
||||
this.buffer = this.buffer.slice(this.buffer.length - this.maxBuffered);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
process(inputs, outputs, parameters) {
|
||||
const output = outputs[0];
|
||||
if (!output || !output[0]) return true;
|
||||
|
||||
const out = output[0]; // 128 samples typically
|
||||
|
||||
if (this.buffer.length >= out.length) {
|
||||
out.set(this.buffer.subarray(0, out.length));
|
||||
this.buffer = this.buffer.slice(out.length);
|
||||
} else if (this.buffer.length > 0) {
|
||||
out.set(this.buffer);
|
||||
for (let i = this.buffer.length; i < out.length; i++) out[i] = 0;
|
||||
this.buffer = new Float32Array(0);
|
||||
} else {
|
||||
for (let i = 0; i < out.length; i++) out[i] = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
registerProcessor('playback-processor', PlaybackProcessor);
|
||||
Reference in New Issue
Block a user