如何找到HTML5音频实际开始播放的时间(onplay事件似乎无法在任何地方工作)

时间:2014-05-29 23:36:20

标签: javascript html5 html5-video html5-audio html5-apps

我需要抓住HTML5音频开始产生声音的确切时刻。

事实证明并非如此简单。

您可能希望在onplayonplaying事件被触发时播放音频?没门。至少在WebKit系列中,似乎没有浏览器事件在这个时间点完全触发。在Chrome中,Safari和Firefox onplayonplaying事件只是通过与oncanplay一起解雇来伪装他们的行为!

我准备了一个简单的测试来证明这个事实。它表明,当所有事件都已被触发后,音频实际上会在一段合理的时间(超过100毫秒 - 400毫秒)后开始播放。

如果您查看控制台日志,您可以通过耳朵和耳朵注意到这一点。在日志中,我每15ms输出currentTime。它似乎正确地反映了实际的音频状态,并且在任何事件被触发后它开始改变10-40个民意调查。因此,在play被触发后,音频仍然会被冻结。

测试代码如下所示:

    var audioEl = new Audio('http://www.w3schools.com/tags/horse.ogg');

    audioEl.oncanplay = function () {
        console.log('oncanplay');

        audioEl.currentTime = 1;    

        console.log('ready state is: ' + audioEl.readyState);
        audioEl.play();
    }


    audioEl.oncanplay = function () {
        console.log('oncanplay again');
    }

    audioEl.onplay = function() {
        console.log('onplay -----------------');
    }

    audioEl.onplaying = function() {
        console.log('onplaying ----------------');
    }

    setInterval(function () {
        console.log(audioEl.currentTime);
    }, 15);

JsFiddle

我非常需要知道音频开始播放的确切时刻,以便与视觉动画进行精确同步。

当然,我可以粗略地使用快速轮询找到这个时刻。这对于实时应用程序的性能非常不利,特别是在移动设备上。

我在问是否有人知道更好的解决方案。 2014年HTML音频实现看起来仍然很差:(

2 个答案:

答案 0 :(得分:3)

正如@justin所说,你可以听取playing事件,以获得媒体开始实际播放的(或多或少)精确时刻。但是,我一直看到对媒体事件的一些支持,readyState一般even in latest Chrome

无论这些事件是否有效,我建议不要将setInterval用于动画(或者就其他任何事情而言)。相反,使用requestAnimationFrame,它会更频繁地触发,并且应该与浏览器和视频卡的重绘同步。并且您可以在每个帧上轮询currentTime值以计算您应该在动画中的位置。表现应该不是问题;您的案例完全 requestAnimationFrame的设计目的。

function update() {
    var currentTime = audioEl.currentTime;
    // update your animation here
    requestAnimationFrame(update);
}

update();

当您遇到此问题时,请勿在{{1​​}}或currentTime事件触发后将readyState > 0设置为5。如果您尝试在浏览器加载足够的视频文件之前设置loadedmetadata以了解持续时间,则会引发错误。但是你可以随时打电话给currentTime;它不必等待play()

答案 1 :(得分:-1)

尝试使用canplaythrough。可能会有所帮助,最好还是确保你的音频可以一路走到尽头......

audioEl.oncanplay = function () {
      console.log('ready state is: ' + audioEl.readyState);
      audioEl.play();
}