82

I've been playing with HTML5 audio recently, and though I can get it to play the sound it only ever will play once. No matter what I try (setting the properties, event handlers, etc) I can't seem to get it to loop.

Here's the basic code I'm using:

//myAudio is declared at a global scope, so it doesn't get garbage collected.
myAudio = new Audio('someSound.ogg');
myAudio.loop = true;
myAudio.play();

I'm testing using Chrome (6.0.466.0 dev) and Firefox (4 beta 1), both of which seem happy to ignore my requests for looping. Any ideas?

UPDATE: The loop property is now supported in all major browsers.

Damjan Pavlica
  • 21,431
  • 6
  • 55
  • 65
Toji
  • 31,923
  • 20
  • 95
  • 113
  • 1
    Not sure about Chrome, but Firefox doesn't support looping. – luiscubal Jul 17 '10 at 22:42
  • 1
    Just start it once it's ended: myAudio.addEventListener("ended", function(e){myAudio.play();}, false); – mattbasta Jul 17 '10 at 22:47
  • @Brandon I wonder why this doesn't work? The only difference between this code and the accepted answer is that in the accepted answer, it sets `currentTime` to 0 before calling `play`. Is that necessary? – mgiuca Jun 23 '11 at 04:22
  • 2
    @Brandon Yes, see kingjeffrey's second comment on his own answer. You do need to set `currentTime`. – mgiuca Jun 23 '11 at 10:38
  • This does work just fine (at least today) – dvlden Apr 09 '16 at 00:20

9 Answers9

118

While loop is specified, it is not implemented in any browser I am aware of Firefox [thanks Anurag for pointing this out]. Here is an alternate way of looping that should work in HTML5 capable browsers:

var myAudio = new Audio('someSound.ogg'); 
myAudio.addEventListener('ended', function() {
    this.currentTime = 0;
    this.play();
}, false);
myAudio.play();
Popnoodles
  • 27,674
  • 1
  • 40
  • 53
kingjeffrey
  • 13,546
  • 6
  • 39
  • 47
  • 1
    Hm... interesting. I didn't have much luck with this method previously but I wasn't setting the current time. When I try this, however I get: "Uncaught Error: INDEX_SIZE_ERR: DOM Exception 1" on the line "this.currentTime = 0" – Toji Jul 17 '10 at 22:54
  • 1
    @Toji Here is the documentation for the [INDEX_SIZR_ERR error](http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#offsets-into-the-media-resource). It means the beginning of the song is outside the range the browser can seek. This sometimes occurs if the browser thinks it is streaming media, or if the server lacks certain capabilities (I forget offhand what this specific capability is, but I will try to track it down). You can also use `this.startTime` to return to the earliest available time. – kingjeffrey Jul 17 '10 at 23:19
  • @Toji The reason `.currentTime` is needed has to do with how the spec handles the end of a song. Browsers are supposed to just pause the song. So reinitiating play does so at the end of the song. The playhead must be reset. – kingjeffrey Jul 17 '10 at 23:21
  • @Toji Here is another thought if you are unable to get `.currentTime` working. Inside the callback function, you could simply redeclare `myAudio` with the same file and play it again. Redeclaring it should also reset the playhead to the beginning of the song. – kingjeffrey Jul 17 '10 at 23:23
  • setting it to this.startTime gives me the same error, though now I'm starting to wonder if it's a server issue. I'm serving static files from a local django server (which is not django's most robust feature). Pair that with the fact that Anurag's does work and I think it's probably just me. I'll toy with it a bit more and let you know the results. – Toji Jul 18 '10 at 01:45
  • Whoops! Forgot about this question! The core issue was that I was using a local Django test server to serve up my media files, and apparently it's not too happy about providing streaming information. Uploading and trying scripts like the one listed here to my site's server allows looping. – Toji Sep 14 '10 at 22:31
  • FF does support loop, but at the date of this comment (Sept 2012), not very well. The bug report is here: https://bugzilla.mozilla.org/show_bug.cgi?id=449157 – Lee Goddard Sep 13 '12 at 11:21
  • Having a issue with audio only looping when it's cached anyone else have this issue? – Josh Bedo Oct 10 '13 at 14:40
  • This code works great in all the desktop browsers I tested it on. Although I did not have any luck on mobile browsers (Android, safari or chrome) for both iOS and Android phones. I think it's a widely known issue of support for mobile browsers being inconsistent and/or fragmented? http://pupunzi.open-lab.com/2013/03/13/making-html5-audio-actually-work-on-mobile/ (does anyone have suggestions as to a workaround?) – Ryan Coolwebs Apr 13 '16 at 03:45
62

To add some more advice combining the suggestions of @kingjeffrey and @CMS: You can use loop where it is available and fall back on kingjeffrey's event handler when it isn't. There's a good reason why you want to use loop and not write your own event handler: As discussed in the Mozilla bug report, while loop currently doesn't loop seamlessly (without a gap) in any browser I know of, it's certainly possible and likely to become standard in the future. Your own event handler will never be seamless in any browser (since it has to pump around through the JavaScript event loop). Therefore, it's best to use loop where possible instead of writing your own event. As CMS pointed out in a comment on Anurag's answer, you can detect support for loop by querying the loop variable -- if it is supported it will be a boolean (false), otherwise it will be undefined, as it currently is in Firefox.

Putting these together:

myAudio = new Audio('someSound.ogg'); 
if (typeof myAudio.loop == 'boolean')
{
    myAudio.loop = true;
}
else
{
    myAudio.addEventListener('ended', function() {
        this.currentTime = 0;
        this.play();
    }, false);
}
myAudio.play();
mgiuca
  • 19,797
  • 6
  • 50
  • 70
  • Thx. this worked perfectly for Opera, Firefox, Chrome... so how can we add more sounds(mp3) for Safari.... ??? adding more variables would probably cause duplicates for Chrome (which supports ogg and mp3)... –  Jan 01 '12 at 22:29
  • @pixelass I'm not entirely sure how to do it in code. In HTML, you would nest the – mgiuca Jan 02 '12 at 01:38
  • i am aware of the html method. I might try around with the Audio.canPlayType method. right now I'm using 2 variables, so in chrome 2 files are played. this actually doesn't matter too much since it's only some oceanwaves loop I made. ... but simply adding 2 sources would be a lot nicer,. http://pixelass.com if you care. –  Jan 02 '12 at 06:33
19

Your code works for me on Chrome (5.0.375), and Safari (5.0). Doesn't loop on Firefox (3.6).

See example.

var song = new Audio("file");
song.loop = true;
document.body.appendChild(song);​
Anurag
  • 132,806
  • 34
  • 214
  • 257
5

Simplest way is:

bgSound = new Audio("sounds/background.mp3");
bgSound.loop = true;
bgSound.play();
jai3232
  • 161
  • 1
  • 4
4
var audio = new Audio("http://rho.nu/pub/Game%20Of%20Thrones%20-%20Main%20Theme%20-%20Soundtrack.mp3");

audio.addEventListener('canplaythrough', function() {
    this.currentTime = this.duration - 10;
    this.loop = true;
    this.play();
});

Just set loop = true in the canplaythrough eventlistener.

http://jsbin.com/ciforiwano/1/edit?html,css,js,output

JazzCat
  • 3,218
  • 1
  • 24
  • 38
2

Try using jQuery for the event listener, it will then work in Firefox.

myAudio = new Audio('someSound.ogg');

$(myAudio).bind('ended', function()  {
    myAudio.currentTime = 0;
    myAudio.play();
});

myAudio.play();

Something like that.

Matt
  • 21
  • 1
1

I did it this way,

<audio controls="controls" loop="loop">
<source src="someSound.ogg" type="audio/ogg" />
</audio>

and it looks like this

enter image description here

Tomarinator
  • 716
  • 9
  • 26
0

This works and it is a lot easier to toggle that the methods above:

use inline: onended="if($(this).attr('data-loop')){ this.currentTime = 0; this.play(); }"

Turn the looping on by $(audio_element).attr('data-loop','1'); Turn the looping off by $(audio_element).removeAttr('data-loop');

ACarter
  • 4,784
  • 9
  • 36
  • 47
0

You could try a setInterval, if you know the exact length of the sound. You could have the setInterval play the sound every x seconds. X would be the length of your sound.

Zack
  • 9
  • 1
  • This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post - you can always comment on your own posts, and once you have sufficient [reputation](http://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](http://stackoverflow.com/help/privileges/comment). – Alex Char Mar 11 '15 at 09:10
  • 4
    @AlexChar I disagree. This is at the least an attempt to answer the question. It could benefit from some expanding to show exactly what the code might look like, and it's probably not the best way to solve the problem, but it's not "not an answer". – Anthony Grist Mar 11 '15 at 09:39
  • Doing it so get experience troubles. – Klaider Mar 04 '16 at 10:55