Can you help me convert Twilio mu-law 8Hz audio format into a playable format for real-time use in Discord.js? I'm trying to create a Discord bot that can stream audio received from a Twilio call, but I'm having trouble with the format conversion. Any suggestions on how I can achieve this?
const { WebSocketServer } = require("ws");
const base64 = require("base64-js");
const Discord = require("discord.js");
const client = new Discord.Client();
const { VoiceConnectionStatus, Events } = require("@discordjs/voice");
const { getVoiceConnection, createAudioResource, createAudioPlayer, NoSubscriberBehavior, joinVoiceChannel, StreamType, createDefaultAudioReceiveStreamOptions } = require("@discordjs/voice");
const { createReadStream } = require("node:fs");
const { Readable } = require("stream");
const WaveFile = require("wavefile").WaveFile;
const { OpusEncoder } = require("@discordjs/opus");
const wss = new WebSocketServer({ port: 5000 });
wss.on("connection", (ws) => {
console.log("Connection accepted");
ws.on("message", (message) => {
const msg = JSON.parse(message);
switch (msg.event) {
case "connected":
console.log("A new call has connected");
break;
case "start":
console.log(`Starting media stream...`, msg);
break;
case "media":
console.log("Receiving audio...");
const payload = Buffer.from(msg.media.payload, "base64");
// CONVERT THE MU-LAW 8KHZ 1 CHANNEL PAYLOAD INTO SOMETHING PLAYABLE BY DISCORD ???
const resource = createAudioResource(createReadStream(payload), {
inputType: StreamType.Raw
});
player.play(resource);
connection.subscribe(player);
case "stop":
console.log("Call has ended");
break;
default:
break;
}
});
ws.on("close", () => {
console.log(`Connection closed.`);
});
});
I have tried to convert the payload in PCM, and then in opus but without success because the @discord/opus lib return "Error: Cannot create a Buffer larger than 0x100000000 bytes". Someone explained here : https://github.com/discordjs/opus/issues/51 what i should do to prevent this problem but i am unable to apply that.
This is what i tried to do :
const wav = new WaveFile();
wav.fromScratch(1, 8000, '16', payload);
wav.fromMuLaw();
const pcmBuffer = wav.toBuffer();
const paddingBytes = Math.ceil(pcmBuffer.length / 160) * 160 - pcmBuffer.length;
if (paddingBytes > 0) {
const paddingBuffer = Buffer.alloc(paddingBytes);
pcmBuffer = Buffer.concat([pcmBuffer, paddingBuffer]);
}
// Create the encoder.
// Specify 16kHz sampling rate and 2 channel size.
const encoder = new OpusEncoder(8000, 1);
// Encode and decode.
const encoded = encoder.encode(pcmBuffer);