fix(core): only the clips the start wait gave up on run on without data

This commit is contained in:
Miguel Angel Simon Sierra
2026-11-02 02:11:19 -05:00
parent 4e0740ee16
commit 2546ed040a
2 changed files with 29 additions and 10 deletions
@@ -148,6 +148,23 @@ it("after a start that ran on without data, the next clip without data holds aga
expect(states.at(-1)).toEqual({ isPlaying: true, buffering: true });
});
it("a clip due while another catches up from the start still holds, then plays with the first one still cold", () => {
const { voiceReady, states, playFor } = playPodcast(0.5, "audio", 1);
playFor(0.45);
expect(states.at(-1)).toEqual({ isPlaying: true, buffering: false });
playFor(0.45);
expect(states.at(-1)).toEqual({ isPlaying: true, buffering: true });
const heldAt = window.__player!.getTime();
playFor(0.3);
expect(window.__player!.getTime()).toBe(heldAt);
voiceReady.value = 4;
playFor(0.3);
expect(states.at(-1)).toEqual({ isPlaying: true, buffering: false });
expect(window.__player!.getTime()).toBeGreaterThan(heldAt);
});
it("holds on the frame a slow tick skips into a clip with no data, after asking it to play", () => {
const { voice, states, playFor, step } = playPodcast(0.5);
+12 -10
View File
@@ -3447,7 +3447,7 @@ export function initSandboxRuntimeModular(): void {
// Play waits this long for a clip with no data, then runs on and lets the clip catch up; mid-film it holds.
const START_WAIT_MS = 300;
let startWaitUntilMs: number | null = null;
let catchingUp = false;
let catchingUpFor: HTMLMediaElement[] = [];
let resumingFromBuffering = false;
// The one definition of "media the transport drives": timed itself, or hosted
@@ -4785,7 +4785,7 @@ export function initSandboxRuntimeModular(): void {
bufferingFor = [];
if (!resumingFromBuffering) {
startWaitUntilMs = performance.now() + START_WAIT_MS;
catchingUp = false;
catchingUpFor = [];
}
const tl = state.capturedTimeline;
if (clock.isPlaying()) return;
@@ -4822,7 +4822,7 @@ export function initSandboxRuntimeModular(): void {
const wasBuffering = bufferingFor.length > 0;
bufferingFor = [];
startWaitUntilMs = null;
catchingUp = false;
catchingUpFor = [];
if (clock.isPlaying()) haltPlayback();
else if (wasBuffering) postState(true);
},
@@ -5674,7 +5674,7 @@ export function initSandboxRuntimeModular(): void {
if (clock.hasAudioSource()) clock.detachAudioSource();
} else if (
source &&
catchingUp &&
catchingUpFor.includes(source.el) &&
source.el.readyState < HTMLMediaElement.HAVE_FUTURE_DATA
) {
// Past the start wait the playhead runs on its own clock while this track catches up.
@@ -5908,16 +5908,18 @@ export function initSandboxRuntimeModular(): void {
const notReady = mediaNotReadyAt(state.currentTime);
if (startWaitUntilMs !== null && performance.now() >= startWaitUntilMs) {
startWaitUntilMs = null;
catchingUp = notReady.length > 0;
catchingUpFor = notReady;
}
if (notReady.length === 0) catchingUp = false;
if (clock.isPlaying() && notReady.length > 0 && !catchingUp) {
bufferingFor = notReady;
catchingUpFor = catchingUpFor.filter((el) => notReady.includes(el));
const mustWaitFor = notReady.filter((el) => !catchingUpFor.includes(el));
if (clock.isPlaying() && mustWaitFor.length > 0) {
bufferingFor = mustWaitFor;
haltPlayback(true);
} else if (
bufferingFor.length > 0 &&
(catchingUp ||
!mediaNotReadyAt(state.currentTime, canResumeFrom).some((el) => bufferingFor.includes(el)))
!mediaNotReadyAt(state.currentTime, canResumeFrom)
.filter((el) => !catchingUpFor.includes(el))
.some((el) => bufferingFor.includes(el))
) {
resumingFromBuffering = true;
try {