twilioaudio-streamingnodejs-streamtwilio-programmable-voice

Is there any way to save mulaw audio stream from twilio in a file


I am using Twilio voice stream feature and i don't want to use Twilio record functionality. When Twilio starts sending voice stream to my server i want to store it into disk as an audio file in realtime.


Solution

  • I was running into the same issue today and figured a way to generate a WAVE Header for the mu-law header:

    If you're following Twilio's blog post, that's the code I ended implementing:

        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;
            }
          });
        });