Josip Codes
Josip Codes

Reputation: 9521

HTML5 audio to reload file

I'm using AJAX to load some rows from my database, among all data the most important is a path to audio file, for example uploads/song.mp3.

I clear the content div with $('#content').html(''); and then loop (with jQuery.each) through data - creating containers with text and <audio> element, that have song path loaded into src attribute.

The problem is that not all songs play - on first load some of them do and some don't; then on next AJAX request, when I get new data and remove everything from #content - not a single <audio> element plays a song.

Here's some of the code:

$.ajax({
                type: 'POST',
                url: 'xxx.php',
                data: {fr : fraza, ajax : true},
                dataType: 'json'
           }).success(function(retData) {
                //console.log(retData);
                $('#container').html('');
                $.each(retData, function(index, value) {
                    var unos = value;
                    $('#glavni').append('<div class="pesma-item" id="pesma-id-'+ unos.id +'"><h2>' + unos.naziv + '</h2><img src="' + unos.note + '" alt="" /><div><p><pre>' + unos.temp + '</pre></p><br style="clear: both" /><audio controls preload="auto"><source src="' + unos.audio + '" type="audio/mpeg"></audio></div><br style="clear:both" /></div>');
                    $('#pesma-id-' + unos.id + ' audio')[0].load();
                });


           });

How can I force every audio element to reload the file, so it can be playable?

Upvotes: 2

Views: 8554

Answers (2)

couzzi
couzzi

Reputation: 6366

I believe there are a few issues that could be sorted out. For starters, I believe at least some of your issue is related to garbage collection. The Mozilla Docs suggest a method that first calls the pause() method on the <audio> element in question, then set the src to an empty string. What I think is going on is that because preload="auto" is set — which instructs (Read: suggests) the browser to load the entire stream on page load—this process continues, even though you've wiped out the <audio> elements by emptying out your container $('#container').html('')

I've reworked a bit of your code to do a few things. The first being a loop to first pause() all <audio> elements, then set their src to an empty string:

...
$('audio').each(function(){
    $(this).pause().attr('src', '');
});
$('#container').empty();
...

The next thing I did was reformat the markup that you append to $("#glavni") (main), mostly for my own sanity, but more importantly I removed the <source> tag from your <audio> element. With the src property back on the <audio> element, we can be sure which source is playing, as well as knowing our pause() method is being called directly on the element in question.

JS

$.ajax({
    type: 'POST',
    url: 'xxx.php',
    data: {
        fr: fraza,
        ajax: true
    },
    dataType: 'json'
}).success(function (retData) {
    //console.log(retData);
    $('audio').each(function(){
        $(this).pause().attr('src', '');
    });
    $('#container').html('');
    $.each(retData, function (index, value) {
        var unos = value, markup;   
        markup += '<div class="pesma-item" id="pesma-id-' + unos.id + '">';
        markup +=     '<h2>' + unos.naziv + '</h2>';
        markup +=     '<img src="' + unos.note + '" alt="" />';
        markup +=     '<div>';
        markup +=         '<p>';
        markup +=             '<pre>' + unos.temp + '</pre>';
        markup +=         '</p>';
        markup +=         '<br style="clear: both" />';
        markup +=         '<audio controls preload="auto" src="' + unos.audio + '">';
        markup +=         '</audio>';
        markup +=     '</div>';
        markup +=     '<br style="clear:both" />';
        markup += '</div>';
        $('#glavni').append(markup);
       // $('#pesma-id-' + unos.id + ' audio')[0].load();
    });
});

One other thing — I commented out your load() method.

The load() method is used to update the audio/video element after changing the source or other settings - Source

This was more of a precaution than anything—in theory, it shouldn't hurt you, but since the issues described are related to load/unload woes, I thought it best to remove it.

Other options

In the comments on your question, I mentioned the possibility of using one <audio> element that is basically a recyclable object, reworked on-the-fly. If you continue to have issues, this approach may be worth exploring as its much easier to debug the behavior of one instance—not to mention it's less markup, which [if you ask me] is pretty much always a good thing.

Upvotes: 8

Lucky Soni
Lucky Soni

Reputation: 6888

Maybe try this..

HTML:

<div id="audio_player_container">

</div>

JS :

$.ajax({
   type: 'POST',
   url: 'xxx.php',
   data: {fr : fraza, ajax : true},
   dataType: 'json'
}).success(function(retData) {
//$('#container').html('');
// Maybe instead of removing html from #container you should do this
$('#glavni').empty();
$.each(retData, function(index, value) {
    // store audio source in anchor href
    var unos = value, markup;   
    markup += '<div class="pesma-item" id="pesma-id-' + unos.id + '">';
    markup +=     '<h2>' + unos.naziv + '</h2>';
    markup +=     '<img src="' + unos.note + '" alt="" />';
    markup +=     '<div>';
    markup +=         '<p>';
    markup +=             '<pre>' + unos.temp + '</pre>';
    markup +=         '</p>';
    markup +=         '<br style="clear: both" />';
    markup +=         '<a class="trigger" href="' + unos.audio + '">Play This';
    markup +=         '</a>';
    markup +=     '</div>';
    markup +=     '<br style="clear:both" />';
    markup += '</div>';
    $('#glavni').append(markup);
    });
});

$(".trigger").on("click", function(e) {
   e.preventDefault();
   var sourceUrl = $(this).attr("href"), audio_markup;
   audio_markup += '<audio id="audio_player" controls preload="auto">';
   audio_markup += '<source id="audio_src" src="' + sourceUrl + '" type="audio/mpeg">';
   audio_markup += '</audio>';
   $("#audio_player_container").html(audio_markup);
   var player = $("#audio_player"); 
   // maybe then do something
   player[0].load();
   player[0].play();
});

Upvotes: 1

Related Questions