Repository navigation
fix(core): music keeps playing while a preview video swaps to a new copy - #6937
Conversation
Edit accuracy: accurate 271 (base branch 271), smooth 124 of thoseThe gate passes. Quarantined, measured but not gated (0) Unstable (1)
|
There was a problem hiding this comment.
Verdict: APPROVE · 0 blocker · 1 important · 0 nits · head 50a927b0
The Comments ratchet fails, but it is not a required check. See the inline comment.
Scope
I read all 4 files. The only places heldPosters is set and released are in mediaProxy.ts, and both moved to the new {poster, since} shape. mediaNotReadyAt is the only stall gate, so stillStandsIn is the only bypass. A still is held only when the old copy had a frame, so a video with nothing to show still waits.
The fails without the fix: line holds: with !stillStandsIn(el) removed, the named test fails (1 failed, 5 passed); with it back, all 6 pass.
The ~0.16 s lag the PR lists as a known limit gets closed by rate steering, not a seek. The swap evicts the sync state, and 0.16 s is under the 0.5 s hard-sync threshold. That matters only for a swapped video that has its own audible track.
CI, CodeQL, captures, regression, Windows, Player perf and Safari audio are green. Player Safari perf was still running when I reviewed.
| return heldPosters.has(el) ? (heldPosters.get(el)?.poster ?? null) : el.getAttribute("poster"); | ||
| } | ||
|
|
||
| // A swap takes well under a second; a copy still not drawing by now is a real stall. |
There was a problem hiding this comment.
important: Comments fails here. proxySrc.ts goes from 14.3% comments (2/14) to 17.4% (4/23). Cutting this line is enough to pass, because the constant's name already says it.
somanshreddy
left a comment
There was a problem hiding this comment.
Approving at 5b91b744 on Miguel's re-stamp ask, after my own pass over the full diff. The only change since Genesis's approval at 50a927b0 is one deleted comment line in proxySrc.ts.
stillStandsIn: excludes a video showing its held still frommediaNotReadyAtfor at most 2 s, measured fromheldPosters.since. So a proxy swap no longer stops the clock and every playing track, while a copy that never lands still falls back to Buffering after 2 s. Both directions are pinned ininit.buffering.test.ts: stand-in is ~1 s of play with the music unpaused, and expiry withsince60 s back gives a held clock and Buffering.- Type change: moving
heldPostersfromstring | nullto{ poster, since }is applied at both readers:unheldPosterand theletGorestore inmediaProxy.ts. - Nits, non-blocking:
- A re-swap while a still is already held keeps the first
since(holdShownFramereturns early onheldPosters.has). So a panel that settles over more than 2 s of swaps reaches the Buffering fallback sooner than "2 s per swap" suggests. - The ~0.16 s lag matters only for a swapped video that plays its own audio, as stated in the PR.
- A re-swap while a still is already held keeps the first
— Somu
What
Music keeps playing when a preview video swaps to a new copy. The video shows a still of its last frame until the copy can draw. Before, the whole film stopped, music included, for about 200 ms.
Why
Each transport tick stops the film when a clip in view has no data (
mediaNotReadyAt, thenhaltPlayback). A copy swap empties the video on purpose, so the swap itself counted as a stall. The clock and every playing track stopped, then restarted once the copy could draw.How to reproduce: a film of muted video clips over one continuous audio clip, with a swap during play, such as a change of preview quality. A level meter on the audio element reads silence at the swap.
Related work
#6922 added the still that stands in during a swap; this PR lets the film rely on it. A swap of a video that has no frame to show still waits, as before.
How
stillStandsIn(inproxySrc.ts): true while a video shows its held still, for up to 2 s.mediaNotReadyAtskips such a video, so the film plays on.heldPostersnow also keeps when the hold began.Known limit: the copy lands slightly behind the film (0.16 s in the run below), since the clock kept moving while it loaded. I did not measure how quickly that closes before the next cut.
Test plan
init.buffering.test.tsstillStandsIncheck fails the first test; removing its time limit fails the second.packages/core:init.buffering.test.tsandmediaProxy.test.tspassed 3 runs in a row;vitest run src/runtime2702 passed;tsc --noEmitclean;oxlintandoxfmton the changed files.