Handling Audio
This library uses Node Streams
to handle playing and recieving audio. It's simple.
Warning: Encoder
You need ffmpeg or avconv in order to do any audio encoding. Make sure it's installed and added to your system's PATH. This does not apply to just joining the voice channel and capturing speaking events (on Node or the Browser).
- Join a Voice Channel with
joinVoiceChannel()
- Get the context for that Voice Channel with
getAudioContext()
pipe()
/write()
data to, orpipe()
/read()
data from, thestream
argument.
Let's assume
//Node's internal fs module
var fs = require('fs');
var voiceChannelID = "66192955798458368";
var izy = "66186356581208064";
Playing audio
The simplest way to get started is:
//Let's join the voice channel, the ID is whatever your voice channel's ID is.
client.joinVoiceChannel(voiceChannelID, function(error, events) {
//Check to see if any errors happen while joining.
if (error) return console.error(error);
//Then get the audio context
client.getAudioContext(voiceChannelID, function(error, stream) {
//Once again, check to see if any errors exist
if (error) return console.error(error);
//Create a stream to your file and pipe it to the stream
//Without {end: false}, it would close up the stream, so make sure to include that.
fs.createReadStream('myFile.mp3').pipe(stream, {end: false});
//The stream fires `done` when it's got nothing else to send to Discord.
stream.on('done', function() {
//Handle
});
});
});
While that should be enough for anyone to just play an audio file, some users may have more advanced needs like receiving audio, or capturing speaking packets. The lib can handle both of those easily.
Capturing speaking events
client.joinVoiceChannel(voiceChannelID, function(error, events) {
if (error) return console.error(error);
//This can be done on both Node and the Browser using the same code
events.on('speaking', function(userID, SSRC, speakingBool) {
//This will log either "[userID] is speaking" or "[userID] is done speaking"
console.log("%s is %s", userID, (speakingBool ? "speaking" : "done speaking") );
});
});
Receiving audio
Audio received back to you is decoded from Opus to S16LE PCM (in the back-end). Unless getAudioContext()
is called with a certain option, there is no decoding or storing done (for performance reasons), so you have to specify.
In order to activate receiving, we have to turn the first argument into an Object then include the maxStreamSize
key. The value for this key will be how many kilobytes of audio data that you want the library to keep before pushing the earliest data out. FIFO (First In First Out).
client.joinVoiceChannel(voiceChannelID, function(error, events) {
if (error) return console.error(error);
//Let's use a maxStreamSize of 50MiB
client.getAudioContext({channelID: voiceChannelID, maxStreamSize: 50 * 1024}, function(error, stream) {
//You can access a Member's stream
//Members are Readable Streams
if (stream.members[izy]) {
//Will give you all of the PCM data saved for this user.
stream.members[izy].read();
}
//The stream variable is also a Stream, a Duplex.
//You can use Stream methods on it. It contains
//the last 50MiB (maxStreamSize) of mixed audio
//data (from everyone speaking).
stream.pipe(fs.createWriteStream('./everyone.wav'));
//Any time any new audio is recieved
//'incoming' will be emitted with the
//decoded audio buffer, if you'd rather
//use this method
stream.on('incoming', function(SSRC, buffer) {});
});
});
getAudioContext
getAudioContext()
is a method that gets a stateful audio instance of a voice session in the back-end. You can call it as many times as you want, the stream
variable will be equivalent to accessing client._vChannels[voiceChannelID].audio
, if it exists. This means if you intend to receive audio, but have already instanced an audio context without maxStreamSize
, you have to leave the audio channel and re-join, then use getAudioConext()
with maxStreamSize
.