将音频文件转换为线性 PCM 16 位

dav*_*dla 5 audio websocket node.js vonage

我正在尝试通过 websocket 发送音频文件,我意识到为了做到这一点,我需要将 mp3 文件转换为线性 PCM 16 位代码,但我找不到方法来做到这一点。

这就是我想做的:

 let mp3File = // the 16-bit pcm file 

    ws.on('message', async(msg) => {
        if (typeof msg === "string") {

        } else if (recognizeStream) {
            recognizeStream.write(msg);
        }
        ws.send(mp3File) <== stream back the audio file
    });
});

Run Code Online (Sandbox Code Playgroud)

一些背景,流是一个电话呼叫(通过 vonage api),所以 ny ws 连接到电话呼叫并听到用户输入,然后在我的服务器上的一些逻辑之后我想向用户播放一个本地文件的 mp3 文件在我的服务器中,通过 ws.send()。

- - - - - -更新 - - - -

现在,如果我从流中发送 pcm 数据(来自电话呼叫的原始音频),它的工作原理(服务器回显电话呼叫),所以我想将 mp3 文件转换为相同的格式,以便我可以通过 ws 发送它。发送()。

------------更新2--------

以正确的格式制作音频文件后,该格式为:“线性 PCM 16 位,具有 8kHz 或 16kHz 采样率,以及 20ms 帧大小”

我正在尝试通过网络套接字发送文件,但我不知道该怎么做,我在项目文件夹中有该文件,但我不知道如何通过 websocket 发送它,我寻找如何做到这一点,但我没有找到任何事物。

我正在尝试执行此处指定的操作: 在此输入图像描述

lea*_*rav 6

首先我们来了解一下这意味着什么:

线性 PCM 16 位,采样率为 8kHz 或 16kHz,帧大小为 20ms

他们在这里谈论两件事:

  1. 音频数据的格式,为“线性 PCM 16 位,采样率为 8kHz 或 16kHz”
  2. 您如何将此音频数据发送给他们以及他们如何将其发送给您:以价值 20 毫秒帧的音频数据块的形式

根据音频格式,如果选择“16bit Linear PCM with Sample Rate of 16K”意味着:

  • 采样率 = 16000
  • 样本宽度 = 16 位 = 2 字节

因此,1 秒的音频块将包含字节 = (16000 * 2) = 32000 字节,这意味着 20ms/0.02s 的音频帧将相当于 (32000*0.2) = 640 字节

需要做两件事:

  1. 将 mp3 转换为 wav。在您的系统上安装 ffmpeg 并运行此命令
    ffmpeg -i filename.mp3 -ar 16000 -sample_fmt s16 output.wav
    这会将您的文件转换filename.mp3output.wav16K 采样率的线性 PCM 16 位

  2. 在您的代码中,当您发回音频时,您需要将其作为 640 字节的块进行流式传输,而不是一次性传输整个文件数据。有 3 个选项:

    • 运行一个循环将所有音频写入 websocket,但以 640 字节为单位。但这有一个问题,Nexmo 只会缓冲前 20 秒的音频。超过此数量的任何内容都将被丢弃
    • 启动一个每 20 毫秒运行一次的异步任务,并向 websocket 写入 640 字节的数据。
    • 当您从 nexmo 获取音频时写入(这是我将展示的)由于 nexmo 将每 20 毫秒向您发送 640 字节,因此您可以同时发回 640 字节。

我正在使用 npmwebsocket包编写这个示例。

var fs = require('fs');
var binaryData = fs.readFileSync('output.wav');
var start = 44 // discard the wav header
var chunkSize = 640

...

// ws is a websocket connection object
connection.on('message', function(message) {
  if (message.type === 'utf8') {
    // handle a text message here
  }
  else if (message.type === 'binary') {
    // print length  of audio sent by nexmo. will be 640 for 16K and 320 for 8K 
    console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');

    if (start >= binaryData.length) {
      // slice a chunk and send
      toSend = binaryData.slice(start, start + chunkSize)
      start = start + chunkSize
      connection.sendBytes(toSend); 
      console.log('Sent Binary Message of ' + toSend.length + ' bytes');
    } 
  } ...
  
});
Run Code Online (Sandbox Code Playgroud)

请记住,从您将音频从服务器发送到 nexmo 到您在另一端听到,会有一些延迟。它可能从半秒到更长不等,具体取决于 Nexmo 数据中心的位置、运行代码的服务器的位置、网络速度等。我观察到它接近 0.5 秒。