74

How to jump to certain time offsets in HTML5 Audio elements?

They say you can simply set their currentTime property (emphasis mine):

The currentTime attribute must, on getting, return the current playback position, expressed in seconds. On setting, if the media element has a current media controller, then it must throw an INVALID_STATE_ERR exception; otherwise, the user agent must seek to the new value (which might raise an exception).

Alas, it doesn't seem to work (I need it in Chrome).

There are similar questions, although, no answers.

katspaugh
  • 15,752
  • 9
  • 61
  • 97
  • 3
    fixed it with [`audioelement.onloadedmetadata = function(){ audioelement.currentTime = time; }`](http://stackoverflow.com/questions/11231081/selecting-the-html5-video-object-with-jquery) – Stano Aug 03 '13 at 22:58

9 Answers9

74

To jump around an audio file, your server must be configured properly.

The client sends byte range requests to seek and play certain regions of a file, so the server must response adequately:

In order to support seeking and playing back regions of the media that aren't yet downloaded, Gecko uses HTTP 1.1 byte-range requests to retrieve the media from the seek target position. In addition, if you don't serve X-Content-Duration headers, Gecko uses byte-range requests to seek to the end of the media (assuming you serve the Content-Length header) in order to determine the duration of the media.

Then, if the server responses to byte range requests correctly, you can set the position of audio via currentTime:

audio.currentTime = 30;

See MDN's Configuring servers for Ogg media (the same applies for other formats, actually).

Also, see Configuring web servers for HTML5 Ogg video and audio.

Jeremy
  • 1
  • 77
  • 324
  • 346
katspaugh
  • 15,752
  • 9
  • 61
  • 97
  • 9
    +1 for getting at the real problem, which is that SimpleHTTPServer is just an HTTP 1.0 server which doesn't understand byte range requests. – Daniel Lubarov Apr 19 '12 at 08:56
  • 3
    +1 for answering a JavaScript question with JavaScript and not a lets-all-jump-off-a-bridge-because-everyone-else-is framework. – John Sep 22 '14 at 18:20
  • 5
    As near as I've been able to figure out, WebKit/Chrome seeking **only** works when using `Accept-Ranges: bytes`, even for data that is already buffered (setting `Content-Length` or `X-Content-Duration` doesn't help)... This is rather strange, since not all backends are able to support content ranges (mine doesn't, since we convert files on-the-fly)... Firefox is saner, and works as expected (you can seek in buffered content, and not in unbuffered content). – Martin Tournoij Jan 03 '15 at 19:30
  • 1
    Exactly what i was dealing with - Django's webserver is not able to process byte-range requests and playback always started from the beginning in Chrome regardless loaded status or passed currentTime value. – Marek Jalovec Mar 23 '15 at 07:48
  • 1
    So in summary, put `Header set Accept-Ranges bytes ` in your `.htaccess` guys, thanks. I'm on this since 2013 :| – yPhil Aug 13 '15 at 12:14
60

Works on my chrome...

$('#audio').bind('canplay', function() {
  this.currentTime = 29; // jumps to 29th secs
});
marko
  • 1,662
  • 15
  • 24
  • 6
    soemarko, thanks! After setting the URL of the audio to the one you provided in your jsbin, `currentTime` started to work. So I guess it was the server thing, because I used `python -m SimpleHTTPServer` to serve an audio file. – katspaugh Mar 05 '12 at 10:18
19

Both audio and video media accept the #t URI Time range property

song.mp3#t=8.5

To dynamically skip to a specific point use HTMLMediaElement.currentTime:

audio.currentTime = 8.5;
Roko C. Buljan
  • 164,703
  • 32
  • 260
  • 278
12

A much easier solution is

var element = document.getElementById('audioPlayer');

//first make sure the audio player is playing
element.play(); 

//second seek to the specific time you're looking for
element.currentTime = 226;
Community
  • 1
  • 1
Cedric Dahl
  • 129
  • 1
  • 2
9

Make sure you attempt to set the currentTime property after the audio element is ready to play. You can bind your function to the oncanplay event attribute defined in the specification.

Can you post a sample of the code that fails?

dragon
  • 1,668
  • 15
  • 17
  • dragon, I'll try the event, thanks! Although, I set `currentTime` from the console, when the audio is already playing. – katspaugh Mar 05 '12 at 09:26
8

Firefox also makes byte range requests when seeking content that it has not yet loaded- it is not just a chrome issue. Set the response header "Accept-Ranges: bytes" and return a 206 Partial Content status code to allow any client to make byte range requests.

See https://developer.mozilla.org/en-US/docs/Web/HTTP/Configuring_servers_for_Ogg_media#Handle_HTTP_1.1_byte_range_requests_correctly

user3834658
  • 336
  • 3
  • 6
7

I was facing problem that progress bar of audio was not working but audio was working properly. This code works for me. Hope it will help you too. Here song is the object of audio component.

HTML Part

<input type="range" id="seek" value="0" max=""/>

JQuery Part

    $("#seek").bind("change", function() {
            song.currentTime = $(this).val();               
        });

song.addEventListener('timeupdate',function (){

    $("#seek").attr("max", song.duration);
    $('#seek').val(song.currentTime);
    });
Anuj Sharma
  • 4,016
  • 2
  • 32
  • 50
5

The @katspaugh's answer is correct, but there is a workaround that does not require any additional server configuration. The idea is to get the audio file as a blob, transform it to dataURL and use it as the src for the audio element.

Here is solution for angular $http, but if needed I can add vanilla JS version as well:

$http.get(audioFileURL,
        {responseType:'blob'})
        .success(function(data){
            var fr = new FileReader;
            fr.readAsDataURL(data);
            fr.onloadend = function(){
                domObjects.audio.src = fr.result;
            };
        });

cautions

  1. This workaround is not suitable for large files.
  2. It will not work cross-origin unless CORS are set properly.
artur grzesiak
  • 19,110
  • 5
  • 43
  • 54
  • Intereesting, alhough I'm not sure if you need a dataURL, could you possible just generate a blob URL: URL.createObjectURL(data) ? – bluejayke Feb 10 '20 at 00:14
  • @bluejayke yes, after fetching the data you can do: `URL.createObjectURL(new Blob([data]))`, but you need to have a new blob object from your blob data – Lucas Andrade May 30 '20 at 22:23
1

Set time position to 5 seconds:

var vid = document.getElementById("myAudio");
vid.currentTime = 5;
Jijo Paulose
  • 1,768
  • 16
  • 19