在Javascript中预加载音频的问题

时间:2011-12-04 14:16:51

标签: javascript html5 audio

我正在尝试为我正在开发的GameAPI制作跨设备/浏览器图像和音频预加载方案。音频文件将预加载,并在完成后发出回调。

问题是,音频不会在慢速页面加载时开始加载,但通常会在第二次尝试时起作用,可能是因为它缓存了它并且知道它存在。

我已将其缩小为audio.load()函数。摆脱它解决了这个问题,但有趣的是,我的摩托罗拉机器人需要这个功能。

您对HTML5音频预加载有哪些经验?

这是我的代码。是的,我知道在单独的函数中加载图像可能会导致竞争条件:)

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();
}

很难诊断问题,因为它没有显示错误,只是偶尔失败。

4 个答案:

答案 0 :(得分:5)

我得到了它的工作。解决方案实际上相当简单:

基本上,它的工作原理如下:

channel.load();
channel.volume = 0.00000001;
channel.play();

如果不明显,load函数会告诉支持它的浏览器和设备开始加载,然后声音立即尝试playvolume实际上为零。因此,如果load功能不够,则“需要”播放声音足以触发我测试的所有设备的负载。

load函数现在可能实际上是多余的,但基于音频实现的不一致性,它可能没有什么坏处。

编辑:在Opera,Safari,Firefox和Chrome上测试后,看起来将volume设置为0仍会预先加载资源。

答案 1 :(得分:2)

足够的数据缓冲时,

canplaythrough会触发,如果您开始播放该事件,它可能会不停地播放到最后。 HTML Audio元素专为流式传输而设计,因此在此事件触发时,文件可能尚未完全下载

将此与仅在完全下载后触发其事件的图像进行对比。

如果您离开页面并且音频尚未完全下载,则浏览器可能根本不会对其进行缓存。但是,如果它已完成完全下载,它可能会被缓存,这解释了您已经看到的行为。

我建议使用HTML5 AppCache来确保图片和音频肯定是高速缓存的。

答案 2 :(得分:1)

如上所述,AppCache可能是您将音频从一个浏览器会话缓存到另一个浏览器会话的唯一解决方案(这不是您要求的,对吧?)。但请记住,有些浏览器提供的空间有限。例如,Safari允许用户在设置中更改此值,但默认值为5MB - 几乎不足以保存一堆歌曲,特别是如果用户经常光顾的其他网站也使用AppCache。 IE< 10也不支持AppCache。

答案 3 :(得分:0)

好吧所以我最近遇到了同样的问题,我的诀窍是使用一个简单的ajax请求完全加载文件一次(结束到缓存中),然后直接从缓存中再次加载声音并使用事件绑定canplaythrough

使用Buzz.js作为我的HTML5音频库,我的代码基本上是这样的:

var self = this;
$.get(this.file_name+".mp3", function(data) {
    self.sound = new buzz.sound(self.file_name, {formats: [ "mp3" ], preload: true});
    self.sound.bind("error", function(e) {
        console.log("Music Error: " + this.getErrorMessage());
    });
    self.sound.decreaseVolume(20);
    self.sound.bind("canplaythrough",function(){ self.onSoundLoaded(self); }); 
});