【问题标题】:WebAudio - seamlessly playing sequence of audio chunksWebAudio - 无缝播放音频块序列
【发布时间】:2016-09-24 08:41:26
【问题描述】:

我有一个实时的、恒定的波形数据源,它为我提供了一秒钟的单通道音频,并且每秒具有恒定的采样率。目前我是这样玩的:

// data : Float32Array, context: AudioContext
function audioChunkReceived (context, data, sample_rate) { 
    var audioBuffer = context.createBuffer(2, data.length, sample_rate);
    audioBuffer.getChannelData(0).set(data);
    var source = context.createBufferSource(); // creates a sound source
    source.buffer = audioBuffer;
    source.connect(context.destination);
    source.start(0);
}

音频播放正常,但在连续播放的块之间有明显的停顿(如预期的那样)。我想摆脱它们,我知道我必须引入某种缓冲。

问题:

  • 有没有 JS 库可以为我做这件事? (我正在搜索它们)
  • 如果没有图书馆可以做到这一点,我应该如何自己做?
  • 检测到何时在一个源中完成播放并准备好之后立即播放另一个源? (使用 AudioBufferSourceNode.onended 事件处理程序)
  • 创建一个大缓冲区并一个接一个地复制我的音频块并使用 AudioBufferSourceNode.start AudioBufferSourceNode.stop 函数控制流?
  • 有什么不同?

【问题讨论】:

标签: javascript html streaming web-audio-api


【解决方案1】:

您没有显示audioChunkReceived 的方式,但要获得无缝播放,您必须确保在播放之前拥有数据并且前一个停止播放之前。

一旦你有了这个,你可以通过调用 start(t) 来安排最新的块在前一个块结束时开始播放,其中 t 是前一个块的结束时间。

但是,如果缓冲区采样率与 context.sampleRate 不同,则可能无法顺利播放,因为需要重新采样才能将缓冲区转换为上下文率。

【讨论】:

  • 谢谢您,我已采纳您的建议并拼凑出简单的解决方案。您可以在另一个答案中查看它。如果我有更多的业力,我会支持你的答案:)
【解决方案2】:

我在 TypeScript 中编写了一个小类,现在用作缓冲区。它定义了 bufferSize 来控制它可以容纳多少块。它很短且具有自我描述性,因此我将其粘贴在这里。有很多需要改进的地方,欢迎提出任何想法。

(您可以使用:https://www.typescriptlang.org/play/ 快速将其转换为 JS)

class SoundBuffer {
    private chunks : Array<AudioBufferSourceNode> = [];
    private isPlaying: boolean = false;
    private startTime: number = 0;
    private lastChunkOffset: number = 0;

    constructor(public ctx:AudioContext, public sampleRate:number,public bufferSize:number = 6, private debug = true) { }

    private createChunk(chunk:Float32Array)  {
        var audioBuffer = this.ctx.createBuffer(2, chunk.length, this.sampleRate);
        audioBuffer.getChannelData(0).set(chunk);
        var source = this.ctx.createBufferSource();
        source.buffer = audioBuffer;
        source.connect(this.ctx.destination);
        source.onended = (e:Event) => { 
            this.chunks.splice(this.chunks.indexOf(source),1);
            if (this.chunks.length == 0) {
                this.isPlaying = false;
                this.startTime = 0;
                this.lastChunkOffset = 0;
            }
        };

        return source;
    }

    private log(data:string) {
        if (this.debug) {
            console.log(new Date().toUTCString() + " : " + data);
        }
    }

    public addChunk(data: Float32Array) {
        if (this.isPlaying && (this.chunks.length > this.bufferSize)) {
            this.log("chunk discarded");
            return; // throw away
        } else if (this.isPlaying && (this.chunks.length <= this.bufferSize)) { // schedule & add right now
            this.log("chunk accepted");
            let chunk = this.createChunk(data);
            chunk.start(this.startTime + this.lastChunkOffset);
            this.lastChunkOffset += chunk.buffer.duration;
            this.chunks.push(chunk);
        } else if ((this.chunks.length < (this.bufferSize / 2)) && !this.isPlaying) {  // add & don't schedule
            this.log("chunk queued");
            let chunk = this.createChunk(data);
            this.chunks.push(chunk);
        } else  { // add & schedule entire buffer
            this.log("queued chunks scheduled");
            this.isPlaying = true;
            let chunk = this.createChunk(data);
            this.chunks.push(chunk);
            this.startTime = this.ctx.currentTime;
            this.lastChunkOffset = 0;
            for (let i = 0;i<this.chunks.length;i++) {
                let chunk = this.chunks[i];
                chunk.start(this.startTime + this.lastChunkOffset);
                this.lastChunkOffset += chunk.buffer.duration;
            }
        }
    }
}

【讨论】:

  • 伙计,我花了几天时间寻找它。非常感谢
  • 每个块之间的间隙仍然很小(
  • 仍有 6 毫秒的延迟
  • 您能展示如何将您的类与 MediaRecoder 数据一起使用吗?
【解决方案3】:

我认为这是因为您将缓冲区分配给 2 个通道。 将其更改为一个。

context.createBuffer(2, data.length, sample_rate);

context.createBuffer(1, data.length, sample_rate);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-14
    • 1970-01-01
    • 2013-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-07
    • 1970-01-01
    相关资源
    最近更新 更多