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

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

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

Я пробовал Wavefile

Вот как я закодировал ответ от @google-cloud/text-to-speech

 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/ преобразования текста в речь, сохранив его в файле, и он был правильным и понятным.

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

2 ответа

У меня тоже была такая же проблема. Ошибка в 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');

У меня была такая же проблема. Решение состоит в том, что вам необходимо вручную преобразовать 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 & 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.

Другие вопросы по тегам