将LINEAR16音频编码为Twilio媒体音频/ x-mulaw |节点JS

问题描述

我一直试图将mulaw媒体流流回Twilio。要求有效载荷必须是音频/ x-mulaw编码的,采样率为8000,base64编码

我的输入来自LINEAR16 Google Docs

中的@ google-cloud / text-to-speech

我尝试了Wavefile

这是我编码来自@ google-cloud / text-to-speech的回复的方式

 const wav = new wavefile.WaveFile(speechResponse.audioContent)
    wav.toBitDepth('8')
    wav.toSampleRate(8000)
    wav.toMuLaw()

然后我将结果通过websocket发送回twilio

twilioWebsocket.send(JSON.stringify({
      event: 'media',media: {
        payload: wav.toBase64(),},streamSid: Meta.streamSid,}))

问题是我们仅在twilio调用的另一端出现随机噪声,似乎编码不正确

第二,我通过保存在文件中来检查@ google-cloud / text-to-speech输出音频,它是正确且清晰的

有人可以帮我编码吗

解决方法

我只是遇到了同样的问题。解决方案是,您需要将LINEAR16手动转换为相应的MULAW编解码器。

您可以使用a music libary中的代码。

我由此创建了一个函数,用于将linear16字节数组转换为mulaw:

short2ulaw(b: Buffer): Buffer {
    // Linear16 to linear8 -> buffer is half the size
    // As of LINEAR16 nature,the length should ALWAYS be even
    const returnbuffer = Buffer.alloc(b.length / 2)

    for (let i = 0; i < b.length / 2; i++) {
      // The nature of javascript forbids us to use 16-bit types. Every number is
      // A double precision 64 Bit number.
      let short = b.readInt16LE(i * 2)

      let sign = 0

      // Determine the sign of the 16-Bit byte
      if (short < 0) {
        sign = 0x80
        short = short & 0xef
      }

      short = short > 32635 ? 32635 : short

      const sample = short + 0x84
      const exponent = this.exp_lut[sample >> 8] & 0x7f
      const mantissa = (sample >> (exponent + 3)) & 0x0f
      let ulawbyte = ~(sign | (exponent << 4) | mantissa) & 0x7f

      ulawbyte = ulawbyte == 0 ? 0x02 : ulawbyte

      returnbuffer.writeUInt8(ulawbyte,i)
    }

    return returnbuffer
  }

现在,您可以在Raw PCM(Linear16)上使用它。现在,您只需要考虑在Google流的开头删除字节,因为Google添加了wav标头。 然后,您可以对生成的base64缓冲区进行编码,并将其发送到twilio。

,

我也有同样的问题。错误出现在wav.toBase64()中,因为其中包括wav标头。 Twilio媒体流需要原始音频数据,您可以通过wav.data.samples获得该数据,因此您的代码应为:

 const wav = new wavefile.WaveFile(speechResponse.audioContent)
    wav.toBitDepth('8')
    wav.toSampleRate(8000)
    wav.toMuLaw()

 const payload = Buffer.from(wav.data.samples).toString('base64');