D++ (DPP)
C++ Discord API Bot Library
Streaming MP3 files

To stream MP3 files via D++ you need to link an additional dependency to your bot, namely libmpg123. It is relatively simple when linking this library to your bot to then decode audio to PCM and send it to the dpp::discord_voice_client::send_audio_raw function as shown below:

#include <dpp/dpp.h>
#include <dpp/nlohmann/json.hpp>
#include <fmt/format.h>
#include <iomanip>
#include <sstream>
#include <vector>
#include <fstream>
#include <iostream>
#include <mpg123.h>
#include <out123.h>
/* For an example we will hardcode a path to some awesome music here */
#define MUSIC_FILE "/media/music/Rick Astley/Whenever You Need Somebody/Never Gonna Give You Up.mp3"
int main(int argc, char const *argv[])
{
/* This will hold the decoded MP3.
* The D++ library expects PCM format, which are raw sound
* data, 2 channel stereo, 16 bit signed 48000Hz.
*/
std::vector<uint8_t> pcmdata;
mpg123_init();
int err = 0;
unsigned char* buffer;
size_t buffer_size, done;
int channels, encoding;
long rate;
/* Note it is important to force the frequency to 48000 for Discord compatibility */
mpg123_handle *mh = mpg123_new(NULL, &err);
mpg123_param(mh, MPG123_FORCE_RATE, 48000, 48000.0);
/* Decode entire file into a vector. You could do this on the fly, but if you do that
* you may get timing issues if your CPU is busy at the time and you are streaming to
* a lot of channels/guilds.
*/
buffer_size = mpg123_outblock(mh);
buffer = new unsigned char[buffer_size];
/* Note: In a real world bot, this should have some error logging */
mpg123_open(mh, MUSIC_FILE);
mpg123_getformat(mh, &rate, &channels, &encoding);
unsigned int counter = 0;
for (int totalBytes = 0; mpg123_read(mh, buffer, buffer_size, &done) == MPG123_OK; ) {
for (auto i = 0; i < buffer_size; i++) {
pcmdata.push_back(buffer[i]);
}
counter += buffer_size;
totalBytes += done;
}
delete buffer;
mpg123_close(mh);
mpg123_delete(mh);
/* Setup the bot */
/* Use the on_message_create event to look for commands */
bot.on_message_create([&bot, &pcmdata](const dpp::message_create_t & event) {
std::stringstream ss(event.msg.content);
std::string command;
ss >> command;
/* Tell the bot to join the discord voice channel the user is on. Syntax: .join */
if (command == ".join") {
if (!g->connect_member_voice(event.msg.author.id)) {
bot.message_create(dpp::message(event.msg.channel_id, "You don't seem to be on a voice channel! :("));
}
}
/* Tell the bot to play the mp3 file. Syntax: .mp3 */
if (command == ".mp3") {
dpp::voiceconn* v = event.from->get_voice(event.msg.guild_id);
if (v && v->voiceclient && v->voiceclient->is_ready()) {
/* Stream the already decoded MP3 file. This passes the PCM data to the library to be encoded to OPUS */
v->voiceclient->send_audio_raw((uint16_t*)pcmdata.data(), pcmdata.size());
}
}
});
/* Start bot */
bot.start(dpp::st_wait);
/* Clean up */
mpg123_exit();
return 0;
}
The cluster class represents a group of shards and a command queue for sending and receiving commands...
Definition: cluster.h:271
discord_voice_client & send_audio_raw(uint16_t *audio_data, const size_t length)
Send raw audio to the voice channel.
bool is_ready()
voice client is ready to stream audio. The voice client is considered ready if it has a secret key.
Represents a guild on Discord (AKA a server)
Definition: guild.h:395
bool connect_member_voice(snowflake user_id, bool self_mute=false, bool self_deaf=false)
Connect to a voice channel another guild member is in.
snowflake id
Unique ID of object set by Discord. This value contains a timestamp, worker ID, internal server ID,...
Definition: managed.h:38
Represents a connection to a voice channel. A client can only connect to one voice channel per guild ...
Definition: discordclient.h:58
class discord_voice_client * voiceclient
voice websocket client
Definition: discordclient.h:87
std::function< void(const dpp::log_t &)> DPP_EXPORT cout_logger()
Get a default logger that outputs to std::cout. e.g.
@ i_message_content
Intent for receipt of message content.
Definition: intents.h:64
@ i_default_intents
Default D++ intents (all non-privileged intents)
Definition: intents.h:72
DPP_EXPORT class guild * find_guild(snowflake id)
@ st_wait
Wait forever on a condition variable. The cluster will spawn threads for each shard and start() will ...
Definition: cluster.h:254
Create message.
Definition: dispatcher.h:1354
message msg
message that was created (sent).
Definition: dispatcher.h:1363
Represents messages sent and received on Discord.
Definition: message.h:1103
user author
Definition: message.h:1109
snowflake guild_id
Definition: message.h:1107
std::string content
Definition: message.h:1113
snowflake channel_id
Definition: message.h:1105

To compile this program you must remember to specify libmpg123 alongside libdpp in the build command, for example:

g++ -std=c++17 -o musictest musictest.cpp -lmpg123 -ldpp

D++ Library version 10.0.16D++ Library version 10.0.15D++ Library version 10.0.14D++ Library version 10.0.13D++ Library version 10.0.12D++ Library version 10.0.11D++ Library version 10.0.10D++ Library version 10.0.9D++ Library version 10.0.8D++ Library version 10.0.7D++ Library version 10.0.6D++ Library version 10.0.5D++ Library version 10.0.4D++ Library version 10.0.3D++ Library version 10.0.2D++ Library version 10.0.1D++ Library version 10.0.0D++ Library version 9.0.19D++ Library version 9.0.18D++ Library version 9.0.17D++ Library version 9.0.16D++ Library version 9.0.15D++ Library version 9.0.14D++ Library version 9.0.13D++ Library version 9.0.12D++ Library version 9.0.11D++ Library version 9.0.10D++ Library version 9.0.9D++ Library version 9.0.8D++ Library version 9.0.7D++ Library version 9.0.6D++ Library version 9.0.5D++ Library version 9.0.4D++ Library version 9.0.3D++ Library version 9.0.2D++ Library version 9.0.1D++ Library version 9.0.0D++ Library version 1.0.2D++ Library version 1.0.1D++ Library version 1.0.0