【问题标题】:Web audio API does not play sound ContinuouslyWeb 音频 API 不连续播放声音
【发布时间】:2017-06-04 23:33:06
【问题描述】:

我正在尝试使用节点 js 和套接字 io 实时缓冲 MP3 歌曲。我基本上将 MP3 划分为字节段并将其发送到客户端,Web 音频 API 将在客户端接收它、解码并开始播放。这里的问题是声音不会连续播放,每个缓冲段之间有大约 0.5 秒的间隙。我该如何解决这个问题

// buffer is a 2 seconds decoded audio ready to be played 
// the function is called  when a new buffer is recieved
function stream(buffer)
{
    // creates a new buffer source and connects it to the Audio context
    var source = context.createBufferSource();
    source.buffer = buffer;
    source.connect(context.destination);
    source.loop = false;
    // sets it and updates the time 
    source.start(time + context.currentTime);

    time += buffer.duration; // time is global variable initially set to zero
}

调用stream的部分

    // where stream bufferQ is an array of decoded MP3 data 
    // so the stream function is called after every 3 segments that are recieved 
     // the Web audio Api plays it with gaps between the sound
    if(bufferQ.length == 3)
    {
        for(var i = 0, n = bufferQ.length ; i < n; i++)
        {
              stream(bufferQ.splice(0,1)[0]);
        }
    }

我应该使用网络音频 API 以外的其他 API,还是有办法安排我的缓冲区以便连续播放?

【问题讨论】:

  • 何时调用stream()
  • @guest271314 抱歉,我没有澄清这一点。我已经编辑了我的答案。你能看一下吗?
  • 您可以在前一个bufferSource 的结尾处开始下一个bufferSource。您还可以利用MediaSourceupdateend 事件将媒体源片段的ArrayBuffer 表示附加到媒体播放,请参阅HTML5 audio streaming: precisely measure latency?
  • @guest271314 我试图通过执行类似 source.start(time + context.currentTime - 0.5);但是,它没有按预期工作。我将尝试使用 updateend。我是否应该创建一个媒体源,并在每次收到一个段时将新的解码缓冲区附加到它?感谢您的帮助和时间
  • 非常感谢!我将阅读这个以及之前的堆栈溢出问题并尝试一下!

标签: javascript node.js socket.io buffer web-audio-api


【解决方案1】:

context.currentTime 将根据评估时间而有所不同,并且由于四舍五入到最接近的 2ms 左右,每次读取都具有隐含的不准确性(请参阅Firefox BaseAudioContext/currentTime#Reduced time precision)。考虑:

function stream(buffer)
{
...
source.start(time + context.currentTime);

time += buffer.duration; // time is global variable initially set to zero

为每个 PCM 数据块调用 source.start(time + context.currentTime) 将始终在当前时间(不一定与播放时间相关)四舍五入为 2 毫秒加上 time 偏移量时开始播放该块。

要播放背靠背 PCM 块,请在流的开头读取一次 currentTime,然后在安排播放后将每个持续时间添加到其中。例如,PCMPlayer 会:

PCMPlayer.prototype.flush = function() {
...
    if (this.startTime < this.audioCtx.currentTime) {
        this.startTime = this.audioCtx.currentTime;
    }
...
    bufferSource.start(this.startTime);
    this.startTime += audioBuffer.duration;
};

注意startTime 仅在表示过去的时间时才会重置 - 对于连续缓冲流,它不会重置,因为它将是未来某个时间的值。在每次flush调用中,startTime用于调度播放,只增加每个PCM数据的时长,不依赖于currentTime。


另一个潜在问题是您正在解码的 PCM 缓冲区的采样率可能与 AudioContext 的采样率不匹配。在这种情况下,浏览器会分别对每个 PCM 缓冲区进行重新采样,从而导致块边界处的不连续性。见Clicking sounds in Stream played with Web Audio Api

【讨论】:

    【解决方案2】:

    这是 mp3 文件的问题,每个 mp3 文件的开头和结尾都有几帧静音。 如果您使用 wav 文件或正确计时每个文件的开始和停止时间,则可以修复它

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-14
      相关资源
      最近更新 更多