Jump to content

preloading html5 audio


astralaaron

Recommended Posts

I need to be able to preload my audio files for some small games I am making... Ideally I would like to do it similarly to how I am preloading my images, as shown in the following code:

	this.preload = function(images) {		var loaded = 0;		    for (var i = 0; i < images.length; i++) {			var temp = new Image();			temp.addEventListener("load", function() {				loaded++;				if (loaded == images.length) LOADED = true;			}, true);			temp.src = images[i];		}	}

I am having a hard time searching around the web for help.. still looking, just thought I would start a thread to see if anyone here has an answer, or knows a good site with info.

 

edit:

 

I am aware of this: HTML5 preload attribute

However I need to be able to detect when all audio is loaded before executing certain code...

Edited by astralaaron
Link to comment
Share on other sites

Perfect, thank you.

 

I am pretty close to having this working...I have one problem though. Since I am creating my audio elements with javascript, how do I go about adding multiple sources (one for mp3 and 1 for ogg) ?

 

for example:

<audio controls>  <source src="horse.ogg" type="audio/ogg">  <source src="horse.mp3" type="audio/mpeg"></audio> 

Edit, just found this page which seems like it will work:

http://stackoverflow.com/questions/4053262/how-can-i-add-multiple-sources-to-an-html5-audio-tag-programmatically

Edited by astralaaron
Link to comment
Share on other sites

I have ran into a problem...my sound preloading seems to work fine in FireFox, but will not work with IE.

this.loadSounds = function(snd) {		var loadedSounds = 0;		for (var i = 0; i < snd.length; i++) {			var temp = new Audio();			temp.addEventListener("canplaythrough", function() {				loadedSounds++;				console.log('SOUND LOADED ' + loadedSounds);				if (loadedSounds == snd.length){					LOADED_SND = true;					console.log('LOADED_SND ' + LOADED_SND);				}			}, true);			if (temp.canPlayType('audio/mpeg')) {				console.log('temp canPlayType mp3');				temp.type = "audio/mpeg";				temp.src = snd[i] + ".mp3";			} else {				temp.type = "audio/ogg";				console.log('temp canPlayType ogg');				temp.src = snd[i] + ".ogg";			}			//temp.preload = "auto";			console.log('after canplaythrough event set');		}	}

these console.log()'s fire in IE:

console.log('temp canPlayType mp3');

console.log('after canplaythrough event set');

 

however, the addEventListener function never happens, does anyone know why? and a fix?

 

thank you.

 

EDIT: is temp.preload = "auto"; neccessary?

Edited by astralaaron
Link to comment
Share on other sites

Well, this doesn't seem to be a good method anyway, as Chrome seems to not preload the audio. I read on a website saying that chrome fires the canplaythrough event imediately after the canplay event. (therefore is basically useless, as they put it)

 

is there any other way to detect the file has loaded?

 

also..the addEventListener seems to not be working at all on IE. I've tried the 'progress' event as well, which works on firefox and, still nothing on IE...

Link to comment
Share on other sites

ok, I figured out in IE you must appendChild(temp) before adding an event listener in order for it to work...

 

That only solves one problem, in Chrome, the preload doesn't work considering 'canplaythrough' fires immediately after 'canplay'. Any suggestions are very appreciated

Link to comment
Share on other sites

OMG....

I cannot catch a break with Chrome.

 

I am trying this:

			temp.addEventListener("progress", function() {				tracker++;				console.log(tracker + " progress= " + this.buffered.end(0) + ' total duration = ' + this.duration);				//if(this.buffered.end(0) >= this.duration)			}, true);

which looked very promising on firefox and IE with the final output of the console looking like I can simply check this.buffered.end(0) against this.duration...

 

FireFox console output:

2 progress fireing : 317.966333 total duration : 317.966333

 

Internet Explorer output:

17 progress fireing : 317.9716666 total duration : 317.9716666

 

And then Chrome has to go and output this:

6 progress= 93.07910919189453 total duration = 317.936327

 

 

I don't know what to do with chrome.....

Link to comment
Share on other sites

I am pretty sure it is preloading... does it even make sense? just call the sound file with an ajax call? viewing the developer network tool it shows it downloading the information from the sound file. but when that is done, does that mean the sound file is cached, or "preloaded" ?

Link to comment
Share on other sites

You should be able to tell in the network console. When you later play the sound, if you see another request for the mp3 with a 200 response then it was downloaded again. If it shows a 304 response then the server is telling the browser to use the cached version. If you don't see any request at all then the browser doesn't bother to ask the server, it just plays what it already downloaded.

Link to comment
Share on other sites

ahh well again chrome is showing a different result form other browsers....

It downloads from the AJAX call, then once the sound begins, it posts a 204 "partial content" status and begins downloading again as the music plays..

 

EDIT: [ I guess there is no way to force chrome to check for a cached file? ]

 

Something that might solve my problem would be if I could just detect when addEventListener("progress", STOPS fireing.. is there any way I could do that?

 

Although a problem with it might be if the file is already buffered..I think it might not even fire the progress event..

 

Does anyone know if it is possible anyway?

Edited by astralaaron
Link to comment
Share on other sites

I'm quite sure Chrome will work just fine. The <audio> and <video> elements, the way browsers have implented then, don't necessarily have to load fully.Some browsers may choose to load only part of a file and load the rest after the file has started playing. This is up to the browser's implementation.

It's possible that Chrome only fires the "canplay" event when "canplaythrough" is ready, which means that you really don't have any problem at all.

Link to comment
Share on other sites

I'm quite sure Chrome will work just fine. The <audio> and <video> elements, the way browsers have implented then, don't necessarily have to load fully.Some browsers may choose to load only part of a file and load the rest after the file has started playing. This is up to the browser's implementation.

It's possible that Chrome only fires the "canplay" event when "canplaythrough" is ready, which means that you really don't have any problem at all.

 

 

I am going back to this method...but I am having an issue with Chrome (again....)

 

here is the code I am using for the preload:

this.loadSounds = function( path, snd ) {	if (snd.length < 1) LOADED_SND = true;		var loadedSounds = 0;		for (var i = 0; i < snd.length; i++) {			var temp = new Audio();			document.body.appendChild(temp);			temp.addEventListener("canplaythrough", function() {				loadedSounds++;				console.log('SOUND LOADED ' + loadedSounds);				if (loadedSounds == snd.length){					LOADED_SND = true;					console.log('LOADED_SND ' + LOADED_SND);				}			}, true);			if (temp.canPlayType('audio/ogg')) {				temp.type = "audio/ogg";				console.log('temp canPlayType ogg');				temp.src = path + snd[i] + ".ogg";			} else {				console.log('temp canPlayType mp3');				temp.type = "audio/mpeg";				temp.src = path + snd[i] + ".mp3";			}			//temp.preload = "auto";			console.log('after canplaythrough event set');		}	}

The issue now is that after all of the sounds preload, Chrome will not play the sound when I create another instance of it. For example, this loading happens before each stage runs its "init()" function. The sounds get loaded, then the init() gets run. within the init function there is something like this:

this.bgMusic = new Audio();  //this line is actually called when the object of the class is created, not in the init()if (this.bgMusic.canPlayType('audio/ogg')) {        this.bgMusic.type = "audio/ogg";        this.bgMusic.src = "audio/Clasico.ogg";    } else {        this.bgMusic.type = "audio/mpeg";        this.bgMusic.src = "audio/Clasico.mp3";    }   this.bgMusic.play();

The problem which seems to be happening, is after the preload function, when trying to load / play that sound later in the game, it doesn't play. From watching the network tools, it appears that it will not call the same sound file twice. it says status "pending".

 

now if I change it and add a random number to the end of the sound file name (similar to AJAX requests to the same file), then it will call the file and play the sound.

 

for example:

this.loadSounds = function( path, snd ) {	if (snd.length < 1) LOADED_SND = true;		var loadedSounds = 0;		for (var i = 0; i < snd.length; i++) {		var rand = Math.floor(Math.random() * 100) + 1;			var temp = new Audio();			document.body.appendChild(temp);			temp.addEventListener("canplaythrough", function() {				loadedSounds++;				console.log('SOUND LOADED ' + loadedSounds);				if (loadedSounds == snd.length){					LOADED_SND = true;					console.log('LOADED_SND ' + LOADED_SND);				}			}, true);			if (temp.canPlayType('audio/ogg')) {				temp.type = "audio/ogg";				console.log('temp canPlayType ogg');				temp.src = path + snd[i] + ".ogg"  + "?r=" + rand;			} else {				console.log('temp canPlayType mp3');				temp.type = "audio/mpeg";				temp.src = path + snd[i] + ".mp3"  + "?r=" + rand;			}			//temp.preload = "auto";			console.log('after canplaythrough event set');		}	}

My concern is...if I am doing this, and adding a variable to the end of the sound file...wouldn't it be ignoring the cached file and downloading the entire file again when I try to play it in my game?

Link to comment
Share on other sites

ahhh sounds are driving me crazy.... in internet explorer it seems as if the sounds download every time it is fired...so even a little 1 second sound file downloads (status 200) each time you click on something in the game...so in IE it delays about 1 second before firing each sound....

Link to comment
Share on other sites

Just create one <audio> element for each sound that will be in the game. Keep a pointer to that audio element the whole time and simply call the play method when you need to. No need to create a new audio element to play a sound if another audio element already has it.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...