zebra-spaces: only prune mute AFTER data flowed — fresh tiles stop disappearing
Symptom: listener saw camera tiles appear black, then vanish ~1.5s later. Cause: remote MediaStreamTracks ALWAYS start in muted state until the first RTP packet arrives. My watchVideoTrackForRemoval had a 'defensive' branch that scheduled a prune if the track was already muted at attach time — so the moment we attached, the 1.5s timer started, and if the publisher's encoder hadn't pushed a keyframe yet (common for cameras), the tile was pruned before any frame rendered. Fix: track a hasFlowed flag. Set true on the FIRST 'unmute' (RTP actually arrived). Only schedule a prune on 'mute' events that fire AFTER hasFlowed — those are the real 'publisher stopped sending' case. Initial muted state is now ignored. Also bumped the debounce from 1.5s to 3s for extra safety on slow networks. 'ended' still removes immediately (terminal state, no debounce). 83 FSM tests green.
This commit is contained in:
parent
aa36b84a47
commit
9869e7861d
1 changed files with 14 additions and 11 deletions
|
|
@ -1459,30 +1459,33 @@ function flushSfuStreams(){
|
|||
* (transient network blip) we cancel the removal. */
|
||||
function watchVideoTrackForRemoval(track, removeFn){
|
||||
if (!track) return;
|
||||
let timer = null, removed = false;
|
||||
let timer = null, removed = false, hasFlowed = false;
|
||||
const remove = () => {
|
||||
if (removed) return;
|
||||
removed = true;
|
||||
if (timer) { clearTimeout(timer); timer = null; }
|
||||
try { removeFn(); } catch(_){}
|
||||
};
|
||||
const onUnmute = () => {
|
||||
/* RTP arrived; future mute events are meaningful (a flow that
|
||||
* existed then stopped — publisher unshared or net dropped) */
|
||||
hasFlowed = true;
|
||||
if (timer){ clearTimeout(timer); timer = null; }
|
||||
};
|
||||
const onMute = () => {
|
||||
if (removed || timer) return;
|
||||
/* fresh remote tracks ALWAYS start muted until the first RTP packet
|
||||
* arrives. If we've never seen data flow on this track, the mute is
|
||||
* its initial state, not a publisher unshare — don't prune. */
|
||||
if (!hasFlowed) return;
|
||||
timer = setTimeout(() => {
|
||||
timer = null;
|
||||
if (!removed && track.muted) remove();
|
||||
}, 1500);
|
||||
};
|
||||
const onUnmute = () => {
|
||||
if (timer){ clearTimeout(timer); timer = null; }
|
||||
}, 3000);
|
||||
};
|
||||
track.addEventListener('ended', remove);
|
||||
track.addEventListener('mute', onMute);
|
||||
track.addEventListener('unmute', onUnmute);
|
||||
/* defensive: if the track is already muted at attach time (the
|
||||
* 'mute' event may have fired before we got here), schedule the
|
||||
* pruning right away */
|
||||
if (track.muted) onMute();
|
||||
}
|
||||
|
||||
/* Spotlight model — every tile keeps its thumbnail permanently in the
|
||||
|
|
@ -3360,8 +3363,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">
|
||||
<span id="pi-seal" style="color:#777;cursor:default;user-select:none" title="">page integrity</span> · built <span class="stamp-date">2026-06-02</span><br>
|
||||
md5 <span class="stamp-md5">e889a0a868e23e2be985f28db80ff031</span><br>
|
||||
sha256 <span class="stamp-sha">e2d9440bd38fc3081eaafe68d972d3ac8a856ace24da919c6eb6b44ec9a0a7d2</span><br>
|
||||
md5 <span class="stamp-md5">f42670fad4ce383bc903910aa43e99a3</span><br>
|
||||
sha256 <span class="stamp-sha">3519283eb1041cef47bab75c9924c4d58702b64c2681aa66ccd71c5d2a9f3cbb</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>
|
||||
</footer>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue