Skip to content

fix(core): decode WebKit sources by memory budget, not by length - #7232

Merged
miguel-heygen merged 1 commit into
mainfrom
rsafari/av-budget
Nov 5, 2026
Merged

miguel-heygen merged 1 commit into
mainfrom
rsafari/av-budget

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Nov 5, 2026 •

Copy link
Copy Markdown
Collaborator

What

Follow-up to the merged decode-first change. A WebKit source is now decoded when its decoded audio fits a 256 MB memory budget shared by all sources, in place of a fixed 600 s length. A source over the budget stays on its element, as before.

Why

The length limit was a stand-in for memory. Two 9-minute sources fit it one by one and together held 400 MB, while one 11-minute source was refused with room to spare. The budget counts what is held (decoded buffers) and what is being decoded (stereo float estimate from the duration), and a source already decoded or decoding keeps its verdict for all of its clips.

Measured

Unit level only. Decoded size of a 321 s source is 62 MB mono or 123 MB stereo. The budget is my number, not measured on a phone.

Not covered

  • A source over the budget still plays sound about 300 ms late on Safari. Constant lag compensation on the element path does not fix it: with +0.3 s on the audio seek target, sound vs timeline moved to -55, -103 and -189 ms in three plays, so the lag is not one fixed number.
  • iPhone memory under the budget is unconfirmed.

Tests

fails without the fix: "bare audio in WebKit > hands a 650 s source to a decoded buffer, past the old 600 s limit". On main it reports expected "releaseRouted" to be called with arguments: [ <audio> ], the sound never leaves its element. New in webAudioTransport.test.ts, "decode budget": a ten minute source fits and one hour does not, a source that is decoding counts against the next, an unloaded clip is left to its source.

Size

About 75 changed lines in two files plus tests; it replaces the 600 s constant the merged change introduced.

heygengenesis[bot]
heygengenesis Bot previously approved these changes Nov 5, 2026

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving at b03b74e8. I found no blocker.

Fails without the fix: confirmed. I put init.ts and webAudioTransport.ts back to the parent (d548e356) and kept the new test. "bare audio in WebKit > hands a 650 s source to a decoded buffer, past the old 600 s limit" then fails with expected "releaseRouted" to be called with arguments: [ <audio …> ]. At the head, webAudioTransport.test.ts and init.test.ts pass locally (402/402).

Checked:

  • No race in the accounting. In init.ts the only caller that checks the budget calls decodeAudioElement straight after fitsDecodeBudget, in the same tick. _pendingDecodeBytes is set before anything awaits, so two sources can't both pass on the same headroom.
  • A source keeps its verdict for all its clips. A source that is cached or decoding short-circuits to true, so a clip whose duration is still NaN follows its source.
  • The estimate is sound. decodeAudioData resamples to the context rate, so the estimate (seconds × ctx rate × 2 ch × 4 B) is exact for stereo and twice the real size for mono. If it's wrong, it leaves sources on their element, which is the safe side.

Non-blocking nits:

  • releaseDecodedExcept drops a buffer from _bufferCache even while an AudioBufferSourceNode is still playing it. The budget then counts less than is actually held. It's small and short-lived, but worth knowing on iPhone.
  • The non-scheduled fallback decode (the effectiveRate === 1 path at the end of the capture callback) still decodes without checking the budget. That is unchanged from before, but its buffers now count against the budget for sources that do check it.
  • As the description says, 256 MB is untested on a real device.

CI: the red Comments check is infrastructure. oven-sh/setup-bun got an HTTP 504, so typescript was missing for the ratchet script. It is not caused by this change and needs a re-run.

Base automatically changed from rsafari/av-offset to main November 5, 2026 11:23
@miguel-heygen
miguel-heygen dismissed heygengenesis[bot]’s stale review November 5, 2026 11:23

The base branch was changed.

@github-actions

github-actions Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 267 (base branch 267), smooth 106 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (8)

Unstable (1)

  • seqplainkeys-none-px-r0-root-z100: tracking 0.06, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo false, teleport true / tracking 0.06, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo true, teleport true / tracking 0.06, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo true, teleport true

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-approving at 69b12fdc after the rebase onto main, now that #7225 has merged. I found no blocker.

  • The patch is unchanged. Compared against its merge-base, the diff matches b03b74e8, which I approved, apart from hunk line offsets in init.ts.
  • Fails without the fix, confirmed on main. With main's init.ts and webAudioTransport.ts, "bare audio in WebKit > hands a 650 s source to a decoded buffer, past the old 600 s limit" fails with expected "releaseRouted" to be called with arguments: [ <audio …> ]. At the head, webAudioTransport.test.ts and init.test.ts pass 402/402.
  • CI on this head: every workflow has a successful run. The cancelled entries are duplicate runs that concurrency superseded.

My earlier non-blocking nits still apply:

  • The budget counts less than is held when a released buffer is still playing.
  • The fallback decode path still skips the budget check.
  • 256 MB hasn't been tried on a phone.

@miguel-heygen
miguel-heygen added this pull request to the merge queue Nov 5, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Nov 5, 2026

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-approving at 33c8aa3b. This head is a rebase only, onto main after the 0.9.16 release.

  • The change is unchanged. Compared against its merge-base, the PR's patch matches 69b12fdc, which I approved, apart from index hashes and hunk offsets. It's still the single commit "fix(core): decode WebKit sources by memory budget, not by length".
  • The tests still pass on the new base. At this head, webAudioTransport.test.ts and init.test.ts pass 402/402. I confirmed on main at the previous head that the named 650 s test fails without the fix.
  • CI: when I approved, PR captures was green and the other workflows were still running on this head.

@miguel-heygen
miguel-heygen added this pull request to the merge queue Nov 5, 2026
Merged via the queue into main with commit 600bfa4 Nov 5, 2026
104 of 106 checks passed
@miguel-heygen
miguel-heygen deleted the rsafari/av-budget branch November 5, 2026 17:12
SanHsien added a commit to SanHsien/hyperframes that referenced this pull request Nov 6, 2026
…view

Adopts heygen-com#7250 (SVG stroke drawing is not a dead stretch), heygen-com#7248
(contract check reads a timeline registered in a local script), heygen-com#7252
(comma-list selectors hidden by authored CSS), heygen-com#7238 (snapshot and
preview show a clip on the render frame), heygen-com#7237 (stalled cloud upload
retries) and heygen-com#7251 (per-scene SVG id namespacing), with prerequisite
heygen-com#6829. Defers heygen-com#7246 (needs the delivery limiter from heygen-com#6940) and heygen-com#7232
(needs the WebKit decode-first pipeline), with conditions in the
ledger. Watermark advances to b108f85.

Co-authored-by: Miguel Ángel <miguel.sierra@heygen.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant