首页 > 解决方案 > 如何不点击切换 Web 音频源节点?

问题描述

我正在尝试为特定的 Web 应用程序编写一个小型音频库,以解决需要较长加载时间的 Web 音频缓冲区源的问题,我正在尝试使用缓冲区源切换 HTML5 音频源(通过 MediaElementSourceNode)一次缓冲源已准备好播放。对于 20 分钟的曲目,Web Audio 的 Buffer Source 大约需要 5 秒才能解码并开始播放。

在 Web 音频中使用 PanNode 需要使用 MediaElementSourceNode

首先,我认为这是一个 JS 主线程延迟问题,它正在抛出“开始时间”。我想我可以通过确保禁用 MediaElementSource 和启用 BufferSourceNode 的代码尽可能接近执行来解决。

然后,虽然它必须是 HTML 在启动时有一个小的延迟,导致记录的 startTime 关闭,但为了解决这个问题,我使用了一个事件处理程序来监听“播放”。

我四处搜索,发现 Gapless 5 显然没有问题,查看它的源代码,我无法发现它是如何无缝切换源的

 play(offset) {
        this.createNodes();
        this.connectNodes();
        //if webAudio's buffer source is not ready, starting playing with HTML5
    if (!this.audioClip.isWebAudioReady() &&
        this.audioClip.playType > 0) {
        this.playHTML5();
    }
    //returns true if buffer != null
    if (!this.audioClip.isWebAudioReady()) {
        this.audioClip.addDecodeListener(this.play.bind(this));
    }

    if (this.audioClip.isWebAudioReady()) {
        this.playBufferSource();

    }
 playHTML5() {
    var context = AudioManager.context();
    if (this.audioClip.isHTML5Ready()) {
        this.createHTMLSourceNode();
        console.log("playing HTML5");
        this.mediaElementSourceNode.connect(this.gainNode);
        this.mediaElementSourceNode.source.play();
        this.startTime = context.currentTime;


    }
    else {
        console.log('not ready yet');
        this.audioClip.addLoadListener(this.playHTML5.bind(this));
    }
}
playBufferSource() {
    var context = AudioManager.context();
    var offset = context.currentTime - this.startTime;
    if (!this.bufferSourceNode) {
        this.createBufferSourceNode();
    }
    this.bufferSourceNode.connect(this.gainNode);
    //hoplessly attempt to make up for Thread latencey
    offset = context.currentTime - this.startTime;

    if (this.audioClip.playType > 0) {
        this.mediaElementSourceNode.disconnect();
        this.mediaElementSourceNode = null;
    }
    if (this.audioClip.playType == 0) {
        offset = 0;
        this.bufferSourceNode.start(0, offset);
    }
    else {
        offset = context.currentTime - this.startTime;
        this.bufferSourceNode.start(0, offset);
    }

    // console.log("starting web audio at" + offset);
}
createBufferSourceNode() {
    var context = AudioManager.context();
    if (!this.audioClip.webAudioReady) {
        console.log('Web Audio not ready!, Sometihng went wrong!');
        return;

    }
    var buffer = this.audioClip.buffer;
    this.bufferSourceNode = context.createBufferSource();
    //When using anything other than Buffer, 
    //we want to disable pitching.
    if (this.audioClip.playType == NS.PlayTypes.Buffer) {
        this.bufferSourceNode.playbackRate.setValueAtTime(this._pitch,
            context.currentTime);

    }
    this.bufferSourceNode.buffer = buffer;
}


createHTMLSourceNode() {
    var context = AudioManager.context();
    var HTMLAudio = this.audioClip.mediaElement.cloneNode(false);

    //HTMLAudio.addEventListener('ended', onHTML5Ended.bind(this), false);
    HTMLAudio.addEventListener('play', this.onHTML5Play.bind(this), false);

    var sourceNode = context.createMediaElementSource(HTMLAudio);

    sourceNode.source = HTMLAudio;
    this.mediaElementSourceNode = sourceNode;

}
/**
 * 
 */
onHTML5Play() {
    this.startTime = AudioManager.context().currentTime;
    console.log("HTML5 started playing");
}

由于我在尽可能靠近第一个源的时间启动第二个源,如果波形排列得足够近,从技术上讲,我应该听不到任何咔嗒声,但产生的咔嗒声非常可听,有时可以听到 2 次咔嗒声。

标签: javascriptaudio

解决方案


推荐阅读