I'm trying to make a cross-device/browser image and audio preloading scheme for a GameAPI I'm working on. An audio file will preload, and issue a callback once it completes.
The problem is, audio will not start to load on slow page loads, but will usually work on the second try, probably because it cached it and knows it exists.
I've narrowed it down to the audio.load() function. Getting rid of it solves the problem, but interestingly, my motorola droid needs that function.
What are some experiences you've had with HTML5 audio preloading?
Here's my code. Yes, I know loading images in a separate function could cause a race condition :)
var resourcesLoading = 0;
function loadImage(imgSrc) {
//alert("Starting to load an image");
resourcesLoading++;
var image = new Image();
image.src = imgSrc;
image.onload = function() {
//CODE GOES HERE
//alert("A image has been loaded");
resourcesLoading--;
onResourceLoad();
}
}
function loadSound(soundSrc) {
//alert("Starting to load a sound");
resourcesLoading++;
var loaded = false;
//var soundFile = document.createElement("audio");
var soundFile = document.createElement("audio");
console.log(soundFile);
soundFile.autoplay = false;
soundFile.preload = false;
var src = document.createElement("source");
src.src = soundSrc + ".mp3";
soundFile.appendChild(src);
function onLoad() {
loaded = true;
soundFile.removeEventListener("canplaythrough", onLoad, true);
soundFile.removeEventListener("error", onError, true);
//CODE GOES HERE
//alert("A sound has been loaded");
resourcesLoading--;
onResourceLoad();
}
//Attempt to reload the resource 5 times
var retrys = 4;
function onError(e) {
retrys--;
if(retrys > 0) {
soundFile.load();
} else {
loaded = true;
soundFile.removeEventListener("canplaythrough", onLoad, true);
soundFile.removeEventListener("error", onError, true);
alert("A sound has failed to loaded");
resourcesLoading--;
onResourceLoad();
}
}
soundFile.addEventListener("canplaythrough", onLoad, true);
soundFile.addEventListener("error", onError, true);
}
function onResourceLoad() {
if(resourcesLoading == 0)
onLoaded();
}
It's hard to diagnose the problem because it shows no errors and only fails occasionally.
I got it working. The solution was fairly simple actually:
Basically, it works like this:
channel.load();
channel.volume = 0.00000001;
channel.play();
If it isn't obvious, the load
function tells browsers and devices that support it to start loading, and then the sound immediately tries to play
with the volume
virtually at zero. So, if the load
function isn't enough, the fact that the sound 'needs' to be played is enough to trigger a load on all the devices I tested.
The load
function may actually be redundant now, but based off the inconsistiency with audio implementation, it probably doesn't hurt to have it.
Edit: After testing this on Opera, Safari, Firefox, and Chrome, it looks like setting the volume
to 0 will still preload the resource.
canplaythrough
fires when enough data has buffered that it probably could play non-stop to the end if you started playing on that event. The HTML Audio element is designed for streaming, so the file may not have completely finished downloading by the time this event fires.
Contrast this to images which only fire their event once they are completely downloaded.
If you navigate away from the page and the audio has not finished completely downloading, the browser probably doesn't cache it at all. However, if it has finished completely downloading, it probably gets cached, which explains the behavior you've seen.
I'd recommend the HTML5 AppCache to make sure the images and audio are certainly cached.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With