node.js - 将音频文件转换为 16 位线性 PCM

标签 node.js audio websocket nexmo

我试图通过 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
    });
});

一些背景,流是一个电话(通过vonage api)所以ny ws连接到电话并听到用户输入,然后在我的服务器上进行一些逻辑之后我想向用户播放一个本地文件的mp3文件在我的服务器中,通过 ws.send()。
- - - - - -更新 - - - -
现在,如果我从流中发送 pcm 数据(来自电话的原始音频)
它的工作原理(服务器响应电话)
所以我想将 mp3 文件转换为相同的格式,以便我可以通过 ws.send() 将其发送到。
-----------更新2--------
在以正确的格式制作我的音频文件后:
“16 位线性 PCM,具有 8kHz 或 16kHz 采样率,以及 20 毫秒的帧大小”
我正在尝试通过网络套接字发送文件,但我不知道该怎么做,
我在项目文件夹中有该文件,但我不知道如何通过 websocket 发送它,我寻找了如何发送,但我没有找到任何东西。
我正在尝试执行此处指定的操作:
enter image description here

最佳答案

首先让我们明白这是什么意思:

Linear PCM 16-bit, with either a 8kHz or a 16kHz sample rate, and a 20ms frame size


他们在这里谈论两件事:
  • 音频数据的格式,即“线性 PCM 16 位,具有 8kHz 或 16kHz 采样率”
  • 您如何将此音频数据发送给他们以及他们如何将其发送给您:以值(value) 20 毫秒帧的音频数据块形式

  • 根据音频格式,如果选择“采样率为 16K 的 16 位线性 PCM”意味着:
  • 采样率 = 16000
  • 样本宽度 = 16 位 = 2 字节

  • 所以 1 秒的音频块将包含字节 = (16000 * 2) = 32000 字节
    这意味着 20 毫秒/0.02 秒的音频帧将等价于 (32000*0.2) = 640 字节
    有两件事需要:
  • 将 mp3 转换为 wav。在您的系统上安装 ffmpeg 并运行此命令ffmpeg -i filename.mp3 -ar 16000 -sample_fmt s16 output.wav这会转换您的 filename.mp3output.wav这将是 16K 采样率的 16 位线性 PCM
  • 在您的代码中,当您发回音频时,您需要 将其作为 640 字节的块流式传输,而不是一次性传输整个文件数据 .有3个选项:
  • 运行一个循环将所有音频写入 websocket,但以 640 字节为单位。
    但这有一个问题,Nexmo 只会缓冲前 20 秒的音频。超出此范围的任何内容都将被丢弃
  • 启动一个每 20 毫秒运行一次的异步任务,并将 640 字节的数据写入 websocket。
  • 当你从 nexmo 获得音频时写(这是我将展示的)
    由于 nexmo 每 20 毫秒会向您发送 640 个字节,因此您可以同时发送回 640 个字节。


  • 我正在使用 npm websocket 编写此示例包裹。
    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');
        } 
      } ...
      
    });
    
    请记住,从您将音频从您的服务器发送到 nexmo 和您在另一侧听到的那一刻,会有一些延迟。
    根据 Nexmo 数据中心的位置、运行代码的服务器的位置、网络速度等,它可以从半秒到更长的时间变化。
    我观察到它接近 0.5 秒。

    关于node.js - 将音频文件转换为 16 位线性 PCM,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66885964/

    相关文章:

    android - 如何检测 AAC 音频配置文件并确保 Android 兼容性

    apache - 为从浏览器到 apache http 服务器到 Web 服务的 Web 套接字调用创建了多少 TCP 连接总数

    ios - 使用套接字推送 iOS Web 应用程序的通知?

    node.js - 在elasticbeanstalk上安装npm canvas - npm安装错误

    node.js - 将 req.user 传递给 graphQL

    JavaScript play() 函数在 Chrome 中不起作用

    java - tomcat7 spring boot 应用程序中的 websockets

    javascript - 从客户端下载AWS S3文件

    javascript - 错误: Corrupted zip : can't find end of central directory - XLSX

    javascript - 使用howler.js或其他库环绕3d音效?