HTML5 audio object doesn't play on iPad (when called from a setTimeout)
audio, html, ipad, javascript, settimeout
Solution
See Apple's iOS considerations guide:
...the JavaScript `play()` and `load()` methods are also inactive until the user initiates playback, unless the `play()` or `load()` method is triggered by user action. In other words, a user-initiated Play button works, but an `onLoad="play()"` event does not.
It appears that your `setTimeout()` callback does not qualify as user-initiated action, despite the fact that the `setTimeout()` itself was in a user-initiated function.
Suggestion: I don't have an iOS device to test on, but maybe doing an initial play/pause when the user presses the button will relieve this restriction. That is, you call `play()` and then pause it at once, then make your call to animate and the `setTimeout()` function with the `play()` call. This makes the user-initiated function let iOS know that it is okay to load and play this video in the future.
Problem
I have a page with a hidden `<audio>` object which is being started and stopped using a custom button via javascript. (The reason being I want to customise the button, and that drawing an audio player seems to destroy rendering performance on iPad anyway). A simplified example (in coffeescript): ``` // Works fine on all browsers constructor: (@_button, @_audio) -> @_button.on 'click', @_play // Bind button's click event with jQuery _play: (e) => @_audio[0].play() // Call play() on audio element ``` The audio plays fine when triggered from a function bound to a `click` event, but I actually want an animation to complete before the file plays so I put `.play()` inside a `setTimeout`. However I just can't get this to work: ``` // Will not play on iPad constructor: (@_button, @_audio) -> @_button.on 'click', @_play // Bind button's click event with jQuery _play: (e) => setTimeout (=> // Declare a 300ms timeout @_audio[0].play() // Call play() on audio element ), 300 ``` I've checked that `@_audio` (`this._audio`) is in scope and that its `play()` method exists. Why doesn't this work on iPad? Edit: As it happens, the simplified test case above actually does work. See @apsillers' answer below and my comments on it.