D++ (DPP)
C++ Discord API Bot Library
dpp::discord_voice_client Class Reference

Implements a discord voice connection. Each discord_voice_client connects to one voice channel and derives from a websocket client. More...

#include <discordvoiceclient.h>

+ Inheritance diagram for dpp::discord_voice_client:
+ Collaboration diagram for dpp::discord_voice_client:

Public Member Functions

virtual void log (dpp::loglevel severity, const std::string &msg) const
 
virtual void one_second_timer ()
 Fires every second from the underlying socket I/O loop, used for sending heartbeats. More...
 
bool is_ready ()
 voice client is ready to stream audio. The voice client is considered ready if it has a secret key. More...
 
bool is_connected ()
 Returns true if the voice client is connected to the websocket. More...
 
dpp::utility::uptime get_uptime ()
 Returns the connection time of the voice client. More...
 
 discord_voice_client (dpp::cluster *_cluster, snowflake _channel_id, snowflake _server_id, const std::string &_token, const std::string &_session_id, const std::string &_host)
 
virtual ~discord_voice_client ()
 
virtual bool handle_frame (const std::string &buffer)
 
virtual void error (uint32_t errorcode)
 
void run ()
 
discord_voice_clientsend_audio_raw (uint16_t *audio_data, const size_t length)
 Send raw audio to the voice channel. More...
 
discord_voice_clientsend_audio_opus (uint8_t *opus_packet, const size_t length, uint64_t duration)
 Send opus packets to the voice channel. More...
 
discord_voice_clientsend_audio_opus (uint8_t *opus_packet, const size_t length)
 Send opus packets to the voice channel. More...
 
discord_voice_clientsend_silence (const uint64_t duration)
 Send silence to the voice channel. More...
 
discord_voice_clientset_timescale (uint64_t new_timescale)
 Set the timescale in nanoseconds. More...
 
uint64_t get_timescale ()
 Get the current timescale, this will default to 1000000 which means 1 millisecond. More...
 
discord_voice_clientspeak ()
 Mark the voice connection as 'speaking'. This sends a JSON message to the voice websocket which tells discord that the user is speaking. The library automatically calls this for you whenever you send audio. More...
 
void pause_audio (bool pause)
 Pause sending of audio. More...
 
void stop_audio ()
 Immediately stop all audio. Clears the packet queue. More...
 
bool is_playing ()
 Returns true if we are playing audio. More...
 
float get_secs_remaining ()
 Get the number of seconds remaining of the audio output buffer. More...
 
uint32_t get_tracks_remaining ()
 Get the number of tracks remaining in the output buffer. This is calculated by the number of track markers plus one. More...
 
dpp::utility::uptime get_remaining ()
 Get the time remaining to send the audio output buffer in hours:minutes:seconds. More...
 
void insert_marker (const std::string &metadata="")
 Insert a track marker into the audio output buffer. A track marker is an arbitrary flag in the buffer contents that indicates the end of some block of audio of significance to the sender. This may be a song from a streaming site, or some voice audio/speech, a sound effect, or whatever you choose. You can later skip to the next marker using the dpp::discord_voice_client::skip_to_next_marker function. More...
 
void skip_to_next_marker ()
 Skip tp the next track marker, previously inserted by using the dpp::discord_voice_client::insert_marker function. If there are no markers in the output buffer, then this skips to the end of the buffer and is equivalent to the dpp::discord_voice_client::stop_audio function. More...
 
const std::vector< std::string > get_marker_metadata ()
 Get the metadata string associated with each inserted marker. More...
 
bool is_paused ()
 Returns true if the audio is paused. You can unpause with dpp::discord_voice_client::pause_audio. More...
 
std::string discover_ip ()
 Discord external IP detection. More...
 
virtual void write (const std::string &data)
 Write to websocket. Encapsulates data in frames if the status is CONNECTED. More...
 
virtual bool handle_buffer (std::string &buffer)
 Processes incoming frames from the SSL socket input buffer. More...
 
virtual void close ()
 Close websocket. More...
 
uint64_t get_bytes_out ()
 
uint64_t get_bytes_in ()
 
std::string get_cipher ()
 
void read_loop ()
 Nonblocking I/O loop. More...
 

Public Attributes

class dpp::clustercreator
 
bool terminating
 
bool decode_voice_recv
 
uint32_t heartbeat_interval
 
time_t last_heartbeat
 
std::thread::native_handle_type thread_id
 
std::string token
 
std::string sessionid
 
snowflake server_id
 
snowflake channel_id
 
socket_callback_t custom_readable_fd
 Attaching an additional file descriptor to this function will send notifications when there is data to read. More...
 
socket_callback_t custom_writeable_fd
 Attaching an additional file descriptor to this function will send notifications when you are able to write to the socket. More...
 
socket_notification_t custom_readable_ready
 This event will be called when you can read from the custom fd. More...
 
socket_notification_t custom_writeable_ready
 This event will be called when you can write to a custom fd. More...
 

Static Public Attributes

static bool sodium_initialised
 

Protected Member Functions

virtual void connect ()
 
ws_state get_state ()
 

Protected Attributes

std::string buffer
 
std::string obuffer
 
bool nonblocking
 
dpp::socket sfd
 
opensslcontext * ssl
 
std::string cipher
 
time_t last_tick
 
std::string hostname
 
uint64_t bytes_out
 
uint64_t bytes_in
 
bool plaintext
 

Detailed Description

Implements a discord voice connection. Each discord_voice_client connects to one voice channel and derives from a websocket client.

Constructor & Destructor Documentation

◆ discord_voice_client()

dpp::discord_voice_client::discord_voice_client ( dpp::cluster _cluster,
snowflake  _channel_id,
snowflake  _server_id,
const std::string &  _token,
const std::string &  _session_id,
const std::string &  _host 
)

Constructor takes shard id, max shards and token.

Parameters
_clusterThe cluster which owns this voice connection, for related logging, REST requests etc
_channel_idThe channel id to identify the voice connection as
_server_idThe server id (guild id) to identify the voice connection as
_tokenThe voice session token to use for identifying to the websocket
_session_idThe voice session id to identify with
_hostThe voice server hostname to connect to (hostname:port format)
Exceptions
dpp::voice_exceptionSodium or Opus failed to initialise, or D++ is not compiled with voice support

◆ ~discord_voice_client()

virtual dpp::discord_voice_client::~discord_voice_client ( )
virtual

Destructor

Member Function Documentation

◆ close()

virtual void dpp::websocket_client::close ( )
virtualinherited

Close websocket.

Reimplemented from dpp::ssl_client.

◆ connect()

virtual void dpp::websocket_client::connect ( )
protectedvirtualinherited

(Re)connect

Reimplemented from dpp::ssl_client.

◆ discover_ip()

std::string dpp::discord_voice_client::discover_ip ( )

Discord external IP detection.

Returns
std::string Your external IP address
Note
This is a blocking operation that waits for a single packet from Discord's voice servers.

◆ error()

virtual void dpp::discord_voice_client::error ( uint32_t  errorcode)
virtual

Handle a websocket error.

Parameters
errorcodeThe error returned from the websocket

Reimplemented from dpp::websocket_client.

◆ get_bytes_in()

uint64_t dpp::ssl_client::get_bytes_in ( )
inherited

Get total bytes received

◆ get_bytes_out()

uint64_t dpp::ssl_client::get_bytes_out ( )
inherited

Get total bytes sent

◆ get_cipher()

std::string dpp::ssl_client::get_cipher ( )
inherited

Get SSL cipher name

◆ get_marker_metadata()

const std::vector< std::string > dpp::discord_voice_client::get_marker_metadata ( )

Get the metadata string associated with each inserted marker.

Returns
const std::vector<std::string>& list of metadata strings

◆ get_remaining()

dpp::utility::uptime dpp::discord_voice_client::get_remaining ( )

Get the time remaining to send the audio output buffer in hours:minutes:seconds.

Returns
dpp::utility::uptime length of buffer

◆ get_secs_remaining()

float dpp::discord_voice_client::get_secs_remaining ( )

Get the number of seconds remaining of the audio output buffer.

Returns
float number of seconds remaining

◆ get_state()

ws_state dpp::websocket_client::get_state ( )
protectedinherited

Get websocket state

Returns
websocket state

◆ get_timescale()

uint64_t dpp::discord_voice_client::get_timescale ( )

Get the current timescale, this will default to 1000000 which means 1 millisecond.

Returns
uint64_t timescale in nanoseconds

◆ get_tracks_remaining()

uint32_t dpp::discord_voice_client::get_tracks_remaining ( )

Get the number of tracks remaining in the output buffer. This is calculated by the number of track markers plus one.

Returns
uint32_t Number of tracks in the buffer

◆ get_uptime()

dpp::utility::uptime dpp::discord_voice_client::get_uptime ( )

Returns the connection time of the voice client.

Returns
dpp::utility::uptime Detail of how long the voice client has been connected for

◆ handle_buffer()

virtual bool dpp::websocket_client::handle_buffer ( std::string &  buffer)
virtualinherited

Processes incoming frames from the SSL socket input buffer.

Parameters
bufferThe buffer contents. Can modify this value removing the head elements when processed.

Reimplemented from dpp::ssl_client.

◆ handle_frame()

virtual bool dpp::discord_voice_client::handle_frame ( const std::string &  buffer)
virtual

Handle JSON from the websocket.

Parameters
bufferThe entire buffer content from the websocket client
Returns
bool True if a frame has been handled
Exceptions
dpp::exceptionIf there was an error processing the frame, or connection to UDP socket failed

Reimplemented from dpp::websocket_client.

◆ insert_marker()

void dpp::discord_voice_client::insert_marker ( const std::string &  metadata = "")

Insert a track marker into the audio output buffer. A track marker is an arbitrary flag in the buffer contents that indicates the end of some block of audio of significance to the sender. This may be a song from a streaming site, or some voice audio/speech, a sound effect, or whatever you choose. You can later skip to the next marker using the dpp::discord_voice_client::skip_to_next_marker function.

Parameters
metadataArbitrary information related to this track

◆ is_connected()

bool dpp::discord_voice_client::is_connected ( )

Returns true if the voice client is connected to the websocket.

Returns
True if connected

◆ is_paused()

bool dpp::discord_voice_client::is_paused ( )

Returns true if the audio is paused. You can unpause with dpp::discord_voice_client::pause_audio.

Returns
true if paused

◆ is_playing()

bool dpp::discord_voice_client::is_playing ( )

Returns true if we are playing audio.

Returns
true if audio is playing

◆ is_ready()

bool dpp::discord_voice_client::is_ready ( )

voice client is ready to stream audio. The voice client is considered ready if it has a secret key.

Returns
true if ready to stream audio

◆ log()

virtual void dpp::discord_voice_client::log ( dpp::loglevel  severity,
const std::string &  msg 
) const
virtual

Log a message to whatever log the user is using. The logged message is passed up the chain to the on_log event in user code which can then do whatever it wants to do with it.

Parameters
severityThe log level from dpp::loglevel
msgThe log message to output

Reimplemented from dpp::ssl_client.

◆ one_second_timer()

virtual void dpp::discord_voice_client::one_second_timer ( )
virtual

Fires every second from the underlying socket I/O loop, used for sending heartbeats.

Exceptions
dpp::exceptionif the socket needs to disconnect

Reimplemented from dpp::websocket_client.

◆ pause_audio()

void dpp::discord_voice_client::pause_audio ( bool  pause)

Pause sending of audio.

Parameters
pauseTrue to pause, false to resume

◆ read_loop()

void dpp::ssl_client::read_loop ( )
inherited

Nonblocking I/O loop.

Exceptions
std::exceptionAny std::exception (or derivative) thrown from read_loop() causes reconnection of the shard

◆ run()

void dpp::discord_voice_client::run ( )

Start and monitor I/O loop

◆ send_audio_opus() [1/2]

discord_voice_client & dpp::discord_voice_client::send_audio_opus ( uint8_t *  opus_packet,
const size_t  length 
)

Send opus packets to the voice channel.

Some containers such as .ogg may contain OPUS encoded data already. In this case, we don't need to encode the frames using opus here. We can bypass the codec, only applying libsodium to the stream.

Duration is calculated internally

Parameters
opus_packetOpus packets. Discord expects opus frames to be encoded at 48000Hz
lengthThe length of the audio data.
Returns
discord_voice_client& Reference to self
Note
It is your responsibility to ensure that packets of data sent to send_audio are correctly repacketized for streaming, e.g. that audio frames are not too large or contain an incorrect format. Discord will still expect the same frequency and bit width of audio and the same signedness.
Exceptions
dpp::voice_exceptionIf data length is invalid or voice support not compiled into D++

◆ send_audio_opus() [2/2]

discord_voice_client & dpp::discord_voice_client::send_audio_opus ( uint8_t *  opus_packet,
const size_t  length,
uint64_t  duration 
)

Send opus packets to the voice channel.

Some containers such as .ogg may contain OPUS encoded data already. In this case, we don't need to encode the frames using opus here. We can bypass the codec, only applying libsodium to the stream.

Parameters
opus_packetOpus packets. Discord expects opus frames to be encoded at 48000Hz
lengthThe length of the audio data.
durationGenerally duration is 2.5, 5, 10, 20, 40 or 60 if the timescale is 1000000 (1ms)
Returns
discord_voice_client& Reference to self
Note
It is your responsibility to ensure that packets of data sent to send_audio are correctly repacketized for streaming, e.g. that audio frames are not too large or contain an incorrect format. Discord will still expect the same frequency and bit width of audio and the same signedness.
Exceptions
dpp::voice_exceptionIf data length is invalid or voice support not compiled into D++

◆ send_audio_raw()

discord_voice_client & dpp::discord_voice_client::send_audio_raw ( uint16_t *  audio_data,
const size_t  length 
)

Send raw audio to the voice channel.

You should send an audio packet of n11520 bytes. Note that this function can be costly as it has to opus encode the PCM audio on the fly, and also encrypt it with libsodium.

Note
Because this function encrypts and encodes packets before pushing them onto the output queue, if you have a complete stream ready to send and know its length it is advisable to call this method multiple times to enqueue the entire stream audio so that it is all encoded at once (unless you have set use_opus to false). Constantly calling this from the dpp::on_voice_buffer_send callback can and will eat a TON of cpu!
Parameters
audio_dataRaw PCM audio data. Channels are interleaved, with each channel's amplitude being a 16 bit value.

The audio data should be 48000Hz signed 16 bit audio.

Parameters
lengthThe length of the audio data. The length should be a multiple of 4 (2x 16 bit stereo channels) with a maximum length of 11520, which is a complete opus frame at highest quality.
Returns
discord_voice_client& Reference to self
Exceptions
dpp::voice_exceptionIf data length is invalid or voice support not compiled into D++

◆ send_silence()

discord_voice_client & dpp::discord_voice_client::send_silence ( const uint64_t  duration)

Send silence to the voice channel.

Parameters
durationHow long to send silence for. With the standard timescale this is in milliseconds. Allowed values are 2.5, 5, 10, 20, 40 or 60 milliseconds.
Returns
discord_voice_client& Reference to self
Exceptions
dpp::voice_exceptionif voice support is not compiled into D++

◆ set_timescale()

discord_voice_client & dpp::discord_voice_client::set_timescale ( uint64_t  new_timescale)

Set the timescale in nanoseconds.

Parameters
new_timescaleTimescale to set. This defaults to 1000000, which means 1 millisecond.
Returns
discord_voice_client& Reference to self
Exceptions
dpp::voice_exceptionIf data length is invalid or voice support not compiled into D++

◆ skip_to_next_marker()

void dpp::discord_voice_client::skip_to_next_marker ( )

Skip tp the next track marker, previously inserted by using the dpp::discord_voice_client::insert_marker function. If there are no markers in the output buffer, then this skips to the end of the buffer and is equivalent to the dpp::discord_voice_client::stop_audio function.

Note
It is possible to use this function while the output stream is paused.

◆ speak()

discord_voice_client & dpp::discord_voice_client::speak ( )

Mark the voice connection as 'speaking'. This sends a JSON message to the voice websocket which tells discord that the user is speaking. The library automatically calls this for you whenever you send audio.

Returns
discord_voice_client& Reference to self

◆ stop_audio()

void dpp::discord_voice_client::stop_audio ( )

Immediately stop all audio. Clears the packet queue.

◆ write()

virtual void dpp::websocket_client::write ( const std::string &  data)
virtualinherited

Write to websocket. Encapsulates data in frames if the status is CONNECTED.

Parameters
dataThe data to send.

Reimplemented from dpp::ssl_client.

Member Data Documentation

◆ buffer

std::string dpp::ssl_client::buffer
protectedinherited

Input buffer received from openssl

◆ bytes_in

uint64_t dpp::ssl_client::bytes_in
protectedinherited

Bytes in

◆ bytes_out

uint64_t dpp::ssl_client::bytes_out
protectedinherited

Bytes out

◆ channel_id

snowflake dpp::discord_voice_client::channel_id

Channel ID

◆ cipher

std::string dpp::ssl_client::cipher
protectedinherited

SSL cipher in use

◆ creator

class dpp::cluster* dpp::discord_voice_client::creator

Owning cluster

◆ custom_readable_fd

socket_callback_t dpp::ssl_client::custom_readable_fd
inherited

Attaching an additional file descriptor to this function will send notifications when there is data to read.

NOTE: Only hook this if you NEED it as it can increase CPU usage of the thread! Returning -1 means that you don't want to be notified.

◆ custom_readable_ready

socket_notification_t dpp::ssl_client::custom_readable_ready
inherited

This event will be called when you can read from the custom fd.

◆ custom_writeable_fd

socket_callback_t dpp::ssl_client::custom_writeable_fd
inherited

Attaching an additional file descriptor to this function will send notifications when you are able to write to the socket.

NOTE: Only hook this if you NEED it as it can increase CPU usage of the thread! You should toggle this to -1 when you do not have anything to write otherwise it'll keep triggering repeatedly (it is level triggered).

◆ custom_writeable_ready

socket_notification_t dpp::ssl_client::custom_writeable_ready
inherited

This event will be called when you can write to a custom fd.

◆ decode_voice_recv

bool dpp::discord_voice_client::decode_voice_recv

Decode received voice packets to PCM

◆ heartbeat_interval

uint32_t dpp::discord_voice_client::heartbeat_interval

Heartbeat interval for sending heartbeat keepalive

◆ hostname

std::string dpp::ssl_client::hostname
protectedinherited

Hostname connected to

◆ last_heartbeat

time_t dpp::discord_voice_client::last_heartbeat

Last heartbeat

◆ last_tick

time_t dpp::ssl_client::last_tick
protectedinherited

For timers

◆ nonblocking

bool dpp::ssl_client::nonblocking
protectedinherited

True if in nonblocking mode. The socket switches to nonblocking mode once ReadLoop is called.

◆ obuffer

std::string dpp::ssl_client::obuffer
protectedinherited

Output buffer for sending to openssl

◆ plaintext

bool dpp::ssl_client::plaintext
protectedinherited

◆ server_id

snowflake dpp::discord_voice_client::server_id

Server ID

◆ sessionid

std::string dpp::discord_voice_client::sessionid

Discord voice session id

◆ sfd

dpp::socket dpp::ssl_client::sfd
protectedinherited

Raw file descriptor of connection

◆ sodium_initialised

bool dpp::discord_voice_client::sodium_initialised
static

◆ ssl

opensslcontext* dpp::ssl_client::ssl
protectedinherited

Openssl opaque contexts

◆ terminating

bool dpp::discord_voice_client::terminating

True when the thread is shutting down

◆ thread_id

std::thread::native_handle_type dpp::discord_voice_client::thread_id

Thread ID

◆ token

std::string dpp::discord_voice_client::token

Discord voice session token

D++ Library version 10.0.29D++ Library version 10.0.28D++ Library version 10.0.27D++ Library version 10.0.26D++ Library version 10.0.25D++ Library version 10.0.24D++ Library version 10.0.23D++ Library version 10.0.22D++ Library version 10.0.21D++ Library version 10.0.20D++ Library version 10.0.19D++ Library version 10.0.18D++ Library version 10.0.17D++ 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