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:

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);
    }
  })();
};

see also