diff --git a/zebra-report/zebra-spaces.html b/zebra-report/zebra-spaces.html index 892c79f..18ecd80 100644 --- a/zebra-report/zebra-spaces.html +++ b/zebra-report/zebra-spaces.html @@ -3426,7 +3426,10 @@ async function dumpTelemetry(){ /* every element in the room — both the WebRTC remoteAudio * pool (rtc[]) and the DJ HTTP-pull streamAudio (stream[]). */ let i = 0; + let pausedZeroCt = 0, totalAudio = 0; for (const [uuid, a] of remoteAudio){ + totalAudio++; + if (a.paused && a.currentTime === 0 && a.readyState >= 2) pausedZeroCt++; parts.push('rtc[' + uuid.slice(0,4) + '] rs=' + a.readyState + ' ns=' + a.networkState + ' pa=' + (a.paused?1:0) + ' mu=' + (a.muted?1:0) + ' ct=' + a.currentTime.toFixed(2) + ' err=' + (a.error?a.error.code:'_')); @@ -3434,6 +3437,8 @@ async function dumpTelemetry(){ } i = 0; for (const [uuid, a] of streamAudio){ + totalAudio++; + if (a.paused && a.currentTime === 0 && a.readyState >= 2) pausedZeroCt++; parts.push('stream[' + uuid.slice(0,4) + '] rs=' + a.readyState + ' ns=' + a.networkState + ' pa=' + (a.paused?1:0) + ' mu=' + (a.muted?1:0) + ' ct=' + a.currentTime.toFixed(2) + ' src=' + (a.src ? (a.src.length>30 ? '…'+a.src.slice(-30) : a.src) : 'none') + @@ -3441,6 +3446,19 @@ async function dumpTelemetry(){ if (++i > 4) { parts.push('stream…+' + (streamAudio.size - i) + ' more'); break; } } logLine('', '· ' + parts.join(' ')); + /* State-based autoplay-block detection: if any audio element has data + * (rs>=2 HAVE_CURRENT_DATA) but stays paused at ct=0, play() either + * silently failed or the pre-blessing wore off when srcObject was + * swapped. The Firefox Android phone hits this consistently: receiver + * decodes audio (level>0 in aud.recv stats) but the stays + * pa=1 ct=0.00 forever. play()-promise-reject doesn't fire in that + * shape, so a state-based trigger is the only reliable detector. + * Only fire on listener role — speakers/cohosts/hosts get the same + * pre-blessing path but also have an active mic that requires its + * own gesture chain we don't want to disturb. */ + if (pausedZeroCt > 0 && totalAudio > 0 && myRole === 'listener'){ + flagAudioBlocked('telemetry: '+pausedZeroCt+'/'+totalAudio+' audio paused at ct=0'); + } } function startTelemetryLoop(){ if (telemetryTimer) return; @@ -5253,8 +5271,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');