【问题标题】:Clicking sounds in Stream played with Web Audio Api在使用 Web Audio Api 播放的 Stream 中单击声音
【发布时间】:2020-04-29 03:44:41
【问题描述】:

我有一个奇怪的问题。我正在使用网络音频播放来自服务器的流。我这样做的方式如下:

 var d2 = new DataView(evt.data);

var data = new Float32Array(d2.byteLength / Float32Array.BYTES_PER_ELEMENT);
for (var jj = 0; jj < data.length; ++jj) {
    data[jj] = d2.getFloat32(jj * Float32Array.BYTES_PER_ELEMENT, true);
}

var buffer = context.createBuffer(1, data.length, 44100);
buffer.getChannelData(0).set(data);

source = context.createBufferSource();
source.buffer = buffer;
source.start(startTime);
source.connect(context.destination);

startTime += buffer.duration;

这很好用。 如果我在我的电脑上播放流,我没有任何问题。

如果我在我的 Windows 8 平板电脑(相同的 Chrome 版本)上播放相同的流,我的音频中有很多点击声音。一秒钟内有多个。 它有点接缝,在每个缓冲区的末端我听到咔哒声。

我不明白区别...我能找到的唯一区别是我的计算机上声卡的采样率为 44100,而平板电脑上的采样率为 48000。

传输的流在 44100 中,我没有任何采样率问题。只是点击的声音。

有人知道为什么会这样吗?

谢谢, 代谢

【问题讨论】:

    标签: javascript web-audio-api


    【解决方案1】:

    AudioBufferSourceNode 将其缓冲区重新采样到 AudioContext 采样率。可以想象,API 不允许您在一个 AudioBufferSourceNode 和另一个之间保持重采样器状态,因此两个缓冲区之间存在不连续性。

    我认为最简单的方法是通过在服务器端重新采样以设备的采样率提供流。当 AudioWorkerNode 准备好并实现时,您将能够自己修复这个问题以及客户端,但事实并非如此。

    或者,您也可以只使用一个元素进行流式传输,然后使用 AudioContext.createMediaElementSource() 将其通过管道传输到 Web Audio API。

    【讨论】:

    • 谢谢!我现在在服务器端重新采样流并等到实现 AudioWorkerNode :)。我没有找到任何可能的信息。你对此有什么见解吗?
    • 我们会在规范完成后实现它,我们真的不知道什么时候会实现,抱歉。
    【解决方案2】:

    我遇到了同样的问题,感谢 Padenot 的回答,我检查了采样率。 AudioContext.sampleRate 默认为 44100,但 PCM 数据和 AudioBuffer 为 48000。使用匹配的 sampleRate 初始化 AudioContext 解决了问题:

    var AudioContext = window.AudioContext || window.webkitAudioContext;
    var audioCtx = new AudioContext({
      latencyHint: 'interactive',
      sampleRate: 48000,
    });
    
    

    有了这个,我可以安排播放 20ms 48khz PCM16 AudioBuffers 背靠背,没有任何点击或失真。

    【讨论】:

    • 我真的很好奇如何安排 20 毫秒 AudioBuffers 背靠背,因为 AudioBufferSourceNode.start(when) 需要一个 when 参数,单位为 seconds
    • @Todd 秒值被解释为实数(不是整数),所以它可以是当前时间加上 0.02,然后是 0.04,等等。
    • 谢谢!另一个问题 - 您不必转换为 Float32 PCM 缓冲区吗? AudioBuffer.copyToChannel() 好像需要 Float32,怎么玩 PCM16 缓冲区?
    • @ToddFreed 为 AudioContext 转换 pcm16 -> float32,将每个值除以最大值 32768,例如类似audiobuf = Audio.context.createBuffer(1, pcm.length, 48000); chanpcm = audiobuf.getChannelData(0); for (i = 0; i &lt; chanpcm.length; i += 1) { chanpcm[i] = pcm[i] / 32768.0; } 的其他示例参见pcm-player.js 中的getFormatedValueflush,以及AudioContext.getChannelData 中的示例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-14
    • 1970-01-01
    • 1970-01-01
    • 2017-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多