zebra-spaces: mesh.recv telemetry — surface mesh PC audio decoder stats
Fox 2026-06-07 follow-up to ticket 0001: with the caa0548 fix live,
SFU sub PC receivers still show level=0 + jbuf=? on blanka-chrome.
That's EXPECTED when mesh has taken the swap (SFU receiver becomes
orphaned by design), but without a corresponding stat from the mesh
PC's own receiver we can't distinguish "mesh decoder is alive and
producing samples; SFU orphan is fine" from "mesh decoder is also
silent — both paths dead, listener hears nothing".
Add per-peer mesh.recv lines to the telemetry tick, tagged with the
short uuid prefix:
mesh.recv u=8afc pkt=23900 lost=8 bytes=339884 jitter=0.0080
level=0.025 jbuf=0.48s lp=0.1s
Same fields as aud.recv (the SFU sub PC line) so direct comparison
is easy. We skip peers whose connectionState !== 'connected' so a
failed mesh PC doesn't poison the line. Failure on one peer's
getStats is swallowed independently — multi-peer rooms remain
readable even if one mesh PC's stats reporter throws.
Reveals (per ticket 0001 next narrowing):
- mesh decoder level + jbuf — proves or rules out the mesh decoder
being orphaned at the worklet swap point
- per-peer breakdown when mesh=N > 1, so we can tell which peer's
mesh path is healthy and which is stalled
- same lastPacketReceived 'lp' so a mesh RTP stall is visible at
a glance
This commit is contained in:
parent
caa0548113
commit
b9e254172b
1 changed files with 37 additions and 2 deletions
|
|
@ -5877,6 +5877,41 @@ async function dumpTelemetry(){
|
||||||
});
|
});
|
||||||
} catch(e){ parts.push('stats.err=' + e.message); }
|
} catch(e){ parts.push('stats.err=' + e.message); }
|
||||||
}
|
}
|
||||||
|
/* mesh receiver stats — one line per peer's mesh PC inbound audio.
|
||||||
|
* Lets us tell whether the worklet is being fed by a live mesh
|
||||||
|
* decoder vs an orphaned one. For ticket 0001 we needed to answer:
|
||||||
|
* when handleRemoteSfuTrack hands off to mesh and the SFU receiver
|
||||||
|
* reports level=0+jbuf=? (expected — orphaned), is the MESH receiver
|
||||||
|
* actually decoding (level>0+jbuf>0) or also silent? fox 2026-06-07.
|
||||||
|
*
|
||||||
|
* Each peer's PC has one audio inbound-rtp; tag with the short uuid
|
||||||
|
* so a multi-peer room is readable. Failure on one peer's getStats
|
||||||
|
* doesn't stop the others. */
|
||||||
|
for (const [uuid, pc] of peers){
|
||||||
|
if (!pc || typeof pc.getStats !== 'function') continue;
|
||||||
|
if (pc.connectionState !== 'connected') continue; /* skip non-live PCs */
|
||||||
|
try {
|
||||||
|
const stats = await pc.getStats(null);
|
||||||
|
const nowMs = Date.now();
|
||||||
|
stats.forEach(r => {
|
||||||
|
if (r.type !== 'inbound-rtp' || r.kind !== 'audio') return;
|
||||||
|
const lp = r.lastPacketReceivedTimestamp
|
||||||
|
? ((nowMs - r.lastPacketReceivedTimestamp) / 1000).toFixed(1) + 's'
|
||||||
|
: '?';
|
||||||
|
const jbuf = (r.jitterBufferEmittedCount > 0)
|
||||||
|
? (r.jitterBufferDelay / r.jitterBufferEmittedCount).toFixed(2) + 's'
|
||||||
|
: '?';
|
||||||
|
parts.push('mesh.recv u=' + uuid.slice(0,4) +
|
||||||
|
' pkt=' + (r.packetsReceived|0) +
|
||||||
|
' lost=' + (r.packetsLost|0) +
|
||||||
|
' bytes=' + (r.bytesReceived|0) +
|
||||||
|
' jitter=' + (r.jitter || 0).toFixed(4) +
|
||||||
|
' level=' + (r.audioLevel || 0).toFixed(3) +
|
||||||
|
' jbuf=' + jbuf +
|
||||||
|
' lp=' + lp);
|
||||||
|
});
|
||||||
|
} catch(_){}
|
||||||
|
}
|
||||||
/* publisher-side stats — what we are actually emitting on the wire.
|
/* publisher-side stats — what we are actually emitting on the wire.
|
||||||
* One line per kind so screen-audio shows up independently of
|
* One line per kind so screen-audio shows up independently of
|
||||||
* screen-video (earlier collapse hid scr.send.aud entirely under
|
* screen-video (earlier collapse hid scr.send.aud entirely under
|
||||||
|
|
@ -8148,8 +8183,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');
|
||||||
|
|
||||||
<footer style="margin:2.2rem auto 0;font-size:0.65rem;color:#999;line-height:1.7;word-break:break-all;font-family:monospace">
|
<footer style="margin:2.2rem auto 0;font-size:0.65rem;color:#999;line-height:1.7;word-break:break-all;font-family:monospace">
|
||||||
<span id="pi-seal" style="color:#777;cursor:default;user-select:none" title="">page integrity</span> · built <span class="stamp-date">2026-06-07</span><br>
|
<span id="pi-seal" style="color:#777;cursor:default;user-select:none" title="">page integrity</span> · built <span class="stamp-date">2026-06-07</span><br>
|
||||||
md5 <span class="stamp-md5">59cd5e54142e3880cfe784df09204e52</span><br>
|
md5 <span class="stamp-md5">bb5c7dea19fcb19f88c479d1cb26f24f</span><br>
|
||||||
sha256 <span class="stamp-sha">9ba89654f5a18538ee2e4ed6d614b8901e1088c4892fcbfc41d0b5a991692517</span><br>
|
sha256 <span class="stamp-sha">03e08e3499cf18fac3aec4b5dbeb808e6b3b6bceb5222ca560026c6d65864d38</span><br>
|
||||||
<span style="color:#bbb">hashes are of this page with these two fields zeroed — to verify, blank them and re-hash</span><br>
|
<span style="color:#bbb">hashes are of this page with these two fields zeroed — to verify, blank them and re-hash</span><br>
|
||||||
<span style="color:#bbb">one self-contained file — <strong>save a copy</strong> and verify against these hashes; point at your own servers with ?signal= and ?turncred=, or <a href="host-your-own.html" style="color:#999">host your own community</a></span>
|
<span style="color:#bbb">one self-contained file — <strong>save a copy</strong> and verify against these hashes; point at your own servers with ?signal= and ?turncred=, or <a href="host-your-own.html" style="color:#999">host your own community</a></span>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue