在流式传输音频数据期间,webaudio播放出现裂缝

时间:2017-04-12 10:13:19

标签: html5 html5-audio audio-streaming web-audio web-audio-api

我有一台服务器通过websocket发送原始音频块。我们的想法是检索它们并以尽可能顺畅播放的方式播放它们。

以下是最重要的代码:

ws.onmessage = function (event) {
    var view = new Int16Array(event.data);
    var viewf = new Float32Array(view.length);

    audioBuffer = audioCtx.createBuffer(1, viewf.length, 22050);
    audioBuffer.getChannelData(0).set(viewf);
    source = audioCtx.createBufferSource();
    source.buffer = audioBuffer;
    source.connect(audioCtx.destination);
    source.start(0);
};

这种方法效果不错,但播放中存在一些问题:网络延迟并不总是恒定的,因此最新的数据块并没有完全到达前一个播放的结尾,所以我最终可能会有两个缓冲区一起播放很短的时间,或者根本没有播放。

我试过了:

  • 挂钩source.onended播放下一个,但它不是无缝的:每个块的末尾都有一个裂缝,每个接缝都在积累,所以播放越来越晚了与溪流相比。
  • 将新数据附加到当前播放的缓冲区,但这似乎是禁止的:缓冲区大小固定。

是否有适当的解决方案来修复播放?唯一的要求是播放来自websocket的未压缩音频。

编辑:解决方案:鉴于我知道我的缓冲区长度,我可以这样安排播放:

if(nextStartTime == 0) nextStartTime = audioCtx.currentTime + (audioBuffer.length / audioBuffer.sampleRate)/2;
source.start(nextStartTime);
nextStartTime += audioBuffer.length / audioBuffer.sampleRate;

第一次,我将播放的开始安排到半个缓冲区之后,以允许最大的意外延迟。然后,我将下一个缓冲区开始时间存储在缓冲区结束的最后。

3 个答案:

答案 0 :(得分:3)

你应该从https://www.html5rocks.com/en/tutorials/audio/scheduling/开始,这很好地解释了如何在WebAudio中安排事情。

对于您的使用案例,您还应该利用这样的事实,即您知道PCM样本的采样率,并且您知道您已阅读了多少样本。这决定了播放缓冲区所需的时间。用它来计算何时安排下一个缓冲区。

(但请注意,如果PCM采样率与audioCtx.sampleRate不同,则会重新采样数据,这可能会使您的时间陷入混乱。

答案 1 :(得分:1)

现在有更好的方法来处理这个问题......请考虑使用Media Source Extensions。

您不必自己安排缓冲区并自行完成,而是将接收到的数据转储到缓冲区中,让浏览器担心缓冲播放,就好像它是一个基于HTTP的文件一样。

Chrome支持播放WAV文件。由于您的数据是原始PCM,因此您需要欺骗WAV文件头。幸运的是,这并不困难:http://soundfile.sapp.org/doc/WaveFormat/

答案 2 :(得分:1)

我在答案here中解决了这个问题。请查看它以获取更多信息和大量代码。

快速摘要:

您必须创建一个新的 AudioBuffer AudioBufferSourceNode 两者(或至少是后者) 每个要缓冲的数据...我尝试循环相同的AudioBuffer,但是一旦在AudioContext上设置了.audioBuffer,您对AudioBuffer所做的任何修改变得无关紧要。

(注意:这些类具有您也应查看的基类/父类(在文档中已引用)。)