Web Audio API和播放音频文件时的实时当前时间

Web Audio API and real current time when playing an audio file

本文关键字:实时 时间 文件 API Audio 播放 音频 Web      更新时间:2023-09-26

当我想知道使用Web音频API播放文件的当前时间时,我遇到了问题。我的代码很好地播放文件,getCurrentTime()函数返回的当前时间足够准确,当涉及到加载快的短文件时。

但是当我尝试加载大文件时,有时getCurrentTime()函数返回的当前时间是准确的,有时不是。有时,在等待例如20秒后听到文件播放,当它开始播放时,它说当前时间大约是20秒(这是不正确的,因为它只是播放文件的开头)。它发生在任何音频格式(OGG, MP3, WAV…),但只是有时。

我使用的是慢速系统(华硕EEE PC 901,英特尔Atom 1.60 Ghz, 2gb RAM, Windows XP家庭版和SP3)和Firefox 41.0.1。

我不确定,但似乎source.start()方法开始播放声音的方式太晚了,所以调用该方法后的行,我设置了startTime变量的值,不是真正的开始时间。

下面是代码(简化):
var context, buffer, startTime, source;
var stopped = true;
function load(file, startAt)
{
    //Here creates the AudioContext and loads the file through XHR (AJAX) and gets the buffer. All works fine.
    //When it gots the buffer through XHR (AJAX) and all is fine, it calls play(startAt) function immediately.
    //Note: normally, startAt is 0.
}
function play(startAt)
{
    source = context.createBufferSource(); //Context created before.
    source.buffer = buffer; //Buffer got before from XHR (AJAX).
    //Creates a gain node to be able to set the volume later:
    var gainNode = context.createGain();
    source.connect(gainNode);
    gainNode.connect(context.destination);
    //Plays the sound:
    source.loop = false;
    source.start(startAt, 0, buffer.duration - 3); //I don't want the last 3 seconds.
    //Stores the start time (useful for pause/resume):
    startTime = context.currentTime - startAt; //Here I store the startTime but maybe the file has still not begun to play (should it be just startTime = context.currentTime?).
    stopped = false;
}
function stop()
{
    source.stop(0);
    stopped = true;
}
function getCurrentTime()
{
    return (stopped) ? 0 : context.currentTime - startTime;
}

我如何检测何时确切地source.start()方法开始播放文件?所以我可以在那一刻设置startTime变量值,而不是之前。

提前谢谢你。我将非常感谢任何帮助。

来自MDN (https://developer.mozilla.org/en-US/docs/Web/API/AudioBufferSourceNode/start),关于start()函数的第一个参数:

when (Optional)

声音开始播放的时间,以秒为单位,与AudioContext使用的时间坐标系统相同。如果when小于(AudioContext。currentTime,或者如果它为0,声音立即开始播放。默认值为0。

你的代码没有明显的问题(尽管没有调用play()的例子):如果你调用play(0)play(context.currentTime + someDelayInSeconds), start()应该像预期的那样表现。不幸的是,这里的问题是AudioBufferSource并不适用于大文件。再次从AudioBuffer的MDN文档(https://developer.mozilla.org/en-US/docs/Web/API/AudioBuffer):

)

这些类型的对象被设计用来保存小的音频片段,通常小于45秒。

我怀疑对于大的东西不太好工作与"声音立即开始播放";假设(我也经历过,尽管20秒似乎太长了……)不幸的是,没有办法在WebAudio中获得AudioBufferSource的确切开始时间。

如果你没有任何真正的理由用AudioBufferSource加载这个大文件,我建议你使用MediaElementSourceNode (https://developer.mozilla.org/en-US/docs/Web/API/MediaElementAudioSourceNode):,你可以从链接文档的例子中看到,它允许你插入一个简单的HTML5 Audio元素到AudioContext。然后你可以对元素本身进行所有通常的控制,即你也可以访问audioElement.currentTime属性,它告诉你当前的播放时间(在这种情况下,文件本身,这是你所需要的)。此外,您不必处理在内存中加载文件,并且可以在一些数据可用时立即开始播放。

context.currentTime从创建上下文对象的那一刻开始计数。这意味着如果你的音频需要20秒才能加载,context.currentTime == 20 .

为了解决这个延迟,你可以设置一个简单的计时器,从你创建上下文的时间到音频加载完成的时间。

var context; //Create your context here
var audioLoadStart = new Date();
//Do audio load
var audioLoadOffset = (new Date() - audioLoadStart) / 1000;
currentTime = context.currentTime - audioLoadOffset - startTime;