mirror of
https://github.com/uowuo/abaddon.git
synced 2024-11-10 06:00:10 +00:00
display user list, client side mute
This commit is contained in:
parent
a96d96b3aa
commit
dc127d15fb
@ -44,7 +44,7 @@ has to be separate to allow main.css to override certain things
|
||||
background: @secondary_color;
|
||||
}
|
||||
|
||||
.app-popup list {
|
||||
.app-window list, .app-popup list {
|
||||
background: @secondary_color;
|
||||
}
|
||||
|
||||
|
@ -419,7 +419,7 @@ void Abaddon::DiscordOnThreadUpdate(const ThreadUpdateData &data) {
|
||||
|
||||
#ifdef WITH_VOICE
|
||||
void Abaddon::OnVoiceConnected() {
|
||||
auto *wnd = new VoiceWindow;
|
||||
auto *wnd = new VoiceWindow(m_discord.GetVoiceChannelID());
|
||||
|
||||
wnd->signal_mute().connect([this](bool is_mute) {
|
||||
m_discord.SetVoiceMuted(is_mute);
|
||||
@ -431,6 +431,12 @@ void Abaddon::OnVoiceConnected() {
|
||||
m_audio->SetPlayback(!is_deaf);
|
||||
});
|
||||
|
||||
wnd->signal_mute_user_cs().connect([this](Snowflake id, bool is_mute) {
|
||||
if (const auto ssrc = m_discord.GetSSRCOfUser(id); ssrc.has_value()) {
|
||||
m_audio->SetMuteSSRC(*ssrc, is_mute);
|
||||
}
|
||||
});
|
||||
|
||||
wnd->show();
|
||||
wnd->signal_hide().connect([this, wnd]() {
|
||||
m_discord.DisconnectFromVoice();
|
||||
|
@ -1,5 +1,6 @@
|
||||
#ifdef WITH_VOICE
|
||||
// clang-format off
|
||||
// clang-format off
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
@ -138,6 +139,10 @@ void AudioManager::SetOpusBuffer(uint8_t *ptr) {
|
||||
|
||||
void AudioManager::FeedMeOpus(uint32_t ssrc, const std::vector<uint8_t> &data) {
|
||||
if (!m_should_playback) return;
|
||||
{
|
||||
std::lock_guard<std::mutex> _(m_muted_ssrc_mutex);
|
||||
if (m_muted_ssrcs.find(ssrc) != m_muted_ssrcs.end()) return;
|
||||
}
|
||||
|
||||
size_t payload_size = 0;
|
||||
const auto *opus_encoded = StripRTPExtensionHeader(data.data(), static_cast<int>(data.size()), payload_size);
|
||||
@ -162,6 +167,15 @@ void AudioManager::SetPlayback(bool playback) {
|
||||
m_should_playback = playback;
|
||||
}
|
||||
|
||||
void AudioManager::SetMuteSSRC(uint32_t ssrc, bool mute) {
|
||||
std::lock_guard<std::mutex> _(m_muted_ssrc_mutex);
|
||||
if (mute) {
|
||||
m_muted_ssrcs.insert(ssrc);
|
||||
} else {
|
||||
m_muted_ssrcs.erase(ssrc);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioManager::OnCapturedPCM(const int16_t *pcm, ma_uint32 frames) {
|
||||
if (m_opus_buffer == nullptr || !m_should_capture) return;
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <miniaudio.h>
|
||||
#include <opus.h>
|
||||
@ -29,6 +30,8 @@ public:
|
||||
void SetCapture(bool capture);
|
||||
void SetPlayback(bool playback);
|
||||
|
||||
void SetMuteSSRC(uint32_t ssrc, bool mute);
|
||||
|
||||
[[nodiscard]] bool OK() const;
|
||||
|
||||
private:
|
||||
@ -58,6 +61,10 @@ private:
|
||||
std::atomic<bool> m_should_capture = true;
|
||||
std::atomic<bool> m_should_playback = true;
|
||||
|
||||
std::unordered_set<uint32_t> m_muted_ssrcs;
|
||||
|
||||
mutable std::mutex m_muted_ssrc_mutex;
|
||||
|
||||
public:
|
||||
using type_signal_opus_packet = sigc::signal<void(int payload_size)>;
|
||||
type_signal_opus_packet signal_opus_packet();
|
||||
|
@ -1203,6 +1203,14 @@ Snowflake DiscordClient::GetVoiceChannelID() const noexcept {
|
||||
return m_voice_channel_id;
|
||||
}
|
||||
|
||||
std::unordered_set<Snowflake> DiscordClient::GetUsersInVoiceChannel(Snowflake channel_id) {
|
||||
return m_voice_state_channel_users[channel_id];
|
||||
}
|
||||
|
||||
std::optional<uint32_t> DiscordClient::GetSSRCOfUser(Snowflake id) const {
|
||||
return m_voice.GetSSRCOfUser(id);
|
||||
}
|
||||
|
||||
void DiscordClient::SetVoiceMuted(bool is_mute) {
|
||||
m_mute_requested = is_mute;
|
||||
SendVoiceStateUpdate();
|
||||
|
@ -186,6 +186,8 @@ public:
|
||||
void DisconnectFromVoice();
|
||||
[[nodiscard]] bool IsConnectedToVoice() const noexcept;
|
||||
[[nodiscard]] Snowflake GetVoiceChannelID() const noexcept;
|
||||
[[nodiscard]] std::unordered_set<Snowflake> GetUsersInVoiceChannel(Snowflake channel_id);
|
||||
[[nodiscard]] std::optional<uint32_t> GetSSRCOfUser(Snowflake id) const;
|
||||
|
||||
void SetVoiceMuted(bool is_mute);
|
||||
void SetVoiceDeafened(bool is_deaf);
|
||||
|
@ -240,6 +240,7 @@ void from_json(const nlohmann::json &j, SupplementalGuildEntry &m) {
|
||||
|
||||
void from_json(const nlohmann::json &j, ReadySupplementalData &m) {
|
||||
JS_D("merged_presences", m.MergedPresences);
|
||||
JS_D("guilds", m.Guilds);
|
||||
}
|
||||
|
||||
void to_json(nlohmann::json &j, const IdentifyProperties &m) {
|
||||
@ -681,6 +682,6 @@ void from_json(const nlohmann::json &j, VoiceState &m) {
|
||||
JS_O("self_stream", m.IsSelfStream);
|
||||
JS_D("suppress", m.IsSuppressed);
|
||||
JS_D("user_id", m.UserID);
|
||||
JS_N("member", m.Member);
|
||||
JS_ON("member", m.Member);
|
||||
JS_D("session_id", m.SessionID);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#ifdef WITH_VOICE
|
||||
// clang-format off
|
||||
|
||||
#include "voiceclient.hpp"
|
||||
#include "json.hpp"
|
||||
#include <sodium.h>
|
||||
@ -220,6 +221,13 @@ void DiscordVoiceClient::SetUserID(Snowflake id) {
|
||||
m_user_id = id;
|
||||
}
|
||||
|
||||
std::optional<uint32_t> DiscordVoiceClient::GetSSRCOfUser(Snowflake id) const {
|
||||
if (const auto it = m_ssrc_map.find(id); it != m_ssrc_map.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool DiscordVoiceClient::IsConnected() const noexcept {
|
||||
return m_connected;
|
||||
}
|
||||
@ -296,6 +304,7 @@ void DiscordVoiceClient::HandleGatewaySessionDescription(const VoiceGatewayMessa
|
||||
|
||||
void DiscordVoiceClient::HandleGatewaySpeaking(const VoiceGatewayMessage &m) {
|
||||
VoiceSpeakingData data = m.Data;
|
||||
m_ssrc_map[data.UserID] = data.SSRC;
|
||||
m_signal_speaking.emit(data);
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,17 @@
|
||||
#pragma once
|
||||
#ifdef WITH_VOICE
|
||||
// clang-format off
|
||||
// clang-format off
|
||||
|
||||
#include "snowflake.hpp"
|
||||
#include "waiter.hpp"
|
||||
#include "websocket.hpp"
|
||||
#include <optional>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <glibmm/dispatcher.h>
|
||||
#include <sigc++/sigc++.h>
|
||||
#include <unordered_map>
|
||||
// clang-format on
|
||||
|
||||
enum class VoiceGatewayCloseCode : uint16_t {
|
||||
@ -190,6 +193,8 @@ public:
|
||||
void SetServerID(Snowflake id);
|
||||
void SetUserID(Snowflake id);
|
||||
|
||||
[[nodiscard]] std::optional<uint32_t> GetSSRCOfUser(Snowflake id) const;
|
||||
|
||||
[[nodiscard]] bool IsConnected() const noexcept;
|
||||
|
||||
private:
|
||||
@ -218,6 +223,8 @@ private:
|
||||
uint16_t m_port;
|
||||
uint32_t m_ssrc;
|
||||
|
||||
std::unordered_map<Snowflake, uint32_t> m_ssrc_map;
|
||||
|
||||
std::array<uint8_t, 32> m_secret_key;
|
||||
|
||||
Websocket m_ws;
|
||||
|
@ -1,24 +1,86 @@
|
||||
#include "voicewindow.hpp"
|
||||
#include "components/lazyimage.hpp"
|
||||
#include "abaddon.hpp"
|
||||
|
||||
VoiceWindow::VoiceWindow()
|
||||
class VoiceWindowUserListEntry : public Gtk::ListBoxRow {
|
||||
public:
|
||||
VoiceWindowUserListEntry(Snowflake id)
|
||||
: m_main(Gtk::ORIENTATION_HORIZONTAL)
|
||||
, m_avatar(32, 32)
|
||||
, m_mute("Mute") {
|
||||
m_name.set_halign(Gtk::ALIGN_START);
|
||||
m_name.set_hexpand(true);
|
||||
m_mute.set_halign(Gtk::ALIGN_END);
|
||||
|
||||
m_main.add(m_avatar);
|
||||
m_main.add(m_name);
|
||||
m_main.add(m_mute);
|
||||
add(m_main);
|
||||
show_all_children();
|
||||
|
||||
auto &discord = Abaddon::Get().GetDiscordClient();
|
||||
const auto user = discord.GetUser(id);
|
||||
if (user.has_value()) {
|
||||
m_name.set_text(user->Username);
|
||||
} else {
|
||||
m_name.set_text("Unknown user");
|
||||
}
|
||||
|
||||
m_mute.signal_toggled().connect([this]() {
|
||||
m_signal_mute_cs.emit(m_mute.get_active());
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
Gtk::Box m_main;
|
||||
LazyImage m_avatar;
|
||||
Gtk::Label m_name;
|
||||
Gtk::CheckButton m_mute;
|
||||
|
||||
public:
|
||||
using type_signal_mute_cs = sigc::signal<void(bool)>;
|
||||
type_signal_mute_cs signal_mute_cs() {
|
||||
return m_signal_mute_cs;
|
||||
}
|
||||
|
||||
private:
|
||||
type_signal_mute_cs m_signal_mute_cs;
|
||||
};
|
||||
|
||||
VoiceWindow::VoiceWindow(Snowflake channel_id)
|
||||
: m_main(Gtk::ORIENTATION_VERTICAL)
|
||||
, m_controls(Gtk::ORIENTATION_HORIZONTAL)
|
||||
, m_mute("Mute")
|
||||
, m_deafen("Deafen") {
|
||||
, m_deafen("Deafen")
|
||||
, m_channel_id(channel_id) {
|
||||
get_style_context()->add_class("app-window");
|
||||
|
||||
set_default_size(300, 300);
|
||||
|
||||
auto &discord = Abaddon::Get().GetDiscordClient();
|
||||
SetUsers(discord.GetUsersInVoiceChannel(m_channel_id));
|
||||
|
||||
m_mute.signal_toggled().connect(sigc::mem_fun(*this, &VoiceWindow::OnMuteChanged));
|
||||
m_deafen.signal_toggled().connect(sigc::mem_fun(*this, &VoiceWindow::OnDeafenChanged));
|
||||
|
||||
m_controls.add(m_mute);
|
||||
m_controls.add(m_deafen);
|
||||
m_main.add(m_controls);
|
||||
m_main.add(m_user_list);
|
||||
add(m_main);
|
||||
show_all_children();
|
||||
}
|
||||
|
||||
void VoiceWindow::SetUsers(const std::unordered_set<Snowflake> &user_ids) {
|
||||
for (auto id : user_ids) {
|
||||
auto *row = Gtk::make_managed<VoiceWindowUserListEntry>(id);
|
||||
row->signal_mute_cs().connect([this, id](bool is_muted) {
|
||||
m_signal_mute_user_cs.emit(id, is_muted);
|
||||
});
|
||||
m_user_list.add(*row);
|
||||
}
|
||||
}
|
||||
|
||||
void VoiceWindow::OnMuteChanged() {
|
||||
m_signal_mute.emit(m_mute.get_active());
|
||||
}
|
||||
@ -34,3 +96,7 @@ VoiceWindow::type_signal_mute VoiceWindow::signal_mute() {
|
||||
VoiceWindow::type_signal_deafen VoiceWindow::signal_deafen() {
|
||||
return m_signal_deafen;
|
||||
}
|
||||
|
||||
VoiceWindow::type_signal_mute_user_cs VoiceWindow::signal_mute_user_cs() {
|
||||
return m_signal_mute_user_cs;
|
||||
}
|
||||
|
@ -1,13 +1,18 @@
|
||||
#pragma once
|
||||
#include "discord/snowflake.hpp"
|
||||
#include <gtkmm/box.h>
|
||||
#include <gtkmm/checkbutton.h>
|
||||
#include <gtkmm/listbox.h>
|
||||
#include <gtkmm/window.h>
|
||||
#include <unordered_set>
|
||||
|
||||
class VoiceWindow : public Gtk::Window {
|
||||
public:
|
||||
VoiceWindow();
|
||||
VoiceWindow(Snowflake channel_id);
|
||||
|
||||
private:
|
||||
void SetUsers(const std::unordered_set<Snowflake> &user_ids);
|
||||
|
||||
void OnMuteChanged();
|
||||
void OnDeafenChanged();
|
||||
|
||||
@ -17,14 +22,21 @@ private:
|
||||
Gtk::CheckButton m_mute;
|
||||
Gtk::CheckButton m_deafen;
|
||||
|
||||
Gtk::ListBox m_user_list;
|
||||
|
||||
Snowflake m_channel_id;
|
||||
|
||||
public:
|
||||
using type_signal_mute = sigc::signal<void(bool)>;
|
||||
using type_signal_deafen = sigc::signal<void(bool)>;
|
||||
using type_signal_mute_user_cs = sigc::signal<void(Snowflake, bool)>;
|
||||
|
||||
type_signal_mute signal_mute();
|
||||
type_signal_deafen signal_deafen();
|
||||
type_signal_mute_user_cs signal_mute_user_cs();
|
||||
|
||||
private:
|
||||
type_signal_mute m_signal_mute;
|
||||
type_signal_deafen m_signal_deafen;
|
||||
type_signal_mute_user_cs m_signal_mute_user_cs;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user