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');