diff --git a/zebra-report/zebra-spaces.html b/zebra-report/zebra-spaces.html index 0a1b028..df01c8f 100644 --- a/zebra-report/zebra-spaces.html +++ b/zebra-report/zebra-spaces.html @@ -3524,15 +3524,28 @@ async function dumpTelemetry(){ if (sfuSubPC && typeof sfuSubPC.getStats === 'function'){ try { const stats = await sfuSubPC.getStats(null); + const nowMs = Date.now(); stats.forEach(r => { if (r.type === 'inbound-rtp' && r.kind === 'audio'){ + /* lastPacketReceivedTimestamp pins the EXACT real-time + * moment audio RTP stopped — pkt-delta only shows it after + * the next tick. Express as 'ago' so a frozen flow stands + * out at a glance ('lp=0.1s' = fine, 'lp=12s' = dead). */ + const lp = r.lastPacketReceivedTimestamp + ? ((nowMs - r.lastPacketReceivedTimestamp) / 1000).toFixed(1) + 's' + : '?'; parts.push('aud.recv pkt=' + (r.packetsReceived|0) + ' lost=' + (r.packetsLost|0) + ' bytes=' + (r.bytesReceived|0) + ' jitter=' + (r.jitter || 0).toFixed(4) + - ' level=' + (r.audioLevel || 0).toFixed(3)); + ' level=' + (r.audioLevel || 0).toFixed(3) + + ' lp=' + lp); } if (r.type === 'inbound-rtp' && r.kind === 'video'){ + const lp = r.lastPacketReceivedTimestamp + ? ((nowMs - r.lastPacketReceivedTimestamp) / 1000).toFixed(1) + 's' + : '?'; parts.push('vid.recv pkt=' + (r.packetsReceived|0) + ' lost=' + (r.packetsLost|0) + - ' frames=' + (r.framesDecoded|0)); + ' frames=' + (r.framesDecoded|0) + + ' lp=' + lp); } }); } catch(e){ parts.push('stats.err=' + e.message); } @@ -3637,6 +3650,21 @@ function openSignal(){ async function handleSignal(raw){ let m; try { m = JSON.parse(raw); } catch(_){ return; } + /* Firehose every received signal event with its epoch. Lets us + * correlate phone-side regressions ('audio went silent at 16:29:07') + * against the exact server events the phone received. Skip the + * uninteresting high-rate types so the log stays readable. */ + const noiseTypes = new Set(['sdp-from', 'mic-state', 'spotlight', 'state']); + if (!noiseTypes.has(m.type)){ + const ep = (m.epoch != null) ? ' e=' + m.epoch : ''; + const who = m.uuid ? (' u=' + String(m.uuid).slice(0,4)) + : m.from ? (' from=' + String(m.from).slice(0,4)) + : m.target ? (' tgt=' + String(m.target).slice(0,4)) + : ''; + const role = m.role ? (' role=' + m.role) : ''; + const action = m.action ? (' action=' + m.action) : ''; + logLine('', '« ' + m.type + ep + who + role + action); + } switch (m.type){ case 'welcome': { @@ -5433,8 +5461,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');