Кодирование аудио LINEAR16 в Twilio media audio / x-mulaw | NodeJS

#node.js #twilio #google-text-to-speech #mu-law

#node.js #twilio #google-преобразование текста в речь #mu-law

Вопрос:

Я пытался передать мультимедийный поток mulaw обратно в Twilio. Требование — полезная нагрузка должна быть закодирована в аудио / x-mulaw с частотой дискретизации 8000 и кодироваться на base64

Мой вклад взят из @google-cloud / преобразование текста в речь в LINEAR16 Google Docs

Я попробовал Wavefile

Вот как я закодировал ответ от @google-cloud / преобразование текста в речь

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

Затем я отправляю результат обратно в Twilio через WebSocket

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

Проблема в том, что мы слышим только случайный шум на других концах вызова Twilio, похоже, что кодирование неправильное

Во-вторых, я проверил аудио вывода @google-cloud / text-to-speech, сохранив его в файле, и он был правильным и понятным

Может кто-нибудь, пожалуйста, помочь мне с кодировкой

Ответ №1:

У меня тоже была такая же проблема. Ошибка wav.toBase64() , так как это включает заголовок wav. Twilio media streams ожидает необработанные аудиоданные, которые вы можете получить 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');
  

Ответ №2:

У меня только что была такая же проблема. Решение заключается в том, что вам нужно вручную преобразовать LINEAR16 в соответствующий кодек MULAW.

Вы можете использовать код из музыкальной библиотеки.

Я создал функцию из этого, чтобы преобразовать линейный 16-байтовый массив в 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 amp; 0xef
      }

      short = short > 32635 ? 32635 : short

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

      ulawbyte = ulawbyte == 0 ? 0x02 : ulawbyte

      returnbuffer.writeUInt8(ulawbyte, i)
    }

    return returnbuffer
  }
  

Теперь вы можете использовать это на необработанном PCM (Linear16). Теперь вам просто нужно подумать о том, чтобы удалить байты в начале потока Google, поскольку Google добавляет заголовок wav.
Затем вы можете закодировать полученный буфер base64 и отправить его в twilio.