Skip to content

audio: don't reset a healthy pipeline on tab refocus - #160

Merged
pcarrier merged 1 commit into
mainfrom
audio-refocus-reset
Aug 3, 2026
Merged

audio: don't reset a healthy pipeline on tab refocus#160
pcarrier merged 1 commit into
mainfrom
audio-refocus-reset

Conversation

@pcarrier

@pcarrier pcarrier commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Problem

Refocusing the blit tab caused a brief audio dropout. The visibilitychange handler in AudioPlayer unconditionally called resetPipeline() whenever the tab became visible after being hidden for more than 3 seconds — tearing down the AudioContext, decoder, and worklet, then rebuilding on the next frame (async worklet reload + decoder reinit + re-buffering to bufferTarget).

The reset was meant as preemptive recovery, but browsers exempt audibly-playing tabs from background throttling: the pipeline usually keeps rendering fine while hidden, so the reset was interrupting working audio on every refocus.

Fix

Gate the reset on evidence of actual breakage:

  • worklet position reports (posted every ~100 ms while the context runs) stale for >3 s, or
  • the AudioContext is "closed".

Otherwise run an immediate checkHealth(), which still resumes a suspended context and escalates to a reset on real stalls — so recovery for genuinely broken background audio is preserved.

Testing

  • tsc --noEmit clean, all 566 js/core tests pass.
  • Manual repro: play audio, background the tab >5 s, refocus — no dropout; audio continues seamlessly.

The visibilitychange handler unconditionally ran resetPipeline() when
the tab became visible after >3 s hidden, causing an audible dropout on
every refocus. Browsers exempt audibly-playing tabs from background
throttling, so the pipeline usually keeps rendering while hidden and
the preemptive reset was interrupting working audio.

Gate the reset on evidence of breakage: stale worklet position reports
(>3 s old) or a closed AudioContext. Otherwise run an immediate health
check, which still escalates to a reset on real stalls.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@indent

indent Bot commented Aug 3, 2026

Copy link
Copy Markdown
PR Summary

Stops AudioPlayer from tearing down and rebuilding a healthy audio pipeline every time the blit tab is refocused. The old visibilitychange handler reset unconditionally after the tab was hidden >3 s, causing a ~100-200 ms audible dropout even though browsers keep audibly-playing tabs rendering while hidden. The reset is now gated on real breakage evidence, otherwise it defers to the existing checkHealth() path.

  • Refocus reset condition tightened from wasHiddenMs > 3_000 to wasHiddenMs > 3_000 && (workletStale || ctxDead), where workletStale = worklet position reports (posted ~every 100 ms) gone stale >3 s and ctxDead = AudioContext.state === "closed".
  • All other refocus cases now run an immediate checkHealth(), which still resumes suspended contexts and escalates to a reset on genuine worklet/decoder stalls, so recovery for actually-broken background audio is preserved.
  • Comment rewritten to document the audible-exempt rationale; change is confined to the startHealthCheck() handler with no API, wire, or consumer impact.

Issues

Review closed.

CI Checks

All CI checks passed on c0a2474.

View session

@pcarrier
pcarrier requested a review from jsegaran August 3, 2026 01:12
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

Coverage

Crate Lines Functions Regions
alacritty-driver 69.7% (698/1002) 72.0% (54/75) 71.7% (1050/1464)
browser 0.0% (0/807) 0.0% (0/65) 0.0% (0/1370)
cli 17.2% (1521/8821) 28.1% (200/712) 20.1% (2730/13555)
compositor 2.6% (246/9558) 7.3% (32/439) 2.7% (352/12801)
fonts 81.4% (721/886) 88.6% (70/79) 83.0% (1427/1719)
fssync 92.5% (4880/5274) 94.1% (445/473) 92.5% (8926/9647)
gateway 26.1% (375/1437) 29.9% (38/127) 19.9% (470/2360)
git 87.3% (4165/4771) 88.2% (328/372) 87.0% (6594/7582)
lsp 76.0% (2503/3295) 78.2% (248/317) 73.8% (3886/5266)
proxy 19.3% (172/892) 20.5% (26/127) 21.2% (293/1381)
remote 90.2% (8628/9561) 92.9% (619/666) 88.0% (14359/16310)
sd-notify 73.9% (68/92) 100.0% (6/6) 83.2% (109/131)
server 37.3% (6504/17458) 51.0% (624/1224) 39.9% (11112/27824)
ssh 1.9% (7/374) 3.2% (1/31) 0.7% (4/613)
upsidedown 31.4% (391/1247) 27.8% (55/198) 34.8% (797/2287)
webrtc-forwarder 2.7% (72/2624) 2.1% (4/187) 1.2% (50/4335)
webserver 60.3% (1051/1742) 64.7% (156/241) 63.1% (1800/2851)
Total 45.8% (32002/69841) 54.4% (2906/5339) 48.4% (53959/111496)

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

🔗 Preview: https://blit-gyldbvd4d-indent.vercel.app

@pcarrier
pcarrier merged commit 0838589 into main Aug 3, 2026
12 checks passed
@pcarrier
pcarrier deleted the audio-refocus-reset branch August 3, 2026 15:41
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.

2 participants