【问题标题】:Web Audio event "ended" not being fired when playing part of a source buffer播放源缓冲区的一部分时未触发 Web 音频事件“结束”
【发布时间】:2014-08-13 18:57:52
【问题描述】:

我们有一个网络音频助手功能,可以播放声音表中的声音,并让我们知道它们何时完成。过去,我们在更新循环中使用 playbackState 来检查节点是否已完成播放,但由于 Chrome 36 现在使用不支持 playbackState 的当前规范,因此我们更新了要使用的代码'ended' 事件。

然而,这似乎并没有被解雇。

以下是我们的playAudio函数:-

playAudio: function(trackName){
    var node = this._atx.createBufferSource();
    node.buffer = this._buffer;

    var gain = this._atx.createGain();

    node.connect(gain);
    gain.connect(this._atx.destination);

    var start = this._tracks[trackName][0];
    var length = this._tracks[trackName][1] - start;

    node.start(0, start, length);

    var sound = {name: trackName, srcNode: node, gainNode: gain, startTime: this._atx.currentTime, duration: length, loop: false, playHeadStart: start};

    if (this._features.hasEvents) {
        //node.addEventListener("ended", function () {
        //   this._soundEnded(sound)
        //}.bind(this));
        node.onended = function(){
            this._soundEnded(sound);
        }.bind(this);
    }

    this._playingSounds[++this._soundId] = sound;
    return this._soundId;
},
_soundEnded: function (sound) {
    this._playingSounds[sound] = null;
    delete this._playingSounds[sound];
}

this._features.hasEvents 变量是通过在加载期间创建的音频节点上检查 node.onended !== null 来设置的。缓冲区是通过 XHR'ing 文件创建的。这可以是 mp3 或 m4a,具体取决于我们正在播放的内容。

_soundedEnded 函数没有被调用的原因是什么?我已经尝试过node.onended = function(){...}node.addEventListener("ended", function(){..}) 语法,但都没有运气。我们似乎在 iOS 7 Safari 和桌面/Android Chrome 中都有相同的行为。

【问题讨论】:

  • 这很有趣。我正在大量使用onended= function(){},它似乎可以在所有平台上的 Safari 和 Chrome 上运行。它可能不会被调用的唯一原因是如果您正在循环缓冲区。否则,当缓冲区用完时,或者在缓冲区上调用 .stop() 时,我会看到它。
  • 我刚刚意识到这取决于_soundedEnded 回调。看起来它实际上 确实 被调用了,但我试图使用一个对象来索引一个数组,所以它从来没有从数组中删除声音。我现在已经更新它以使用 soundId,而不是对象,它又可以工作了。

标签: javascript html web-audio-api


【解决方案1】:

我刚刚解决了这个问题,因为我意识到我在做一些愚蠢的事情。该错误与 WebAudio 无关,而是与应该从 _playingSounds 数组中删除声音对象的回调函数有关。

这段代码:

var sound = {name: trackName, srcNode: node, gainNode: gain, startTime:     this._atx.currentTime, duration: length, loop: false, playHeadStart: start};

if (this._features.hasEvents) {
    //node.addEventListener("ended", function () {
    //   this._soundEnded(sound)
    //}.bind(this));
    node.onended = function(){
        this._soundEnded(sound);
    }.bind(this);
}

this._playingSounds[++this._soundId] = sound;
return this._soundId;

应该更像这样:

var sound = {name: trackName, srcNode: node, gainNode: gain, startTime: this._atx.currentTime, duration: length, loop: false, playHeadStart: start};
var soundId = ++this._soundId;
if (this._features.hasEvents) {

    node.onended = function(){
        this._soundEnded(soundId);
    }.bind(this);
}

this._playingSounds[soundId] = sound;
return soundId;

我试图通过值而不是键来删除对象,这显然不起作用。代码现在将密钥传递给函数,一切都恢复正常了。

【讨论】:

    猜你喜欢
    • 2011-10-31
    • 2017-12-15
    • 2014-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-18
    • 2018-01-20
    • 1970-01-01
    相关资源
    最近更新 更多