mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-04 07:19:52 +00:00
fix(core): avoid live volume probe during render
This commit is contained in:
@@ -1834,6 +1834,10 @@ export function initSandboxRuntimeModular(): void {
|
||||
state.capturedTimeline,
|
||||
getSafeTimelineDurationSeconds(state.capturedTimeline, 0),
|
||||
volumeKeyframeCache,
|
||||
{
|
||||
allowLiveTimelineSeek: !(window as Window & { __HF_RENDER_CAPTURE_MODE?: boolean })
|
||||
.__HF_RENDER_CAPTURE_MODE,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,32 @@ import { describe, expect, it } from "vitest";
|
||||
import { probeAndCacheElementVolume } from "./mediaVolumeEnvelope";
|
||||
|
||||
describe("probeAndCacheElementVolume", () => {
|
||||
it("does not seek or cache when live timeline probing is disabled", () => {
|
||||
const audio = document.createElement("audio");
|
||||
audio.dataset.volume = "1";
|
||||
document.body.append(audio);
|
||||
|
||||
let seekCount = 0;
|
||||
const timeline = {
|
||||
totalTime(next?: number) {
|
||||
if (next !== undefined) {
|
||||
seekCount += 1;
|
||||
audio.volume = next >= 1 ? 0 : 1;
|
||||
}
|
||||
return 0.75;
|
||||
},
|
||||
};
|
||||
const cache = new WeakMap<HTMLMediaElement, { time: number; volume: number }[]>();
|
||||
|
||||
probeAndCacheElementVolume(audio, timeline, 1, cache, {
|
||||
allowLiveTimelineSeek: false,
|
||||
});
|
||||
|
||||
expect(seekCount).toBe(0);
|
||||
expect(audio.volume).toBe(1);
|
||||
expect(cache.has(audio)).toBe(false);
|
||||
});
|
||||
|
||||
it("restores the timeline playhead after sampling volume automation", () => {
|
||||
const audio = document.createElement("audio");
|
||||
audio.dataset.volume = "1";
|
||||
|
||||
@@ -129,6 +129,18 @@ export function probeElementVolumeKeyframes(
|
||||
|
||||
export type RuntimeTimelineRef = Partial<Pick<RuntimeTimelineLike, "totalTime" | "seek">>;
|
||||
|
||||
export interface VolumeProbeOptions {
|
||||
/**
|
||||
* Render/probe pages must not sample the live visual timeline during runtime
|
||||
* initialization. The producer discovers audio automation in its own
|
||||
* isolated pass and bakes it before frame capture, so seeking here is both
|
||||
* redundant and capable of materializing future zero-duration GSAP state.
|
||||
*
|
||||
* Preview callers omit this option and retain live automation discovery.
|
||||
*/
|
||||
allowLiveTimelineSeek?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe a media element and, if volume automation is detected, store the
|
||||
* keyframes in `cache`. Safe to call with a null timeline — returns early.
|
||||
@@ -138,7 +150,9 @@ export function probeAndCacheElementVolume(
|
||||
timeline: RuntimeTimelineRef | null | undefined,
|
||||
compositionDuration: number,
|
||||
cache: WeakMap<HTMLMediaElement, VolumeKeyframe[]>,
|
||||
options: VolumeProbeOptions = {},
|
||||
): void {
|
||||
if (options.allowLiveTimelineSeek === false) return;
|
||||
if (!timeline) return;
|
||||
if (!(mediaEl instanceof HTMLAudioElement) && !(mediaEl instanceof HTMLVideoElement)) return;
|
||||
if (compositionDuration <= 0) return;
|
||||
|
||||
Reference in New Issue
Block a user