Web音频事件“结束”;在播放源缓冲区的一部分时未被触发

Web Audio event "ended" not being fired when playing part of a source buffer

本文关键字:一部 分时 缓冲区 结束 事件 音频 播放 Web      更新时间:2023-09-26

我们有一个web音频助手功能,可以播放声音表中的声音,并让我们知道它们何时完成。在过去,我们在更新循环中使用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];
}

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

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

我刚刚解决了这个问题,在意识到我做了一些愚蠢的事情之后。这个bug不是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;

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