-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathdiscord-voice-connections.h
286 lines (256 loc) · 9.26 KB
/
discord-voice-connections.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
/**
* @file discord-voice-connections.h
* @author cee-studio
* @brief File containing internal functions and datatypes for Voice
* Connections
*/
#ifndef DISCORD_VOICE_CONNECTIONS_H
#define DISCORD_VOICE_CONNECTIONS_H
#include <time.h>
#include <pthread.h>
#include "cee-data-sizes.h"
struct discord_voice; /*forward */
/**
* @brief Idle callback
*
* Runs on every WebSockets loop iteration, no trigger required
* @see discord_set_voice_cbs()
*/
typedef void (*discord_on_voice_idle)(struct discord *client,
struct discord_voice *vc);
/**
* @brief Voice Speaking callback
*
* @see https://discord.com/developers/docs/topics/voice-connections#speaking
* @see discord_set_voice_cbs()
*/
typedef void (*discord_on_voice_speaking)(struct discord *client,
struct discord_voice *vc,
const u64_snowflake_t user_id,
const int speaking,
const int delay,
const int ssrc);
/**
* @brief Voice Client Disconnect callback
*
* @see https://discord.com/developers/docs/topics/voice-connections#speaking
* @see discord_set_voice_cbs()
*/
typedef void (*discord_on_voice_client_disconnect)(
struct discord *client,
struct discord_voice *vc,
const u64_snowflake_t user_id);
/**
* @brief Voice Codec callback
*
* @see https://discord.com/developers/docs/topics/voice-connections#speaking
* @see discord_set_voice_cbs()
*/
typedef void (*discord_on_voice_codec)(struct discord *client,
struct discord_voice *vc,
const char audio_codec[],
const char video_codec[]);
/* CALLBACKS STRUCTURE */
struct discord_voice_cbs {
/** triggers on every event loop iteration */
discord_on_voice_idle on_idle;
/** triggers when a user start speaking */
discord_on_voice_speaking on_speaking;
/** triggers when a user has disconnected from the voice channel */
discord_on_voice_client_disconnect on_client_disconnect;
/** triggers when a codec is received */
discord_on_voice_codec on_codec;
void (*on_ready)(struct discord_voice *vc);
void (*on_session_descriptor)(struct discord_voice *vc);
void (*on_udp_server_connected)(struct discord_voice *vc);
};
/**
* @brief Discord Voice Connection handle, contain information
* about its active session.
*
* @note struct discord_voice are reused on a guild basis, because there can
* be only one active struct discord_voice session per guild.
* @see discord_voice_join()
* @see discord_voice_get_vc()
*/
struct discord_voice {
/** DISCORD_VOICE logging module */
struct logconf conf;
/** the session guild id @note obtained from discord_voice_join() */
u64_snowflake_t guild_id;
/** the session channel id @note obtained from discord_voice_join() */
u64_snowflake_t channel_id;
/** @note obtained from on_voice_server_update() */
/** the session token @note obtained from on_voice_server_update() */
char token[128];
/** the new session token after a voice region change @note obtained from
* on_voice_server_update() */
char new_token[128];
/** the new url after a voice region change @note obtained from
* on_voice_server_update() */
char new_url[512];
/** @note obtained from on_voice_state_update()
* the session id @note obtained from on_voice_state_update() */
char session_id[128];
CURLM *mhandle;
/** the websockets handle that binds to Discord Voice Connections */
struct websockets *ws;
/** @brief handle reconnect logic */
/* RECONNECT STRUCTURE */
struct {
/** will attempt reconnecting if true */
bool enable;
/** current reconnect attempt (resets to 0 when succesful) */
unsigned char attempt;
/** max amount of reconnects before giving up */
unsigned char threshold;
} reconnect;
/** will attempt to resume session if connection shutsdown */
bool is_resumable;
/** redirect to a different voice server */
bool is_redirect;
/** can start sending/receiving additional events to discord */
bool is_ready;
/**
* @see
* https://discord.com/developers/docs/topics/voice-connections#establishing-a-voice-websocket-connection-example-voice-ready-payload
*/
/* VOICE PAYLOAD STRUCTURE */
struct {
/** field 'op' */
enum discord_voice_opcodes opcode;
/** field 'd' */
struct sized_buffer event_data;
} payload;
/* HEARTBEAT STRUCTURE */
struct {
/** fixed interval between heartbeats */
u64_unix_ms_t interval_ms;
/** start pulse timestamp in milliseconds */
u64_unix_ms_t tstamp;
} hbeat;
/** latency between client and websockets server, calculated by the interval
* between HEARTBEAT and HEARTBEAT_ACK */
int ping_ms;
/** pointer to client this struct is part of */
struct discord *p_client;
/** if true shutdown websockets connection as soon as possible */
bool shutdown;
struct {
int ssrc;
int server_port;
char server_ip[CEE_MAX_IP_ADDR_STR_LEN];
char digest[CEE_SHA1_STR_LEN];
char unique_key[128];
int audio_udp_pid;
uintmax_t start_time;
} udp_service;
struct discord_voice_cbs *p_voice_cbs;
/**
* @brief Interval to divide the received packets
*
* 0 store in one file
* n store packets received every n minutes in a new file
*/
int recv_interval;
};
/**
* @brief Set a callback that triggers at every event-loop iteration.
*
* @param vc the voice connection obtained with discord_voice_join()
* @param callback the callback that will be executed
*/
void discord_voice_set_on_idle(struct discord_voice *vc,
discord_on_voice_idle *callback);
enum discord_voice_status {
DISCORD_VOICE_ERROR = 0,
DISCORD_VOICE_JOINED,
DISCORD_VOICE_EXHAUST_CAPACITY,
DISCORD_VOICE_ALREADY_JOINED
};
/**
* @brief Send a Voice State Update to Discord
*
* Necessary to connect to the voice server. When succesful a new voice
* connection instance will start
* @param client the client created with discord_init()
* @param guild_id the guild that houses the voice channel
* @param channel_id the voice channel the client wants to connect to
* @param self_mute true will join as mute
* @param self_deaf true will join as deaf
* @return enum discord_voice_status value
*/
enum discord_voice_status discord_voice_join(struct discord *client,
u64_snowflake_t guild_id,
u64_snowflake_t channel_id,
bool self_mute,
bool self_deaf);
/**
* @brief Notify clients that you are speaking or have stopped speaking.
*
* @param vc the voice connection obtained with discord_voice_join()
* @param flag
* @param delay Should be set to 0.
* @see https://discord.com/developers/docs/topics/voice-connections#speaking
* @see
* https://github.com/discord/discord-api-docs/issues/859#issuecomment-466602485
*/
void discord_send_speaking(struct discord_voice *vc,
enum discord_voice_speaking_flags flag,
int delay);
/**
* @brief Update the voice session with a new session_id
*
* @param client the client created with discord_init()
* @param vs the voice state that has been updated
* @todo move to discord-internal.h
*/
void _discord_on_voice_state_update(struct discord *client,
struct discord_voice_state *vs);
/**
* @brief Update the voice session with a new token and url
*
* @param client the client created with discord_init()
* @param guild_id the guild that houses the voice channel
* @param token the unique token identifier
* @param endpoint unique wss url received
* @todo move to discord-internal.h
* @note will prepend with "wss://" and append with "?v=4"
*/
void _discord_on_voice_server_update(struct discord *client,
u64_snowflake_t guild_id,
char token[],
char endpoint[]);
/**
* @brief Gracefully exits a ongoing Discord Voice connection
*
* @param vc the voice connection obtained with discord_voice_join()
* @note Wraps around ws_set_action()
* @see websockets.h
*/
void discord_voice_shutdown(struct discord_voice *vc);
/**
* @brief Gracefully reconnect a ongoing Discord Voice connection
*
* @param vc the voice connection obtained with discord_voice_join()
* @param resume true to attempt to resume to previous session,
* false reconnect to a fresh session
* @note Helper around ws_set_action()
* @see websockets.h
*/
void discord_voice_reconnect(struct discord_voice *vc, bool resume);
/**
* @brief Check if a Discord Voice connection is alive
*
* @param vc the voice connection obtained with discord_voice_join()
* @return true if WebSockets status is different than
* WS_DISCONNECTED, false otherwise.
*/
bool discord_voice_is_alive(struct discord_voice *vc);
/**
* @brief Initialize the fields of a Discord Voice Connections handle
*
* @param client the client created with discord_init()
*/
void discord_voice_connections_init(struct discord *client);
#endif /* DISCORD_VOICE_CONNECTIONS_H */