Izir Atig
Izir Atig

Reputation: 33

Playing song list with jquery and html5 audio

I'm trying to make html5 audio player to play list of songs but it plays only two first ones and stops there.

I'm using this to make it play next song after one ends:

$(audio).on("ended", function() {
audio.pause();
var next = $('#playlist li.active').next();
if (next.length == 0) {
    next = $('#playlist li:first-child');
}
initAudio(next);
audio.play();
showDuration();
});

Can't find out what is the problem here.

EDIT

Whole code:

JS

var audio;

$('#pause').hide();

initAudio($('#playlist li:first-child'));

function initAudio(element){
var song = element.attr('song');
var title = element.attr('songtitle');
var artist = element.attr('artist');

audio = new Audio('audio/' + song);

if(!audio.currentTime){
    $('#duration').html('0:00');
}

$('#audio-player .title').text(title);
$('#audio-player .artist').text(artist);

$('#playlist li').removeClass('active');
element.addClass('active');
}

$('#play').click(function(){
audio.play();
$('#play').hide();
$('#pause').show();
showDuration();
});

$('#pause').click(function(){
audio.pause();
$('#pause').hide();
$('#play').show();
});

$(audio).on("ended", function() {
audio.pause();
var next = $('#playlist li.active').next();
if (next.length == 0) {
    next = $('#playlist li:first-child');
}
initAudio(next);
audio.play();
showDuration();
});

HTML

<div id="audio-player">
    <button id="play"></button>
    <button id="pause"></button>
    <ul id="playlist">
        <li song="song1.wav" songtitle="Song1" artist="Artist1"></li>
        <li song="song2.wav" songtitle="Song2" artist="Artist2"></li>
        <li song="song3.wav" songtitle="Song3" artist="Artist3"></li>
        <li song="song4.wav" songtitle="Song4" artist="Artist4"></li>
    </ul>
    <div id="audio-info">
    <span class="artist"></span>&nbsp;&nbsp;<span class="title"></span>
    </div>
</div>

Upvotes: 1

Views: 2942

Answers (1)

Dzmitry Kushnarou
Dzmitry Kushnarou

Reputation: 566

Move this code:

$(audio).on("ended", function() {
audio.pause();
var next = $('#playlist li.active').next();
if (next.length == 0) {
    next = $('#playlist li:first-child');
}
initAudio(next);
audio.play();
showDuration();
});

inside the initAudio function, like this:

function initAudio(element){
    var song = element.attr('song');
    var title = element.attr('songtitle');
    var artist = element.attr('artist');

    audio = new Audio('audio/' + song);

    if(!audio.currentTime){
        $('#duration').html('0:00');
    }

    $('#audio-player .title').text(title);
    $('#audio-player .artist').text(artist);

    $('#playlist li').removeClass('active');
    element.addClass('active');

    $(audio).on("ended", function() {
        audio.pause();
        var next = $('#playlist li.active').next();
        if (next.length == 0) {
            next = $('#playlist li:first-child');
        }
        initAudio(next);
        audio.play();
        showDuration();
    });
}

This will ensure the ended call will be triggered for all the audio elements, not only for the first one.

Currently, the ended event is only fired once. So, the code plays the first song, triggers the ended event, plays the second one and then doesn’t trigger ended anymore.

This is because $(audio) refers to the audio element that is destroyed and re-created when you do initAudio. The line:

audio = new Audio('audio/' + song);

creates a new audio element when you call initAudio. This new audio element will not have the same callback attached to it.

$(audio).on("ended", ...); is only attached one time, and if the code creates new elements of the same type, it won’t be re-attached to them. So, you need to re-attach your event callback each time the audio element is re-created, and this can be done in initAudio. If you used selectors, a common method is to use $(document).on("ended", selector, ...); for this, but it won’t work in your example, since audio is not a selector.

Upvotes: 3

Related Questions