Audio duration NaN on certain page request action

I have been trying to create my custom media player using HTML5 and Jquery.

I have followed different approaches and ran into some trouble based on my way of refreshing the page.

First Case

$(document).ready(function(){
    duration = Math.ceil($('audio')[0].duration);
    $('#duration').html(duration);
});

In this case, the duration returns NaN when I redirect the page to the same URL by pressing the ENTER key in the address bar. However, it works completely fine when I refresh using the reload button or by pressing the F5 button.

Second Case

I read in some answers that loading duration after the loadedmetadata event might help. So I tried the following:

$(document).ready(function(){
    $('audio').on('loadedmetadata', function(){
        duration = Math.ceil($('audio')[0].duration);
        $('#duration').html(duration);
    });
});

Surprisingly, in this case, the inverse of the first case happened. The duration gets displayed completely fine in the case of a redirect, ie, pressing ENTER while in the address bar. However, in the case of refreshing using the F5 button or the reload button , the duration doesn't get displayed at all, not even NaN which led me to believe that the code doesn't get executed at all.


Further reading suggested this might be a bug within the webkit browsers but I couldn't find anything conclusive or helpful.

What could be the cause behind this peculiar behavior? It'd be great if you could explain it along with the solution to this problem.

Edit: I am mainly looking for an explanation behind this difference in behavior. I would like to understand the mechanism behind rendering a page in the case of redirect and refresh.


It sounds like the problem is that the event handler is set too late, ie the audio file has loaded its metadata before the document is even ready.

Try setting the event handler as soon as possible by removing the $(document).ready call:

$('audio').on('loadedmetadata', function(){
    duration = Math.ceil($('audio')[0].duration);
    $('#duration').html(duration);
});

Note that this requires that the <script> tag be after the <audio> tag in the document.

Alternatively, you can tweak your logic slightly, so that the code that updates the duration always runs (but fails gracefully if it gets a NaN ):

function updateDuration() {
    var duration = Math.ceil($('audio')[0].duration);
    if (duration)
        $('#duration').html(duration);
}

$(document).ready(function(){
    $('audio').on('loadedmetadata', updateDuration);
    updateDuration();
});

Lovely code examples and stuff from people - but the explanation is actually very simple.

If the file is already in the cache then the loadedmetadata event will not fire (nor will a number of other events - basically because they've already fired by the time you attach your listeners) and the duration will be set. If it's not in the cache then the duration will be NaN , and the event will fire.

The solution is sort of simple.

function runWhenLoaded() { /* read duration etc, this = audio element */ }

if (!audio.readyState) { // or $audio[0].readyState
    audio.addEventListener("loadedmetadata", runWhenLoaded);
    // or $audio.on("loadedmetadata", runWhenLoaded);
} else {
    runWhenLoaded.call(audio);
    // or runWhenLoaded.call($audio[0]);
}

I've included the jQuery alternatives in the code comments.


According to w3 spec this is standard behavior when duration returns NaN. So I suggest use durationchange event:

$('audio').on('durationchange', function(){
    var duration = $('audio')[0].duration;
    if(!isNaN(duration)) {
        $('#duration').html(Math.ceil(duration));
    }
});

NOTE: This code (and your too) will not work correct in case if you have more than one audio element on page. Reason is that you listen events from all audio elements on page and each element will fire own event:

$('audio').on('durationchange', function(){...});

OR

You can try:

    <script>
       function durationchange() {
          var duration = $('audio')[0].duration;
          if(!isNaN(duration)) {
              $('#duration').html(Math.ceil(duration));
          }
        }
    </script>

    <audio ondurationchange="durationchange()">
         <source src="test.mp3" type="audio/mpeg">
    </audio>
链接地址: http://www.djcxy.com/p/85682.html

上一篇: Spark和HBase快照

下一篇: 音频持续时间NaN在某些页面请求动作