在 Node.js 上从 Web Audio API 播放 PCM 流

Posted

技术标签:

【中文标题】在 Node.js 上从 Web Audio API 播放 PCM 流【英文标题】:Playing PCM stream from Web Audio API on Node.js 【发布时间】:2014-01-19 11:59:43 【问题描述】:

我正在使用网络音频 api 从浏览器流式传输录制的 PCM 音频。

我正在使用binaryJS (websocket connection) 将其流式传输到 nodejs 服务器,并且我正在尝试使用扬声器 npm 模块在服务器上播放该流。

这是我的客户。 The audio buffers are at first non-interleaved IEEE 32-bit linear PCM with a nominal range between -1 and +1。我从两个 PCM 通道之一开始并在下面进行流式传输。

var client = new BinaryClient('ws://localhost:9000');
var Stream = client.send();

recorder.onaudioprocess = function(AudioBuffer)
    var leftChannel = AudioBuffer.inputBuffer.getChannelData (0);
    Stream.write(leftChannel);

现在我将数据作为缓冲区接收并尝试将其写入 npm 包中的扬声器对象。

var Speaker = require('speaker');

var speaker = new Speaker(
  channels: 1,          // 1 channel
  bitDepth: 32,         // 32-bit samples
  sampleRate: 48000,     // 48,000 Hz sample rate
  signed:true
);

server.on('connection', function(client)
    client.on('stream', function(stream, meta)
        stream.on('data', function(data)
            speaker.write(leftchannel);
        );
    );
);

结果是我笔记本电脑的扬声器发出高音,这显然不是录制的内容。也不是反馈。我可以确认客户端上的录制缓冲区是有效的,因为我尝试将它们写入 WAV 文件并且播放正常。

有问题的docs for speaker 和docs for the AudioBuffer

这几天我一直在纠结这个问题。有人可以找出问题所在或提供不同的方法吗?

更新解决方案

首先,我错误地使用了 websocket API。我在上面更新以正确使用它。

我需要将音频缓冲区转换为整数数组缓冲区。我选择使用Int16Array。由于给定的音频缓冲区的范围介于 1 和 -1 之间,因此只需乘以新 ArrayBuffer 的范围(32767 到 -32768)即可。

recorder.onaudioprocess = function(AudioBuffer)

    var left = AudioBuffer.inputBuffer.getChannelData (0);

    var l = left.length;
    var buf = new Int16Array(l)

    while (l--) 
        buf[l] = left[l]*0xFFFF;    //convert to 16 bit
    

    Stream.write(buf.buffer);


【问题讨论】:

为了消除或识别扬声器作为错误源,如果您以与客户端相同的方式将接收端的缓冲区写入 wav,它是否正确播放(扬声器有问题)还是尖锐的声音(流有问题)?或者,您是否可以通过扬声器播放正常工作的 AudioBuffer? 嗨,我可以在 github 上的某个地方找到你的代码吗? 【参考方案1】:

看起来您正在通过 meta 对象发送流。

根据文档,BinaryClient.send 按顺序采用 data 对象(流)和 meta 对象。 stream 事件的回调在第一个参数中接收流(作为BinaryStream 对象,而不是Buffer),在第二个参数中接收meta 对象。

您将send() 字符串'channel' 作为流传递,并将getChannelData() 中的Float32Array 作为元对象传递。也许如果您要交换这两个参数(或只使用client.send(leftChannel)),然后将服务器代码更改为将stream 传递给speaker.write 而不是leftchannel(可能应该重命名为meta,或丢弃如果您不需要它),它可能会起作用。

请注意,由于Float32Array 不是流或缓冲区对象,BinaryJS 可能会try to send it in one chunk。您可能想改为发送leftChannel.buffer (the ArrayBuffer behind that object)。

让我知道这是否适合您;我现在无法测试您的确切设置。

【讨论】:

我确实对 websocket API 有问题。我用正确的用法更新了我的答案。这是错误的一部分,我发现了与音频缓冲区有关的另一部分。既然你帮助解决了部分问题,我会奖励你。

以上是关于在 Node.js 上从 Web Audio API 播放 PCM 流的主要内容,如果未能解决你的问题,请参考以下文章

在 python 服务器上从 Fabric.js JSON 构造图像

将音频从 Node.js 服务器流式传输到 HTML5 <audio> 标签

将数据从 iPhone 应用程序发送到 Node.js Web 服务器

Node.js 错误:连接 ECONNREFUSED

从 node.js 将图像上传到 s3 存储桶

在 iPhone 上从线性 PCM 中提取幅度数据