diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/abaddon.cpp | 5 | ||||
-rw-r--r-- | src/abaddon.hpp | 1 | ||||
-rw-r--r-- | src/components/channels.cpp | 25 | ||||
-rw-r--r-- | src/components/channels.hpp | 5 | ||||
-rw-r--r-- | src/discord/discord.cpp | 15 | ||||
-rw-r--r-- | src/discord/discord.hpp | 5 | ||||
-rw-r--r-- | src/discord/objects.cpp | 10 | ||||
-rw-r--r-- | src/discord/objects.hpp | 4 | ||||
-rw-r--r-- | src/discord/voiceclient.cpp | 35 | ||||
-rw-r--r-- | src/discord/voiceclient.hpp | 4 |
10 files changed, 93 insertions, 16 deletions
diff --git a/src/abaddon.cpp b/src/abaddon.cpp index 688aff4..82741be 100644 --- a/src/abaddon.cpp +++ b/src/abaddon.cpp @@ -252,6 +252,7 @@ int Abaddon::StartGTK() { #ifdef WITH_VOICE m_main_window->GetChannelList()->signal_action_join_voice_channel().connect(sigc::mem_fun(*this, &Abaddon::ActionJoinVoiceChannel)); + m_main_window->GetChannelList()->signal_action_disconnect_voice().connect(sigc::mem_fun(*this, &Abaddon::ActionDisconnectVoice)); #endif m_main_window->GetChatWindow()->signal_action_message_edit().connect(sigc::mem_fun(*this, &Abaddon::ActionChatEditMessage)); @@ -917,6 +918,10 @@ void Abaddon::ActionViewThreads(Snowflake channel_id) { void Abaddon::ActionJoinVoiceChannel(Snowflake channel_id) { m_discord.ConnectToVoice(channel_id); } + +void Abaddon::ActionDisconnectVoice() { + m_discord.DisconnectFromVoice(); +} #endif std::optional<Glib::ustring> Abaddon::ShowTextPrompt(const Glib::ustring &prompt, const Glib::ustring &title, const Glib::ustring &placeholder, Gtk::Window *window) { diff --git a/src/abaddon.hpp b/src/abaddon.hpp index 9a98c9e..9b3199a 100644 --- a/src/abaddon.hpp +++ b/src/abaddon.hpp @@ -56,6 +56,7 @@ public: #ifdef WITH_VOICE void ActionJoinVoiceChannel(Snowflake channel_id); + void ActionDisconnectVoice(); #endif std::optional<Glib::ustring> ShowTextPrompt(const Glib::ustring &prompt, const Glib::ustring &title, const Glib::ustring &placeholder = "", Gtk::Window *window = nullptr); diff --git a/src/components/channels.cpp b/src/components/channels.cpp index 201e7c9..eb9d688 100644 --- a/src/components/channels.cpp +++ b/src/components/channels.cpp @@ -21,6 +21,10 @@ ChannelList::ChannelList() , m_menu_channel_open_tab("Open in New _Tab", true) , m_menu_dm_open_tab("Open in New _Tab", true) #endif +#ifdef WITH_VOICE + , m_menu_voice_channel_join("_Join", true) + , m_menu_voice_channel_disconnect("_Disconnect", true) +#endif , m_menu_dm_copy_id("_Copy ID", true) , m_menu_dm_close("") // changes depending on if group or not , m_menu_thread_copy_id("_Copy ID", true) @@ -168,11 +172,15 @@ ChannelList::ChannelList() #ifdef WITH_VOICE m_menu_voice_channel_join.signal_activate().connect([this]() { const auto id = static_cast<Snowflake>((*m_model->get_iter(m_path_for_menu))[m_columns.m_id]); - printf("join voice: %llu\n", static_cast<uint64_t>(id)); m_signal_action_join_voice_channel.emit(id); }); + m_menu_voice_channel_disconnect.signal_activate().connect([this]() { + m_signal_action_disconnect_voice.emit(); + }); + m_menu_voice_channel.append(m_menu_voice_channel_join); + m_menu_voice_channel.append(m_menu_voice_channel_disconnect); m_menu_voice_channel.show_all(); #endif @@ -984,6 +992,17 @@ void ChannelList::OnChannelSubmenuPopup() { #ifdef WITH_VOICE void ChannelList::OnVoiceChannelSubmenuPopup() { + const auto iter = m_model->get_iter(m_path_for_menu); + if (!iter) return; + const auto id = static_cast<Snowflake>((*iter)[m_columns.m_id]); + auto &discord = Abaddon::Get().GetDiscordClient(); + if (discord.IsConnectedToVoice()) { + m_menu_voice_channel_join.set_sensitive(false); + m_menu_voice_channel_disconnect.set_sensitive(discord.GetVoiceChannelID() == id); + } else { + m_menu_voice_channel_join.set_sensitive(true); + m_menu_voice_channel_disconnect.set_sensitive(false); + } } #endif @@ -1041,6 +1060,10 @@ ChannelList::type_signal_action_open_new_tab ChannelList::signal_action_open_new ChannelList::type_signal_action_join_voice_channel ChannelList::signal_action_join_voice_channel() { return m_signal_action_join_voice_channel; } + +ChannelList::type_signal_action_disconnect_voice ChannelList::signal_action_disconnect_voice() { + return m_signal_action_disconnect_voice; +} #endif ChannelList::ModelColumns::ModelColumns() { diff --git a/src/components/channels.hpp b/src/components/channels.hpp index 8c34735..2d2b257 100644 --- a/src/components/channels.hpp +++ b/src/components/channels.hpp @@ -128,6 +128,7 @@ protected: #ifdef WITH_VOICE Gtk::Menu m_menu_voice_channel; Gtk::MenuItem m_menu_voice_channel_join; + Gtk::MenuItem m_menu_voice_channel_disconnect; #endif Gtk::Menu m_menu_dm; @@ -177,7 +178,10 @@ public: #ifdef WITH_VOICE using type_signal_action_join_voice_channel = sigc::signal<void, Snowflake>; + using type_signal_action_disconnect_voice = sigc::signal<void>; + type_signal_action_join_voice_channel signal_action_join_voice_channel(); + type_signal_action_disconnect_voice signal_action_disconnect_voice(); #endif type_signal_action_channel_item_select signal_action_channel_item_select(); @@ -195,5 +199,6 @@ private: #ifdef WITH_VOICE type_signal_action_join_voice_channel m_signal_action_join_voice_channel; + type_signal_action_disconnect_voice m_signal_action_disconnect_voice; #endif }; diff --git a/src/discord/discord.cpp b/src/discord/discord.cpp index 5670d4a..f44c1ed 100644 --- a/src/discord/discord.cpp +++ b/src/discord/discord.cpp @@ -1173,12 +1173,27 @@ void DiscordClient::AcceptVerificationGate(Snowflake guild_id, VerificationGateI void DiscordClient::ConnectToVoice(Snowflake channel_id) { auto channel = GetChannel(channel_id); if (!channel.has_value() || !channel->GuildID.has_value()) return; + m_voice_channel_id = channel_id; VoiceStateUpdateMessage m; m.GuildID = *channel->GuildID; m.ChannelID = channel_id; m.PreferredRegion = "newark"; m_websocket.Send(m); } + +void DiscordClient::DisconnectFromVoice() { + m_voice.Stop(); + VoiceStateUpdateMessage m; + m_websocket.Send(m); +} + +bool DiscordClient::IsConnectedToVoice() const noexcept { + return m_voice.IsConnected(); +} + +Snowflake DiscordClient::GetVoiceChannelID() const noexcept { + return m_voice_channel_id; +} #endif void DiscordClient::SetReferringChannel(Snowflake id) { diff --git a/src/discord/discord.hpp b/src/discord/discord.hpp index 907c3e6..0b88519 100644 --- a/src/discord/discord.hpp +++ b/src/discord/discord.hpp @@ -183,6 +183,9 @@ public: #ifdef WITH_VOICE void ConnectToVoice(Snowflake channel_id); + void DisconnectFromVoice(); + [[nodiscard]] bool IsConnectedToVoice() const noexcept; + [[nodiscard]] Snowflake GetVoiceChannelID() const noexcept; #endif void SetReferringChannel(Snowflake id); @@ -334,6 +337,8 @@ private: #ifdef WITH_VOICE DiscordVoiceClient m_voice; + + Snowflake m_voice_channel_id; #endif mutable std::mutex m_msg_mutex; diff --git a/src/discord/objects.cpp b/src/discord/objects.cpp index a6a7cc6..3cdc6b5 100644 --- a/src/discord/objects.cpp +++ b/src/discord/objects.cpp @@ -644,8 +644,14 @@ void from_json(const nlohmann::json &j, GuildMembersChunkData &m) { #ifdef WITH_VOICE void to_json(nlohmann::json &j, const VoiceStateUpdateMessage &m) { j["op"] = GatewayOp::VoiceStateUpdate; - j["d"]["guild_id"] = m.GuildID; - j["d"]["channel_id"] = m.ChannelID; + if (m.GuildID.has_value()) + j["d"]["guild_id"] = *m.GuildID; + else + j["d"]["guild_id"] = nullptr; + if (m.ChannelID.has_value()) + j["d"]["channel_id"] = *m.ChannelID; + else + j["d"]["channel_id"] = nullptr; j["d"]["self_mute"] = m.SelfMute; j["d"]["self_deaf"] = m.SelfDeaf; j["d"]["self_video"] = m.SelfVideo; diff --git a/src/discord/objects.hpp b/src/discord/objects.hpp index c9c8aff..0a947d4 100644 --- a/src/discord/objects.hpp +++ b/src/discord/objects.hpp @@ -869,8 +869,8 @@ struct GuildMembersChunkData { #ifdef WITH_VOICE struct VoiceStateUpdateMessage { - Snowflake GuildID; - Snowflake ChannelID; + std::optional<Snowflake> GuildID; + std::optional<Snowflake> ChannelID; bool SelfMute = false; bool SelfDeaf = false; bool SelfVideo = false; diff --git a/src/discord/voiceclient.cpp b/src/discord/voiceclient.cpp index b899638..6d45241 100644 --- a/src/discord/voiceclient.cpp +++ b/src/discord/voiceclient.cpp @@ -168,25 +168,34 @@ DiscordVoiceClient::DiscordVoiceClient() { m_udp_dispatch_mutex.unlock(); OnUDPData(data); }); + + Glib::signal_idle().connect_once([this]() { + // cant put in ctor or deadlock in singleton initialization + auto &aud = Abaddon::Get().GetAudio(); + aud.SetOpusBuffer(m_opus_buffer.data()); + aud.signal_opus_packet().connect([this](int payload_size) { + if (m_connected) + m_udp.SendEncrypted(m_opus_buffer.data(), payload_size); + }); + }); } DiscordVoiceClient::~DiscordVoiceClient() { - m_ws.Stop(); - m_udp.Stop(); - m_heartbeat_waiter.kill(); - if (m_heartbeat_thread.joinable()) m_heartbeat_thread.join(); + Stop(); } void DiscordVoiceClient::Start() { m_ws.StartConnection("wss://" + m_endpoint + "/?v=7"); +} - // cant put in ctor or deadlock in singleton initialization - auto &aud = Abaddon::Get().GetAudio(); - aud.SetOpusBuffer(m_opus_buffer.data()); - aud.signal_opus_packet().connect([this](int payload_size) { - if (m_connected) - m_udp.SendEncrypted(m_opus_buffer.data(), payload_size); - }); +void DiscordVoiceClient::Stop() { + if (m_connected) { + m_ws.Stop(); + m_udp.Stop(); + m_heartbeat_waiter.kill(); + if (m_heartbeat_thread.joinable()) m_heartbeat_thread.join(); + m_connected = false; + } } void DiscordVoiceClient::SetSessionID(std::string_view session_id) { @@ -209,6 +218,10 @@ void DiscordVoiceClient::SetUserID(Snowflake id) { m_user_id = id; } +bool DiscordVoiceClient::IsConnected() const noexcept { + return m_connected; +} + void DiscordVoiceClient::OnGatewayMessage(const std::string &str) { VoiceGatewayMessage msg = nlohmann::json::parse(str); puts(msg.Data.dump(4).c_str()); diff --git a/src/discord/voiceclient.hpp b/src/discord/voiceclient.hpp index 67919e5..f81763b 100644 --- a/src/discord/voiceclient.hpp +++ b/src/discord/voiceclient.hpp @@ -173,6 +173,7 @@ public: ~DiscordVoiceClient(); void Start(); + void Stop(); void SetSessionID(std::string_view session_id); void SetEndpoint(std::string_view endpoint); @@ -180,6 +181,8 @@ public: void SetServerID(Snowflake id); void SetUserID(Snowflake id); + [[nodiscard]] bool IsConnected() const noexcept; + private: void OnGatewayMessage(const std::string &str); void HandleGatewayHello(const VoiceGatewayMessage &m); @@ -198,6 +201,7 @@ private: std::string m_endpoint; std::string m_token; Snowflake m_server_id; + Snowflake m_channel_id; Snowflake m_user_id; std::string m_ip; |