Reusing HTML5 Audio Object in Mobile Safari

2019-04-04 19:38发布

问题:

I want to play a short (less than 1s) audio file in response to user input on my web app running in Mobile Safari on the iPad with minimum latency between event and audio playback. The playback can be triggered multiple times between page reloads, therefore I want to cache the audio file.

The following plays the file on the first click but after than nothing happens:

var audio = new Audio("ack.mp3");
$("#button").click(function(e) {
  e.preventDefault();
  audio.play();
}

If I add an event listener to the "ended" event which reloads the file I can get two playbacks from the same object and then silence:

var audio = new Audio("ack.mp3");
audio.addEventListener('ended', function() {
  audio.load();
}, false);
$("#button").click(function(e) {
  e.preventDefault();
  audio.play();
}

If I manually set the currentTime attribute to 0 like this:

var audio = new Audio("ack.mp3");
audio.addEventListener('ended', function() {
  audio.currentTime=0;
}, false);
$("#button").click(function(e) {
  e.preventDefault();
  audio.play();
}

I get the following error in the error console:

INDEX_SIZE_ERR: DOM Exception 1: Index or size was negative, or greater than the allowed value.

Any ideas on how to make this work? Thanks in advance

回答1:

set currentTime to 0.1 instead of zero, don't use load() otherwise it will break the ended event.

if you need to preload the media file use:

media.play(); //start loading
if(media.readyState !== 4){ //HAVE_ENOUGH_DATA
  media.addEventListener('canplaythrough', onCanPlay, false);
  media.addEventListener('load', onCanPlay, false); //add load event as well to avoid errors, sometimes 'canplaythrough' won't dispatch.
  setTimeout(function(){
    media.pause(); //block play so it buffers before playing
  }, 1); //it needs to be after a delay, otherwise it will block download and/or won't pause.
}else{
  onCanPlay();
}


回答2:

i had exactly the same problem. it's a dirty trick, but resetting the src on the sound object worked for me:

audio.src = audio.src;
audio.play();