HTML5 duration time of MP3 sometimes works - javascript

I'm having problems showing the duration time of an MP3 file in my HTML5 audio player. Sometimes it will load the duration time, sometimes it won't.
The times it doesn't load is when I'm making changes to the CSS and when I refresh the page.
When I change the MP3 file to load another MP3 file, the duration time shows up. It goes away when I refresh the page.
This is the code for duration time:
audio.addEventListener('loadedmetadata', function(){
progress.setAttribute('max', Math.floor(audio.duration));
duration.textContent = toHHMMSS(audio.duration);
});
I'm new at JavaScript so I have no idea how to code. I'm using this code from https://codepen.io/davatron5000/pen/uqktG and when you refresh the page, the duration of mp3 file disappears.

This is probably because of cache.
If you are setting your audio's src in the markup (html), the cached version of your media may already be loaded* when you attach the event listener.
Hence your event handler won't fire ever :
window.onload = function(){ // kinda force the situation
aud.onloadedmetadata = function(e){ // this won't fire
console.log('metatadata loaded');
};
};
<audio src="https://dl.dropboxusercontent.com/s/agepbh2agnduknz/camera.mp3" id="aud"/>
But in this case, you can already access its duration.
So you just have to check for its duration :
window.onload = function() {
if (aud.duration) {
doSomething();
} else {
aud.onloadedmetadata = doSomething;
}
}
function doSomething(event) {
console.log(aud.duration);
console.log('from event handler :', !!event);
}
<audio src="https://dl.dropboxusercontent.com/s/agepbh2agnduknz/camera.mp3" id="aud" />
Or you can set again your media src in js.
window.onload = function() {
aud.onloadedmetadata = function doSomething(event) {
console.log(aud.duration);
}
aud.src = aud.src; // forces the event to fire again
}
<audio src="https://dl.dropboxusercontent.com/s/agepbh2agnduknz/camera.mp3" id="aud" />
*UAs have different behavior for this, e.g FF will store all the load events until all the inline scripts has been parsed. Safari and sometimes Chrome fire it as soon as they can.

Related

Differentiate between audio start and audio play(after a pause) in HTML5 <audio>

How to add a listener on audio/video start?
I can do it like:
$audio.on("play", function() {
console.log("audio played");
});
where $audio is a jQuery object representing the single DOM audio element.
but it will also run when we resume the video. I want it to run on start only.
One way I can do it is:
$audio.on("play", function() {
if(this.currentTime === 0) {
console.log("audio started);
}
});
but this will run multiple times when we play/pause the audio on the start.
Is there any better way to do this? The listener should only work on audio start and audio replayed, not when the user manually drags the seek bar to the beginning of the source.
Store a flag into the data-* attribute of the targeted element:
const $audio = $('.audio');
$audio.on("play", function() {
if ($(this).data('once-played')) return; // Do nothing if data exists.
// Your code here
console.log("Audio started for the first time");
// Finally, add a flag.
$(this).data('once-played', true);
});
<audio class="audio" src="http://upload.wikimedia.org/wikipedia/en/4/45/ACDC_-_Back_In_Black-sample.ogg" autoplay controls loop></audio>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Actually, it might be sounding confusing because I was under the impression that there could be a possibility that currentTime could still return 0 if we do it in a fraction of seconds. But after reading #freedomn-m, #roko-c-buljan, #rory-mccrossan comments, I got it that it will never be possible that currentTime returns 0 when we play-pause-play the video immediately.
Now, let's say I want to track how many times a user has watched the video. The requirements might sound weird but by watched I only meant started/replayed. It doesn't count if the user manually drags the seek bar to the beginning of the source.
Here is how I implemented it finally using all your points:
const $audio = $('.audio');
$audio.on("play", function() {
if ($(this).data('once-played')) return; // Do nothing if data exists.
// Your code here
console.log("Audio started/replayed");
// Finally, add a flag.
$(this).data('once-played', true);
});
$audio.on("ended", function() {
$(this).data('once-played', false);
});

Preload Javascript audio to play in script

I have a simple program where I run this script:
function PlayAudio(Location){
var audio = new Audio(Location);
audio.Play()
}
in an onclick HTML attribute. I have a fancy loading picture that I know how to make appear and have successfully made it work. I would like to show this picture while the audio is loading, and then make it go away after the audio file is done loading and ready to play. Right now, there is a considerable delay between clicking the element and hearing the sound.
My trouble is knowing when the audio is done loading and ready to play. I figure the best way to know when it's complete loading is to preload the file in-script. I don't know how to do that.
And that's my question:
How do you preload files inside a script?
Or, is there a way to know when an audio file is finally playing?
Note: I cannot use an <audio> element, unless there is some way to nest a <div> inside the <audio> so that the sound in the <audio> is triggered by clicking anywhere in the content of the <div>
Sorry for my slightly confusing descriptions!
Thanks,
Lucas N
You can use canplaythrough event
Sent when the ready state changes to CAN_PLAY_THROUGH, indicating that
the entire media can be played without interruption, assuming the
download rate remains at least at the current level.
function PlayAudio (Location){
var audio = new Audio;
audio.oncanplaythrough = function(event) {
// do stuff, e.g.; set loading `img` `style` `display` to `none`
this.play();
}
audio.src = Location;
}
You change its preload attr by
. audio.preload = "auto";
It will load the whole audio file on start

Javascript stop and return to poster HTML 5 video

This is my javascript which pause and play the HTML 5 video when a button is pressed but I want to stop the video instead of pausing and returning to the video poster how can I achieve that?
function vidplay() {
var video = document.getElementById("bg-vid");
var button = document.getElementById("play");
if (video.paused) {
video.play();
} else {
video.pause();
}
}
Use load() method (although I believe changing the src attribute implicitly calls it):
...
if (video.paused) {
video.play()
} else {
load();
}
...
Note: this method re-loads the resource, thus depending on caching settings it may be re-downloaded causing unnecessary bandwidth and CPU usage.
The easiest way I have been able to find is to reset the source of the video. The other way to handle it would be to have a div with the poster image in that you swap out for the video.
The problem with this method is that by resetting the source you lose the playhead position so if that's important you'll also need to track the currentTime before resetting, and on play have the playhead set back to that currentTime value
<script>
var vid=document.getElementById('bg-vid');
vid.addEventListener("pause", resetVideo, false);
function resetVideo() {
// resets the video element by resetting the source
this.src = "video.mp4" // **source of video**
}
</script>

Correct way to play <audio> + <video> from Javascript

I'm getting different results i Firefox and Chrome when using <audio> and <video> with preload="none" and then trying to play from Javascript.
Let's say i was using preload="auto" or preload="metadata" :
audio.src = "filename";
audio.play();
That seems to work fine in both Firefox and Chrome but i want to use preload="none" and then Chrome dossent play.
So i'm trying this code with preload="none" :
audio.src = url;
audio.load();
audio.addEventListener('canplay', function(e) {
audio.play(); // For some reason this dossent work in Firefox
}, false);
audio.play(); // Added this so Firefox would play
I don't know if that's the correct way to do it.
I'm using :
Firefox 20.0.1
Chrome 25.0.1364.172 m
I made a demo : http://netkoder.dk/test/test0217.html
Edit :
In the 2nd audio player (on the demo page) it seems that when using preload="none" you have to use load().
But is it correct to just use play() right after load() or is the correct way to use an event to wait for the file to load before playing it ?
In the 3rd audio player it seems Firefox 20.0.1 dossent support the canplay event correctly when used with addEventListener() because it dossent trigger after load(), it triggers after play() and also triggers when scrubbing though the sound which dossent seem to be the way the canplay should work.
Using .oncanplay does work.
So the following code seems to work :
function afspil2(url) {
afspiller2.src = url;
afspiller2.load(); // use load() when <audio> has preload="none"
afspiller2.play();
}
function afspil3(url) {
afspiller3.src = url;
afspiller3.load(); // use load() when <audio> has preload="none"
//afspiller3.addEventListener('canplay', function() { // For some reason this dossent work correctly in Firefox 20.0.1, its triggers after load() and when scrubbing
// afspiller3.play();
//}, false);
afspiller3.oncanplay = afspiller3.play(); // Works in Firefox 20.0.1
}
I updated the demo to include the changes : http://netkoder.dk/test/test0217.html
My way of adding addEventListener inside the afspil3() function dossent seem good because the first time the function is called the code inside addEventListener is called 1 time. The second time the function is called the code inside addEventListener is called 2 time and then 3 times and so on.
It's because your audio tags are missing the required src attribute, or <source> tags. When I added them in your demo, all 3 players immediately began working in both Chrome and FF.
Also, I recently discovered that src cannot be an empty string and subsequently changed with JS. If there's a reason you can't set the src in the HTML, your best alternative, IMO, is to create the audio elements with Javascript:
var audio = new Audio();
audio.src = url;
audio.controls = true;
audio.preload = false;
// and so on
Edit: Ok. It seems that in Chrome, when the HTML is preload="none" it is necessary to call load() before playing when the src is changed. Your second audio doesn't preload, so your function needs to be this:
function afspil2(url) {
afspiller2.src = url;
afspiller2.load(); // add load call
afspiller2.play();
}
Then, it seems that in Firefox, it is necessary to set preload="auto"; when attaching an event to the canplay event, like in the 3rd function.
function afspil3(url) {
afspiller3.src = url;
afspiller3.preload = "auto";
afspiller3.load();
afspiller3.addEventListener('canplay', function(e) {
this.play(); // For some reason this dossent work in Firefox
}, false);
}
That just seems very strange, but I tested it multiple times, and each time it would play if preload="auto" is called, but would not play if it isn't called. Note that it wasn't necessary for the 2nd player, which was also preload="none" in the HTML tag.
Finally, Chrome has some odd behaviors if there are multiple <audio> elements on the page. For all three players, reloading the page and clicking "the big electron" link would play correctly.
Reloading and then clicking "Yoda" on the 2nd or 3rd player won't do anything, but it WILL play for the first player. But, if the top player is played first by any means - play button or either link - then the other two "Yoda" links will suddenly work.
Also, if you click a 2nd or 3rd "Yoda" link first after reload, and then click the top player, the previously clicked "Yoda" (that didn't previously play) will begin to play on its own after the top player stops.
Suffice it to say they have some bugs to work out.
The correct way in my opinion would mean using an existing solution, like http://mediaelementjs.com/
If your really interested in the details on the best way to play audio and video with js then look at the source:
https://github.com/johndyer/mediaelement/tree/master/src/js
https://github.com/johndyer/mediaelement/blob/master/src/js/me-mediaelements.js

HTML5 Audio events not triggering on Chrome

I'm trying to have a load progress bar in my game, and I have a function assigned to the onloadeddata attribute on my audio, but it is not triggering in Chrome. It works in other browsers. I also tried many other events such as oncanplay, oncanplaythrough, onloadedmetadata, etc. None of them trigger.
I think it might have to do with the caching. Tried looking around and there was some reports of this from 2-3 years ago but nothing recent.
Is there any other way I could detect if the audio is loaded, or make these events work?
EDIT: Here's a quick example: http://jsfiddle.net/3vxCu/1/
Works in Opera and Firefox, but not in Chrome. It should give an alert when sound if finished loading.
It seems that the onloadeddata property does not work for some reason. But attaching an event handler through addEventListener (or via jQuery) works: http://jsfiddle.net/3vxCu/4/
bgSound = new Audio();
bgSound.src = "http://www.ehsankia.com/hawkthorne/audio/level.ogg";
bgSound.preload = "auto";
// Standard browsers (not IE before version 9):
// bgSound.addEventListener("loadeddata", testFunction, false);
// jQuery:
$(bgSound).on("loadeddata", testFunction);
function testFunction () {
alert("Data loaded");
}
If the attached jsfiddle is how you have implemented your code then I think I know what is wrong.
Your jsfiddle shows:
bgSound = document.createElement('audio');
bgSound.src = "http://www.ehsankia.com/hawkthorne/audio/level.ogg";
bgSound.onloadeddata = testFunction;
function testFunction(){
alert("Data loaded");
}
It should be like this:
bgSound = document.createElement('audio');
bgSound.onloadeddata = testFunction; // Event listener is attached _before_ loading the resource
bgSound.src = "http://www.ehsankia.com/hawkthorne/audio/level.ogg";
function testFunction(){
alert("Data loaded");
}
Basically, you are attaching the event listener after the src is specified. Specifying the source should be the last thing you do since it sets everything in motion. Chrome is probably already past the point of calling listeners for that event by the time it is attached in your code.

Categories

Resources