Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Html5 Audio timeupdate precision

I am working with HTML5 audio. For my use-case, I need to listen on the audio duration played and once it crosses a certain threshold, pause the audio. So something like:

$(audio).bind('timeupdate', function() {
  if (audio.currentTime >= 10){
     audio.pause();
  }
});

What I am noticing is that by the time my handler executes, audio.currentTime is around 10.12878, 10.34023 etc and hence, some little extra audio is played before it is paused.

Another question seems to have documented the same issue.The question is dated in 2012 so I am wondering if the state of the art has improved.

If not, what other ways exist to do this with more precision? I haven't worked with audio much before and I would really appreciate the help.

like image 374
Rajat Avatar asked May 10 '16 21:05

Rajat


3 Answers

According to MDN documentation, timeupdate event

The event frequency is dependant on the system load, but will be thrown between about 4Hz and 66Hz (assuming the event handlers don't take longer than 250ms to run). User agents are encouraged to vary the frequency of the event based on the system load and the average cost of processing the event each time, so that the UI updates are not any more frequent than the user agent can comfortably handle while decoding the video.

To pause audio at 10.0nnnnn, you can utilize requestAnimationFrame; if condition this.currentTime > 9.999 to call .pause() before reaching 10.000000. Note, 9.999 can be adjust to between 9.9 through 9.99750, which could also periodically pause audio at 9.99nnnn; that is, before reaching 10.0

var requestAnimationFrame = window.requestAnimationFrame;

var audio;

function trackCurrentTime() {
  // `this` : `audio`
  console.log(this.currentTime);
  if (this.currentTime > 9.999) {
    this.pause();
  } else {
    requestAnimationFrame(trackCurrentTime.bind(this))
  }
}

var request = new XMLHttpRequest();
request.open("GET", "/path/to/audio", true);
request.responseType = "blob";
request.onload = function() {
  if (this.status == 200) {
    audio = new Audio(URL.createObjectURL(this.response));
    audio.onpause = function(e) {
      console.log(e.target.currentTime)
    }
    audio.load();
    audio.play();
    trackCurrentTime.call(audio);
  }
}
request.send();

jsfiddle http://jsfiddle.net/Lg5L4qso/7/

like image 177
guest271314 Avatar answered Sep 18 '22 21:09

guest271314


So I researched my way through this problem and came out with the following findings:

1) HTML Audio is no dice for such a scenario. Its a very limited API and doesn't offer fine grain audio control. Web Audio API is the way to go for this.

2) Web Audio API is not the easiest thing to read/understand and is perhaps weakly implemented across various browsers. Its better to find a nice wrapper around it that fallsback to web audio or flash when Web Audio is not available in a browser.

3) Some wrappers exist like howler.js, sound.js and SoundManager2. Off the three SoundManager2 seems the best fit at first thought. Demo 4G at http://www.schillmania.com/projects/soundmanager2/demo/api/ effectively solves a very similar problem as in the scenario in the question.

Update: SoundManager2 actually doesn't support the web audio api. From the technotes:

SM2 does not presently use the Webkit Audio API. It may be experimentally or more formally added at some point in the future, when the API is more universally-supported.

like image 22
Rajat Avatar answered Sep 19 '22 21:09

Rajat


HTML Audio is no dice for such a scenario. Its a very limited API and doesn't offer fine grain audio control. Web Audio API is the way to go for this.

like image 20
h nn n n Avatar answered Sep 20 '22 21:09

h nn n n