35

I'm trying to create a simple looping feature using HTML5 audio and have a very primitive solution as follows:

$(audio).bind('timeupdate', function() {
  if (audio.currentTime >= 26){
    var blah = audio.currentTime; 
    audio.currentTime = 23;
    console.log(blah);
  }
})

This works fine but the only glitch here is that the timeupdate event doesnt trigger very consistently. For instance, the console.log above returned: 26.14031982421875

26.229642868041992

26.13462257385254

26.21796226501465

...etc. (You get the idea..inconsistent times)

Obviously this won't work for an application where the timing is important (music applications). So the obvious solution to me would be to increase the granularity with which the timeupdate event is triggered. I havent been able to find any API docs...but would love to know if there is a way to do this.

udit
  • 2,745
  • 3
  • 33
  • 44

2 Answers2

64

It should be noted that you can read the currentTime property of a video much more often. If time is really critical, and you can live with a little bit of uncertainty, you can try this instead.

It is, however, a lot less elegant than using the tag's own timeupdate event.

setInterval(function () {
    console.log(audio.currentTime); // will get you a lot more updates.
}, 30);

In this case, you'll have to manage the interval yourself, make sure that you clear it before nulling the audio element. But it is a possibility.

I'm using this approach on a video element, but it should apply here, too.

amenthes
  • 3,117
  • 1
  • 32
  • 38
  • 7
    we use this inside a cordova project that plays/pauses a video in tandem with a content-layer the user gets to control. In that case, we didn't have a performance issue with it. But it is true, you now have _one more_ thing to do every few milliseconds. Instead of setInterval, you could also read the `.currentTime` whenever another event occurs (like user interaction). Or you could calculate a "safe margin" if you care about video position, but only "around" the 1 minute mark - set a timeout for 59 seconds and start a tighter interval after those 59 seconds. – amenthes Feb 17 '14 at 12:37
  • 1
    For shorter audio clips, this method is almost invisible – August Jan 22 '16 at 04:22
  • 7
    Probably better to use `requestAnimationFrame` instead of `setInterval`. – ffxsam Dec 17 '16 at 22:12
  • 1
    Only in case you're updating a visual thing. We did not do this for two reasons: we did not display the current state (ok, we did, too, but for that the `timeupdate`-event was good enough) but compared it to an internal reference. Also, at that time, requestAnimationFrame was not widely supported. – amenthes Dec 18 '16 at 15:49
  • FWIW requestAnimationFrame is guaranteed "max 60 fps" it seems...so if you need to do anything with more granularity, use Interval I guess... – rogerdpack Dec 15 '17 at 11:58
  • 2
    This should be the accepted answer since it gives an actual solution instead of just saying it can't be done.. kudos for thinking out of the box and providing a solution! – supersan Jun 22 '19 at 12:44
31

I'm sorry, but that's the way it works. From the html5 specs:

Every 15 to 250ms, or whenever the MediaController's media controller position changes, whichever happens least often, the user agent must queue a task to fire a simple event named timeupdate at the MediaController.

Also,

The event thus is not to be fired faster than about 66Hz or slower than 4Hz (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.

If you read through the specification, you can get the idea that timeupdate event is something of a "best effort" kind of event. It will fire when it can and always as long as it does not to affect performance too much.

You could filter the events discarding some from time to time to smooth the arrival times, but I'm afraid it's not possible to do the opposite.

jbalsas
  • 3,484
  • 22
  • 25