The duration of the NaN sound when a specific page request is executed

I am trying to create my own custom media player using HTML5 and jQuery.

I followed different approaches and ran into some problems 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 great when upgrading with the reload button or pressing the F5 button.

Second case

In some answers, I read that loading duration after a loadedmetadata event may 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 opposite happened to the first case. The duration is displayed completely in case of redirection, i.e. Press ENTER in the address bar. However, in the case of an update using the F5 button or the reload button duration is not displayed at all, even NaN, which made me think that the code was not executed at all.


Further reading suggests that this may be a bug in webkit browsers, but I could not find anything convincing or useful.

What could be the reason for this peculiar behavior? It would be great if you could explain this along with a solution to this problem.

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

+7
javascript jquery html5 html5-audio
source share
4 answers

It seems that the problem is that the event handler is set too late, i.e. the audio file uploaded its metadata before the document is ready.

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

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

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

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

 function updateDuration() { var duration = Math.ceil($('audio')[0].duration); if (duration) $('#duration').html(duration); } $(document).ready(function(){ $('audio').on('loadedmetadata', updateDuration); updateDuration(); }); 
+3
source share

Great examples of code and material from people - but the explanation is actually very simple.

If the file is already in the cache, the loadedmetadata event loadedmetadata not be loadedmetadata (and there will not be a number of other events - mainly because they were already fired by the time your listeners joined), and the duration will be set. If it is not in the cache, then duration will be NaN , and the event will fire.

The solution is 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 have included jQuery alternatives in the code comments.

+1
source share

According to w3 spec , this is standard behavior when duration returns NaN. Therefore, I suggest using the durationchange event:

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

NOTE. This code (and yours too) will not work correctly if there is more than one audio element on the page. The reason is that you listen to events from all the audio elements on the page, and each element fires its 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> 
0
source share

Note that the behavior will vary from one browser to another. In Chrome, you have a different type of download. When resources are not in the cache , it will extract either the full file (for example, for js or css), or part of the file (for example, mp3). This partial file contains metadata , which allows the browser to determine the duration and other data, such as the time it takes to download the entire file at that speed, for example, canplay or canplaythrough . If you look at network usage in your dev console, you will see that the HTTP status code will be either 200 (successful download) or 206 (partial download - for mp3, for example).

When you click refresh , items are checked to see if they have changed. The HTTP status will be 304 , that is, the file has not been changed. If it has not changed and is still in the browser cache, it will not load. A call to determine whether it has been modified or not comes from the server providing the file.

When you simply press enter in the address bar, it is automatically taken from the cache, and not checked online. So it is much faster.

Thus, depending on how you call or refresh your page (or just enter, refresh or fill out the update without a cache), you will have big differences from the moment you get metadata from your mp3. Between receiving metadata from the cache directly and receiving a request to the server, the difference can be several hundred milliseconds, which is enough to change what data is available at another moment.

In this case, listening to loadedmetada should give a consistent result. This event is triggered when data with information about the duration is loaded, therefore, regardless of the page loading method, it does not matter if this called message is executed correctly. At this point, you should consider intervening with some other elements. What you have to do is follow your sound through various events to determine exactly where it is at different times. Therefore, in your document you can add listeners for different events and see where this problem is. Like this:

 $('audio')[0].addEventListener('loadstart', check_event) $('audio')[0].addEventListener('loadeddata', check_event) $('audio')[0].addEventListener('loadedmetadata', check_event)//at this point you should be able to call duration $('audio')[0].addEventListener('canplay', check_event) //and so on function check_event(e) { console.log(e.target, e.type) } 

You will see that depending on how you are updating, these events may occur at different times, possibly explaining inconsistencies in your results.

0
source share

All Articles