D++ (DPP)  10.0.30
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 <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() {
/* 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 (size_t 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 */
dpp::cluster bot("token");
/* The event is fired when someone issues your commands */
bot.on_slashcommand([&bot, &pcmdata](const dpp::slashcommand_t& event) {
/* Check which command they ran */
if (event.command.get_command_name() == "join") {
/* Get the guild */
dpp::guild* g = dpp::find_guild(event.command.guild_id);
/* Attempt to connect to a voice channel, returns false if we fail to connect. */
if (!g->connect_member_voice(event.command.get_issuing_user().id)) {
event.reply("You don't seem to be in a voice channel!");
return;
}
/* Tell the user we joined their channel. */
event.reply("Joined your channel!");
} else if (event.command.get_command_name() == "mp3") {
/* Get the voice channel the bot is in, in this current guild. */
dpp::voiceconn* v = event.from->get_voice(event.command.guild_id);
/* If the voice channel was invalid, or there is an issue with it, then tell the user. */
if (!v || !v->voiceclient || !v->voiceclient->is_ready()) {
event.reply("There was an issue with getting the voice channel. Make sure I'm in a voice channel!");
return;
}
/* 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());
event.reply("Played the mp3 file.");
}
});
bot.on_ready([&bot](const dpp::ready_t & event) {
if (dpp::run_once<struct register_bot_commands>()) {
/* Create a new command. */
dpp::slashcommand joincommand("join", "Joins your voice channel.", bot.me.id);
dpp::slashcommand mp3command("mp3", "Plays an mp3 file.", bot.me.id);
bot.global_bulk_command_create({ joincommand, mp3command });
}
});
/* Start bot */
bot.start(dpp::st_wait);
/* Clean up */
mpg123_exit();
return 0;
}

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

Note
Compiling your bot with a raw `g++` command is not advised in any real project, and the example above should be used only as a test. From here, you should learn to create a bot in D++ by moving on to Building a Discord Bot Using CMake (UNIX) or if you have not yet created a token for your bot, Creating a Bot Token - If you are having trouble setting up CMake, you can try our template cmake bot project.

dpp::slashcommand_t
User has issued a slash command.
Definition: dispatcher.h:715
dpp.h
dpp::st_wait
@ st_wait
Wait forever on a condition variable.
Definition: cluster.h:101
dpp::unicode_emoji::v
constexpr const char v[]
Definition: unicode_emoji.h:1982
dpp::detail::async::state_t::done
@ done
Request was completed.
main
int main()
Definition: soak.cpp:28
dpp::interaction_create_t::command
interaction command
command interaction
Definition: dispatcher.h:698
dpp::utility::cout_logger
std::function< void(const dpp::log_t &)> DPP_EXPORT cout_logger()
Get a default logger that outputs to std::cout.
Definition: dispatcher.h:228
dpp::slashcommand
Represents an application command, created by your bot either globally, or on a guild.
Definition: appcommand.h:1358
dpp::interaction::get_command_name
std::string get_command_name() const
Get the command name for a command interaction.
Definition: slashcommand.cpp:487
dpp::interaction_create_t::reply
void reply(command_completion_event_t callback=utility::log_error()) const
Acknowledge interaction without displaying a message to the user, for use with button and select menu...
Definition: dispatcher.cpp:152
dpp::cluster
The cluster class represents a group of shards and a command queue for sending and receiving commands...
Definition: cluster.h:99
dpp::ready_t
Session ready.
Definition: dispatcher.h:981