I want to record a entire conversation from Discord.JS v12. But, I'm don't really good in audio manipulation and other things like that. I've this code :
const c = message.member.voice?.channel;
if(!c) {
// The user is not in voice channel
return message.channel.send("");
}
switch(args?.[0]?.toLowerCase()){
case 'on':
if(this.vocals.find(r => r.c === c.id && r.u === message.author.id)){
// The user have already an record launched
return message.channel.send("Vous avez déjà un enregistrement de démarré.");
}
const flux = await c.join();
const receiver = flux.receiver;
const audioChunk = this.createNewChunk((message.member.nickname || message.author.username).replace(/[^A-Za-z0-9]/g, ''));
this.vocals.push({
c: c.id,
u: message.author.id,
s: Date.now(),
r: audioChunk
});
flux.on('speaking', (user, speaking) => {
if (speaking) {
const audioStream = receiver.createStream(user, { mode: 'pcm' });
audioStream.on('data', (chunk) => audioChunk.write(chunk));
}
});
return message.channel.send("L'enregistrement a bien été lancé avec succès !")
break;
case 'off':
let f = this.vocals.find(r => r.c === c.id);
const channel = this.bot.channels.cache.get(f.c);
const members = channel.members.array();
f = this.vocals.find(r => r.c === c.id &&
(members.find(r => r.user.id === message.author.id) &&
r.u === message.author.id));
if(!f){
// The user doesnt have any record
return message.channel.send("Vous n'avez aucun enregistrement de démarré.");
}
console.log(f);
f.r.close();
return message.channel.send("L'enregistrement s'est bien terminé avec succès !", )
break;
default:
// const embed = ...
return message.channel.send(
this.help.usage.replace(/{prefix}/g, this.bot.config.prefix)
)
break;
}
And the createNewChunk function :
createNewChunk(name) {
return new wav.FileWriter(`./records/record-${name}.wav`);
}
But, when the users stop speaking in the channel, the record is stopped. Do you know how I can avoid this ?
Thanks you.
Okay, so It's really simple to do.
You have to create a audio chunck with Buffer. Then, detect when nobody is speaking. And you can push every 20ms your Buffer into the Stream.
const { Buffer } = require('buffer');
const emptyBuffer = Buffer.alloc(3840, 0); // You create a Buffer with a length of 3840, and a value to 0 (no sound).
Then, you have to put all your users into an array :
const users = [];
flux.on('speaking', (user, speaking) => {
if (speaking) {
users.push(user.id);
const audioStream = receiver.createStream(user, { mode: 'pcm' });
audioStream.on('end', () => {
users.splice(users.findIndex(r => r == user.id), 1); // Remove the users of users speaking array.
});
}
});
And THEN, you can add your buffer with no sound :
var emptyInterval = setInterval(() => {
if(users.length < 1){
audioChunk.write(emptyBuffer);
}
}, 20)
For stop the stream, stop clear the interval of emptyInterval and stop your event flux.on('speaking').
Works for nodejs v16 and more. I dont know if for nodejs v14 or lower it work.