mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 09:16:55 +00:00
fix(core): a frame capture keeps waiting for a video between its range requests (#4490)
This commit is contained in:
@@ -819,10 +819,17 @@ describe("syncRuntimeMedia", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("releases a loading video that stops fetching before it has data", async () => {
|
||||
it("keeps holding a loading video through a suspend between range requests", async () => {
|
||||
const clip = seekLoadingVideo();
|
||||
const barrier = waitForSeekCompletion();
|
||||
clip.el.dispatchEvent(new Event("suspend"));
|
||||
expect(await barrierSettled(barrier)).toBe(false);
|
||||
Object.defineProperty(clip.el, "seeking", { value: true, configurable: true });
|
||||
clip.el.dispatchEvent(new Event("loadedmetadata"));
|
||||
clip.el.dispatchEvent(new Event("seeking"));
|
||||
expect(await barrierSettled(barrier)).toBe(false);
|
||||
Object.defineProperty(clip.el, "seeking", { value: false, configurable: true });
|
||||
clip.el.dispatchEvent(new Event("seeked"));
|
||||
expect(await barrierSettled(barrier)).toBe(true);
|
||||
});
|
||||
|
||||
|
||||
@@ -19,13 +19,13 @@ export function readElementPlaybackStart(el: Element): number {
|
||||
return readMediaStart(el);
|
||||
}
|
||||
|
||||
const HOLD_END_EVENTS = ["seeked", "loadeddata", "suspend", "error", "emptied", "abort"] as const;
|
||||
const HOLD_END_EVENTS = ["seeked", "loadeddata", "error", "emptied", "abort"] as const;
|
||||
const HOLD_CAP_MS = 5000;
|
||||
const releaseHeldVideo = new WeakMap<HTMLMediaElement, () => void>();
|
||||
|
||||
// A seeking video still paints its previous frame, and one still fetching its first data paints none (its seek
|
||||
// waits for metadata without setting `seeking`); frame captures wait on the seek barrier until it lands. Each seek
|
||||
// re-arms a 5 s cap, and listeners run in the capture phase so a failing <source> child releases the hold.
|
||||
// waits for metadata without setting `seeking`); frame captures wait on the barrier until it lands. The 5 s cap is
|
||||
// the only end for a stalled source (`suspend` also fires between range requests); capture phase catches <source>.
|
||||
function holdSeekBarrierUntilVideoLands(el: HTMLMediaElement): void {
|
||||
const loading =
|
||||
el.readyState < el.HAVE_CURRENT_DATA &&
|
||||
@@ -36,7 +36,7 @@ function holdSeekBarrierUntilVideoLands(el: HTMLMediaElement): void {
|
||||
registerSeekCompletion(
|
||||
new Promise<void>((resolve) => {
|
||||
const done = (event?: Event) => {
|
||||
if ((event?.type === "loadeddata" || event?.type === "suspend") && el.seeking) return;
|
||||
if (event?.type === "loadeddata" && el.seeking) return;
|
||||
clearTimeout(cap);
|
||||
for (const type of HOLD_END_EVENTS) el.removeEventListener(type, done, true);
|
||||
if (releaseHeldVideo.get(el) === done) releaseHeldVideo.delete(el);
|
||||
|
||||
Reference in New Issue
Block a user