request to speak button

This commit is contained in:
ouwou 2024-06-26 04:26:32 -04:00
parent 837e25a0cf
commit af9f9ad803
6 changed files with 75 additions and 2 deletions

View File

@ -1301,6 +1301,32 @@ bool DiscordClient::IsUserSpeaker(Snowflake user_id) const {
return state.has_value() && state->second.IsSpeaker(); return state.has_value() && state->second.IsSpeaker();
} }
bool DiscordClient::HasUserRequestedToSpeak(Snowflake user_id) const {
const auto state = GetVoiceState(user_id);
return state.has_value() && state->second.RequestToSpeakTimestamp.has_value() && util::FlagSet(state->second.Flags, VoiceStateFlags::Suppressed);
}
void DiscordClient::RequestToSpeak(Snowflake channel_id, bool want, const sigc::slot<void(DiscordError code)> &callback) {
if (want && !HasSelfChannelPermission(channel_id, Permission::REQUEST_TO_SPEAK)) return;
const auto channel = GetChannel(channel_id);
if (!channel.has_value() || !channel->GuildID.has_value()) return;
ModifyCurrentUserVoiceStateObject d;
d.ChannelID = channel_id;
if (want) {
d.RequestToSpeakTimestamp = Glib::DateTime::create_now_utc().format_iso8601();
} else {
d.RequestToSpeakTimestamp = "";
}
m_http.MakePATCH("/guilds/" + std::to_string(*channel->GuildID) + "/voice-states/@me", nlohmann::json(d).dump(), [callback](const http::response_type &response) {
if (CheckCode(response, 204)) {
callback(DiscordError::NONE);
} else {
callback(GetCodeFromResponse(response));
}
});
}
DiscordVoiceClient &DiscordClient::GetVoiceClient() { DiscordVoiceClient &DiscordClient::GetVoiceClient() {
return m_voice; return m_voice;
} }

View File

@ -203,6 +203,9 @@ public:
[[nodiscard]] Snowflake GetVoiceChannelID() const noexcept; [[nodiscard]] Snowflake GetVoiceChannelID() const noexcept;
[[nodiscard]] std::optional<uint32_t> GetSSRCOfUser(Snowflake id) const; [[nodiscard]] std::optional<uint32_t> GetSSRCOfUser(Snowflake id) const;
[[nodiscard]] bool IsUserSpeaker(Snowflake user_id) const; [[nodiscard]] bool IsUserSpeaker(Snowflake user_id) const;
[[nodiscard]] bool HasUserRequestedToSpeak(Snowflake user_id) const;
void RequestToSpeak(Snowflake channel_id, bool want, const sigc::slot<void(DiscordError code)> &callback);
DiscordVoiceClient &GetVoiceClient(); DiscordVoiceClient &GetVoiceClient();

View File

@ -699,6 +699,18 @@ void from_json(const nlohmann::json &j, CallCreateData &m) {
JS_D("channel_id", m.ChannelID); JS_D("channel_id", m.ChannelID);
JS_ON("voice_states", m.VoiceStates); JS_ON("voice_states", m.VoiceStates);
} }
void to_json(nlohmann::json &j, const ModifyCurrentUserVoiceStateObject &m) {
JS_IF("channel_id", m.ChannelID);
JS_IF("suppress", m.Suppress);
if (m.RequestToSpeakTimestamp.has_value()) {
if (m.RequestToSpeakTimestamp->empty()) {
j["request_to_speak_timestamp"] = nullptr;
} else {
j["request_to_speak_timestamp"] = *m.RequestToSpeakTimestamp;
}
}
}
#endif #endif
void from_json(const nlohmann::json &j, VoiceState &m) { void from_json(const nlohmann::json &j, VoiceState &m) {

View File

@ -957,4 +957,12 @@ struct CallCreateData {
friend void from_json(const nlohmann::json &j, CallCreateData &m); friend void from_json(const nlohmann::json &j, CallCreateData &m);
}; };
struct ModifyCurrentUserVoiceStateObject {
std::optional<Snowflake> ChannelID;
std::optional<bool> Suppress;
std::optional<std::string> RequestToSpeakTimestamp;
friend void to_json(nlohmann::json &j, const ModifyCurrentUserVoiceStateObject &m);
};
#endif #endif

View File

@ -1,3 +1,4 @@
#include "util.hpp"
#ifdef WITH_VOICE #ifdef WITH_VOICE
// clang-format off // clang-format off
@ -20,6 +21,7 @@ VoiceWindow::VoiceWindow(Snowflake channel_id)
, m_deafen("Deafen") , m_deafen("Deafen")
, m_noise_suppression("Suppress Noise") , m_noise_suppression("Suppress Noise")
, m_mix_mono("Mix Mono") , m_mix_mono("Mix Mono")
, m_request_to_speak("Request to Speak")
, m_disconnect("Disconnect") , m_disconnect("Disconnect")
, m_channel_id(channel_id) , m_channel_id(channel_id)
, m_menu_view("View") , m_menu_view("View")
@ -39,6 +41,7 @@ VoiceWindow::VoiceWindow(Snowflake channel_id)
discord.signal_voice_user_disconnect().connect(sigc::mem_fun(*this, &VoiceWindow::OnUserDisconnect)); discord.signal_voice_user_disconnect().connect(sigc::mem_fun(*this, &VoiceWindow::OnUserDisconnect));
discord.signal_voice_user_connect().connect(sigc::mem_fun(*this, &VoiceWindow::OnUserConnect)); discord.signal_voice_user_connect().connect(sigc::mem_fun(*this, &VoiceWindow::OnUserConnect));
discord.signal_voice_speaker_state_changed().connect(sigc::mem_fun(*this, &VoiceWindow::OnSpeakerStateChanged)); discord.signal_voice_speaker_state_changed().connect(sigc::mem_fun(*this, &VoiceWindow::OnSpeakerStateChanged));
discord.signal_voice_state_set().connect(sigc::mem_fun(*this, &VoiceWindow::OnVoiceStateUpdate));
if (const auto self_state = discord.GetVoiceState(discord.GetUserData().ID); self_state.has_value()) { if (const auto self_state = discord.GetVoiceState(discord.GetUserData().ID); self_state.has_value()) {
m_mute.set_active(util::FlagSet(self_state->second.Flags, VoiceStateFlags::SelfMute)); m_mute.set_active(util::FlagSet(self_state->second.Flags, VoiceStateFlags::SelfMute));
@ -210,6 +213,12 @@ VoiceWindow::VoiceWindow(Snowflake channel_id)
}, },
*this)); *this));
m_request_to_speak.signal_clicked().connect([this]() {
auto &discord = Abaddon::Get().GetDiscordClient();
const bool requested = discord.HasUserRequestedToSpeak(discord.GetUserData().ID);
Abaddon::Get().GetDiscordClient().RequestToSpeak(m_channel_id, !requested, NOOP_CALLBACK);
});
m_TMP_speakers_label.set_markup("<b>Speakers</b>"); m_TMP_speakers_label.set_markup("<b>Speakers</b>");
m_listing.pack_start(m_TMP_speakers_label, false, true); m_listing.pack_start(m_TMP_speakers_label, false, true);
m_listing.pack_start(m_speakers_list, false, true); m_listing.pack_start(m_speakers_list, false, true);
@ -221,10 +230,13 @@ VoiceWindow::VoiceWindow(Snowflake channel_id)
m_controls.add(m_deafen); m_controls.add(m_deafen);
m_controls.add(m_noise_suppression); m_controls.add(m_noise_suppression);
m_controls.add(m_mix_mono); m_controls.add(m_mix_mono);
m_controls.pack_end(m_disconnect, false, true); m_buttons.set_halign(Gtk::ALIGN_CENTER);
m_buttons.pack_start(m_request_to_speak, false, true);
m_buttons.pack_start(m_disconnect, false, true);
m_main.pack_start(m_menu_bar, false, true); m_main.pack_start(m_menu_bar, false, true);
m_main.pack_start(m_TMP_stagelabel, false, true); m_main.pack_start(m_TMP_stagelabel, false, true);
m_main.pack_start(m_controls, false, true); m_main.pack_start(m_controls, false, true);
m_main.pack_start(m_buttons, false, true);
m_main.pack_start(m_vad_value, false, true); m_main.pack_start(m_vad_value, false, true);
m_main.pack_start(*Gtk::make_managed<Gtk::Label>("Input Settings"), false, true); m_main.pack_start(*Gtk::make_managed<Gtk::Label>("Input Settings"), false, true);
m_main.pack_start(*sliders_container, false, true); m_main.pack_start(*sliders_container, false, true);
@ -232,7 +244,7 @@ VoiceWindow::VoiceWindow(Snowflake channel_id)
m_main.pack_start(*combos_container, false, true, 2); m_main.pack_start(*combos_container, false, true, 2);
add(m_main); add(m_main);
show_all_children(); show_all_children();
Glib::signal_timeout().connect(sigc::mem_fun(*this, &VoiceWindow::UpdateVoiceMeters), 40); Glib::signal_timeout().connect(sigc::mem_fun(*this, &VoiceWindow::UpdateVoiceMeters), 40);
} }
@ -349,6 +361,12 @@ void VoiceWindow::OnSpeakerStateChanged(Snowflake channel_id, Snowflake user_id,
} }
} }
void VoiceWindow::OnVoiceStateUpdate(Snowflake user_id, Snowflake channel_id, VoiceStateFlags flags) {
auto &discord = Abaddon::Get().GetDiscordClient();
m_has_requested_to_speak = discord.HasUserRequestedToSpeak(discord.GetUserData().ID);
m_request_to_speak.set_label(m_has_requested_to_speak ? "Cancel Request" : "Request to Speak");
}
VoiceWindow::type_signal_mute VoiceWindow::signal_mute() { VoiceWindow::type_signal_mute VoiceWindow::signal_mute() {
return m_signal_mute; return m_signal_mute;
} }

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "discord/voicestate.hpp"
#ifdef WITH_VOICE #ifdef WITH_VOICE
// clang-format off // clang-format off
@ -29,6 +30,7 @@ private:
void OnUserConnect(Snowflake user_id, Snowflake to_channel_id); void OnUserConnect(Snowflake user_id, Snowflake to_channel_id);
void OnUserDisconnect(Snowflake user_id, Snowflake from_channel_id); void OnUserDisconnect(Snowflake user_id, Snowflake from_channel_id);
void OnSpeakerStateChanged(Snowflake channel_id, Snowflake user_id, bool is_speaker); void OnSpeakerStateChanged(Snowflake channel_id, Snowflake user_id, bool is_speaker);
void OnVoiceStateUpdate(Snowflake user_id, Snowflake channel_id, VoiceStateFlags flags);
void OnMuteChanged(); void OnMuteChanged();
void OnDeafenChanged(); void OnDeafenChanged();
@ -61,7 +63,11 @@ private:
Gtk::CheckButton m_noise_suppression; Gtk::CheckButton m_noise_suppression;
Gtk::CheckButton m_mix_mono; Gtk::CheckButton m_mix_mono;
Gtk::HBox m_buttons;
Gtk::Button m_disconnect; Gtk::Button m_disconnect;
Gtk::Button m_request_to_speak;
bool m_has_requested_to_speak = false;
Gtk::ComboBoxText m_vad_combo; Gtk::ComboBoxText m_vad_combo;
Gtk::ComboBox m_playback_combo; Gtk::ComboBox m_playback_combo;