* Add internal support for @discordjs/opus * Remove redundant try/catch * fix: use setBitrate method in @discordjs/opus * chore: tidy up opus imports * fix: correct imports for DiscordJsOpusEngine * chore: update docs to prefer @discordjs/opus * chore: bump prism-media to 0.0.4 to allow ffmpeg-static
4.1 KiB
Introduction to Voice
Voice in discord.js can be used for many things, such as music bots, recording or relaying audio.
In discord.js, you can use voice by connecting to a VoiceChannel to obtain a VoiceConnection, where you can start streaming and receiving audio.
To get started, make sure you have:
- FFmpeg -
npm install ffmpeg-binaries - an opus encoder, choose one from below:
npm install opusscriptnpm install @discordjs/opus
- a good network connection
The preferred opus engine is @discordjs/opus, as it performs significantly better than opusscript. When both are available, discord.js will automatically choose @discordjs/opus. Using opusscript is only recommended for development environments where @discordjs/opus is tough to get working. For production bots, using @discordjs/opus should be considered a necessity, especially if they're going to be running on multiple servers.
Joining a voice channel
The example below reacts to a message and joins the sender's voice channel, catching any errors. This is important
as it allows us to obtain a VoiceConnection that we can start to stream audio with.
const Discord = require('discord.js');
const client = new Discord.Client();
client.login('token here');
client.on('message', message => {
// Voice only works in guilds, if the message does not come from a guild,
// we ignore it
if (!message.guild) return;
if (message.content === '/join') {
// Only try to join the sender's voice channel if they are in one themselves
if (message.member.voiceChannel) {
message.member.voiceChannel.join()
.then(connection => { // Connection is an instance of VoiceConnection
message.reply('I have successfully connected to the channel!');
})
.catch(console.log);
} else {
message.reply('You need to join a voice channel first!');
}
}
});
Streaming to a Voice Channel
In the previous example, we looked at how to join a voice channel in order to obtain a VoiceConnection. Now that we
have obtained a voice connection, we can start streaming audio to it. The following example shows how to stream an mp3
file:
Playing a file:
// To play a file, we need to give an absolute path to it
const dispatcher = connection.playFile('C:/Users/Discord/Desktop/myfile.mp3');
Your file doesn't have to be just an mp3; ffmpeg can convert videos and audios of many formats.
The dispatcher variable is an instance of a StreamDispatcher, which manages streaming a specific resource to a voice
channel. We can do many things with the dispatcher, such as finding out when the stream ends or changing the volume:
dispatcher.on('end', () => {
// The song has finished
});
dispatcher.on('error', e => {
// Catch any errors that may arise
console.log(e);
});
dispatcher.setVolume(0.5); // Set the volume to 50%
dispatcher.setVolume(1); // Set the volume back to 100%
console.log(dispatcher.time); // The time in milliseconds that the stream dispatcher has been playing for
dispatcher.pause(); // Pause the stream
dispatcher.resume(); // Carry on playing
dispatcher.end(); // End the dispatcher, emits 'end' event
If you have an existing ReadableStream, this can also be used:
Playing a ReadableStream:
connection.playStream(myReadableStream);
// If you don't want to use absolute paths, you can use
// fs.createReadStream to circumvent it
const fs = require('fs');
const stream = fs.createReadStream('./test.mp3');
connection.playStream(stream);
It's important to note that creating a readable stream to a file is less efficient than simply using connection.playFile().
Playing anything else:
For anything else, such as a URL to a file, you can use connection.playArbitraryInput(). You should consult the ffmpeg protocol documentation to see what you can use this for.
// Play an mp3 from a URL
connection.playArbitraryInput('http://mysite.com/sound.mp3');
Again, playing a file from a URL like this is more performant than creating a ReadableStream to the file.
Advanced Topics
soon™️