Apple’s new iOS 9 apparently has broken web audio in some situations. Audio no longer plays on Soundslice in iOS 9 Safari, and I’ve seen one other report of this. I’m trying to figure out a solution; let this blog post and comments serve as a repository for fixes/experiments/knowledge.
I suspect Apple has tightened its draconian “Audio can’t be played unless it’s directly initiated by a user interaction” algorithm somehow, but I’m not sure how. If you have any ideas or fixes, please post a comment here, and I will update this post accordingly.
UPDATE, Sept. 19: There’s a workaround! Use
mousedown instead of
touchstart to initiate audio playback. See comments below.
Posted by Jay Oster on September 19, 2015, at 3:30 a.m.:
Play the sound from the touchend event. It doesn't work with touchstart, anymore. See also: https://github.com/goldfire/howler.js/pull/352
Posted by William Malone on September 19, 2015, at 5:07 a.m.:
I posted a simple web audio player test (http://wmalone.com/ios9webaudio) where sounds only work in iOS 9 when loading from both mousedown and touchstart events, but not just from a touchstart event. Both work on iOS 8.
Posted by Tony Wallace on September 19, 2015, at 1:32 p.m.:
I had a similar issue with https://webx0x.com in iOS 9. I was able to resolve it by initializing the audio context from the touchend event. Thanks to Jay for the solution in his comment.
Posted by Joe Weiss on September 19, 2015, at 2:34 p.m.:
I came here to post the touchend solution. I can also confirm that it works.
Posted by Adrian Holovaty on September 19, 2015, at 5:37 p.m.:
Awesome, thanks, guys! I changed my "mousedown touchstart" event handler in Soundslice to a single "mousedown" and it works. Sounds like there are two solutions -- use "mousedown" or "touchend".
Posted by Jay Oster on September 19, 2015, at 9:16 p.m.:
FYI, this bug has been reported upstream to Apple/WebKit: https://bugs.webkit.org/show_bug.cgi?id=149367
Posted by Mitch Wells on September 24, 2015, at 2:01 a.m.:
Just to add in case it isn't clear, the touchend only needs to happen on the first instance of audio. I'm updating my web audio synth so that if you are running an iOS, it makes you click ok before you start and on touchend of "ok", it triggers the first sound.
After that touchstart does trigger sounds.
I am facing a bigger problem in that iOS 9 seems to be adding lots of noise to web audio that I don't think was there before. The noise actually makes my synth unusable on iPhone. arrrg.
Posted by Thorsten Schomburg on September 24, 2015, at 12:01 p.m.:
FYI: Same problem with starting a video. The solution with the touchend event does not work for a slow touch (hold down the finger half a second)
Posted by Yaphi on October 2, 2015, at 3:57 p.m.:
So I'm not alone in this issue. I like touchstart because it creates non-laggy clicks on mobile, but it messes me up in terms of audio. I might just use a click event in the beginning to load the audio and then use touchstart afterwards.
Posted by Arnaud Leyder on October 2, 2015, at 5:27 p.m.:
The touchend solution seems to work fine for audio and video tags with iOS 9.0.2. If you use a click event it also works (minus the lag). There still seems to be some issue with prolonged touch (over 2 seconds) but I think this could be within specs as Safari might consider it a "cancel touch".
Posted by Jonny on October 6, 2015, at 4:15 p.m.:
The same problem and fix has been reported for createjs. Can someone who has reported a fix on here try this test out for me.
Press and hold the "trigger" for 2 seconds and then release. This should still trigger your "click" and "touchend" events but for me it doesn't trigger the audio to play if you press and hold.
Posted by Carl on October 6, 2015, at 10:14 p.m.:
The bug posted about this says it's closed. https://bugs.webkit.org/show_bug.cgi?id=149367
Does that mean it's getting updated in a new release?
Posted by ism on October 10, 2015, at 9:33 p.m.:
I'm having problems with wad.js too. Anybody got a workaround for that library? touchend, mousedown, etc., don't resolve issue.
Posted by Nikolay Tsenkov on October 13, 2015, at 12:40 p.m.:
I think, they've fixed this in WebKit, but it probably hasn't been released, yet.
I doubt it will be more than a month from official release.
Here is the commit: https://github.com/WebKit/webkit/commit/70969efa4aa9425ceb04346a468de832f88945ac
Posted by Jason on November 11, 2015, at 6:56 p.m.:
Thanks Mitch Wells!
Yeah I'm working on a web synth as well, and touchend is not a good solution.
Handling touchend on first touch, then from then on touchstart works is a better solution.
I think you can avoid the ios9 fix prompt by playing on touchend of the first note that's hit. Just keep a state for hasFirstNoteBeenPlayed, and then play a sound on touchend.
e.g. my touchend event winds up calling this function:
//'this' is the object that defines the stopNote function in this case, not a dom node
var oscFix = this.options.audioContext.createOscillator();
oscFix.type = 'sine';
oscFix.frequency.value = 100000;
oscFix.start ? oscFix.start() : oscFix.noteOn();
oscFix.stop ? oscFix.stop() : oscFix.noteOff();
this.hasFirstNoteBeenPlayed = true;
So the first press won't work, but subsequent presses will work.
Comments have been turned off for this page.