web audio api autoplay policy broke my game on first load, anyone got a clean pattern for this?

448 views 1 reply

Been fighting with the Web Audio API for the past couple weeks on a browser game and I'm slowly losing my mind. The autoplay policy stuff is way more annoying than I expected when you're dealing with actual game audio, not just a music player.

The core problem: browsers require a user gesture before any audio can play. Fine, I get it. But in a game you've got a dozen things that want to make noise: UI clicks, ambient loops, positional SFX. They all depend on the AudioContext being in a running state. My current hack is resuming the context on any pointerdown on the canvas, but this breaks in weird ways on iOS Safari specifically.

I've tried a few approaches:

  • Global click-to-start screen that resumes context before the game loads. Works but feels janky for returning players
  • Lazy context creation on first gesture. Cleaner, but then your very first sound always has a noticeable lag spike
  • Keeping a silent AudioBufferSourceNode "warm". Read about this trick somewhere but I'm not sure if it still works post-Chrome 71

The iOS situation is its own nightmare. AudioContext.state will happily report running while audio just... silently doesn't play. Until you suspend and resume it again manually. It's maddening.

reaction

I'm using Howler.js for audio management but even Howler's built-in unlock mechanism has edge cases I keep hitting, especially when the page goes to background and comes back. Wondering if I should just drop it and write a thin wrapper myself at this point.

Anyone got a pattern they're actually happy with? Specifically curious if anyone's handled the "context auto-suspended after tab loses focus" case cleanly without a bunch of duct tape.

the pattern that finally worked for me: create the AudioContext immediately on page load but don't resume it. attach a single pointerdown listener to document that calls audioCtx.resume() then removes itself. only schedule nodes after that first interaction fires.

the catch: if your game has a loading screen, you want that first pointer interaction to be the "start game" button, not some random UI click before audio is ready. so I gated audio init behind a flag that only sets after assets finish loading. a bit annoying to wire up but it's been consistent across Chrome, Firefox, and Safari for me at least.

Moonjump
Forum Search Shader Sandbox
Sign In Register