1

我正在使用 Twilio 语音流功能,我不想使用 Twilio 记录功能。当 Twilio 开始向我的服务器发送语音流时,我想将其作为音频文件实时存储到磁盘中。

4

3 回答 3

7

我今天遇到了同样的问题,并想出了一种为 mu-law 标头生成 WAVE 标头的方法:

如果您正在关注Twilio 的博客文章,那么这就是我最终实现的代码:

wss.on('connection', (socket) => {
  socket.on('message', (msg) => {
    const { event, ...message } = JSON.parse(msg);
    switch (event) {
      case 'start':
        let streamSid = message.start.streamSid;
        socket.wstream = fs.createWriteStream(__dirname + `/${Date.now()}.wav`, { encoding: 'binary' });
        // This is a mu-law header for a WAV-file compatible with twilio format
        socket.wstream.write(Buffer.from([
          0x52,0x49,0x46,0x46,0x62,0xb8,0x00,0x00,0x57,0x41,0x56,0x45,0x66,0x6d,0x74,0x20,
          0x12,0x00,0x00,0x00,0x07,0x00,0x01,0x00,0x40,0x1f,0x00,0x00,0x80,0x3e,0x00,0x00,
          0x02,0x00,0x04,0x00,0x00,0x00,0x66,0x61,0x63,0x74,0x04,0x00,0x00,0x00,0xc5,0x5b,
          0x00,0x00,0x64,0x61,0x74,0x61,0x00,0x00,0x00,0x00, // Those last 4 bytes are the data length
        ]));
        break;
      case 'media':
        // decode the base64-encoded data and write to stream
        socket.wstream.write(Buffer.from(message.media.payload, 'base64'));
        break;
      case 'stop':
        // Now the only thing missing is to write the number of data bytes in the header
        socket.wstream.write("", () => {
          let fd = fs.openSync(socket.wstream.path, 'r+'); // `r+` mode is needed in order to write to arbitrary position
          let count = socket.wstream.bytesWritten;
          count -= 58; // The header itself is 58 bytes long and we only want the data byte length
          console.log(count)
          fs.writeSync(
            fd,
            Buffer.from([
              count % 256,
              (count >> 8) % 256,
              (count >> 16) % 256,
              (count >> 24) % 256,
            ]),
            0,
            4, // Write 4 bytes
            54, // starts writing at byte 54 in the file
          );
        });
        break;
    }
  });
});
于 2019-11-20T16:52:13.323 回答
1

您可以使用FFmpeg将 Twilio mulaw 转换为常规 WAV 文件。
如果您使用下面的类,那么您只需要在 Twilio 流缓冲区到达时发送它们。

就像是:

recording = StreamAudioRecording(tempDirectory)
recording.start_recording(call_id)

<loop over buffer packets arriving>
    recording.write_buffer(buffer)

recording_audio_path = recording.stop_recording()

这是类的实现

import os

RAW_AUDIO_FILE_EXTENSION = "ulaw"
CONVERTED_AUDIO_FILE_EXTENSION = "wav"


class StreamAudioRecording:
    def __init__(self, audio_recording_path):
        self.audio_recording_path = audio_recording_path
        self.f = None
        self.audio_file_path = None

    def start_recording(self, call_id):
         self.audio_file_path = os.path.join(self.audio_recording_path, f" . 
               {call_id}.{RAW_AUDIO_FILE_EXTENSION}")
         self.f = open(self.audio_file_path, 'wb')

    def write_buffer(self, buffer):
        self.f.write(buffer)

    def stop_recording(self):
        self.f.close()
        converted_audio_path = 
            self.audio_file_path.replace(RAW_AUDIO_FILE_EXTENSION,
                                         CONVERTED_AUDIO_FILE_EXTENSION)
        self.convert_call_recording(self.audio_file_path, converted_audio_path)

        return converted_audio_path

    @staticmethod
    def convert_call_recording(mulaw_path, wav_path):
        command = f"ffmpeg -y -loglevel panic -f mulaw -ar 8k -ac 1 -i {mulaw_path} {wav_path}"
        os.system(command)
于 2019-12-26T17:36:47.707 回答
0

如果您使用 Node.js,@tdeo 提供的解决方案效果很好。我受到启发,并使用此解决方案制作了一个简单的库。它现在可以在 npm 上使用。

https://www.npmjs.com/package/twilio-media-stream-save-audio-file

于 2021-04-05T06:14:13.490 回答