Edit (November 2015): iOS 9 no longer allows audio to start in a touchstart
event, which breaks the solution below. However it works in a touchend
event. The original answer for iOS 6 is left intact below, but for iOS 9 support make sure you use touchend
.
Well, sorry to answer my own bounty question, but after hours of debugging I finally found the answer. Safari on iOS 6 effectively starts with the Web Audio API muted. It will not unmute until you attempt to play a sound in a user input event (create a buffer source, connect it to destination, and call noteOn()
). After this, it unmutes and audio plays unrestricted and as it ought to. This is an undocumented aspect of how the Web Audio API works on iOS 6 (Apple's doc is here, hopefully they update it with a mention of this soon!)
The user can be touching the screen a lot, engaged in the game. But it will remain muted. You have to play inside a user input event like touchstart
[edit: touchend
for iOS 9+], once, then all audio unmutes. After that you can play audio at any time (doesn't have to be in a user input event).
Note this is different to the restrictions on HTML5 audio: typically you can only start audio at all in a user input event, and only play one sound at a time; the Web Audio API fully unmutes after the first play-in-user-input, so that you can play sounds at any time, and then you can mix them polyphonically, process cool effects, etc.
This means many games already on the web using the Web Audio API will never play audio, because they do not happen to issue a noteOn in a touch event. You have to adjust it to wait for the first user input event.
There are a few ways to work around this: don't play your title music until the user touches the screen; have an initial 'touch to enable audio' screen and play a sound then begin the game when they touch; etc. Hopefully this will help anyone else having the same problem save some time trying to debug it!
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…