Skip to content

Commit 4dab53c

Browse files
negotiation in binary
1 parent 7e1d377 commit 4dab53c

File tree

3 files changed

+68
-25
lines changed

3 files changed

+68
-25
lines changed

include/dpp/discordvoiceclient.h

+20
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include <future>
4949
#include <functional>
5050
#include <chrono>
51+
#include <set>
5152

5253
struct OpusDecoder;
5354
struct OpusEncoder;
@@ -57,6 +58,10 @@ namespace dpp {
5758

5859
class audio_mixer;
5960

61+
namespace dave::mls {
62+
class Session;
63+
}
64+
6065
// !TODO: change these to constexpr and rename every occurrence across the codebase
6166
#define AUDIO_TRACK_MARKER (uint16_t)0xFFFF
6267

@@ -66,6 +71,8 @@ inline constexpr size_t send_audio_raw_max_length = 11520;
6671

6772
inline constexpr size_t secret_key_size = 32;
6873

74+
struct dave_transient_key;
75+
6976
/*
7077
* @brief For holding a moving average of the number of current voice users, for applying a smooth gain ramp.
7178
*/
@@ -162,6 +169,12 @@ struct dave_binary_header_t {
162169
* @brief Opcode type
163170
*/
164171
uint8_t opcode;
172+
/**
173+
* @brief Data package
174+
*/
175+
uint8_t package[];
176+
177+
std::vector<uint8_t> get_data(size_t length) const;
165178
};
166179
#pragma pack(pop)
167180

@@ -373,6 +386,7 @@ class DPP_EXPORT discord_voice_client : public websocket_client
373386
* (merges frames into one packet)
374387
*/
375388
OpusRepacketizer* repacketizer;
389+
376390
#else
377391
/**
378392
* @brief libopus encoder
@@ -386,6 +400,12 @@ class DPP_EXPORT discord_voice_client : public websocket_client
386400
void* repacketizer;
387401
#endif
388402

403+
std::unique_ptr<dave::mls::Session> dave_session{};
404+
405+
std::unique_ptr<dave_transient_key> transient_key{};
406+
407+
std::set<std::string> dave_mls_user_list;
408+
389409
/**
390410
* @brief File descriptor for UDP connection
391411
*/

src/davetest/dave.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ int main() {
7676
dave_test.on_guild_create([&](const dpp::guild_create_t & event) {
7777
if (event.created->id == TEST_GUILD_ID) {
7878
dpp::discord_client* s = dave_test.get_shard(0);
79-
s->connect_voice(TEST_GUILD_ID, TEST_VC_ID, false, false, false);
79+
s->connect_voice(TEST_GUILD_ID, TEST_VC_ID, false, false, true);
8080
}
8181
});
8282
dave_test.start(false);

src/dpp/discordvoiceclient.cpp

+47-24
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@
4242
#ifdef HAVE_VOICE
4343
#include <sodium.h>
4444
#include <opus/opus.h>
45+
#include "dave/session.h"
4546
#else
4647
struct OpusDecoder {};
4748
struct OpusEncoder {};
4849
struct OpusRepacketizer {};
50+
struct dpp::dave::Session {};
4951
#endif
5052

5153
namespace dpp {
@@ -70,6 +72,10 @@ constexpr uint8_t voice_protocol_version = 8;
7072
*/
7173
static std::string external_ip;
7274

75+
struct dave_transient_key {
76+
std::shared_ptr<::mlspp::SignaturePrivateKey> mls_key;
77+
};
78+
7379
/**
7480
* @brief Transport encryption type (libsodium)
7581
*/
@@ -483,40 +489,49 @@ int discord_voice_client::udp_recv(char* data, size_t max_length)
483489
return (int) recv(this->fd, data, (int)max_length, 0);
484490
}
485491

492+
std::vector<uint8_t> dave_binary_header_t::get_data(size_t length) const {
493+
return std::vector<uint8_t>(package, package + length - sizeof(dave_binary_header_t));
494+
}
495+
486496
bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcode)
487497
{
488498
json j;
489499

490500
/**
491501
* MLS frames come in as type OP_BINARY, we can also reply to them as type OP_BINARY.
492502
*/
493-
if (opcode == OP_BINARY && data.size() >= sizeof(dave_binary_header_t)) {
494-
495-
log(dpp::ll_trace, "R: " + dpp::utility::debug_dump((uint8_t*)(data.data()), data.length()));
503+
if (opcode == OP_BINARY && data.size() >= sizeof(dave_binary_header_t) && dave_session && transient_key && transient_key->mls_key) {
496504

497-
dave_binary_header_t dave_header{};
498-
std::memcpy(&dave_header, data.data(), sizeof(dave_binary_header_t));
505+
auto* dave_header = reinterpret_cast<const dave_binary_header_t*>(data.data());
499506

500-
switch (dave_header.opcode) {
507+
switch (dave_header->opcode) {
501508
case voice_client_dave_mls_external_sender: {
502509
log(ll_debug, "voice_client_dave_mls_external_sender");
510+
dave_session->SetExternalSender(dave_header->get_data(data.length()));
503511
}
504-
break;
512+
break;
505513
case voice_client_dave_mls_proposals: {
506514
log(ll_debug, "voice_client_dave_mls_proposals");
515+
std::optional<std::vector<uint8_t>> response = dave_session->ProcessProposals(dave_header->get_data(data.length()), dave_mls_user_list);
516+
if (response.has_value()) {
517+
auto r = response.value();
518+
r.insert(r.begin(), voice_client_dave_mls_commit_message);
519+
this->write(std::string_view(reinterpret_cast<const char*>(r.data()), r.size()), OP_BINARY);
520+
}
507521
}
508-
break;
522+
break;
509523
case voice_client_dave_announce_commit_transaction: {
510524
log(ll_debug, "voice_client_dave_announce_commit_transaction");
511525
}
512-
break;
526+
break;
513527
case voice_client_dave_mls_welcome: {
514528
log(ll_debug, "voice_client_dave_mls_welcome");
515529
}
516-
break;
530+
break;
517531
default:
518532
log(ll_debug, "Unexpected DAVE frame opcode");
519-
break;
533+
log(dpp::ll_trace, "R: " + dpp::utility::debug_dump((uint8_t*)(data.data()), data.length()));
534+
break;
520535
}
521536

522537
return true;
@@ -563,8 +578,8 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod
563578
}
564579
break;
565580
case voice_opcode_multiple_clients_connect: {
566-
auto client_list = j["d"]["user_ids"];
567-
log(ll_debug, "Number of new clients in voice channel: " + std::to_string(client_list.size()));
581+
dave_mls_user_list = j["d"]["user_ids"];
582+
log(ll_debug, "Number of clients in voice channel: " + std::to_string(dave_mls_user_list.size()));
568583
}
569584
break;
570585
/* Client Disconnect */
@@ -673,6 +688,13 @@ bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcod
673688
log(ll_error, "We requested DAVE E2EE but didn't receive it from the server, downgrading...");
674689
dave_version = dave_version_none;
675690
send_silence(20);
691+
} else {
692+
dave_session = std::make_unique<dave::mls::Session>(
693+
nullptr, sessionid, [this](std::string const& s1, std::string const& s2) {
694+
log(ll_debug, "Dave session constructor callback: " + s1 + ", " + s2);
695+
});
696+
transient_key = std::make_unique<dave_transient_key>();
697+
dave_session->Init(dave::MaxSupportedProtocolVersion(), channel_id, creator->me.id.str(), transient_key->mls_key);
676698
}
677699
} else {
678700
/* This is needed to start voice receiving and make sure that the start of sending isn't cut off */
@@ -1433,17 +1455,18 @@ discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet
14331455
memcpy(encrypt_nonce, &noncel, sizeof(noncel));
14341456

14351457
/* Execute */
1436-
int r = crypto_aead_xchacha20poly1305_ietf_encrypt(
1437-
payload.data() + sizeof(header),
1438-
nullptr,
1439-
encoded_audio.data(),
1440-
encoded_audio_length,
1441-
/* The RTP Header as Additional Data */
1442-
reinterpret_cast<const unsigned char *>(&header),
1443-
sizeof(header),
1444-
nullptr,
1445-
static_cast<const unsigned char*>(encrypt_nonce),
1446-
secret_key.data());
1458+
crypto_aead_xchacha20poly1305_ietf_encrypt(
1459+
payload.data() + sizeof(header),
1460+
nullptr,
1461+
encoded_audio.data(),
1462+
encoded_audio_length,
1463+
/* The RTP Header as Additional Data */
1464+
reinterpret_cast<const unsigned char *>(&header),
1465+
sizeof(header),
1466+
nullptr,
1467+
static_cast<const unsigned char*>(encrypt_nonce),
1468+
secret_key.data()
1469+
);
14471470

14481471
/* Append the 4 byte nonce to the resulting payload */
14491472
std::memcpy(payload.data() + payload.size() - sizeof(noncel), &noncel, sizeof(noncel));

0 commit comments

Comments
 (0)