demo · v139
Active Speaker & Dominance Router
A 4-participant SFU simulation. Every encoded frame's audioLevel drives the routing decision: the loudest participant gets the “active speaker” spotlight, and anyone below the floor gets their forwarded stream suppressed. Zero decoding required — the whole router runs against the encoded metadata.
Checking
RTCEncodedAudioFrameMetadata.audioLevel support…
-45 dBov
800 ms
Move the silence floor or start the router to inspect boundary cases.
active speaker (spotlight)
forwarded
suppressed (below floor)
Frames seen
0
Frames forwarded
0
Frames suppressed
0
Bandwidth saved (est)
0%
Mode
idle
how the router decides
Each RTCEncodedAudioFrame exposes getMetadata().audioLevel on a 0–127 scale where 0 dBov is the loudest. The router reads it in O(1) with no decode, then makes two decisions per frame:
- Suppress? If the level is below the configured silence floor, drop the forward — no point burning egress bandwidth on near-silence.
- Spotlight? Track the peak level over a sliding window. If a participant is loudest for longer than the active hold, promote them to the spotlight tile.
snippet
// inside an RTCRtpScriptTransform worker for the receiving SFU
self.onrtctransform = (event) => {
const reader = event.transformer.readable.getReader();
const writer = event.transformer.writable.getWriter();
let lastSpotlight = null;
let holdUntil = 0;
const FLOOR = 95; // dBov-ish 0=loudest 127=silent
const HOLD_MS = 800;
(async () => {
while (true) {
const { value: frame, done } = await reader.read();
if (done) break;
const meta = frame.getMetadata();
const level = meta.audioLevel ?? 127;
const ssrc = meta.synchronizationSource;
const now = performance.now();
// 1. suppress silence
if (level > FLOOR) continue;
// 2. active-speaker switch
if (level < (lastSpotlight?.level ?? 127) || now > holdUntil) {
lastSpotlight = { ssrc, level };
holdUntil = now + HOLD_MS;
postMessage({ spotlight: ssrc });
}
writer.write(frame);
}
})();
};