setTimeout 函数是否足够准确以与音频时序同步?
Is setTimeout function accurate enough to sync with audio timing?
我想播放音乐(使用 HTML5 音频)并在特定时间显示一些图形元素(应与音频时间同步)。
用JavaScript的window.setTimeout
函数可以吗?
setTimeout(function() {
requestAnimationFrame(function() {
// display something
});
}, 1400);
setTimeout(function() {
requestAnimationFrame(function() {
// display something else
});
}, 2300);
或者,有没有更好的方法来做到这一点?
如果您能够在音频开始的同时开始超时,那么它就足够准确了。例如,对于 60 Hz 的屏幕频率,您有 16 毫秒到下一帧,因此实际上不必那么准确。
根据您所显示的内容,即使有几帧偏移也是可以接受的。例如,动画电影以 12 Hz 的频率更新(电影电影以 24 Hz 运行,动画每隔一帧更新一次)。
但是请注意,超时回调与其他所有内容都在同一线程上运行,因此只有在您没有任何其他 运行 占用主线程太长时间的情况下,它才会准确。例如,如果您有一些其他的事件处理程序执行一些繁重的工作,则可能会将超时延迟到足以可见的程度。
"Accurate enough"是主观的,但总的来说,没有。您不知道音频何时会完成下载并开始播放,或者它是否会在没有缓冲或被用户暂停的情况下播放。
相反,您可以使用 timeupdate
事件和 currentTime
属性,将事件正确同步到时间线。
var exampleElement = document.getElementById('example');
var lastTime = 0;
exampleElement.addEventListener('timeupdate', function(e) {
var nowTime = this.currentTime;
//Check if just passed the 1.4 second time mark.
if (nowTime > 1.4 && lastTime < 1.4) {
//Add a message to the debug element.
var logElement = document.getElementById('log');
logElement.textContent += 'Do something at 1.4 seconds\n';
}
lastTime = nowTime;
});
<audio id="example" controls="controls" autoplay="autoplay">
<source src="http://media.w3.org/2010/07/bunny/04-Death_Becomes_Fur.mp4" type='audio/mp4'>
<source src="http://media.w3.org/2010/07/bunny/04-Death_Becomes_Fur.oga" type='audio/ogg; codecs=vorbis'>
</audio>
<pre id="log"></pre><!--debug element-->
setTimeout
通常只在 给定的延迟后,并且当浏览器的线程清空时才执行 。
所以不,它并不完全准确,但我认为就您的目的而言,它已经足够接近了,通常延迟不到 0.2%,
图片来自this question
然而,在较慢的用户机器上,效果可能更明显,使用 setTimeout isn't recommended.
相反,您可以使用 timeupdate
事件和 currentTime
属性 来更准确地匹配音频,
var audio = document.querySelector('audio#my-audio');
audio.addEventListener('timeupdate', function(){
switch (this.currentTime){
case 1:
//stuff
break;
/* etc. */
}
}
currentTime
虽然使用秒来计数,因此您将不得不使用不太精确的节拍器,但准确度就在那里。
我想播放音乐(使用 HTML5 音频)并在特定时间显示一些图形元素(应与音频时间同步)。
用JavaScript的window.setTimeout
函数可以吗?
setTimeout(function() {
requestAnimationFrame(function() {
// display something
});
}, 1400);
setTimeout(function() {
requestAnimationFrame(function() {
// display something else
});
}, 2300);
或者,有没有更好的方法来做到这一点?
如果您能够在音频开始的同时开始超时,那么它就足够准确了。例如,对于 60 Hz 的屏幕频率,您有 16 毫秒到下一帧,因此实际上不必那么准确。
根据您所显示的内容,即使有几帧偏移也是可以接受的。例如,动画电影以 12 Hz 的频率更新(电影电影以 24 Hz 运行,动画每隔一帧更新一次)。
但是请注意,超时回调与其他所有内容都在同一线程上运行,因此只有在您没有任何其他 运行 占用主线程太长时间的情况下,它才会准确。例如,如果您有一些其他的事件处理程序执行一些繁重的工作,则可能会将超时延迟到足以可见的程度。
"Accurate enough"是主观的,但总的来说,没有。您不知道音频何时会完成下载并开始播放,或者它是否会在没有缓冲或被用户暂停的情况下播放。
相反,您可以使用 timeupdate
事件和 currentTime
属性,将事件正确同步到时间线。
var exampleElement = document.getElementById('example');
var lastTime = 0;
exampleElement.addEventListener('timeupdate', function(e) {
var nowTime = this.currentTime;
//Check if just passed the 1.4 second time mark.
if (nowTime > 1.4 && lastTime < 1.4) {
//Add a message to the debug element.
var logElement = document.getElementById('log');
logElement.textContent += 'Do something at 1.4 seconds\n';
}
lastTime = nowTime;
});
<audio id="example" controls="controls" autoplay="autoplay">
<source src="http://media.w3.org/2010/07/bunny/04-Death_Becomes_Fur.mp4" type='audio/mp4'>
<source src="http://media.w3.org/2010/07/bunny/04-Death_Becomes_Fur.oga" type='audio/ogg; codecs=vorbis'>
</audio>
<pre id="log"></pre><!--debug element-->
setTimeout
通常只在 给定的延迟后,并且当浏览器的线程清空时才执行 。
所以不,它并不完全准确,但我认为就您的目的而言,它已经足够接近了,通常延迟不到 0.2%,
图片来自this question
然而,在较慢的用户机器上,效果可能更明显,使用 setTimeout isn't recommended.
相反,您可以使用 timeupdate
事件和 currentTime
属性 来更准确地匹配音频,
var audio = document.querySelector('audio#my-audio');
audio.addEventListener('timeupdate', function(){
switch (this.currentTime){
case 1:
//stuff
break;
/* etc. */
}
}
currentTime
虽然使用秒来计数,因此您将不得不使用不太精确的节拍器,但准确度就在那里。