在 Javascript 中预加载音频的问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8375903/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Problems preloading audio in Javascript
提问by Jeffrey Sweeney
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.
我正在尝试为我正在处理的 GameAPI 制作跨设备/浏览器图像和音频预加载方案。音频文件将预加载,并在完成后发出回调。
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.
我已将其缩小到 audio.load() 函数。摆脱它可以解决问题,但有趣的是,我的摩托罗拉机器人需要该功能。
What are some experiences you've had with HTML5 audio preloading?
您在 HTML5 音频预加载方面有哪些经验?
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.
很难诊断问题,因为它没有显示任何错误,只是偶尔失败。
采纳答案by Jeffrey Sweeney
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.
如果不是很明显,该load
函数告诉浏览器和支持它开始加载设备,然后声音会立即尝试play
与volume
几乎为零。因此,如果该load
功能还不够,那么“需要”播放的声音这一事实足以在我测试的所有设备上触发负载。
The load
function may actually be redundant now, but based off the inconsistiency with audio implementation, it probably doesn't hurt to have it.
该load
功能现在实际上可能是多余的,但基于与音频实现的不一致,拥有它可能不会有什么坏处。
Edit: After testing this on Opera, Safari, Firefox, and Chrome, it looks like setting the volume
to 0 will still preload the resource.
编辑:在 Opera、Safari、Firefox 和 Chrome 上对此进行测试后,看起来将 设置volume
为 0 仍会预加载资源。
回答by AshleysBrain
canplaythrough
fires when enough data has bufferedthat 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 downloadingby the time this event fires.
canplaythrough
当缓冲了足够的数据时触发,如果您开始播放该事件,它可能可以不间断地播放到最后。HTML Audio 元素专为流式传输而设计,因此在触发此事件时文件可能尚未完全下载。
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 AppCacheto make sure the images and audio are certainly cached.
我建议使用HTML5 AppCache来确保图像和音频确实被缓存。
回答by J?rn Berkefeld
The AppCache, as suggested above, might be your only solution to keep the audio cached from one browser-session to another (that's not what you asked for, right?). but keep in mind the limited amount of space, some browsers offer. Safari for instance allows the user to change this value in the settings but the default is 5MB - hardly enough to save a bunch of songs, especially if other websites that are frequented by your users use AppCache as well. Also IE <10 does not support AppCache.
如上所述,AppCache 可能是您将音频从一个浏览器会话缓存到另一个浏览器会话的唯一解决方案(这不是您要求的,对吧?)。但请记住,某些浏览器提供的空间有限。例如,Safari 允许用户在设置中更改此值,但默认值为 5MB - 几乎不足以保存一堆歌曲,特别是如果您的用户经常访问的其他网站也使用 AppCache。此外 IE <10 不支持 AppCache。
回答by Mr_Pouet
Alright so I ran into the same problem recently, and my trick was to use a simple ajax request to load the file entirely once (which end into the cache), and then by loading the sound again directly from the cache and use the event binding canplaythrough
.
好吧,所以我最近遇到了同样的问题,我的技巧是使用一个简单的 ajax 请求将文件完全加载一次(最终进入缓存),然后直接从缓存中再次加载声音并使用事件绑定canplaythrough
.
Using Buzz.jsas my HTML5 audio library, my code is basically something like that:
使用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); });
});