From b5f2b7171f7c0a19d4c4a2974cd8977fd4955464 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Sun, 28 May 2023 16:53:07 -0400 Subject: [PATCH 01/10] make RTP timestamp strictly linear this should fix some artificial delay --- src/audio/manager.cpp | 13 +++++++++++++ src/audio/manager.hpp | 4 ++++ src/discord/voiceclient.cpp | 11 ++++++----- src/discord/voiceclient.hpp | 1 - 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/audio/manager.cpp b/src/audio/manager.cpp index 6e85ed8..ce20940 100644 --- a/src/audio/manager.cpp +++ b/src/audio/manager.cpp @@ -50,6 +50,15 @@ void capture_data_callback(ma_device *pDevice, void *pOutput, const void *pInput if (mgr == nullptr) return; mgr->OnCapturedPCM(static_cast(pInput), frameCount); + + /* + * You can simply increment it by 480 in UDPSocket::SendEncrypted but this is wrong + * The timestamp is supposed to be strictly linear eg. if there's discontinuous + * transmission for 1 second then the timestamp should be 48000 greater than the + * last packet. So it's incremented here because this is fired 100x per second + * and is always called in sync with UDPSocket::SendEncrypted + */ + mgr->m_rtp_timestamp += 480; } AudioManager::AudioManager() { @@ -473,6 +482,10 @@ AudioDevices &AudioManager::GetDevices() { return m_devices; } +uint32_t AudioManager::GetRTPTimestamp() const noexcept { + return m_rtp_timestamp; +} + AudioManager::type_signal_opus_packet AudioManager::signal_opus_packet() { return m_signal_opus_packet; } diff --git a/src/audio/manager.hpp b/src/audio/manager.hpp index 9cd7f42..ed40f35 100644 --- a/src/audio/manager.hpp +++ b/src/audio/manager.hpp @@ -63,6 +63,8 @@ public: [[nodiscard]] AudioDevices &GetDevices(); + [[nodiscard]] uint32_t GetRTPTimestamp() const noexcept; + private: void OnCapturedPCM(const int16_t *pcm, ma_uint32 frames); @@ -113,6 +115,8 @@ private: AudioDevices m_devices; + std::atomic m_rtp_timestamp = 0; + public: using type_signal_opus_packet = sigc::signal; type_signal_opus_packet signal_opus_packet(); diff --git a/src/discord/voiceclient.cpp b/src/discord/voiceclient.cpp index c37ba7b..741b07f 100644 --- a/src/discord/voiceclient.cpp +++ b/src/discord/voiceclient.cpp @@ -49,17 +49,18 @@ void UDPSocket::SetSSRC(uint32_t ssrc) { void UDPSocket::SendEncrypted(const uint8_t *data, size_t len) { m_sequence++; - m_timestamp += 480; // this is important + + const uint32_t timestamp = Abaddon::Get().GetAudio().GetRTPTimestamp(); std::vector rtp(12 + len + crypto_secretbox_MACBYTES, 0); rtp[0] = 0x80; // ver 2 rtp[1] = 0x78; // payload type 0x78 rtp[2] = (m_sequence >> 8) & 0xFF; rtp[3] = (m_sequence >> 0) & 0xFF; - rtp[4] = (m_timestamp >> 24) & 0xFF; - rtp[5] = (m_timestamp >> 16) & 0xFF; - rtp[6] = (m_timestamp >> 8) & 0xFF; - rtp[7] = (m_timestamp >> 0) & 0xFF; + rtp[4] = (timestamp >> 24) & 0xFF; + rtp[5] = (timestamp >> 16) & 0xFF; + rtp[6] = (timestamp >> 8) & 0xFF; + rtp[7] = (timestamp >> 0) & 0xFF; rtp[8] = (m_ssrc >> 24) & 0xFF; rtp[9] = (m_ssrc >> 16) & 0xFF; rtp[10] = (m_ssrc >> 8) & 0xFF; diff --git a/src/discord/voiceclient.hpp b/src/discord/voiceclient.hpp index 7bf4295..0112749 100644 --- a/src/discord/voiceclient.hpp +++ b/src/discord/voiceclient.hpp @@ -171,7 +171,6 @@ private: uint32_t m_ssrc; uint16_t m_sequence = 0; - uint32_t m_timestamp = 0; public: using type_signal_data = sigc::signal>; From bf3854daabde896e10d3dfd1be80f51f605ac63e Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Sun, 28 May 2023 18:03:36 -0400 Subject: [PATCH 02/10] copy adwaita theme spec and cache --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1306f00..52ea356 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -95,6 +95,8 @@ jobs: mkdir -p 16x16/devices 24x24/devices 32x32/devices 48x48/devices 64x64/devices 96x96/devices scalable/devices mkdir -p 16x16/status 24x24/status 32x32/status 48x48/status 64x64/status 96x96/status scalable/status cd ${GITHUB_WORKSPACE} + cp ci/gtk-for-windows/gtk-nsis-pack/share/icons/Adwaita/icon-theme.cache ${artifact_dir}/share/icons/Adwaita/icon-theme.cache + cp ci/gtk-for-windows/gtk-nsis-pack/share/icons/Adwaita/index.theme ${artifact_dir}/share/icons/Adwaita/index.theme cat "ci/used-icons.txt" | sed 's/\r$//' | xargs -I % cp ci/gtk-for-windows/gtk-nsis-pack/share/icons/Adwaita/16x16/%.symbolic.png ${artifact_dir}/share/icons/Adwaita/16x16/%.symbolic.png || : cat "ci/used-icons.txt" | sed 's/\r$//' | xargs -I % cp ci/gtk-for-windows/gtk-nsis-pack/share/icons/Adwaita/24x24/%.symbolic.png ${artifact_dir}/share/icons/Adwaita/24x24/%.symbolic.png || : cat "ci/used-icons.txt" | sed 's/\r$//' | xargs -I % cp ci/gtk-for-windows/gtk-nsis-pack/share/icons/Adwaita/32x32/%.symbolic.png ${artifact_dir}/share/icons/Adwaita/32x32/%.symbolic.png || : From 1f765e1ddf0991084843a90446b6b4aec59ffb48 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Sun, 28 May 2023 19:48:23 -0400 Subject: [PATCH 03/10] fix state saving --- src/abaddon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/abaddon.cpp b/src/abaddon.cpp index 5c6f136..bbca8df 100644 --- a/src/abaddon.cpp +++ b/src/abaddon.cpp @@ -341,8 +341,8 @@ void Abaddon::StartDiscord() { } void Abaddon::StopDiscord() { - if (m_discord.Stop()) - SaveState(); + if (m_discord.IsStarted()) SaveState(); + m_discord.Stop(); m_main_window->UpdateMenus(); } From 7da37a2fa90cebf43631c74aa1abfb9842502291 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Mon, 29 May 2023 01:20:41 -0400 Subject: [PATCH 04/10] printf to log --- src/abaddon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/abaddon.cpp b/src/abaddon.cpp index bbca8df..e8911f9 100644 --- a/src/abaddon.cpp +++ b/src/abaddon.cpp @@ -58,7 +58,7 @@ Abaddon::Abaddon() m_discord.signal_voice_connected().connect(sigc::mem_fun(*this, &Abaddon::OnVoiceConnected)); m_discord.signal_voice_disconnected().connect(sigc::mem_fun(*this, &Abaddon::OnVoiceDisconnected)); m_discord.signal_voice_speaking().connect([this](const VoiceSpeakingData &m) { - printf("%llu has ssrc %u\n", (uint64_t)m.UserID, m.SSRC); + spdlog::get("voice")->debug("{} SSRC: {}", m.UserID, m.SSRC); m_audio->AddSSRC(m.SSRC); }); #endif From 366e72cc2a69f2412c74fa6b1768ee6d85fd1032 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Tue, 30 May 2023 01:51:41 -0400 Subject: [PATCH 05/10] fix bad vector access in discovery (#167) --- src/discord/voiceclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/discord/voiceclient.cpp b/src/discord/voiceclient.cpp index 741b07f..524d930 100644 --- a/src/discord/voiceclient.cpp +++ b/src/discord/voiceclient.cpp @@ -383,7 +383,7 @@ void DiscordVoiceClient::Discovery() { const auto response = m_udp.Receive(); if (response.size() >= 74 && response[0] == 0x00 && response[1] == 0x02) { const char *ip = reinterpret_cast(response.data() + 8); - uint16_t port = (response[73] << 8) | response[74]; + uint16_t port = (response[72] << 8) | response[73]; m_log->info("Discovered IP and port: {}:{}", ip, port); SelectProtocol(ip, port); break; From 62d04b9993c3a9dca46255857592e0052fef6cdc Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Tue, 30 May 2023 19:08:35 -0400 Subject: [PATCH 06/10] add missing formatter for Snowflake --- src/discord/snowflake.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/discord/snowflake.hpp b/src/discord/snowflake.hpp index a5c0e6c..83a2bc3 100644 --- a/src/discord/snowflake.hpp +++ b/src/discord/snowflake.hpp @@ -2,6 +2,7 @@ #include #include #include +#include struct Snowflake { Snowflake(); @@ -39,6 +40,13 @@ private: unsigned long long m_num; }; +template<> +struct fmt::formatter : fmt::formatter { + auto format(Snowflake id, format_context &ctx) -> decltype(ctx.out()) { + return format_to(ctx.out(), "[id: {}]", static_cast(id)); + } +}; + namespace std { template<> struct hash { From a5bcc089e7c84a5de8adfbe5932a4ecb68538764 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Tue, 30 May 2023 19:08:49 -0400 Subject: [PATCH 07/10] remove spammy debug log --- src/discord/discord.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/discord/discord.cpp b/src/discord/discord.cpp index 6a530cb..2a25a26 100644 --- a/src/discord/discord.cpp +++ b/src/discord/discord.cpp @@ -2813,7 +2813,6 @@ void DiscordClient::SetVoiceState(Snowflake user_id, const VoiceState &state) { spdlog::get("discord")->error("SetVoiceState called with missing channel ID"); return; } - spdlog::get("discord")->debug("SetVoiceState: {} -> {}", user_id, *state.ChannelID); auto flags = VoiceStateFlags::Clear; if (state.IsSelfMuted) flags |= VoiceStateFlags::SelfMute; From 3931cac71a4d72ec0f39c48411f9220a8c204f67 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Tue, 30 May 2023 19:43:12 -0400 Subject: [PATCH 08/10] include fmt/ostream.h --- src/discord/snowflake.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/discord/snowflake.hpp b/src/discord/snowflake.hpp index 83a2bc3..d63d270 100644 --- a/src/discord/snowflake.hpp +++ b/src/discord/snowflake.hpp @@ -3,6 +3,7 @@ #include #include #include +#include struct Snowflake { Snowflake(); From b53710f47a95a35ed05eaf7a4e39e962308dc33c Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Tue, 30 May 2023 20:44:35 -0400 Subject: [PATCH 09/10] put AudioManager back on the stack --- src/abaddon.cpp | 23 +++++++++++------------ src/abaddon.hpp | 3 ++- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/abaddon.cpp b/src/abaddon.cpp index e8911f9..a1ed343 100644 --- a/src/abaddon.cpp +++ b/src/abaddon.cpp @@ -59,7 +59,7 @@ Abaddon::Abaddon() m_discord.signal_voice_disconnected().connect(sigc::mem_fun(*this, &Abaddon::OnVoiceDisconnected)); m_discord.signal_voice_speaking().connect([this](const VoiceSpeakingData &m) { spdlog::get("voice")->debug("{} SSRC: {}", m.UserID, m.SSRC); - m_audio->AddSSRC(m.SSRC); + m_audio.AddSSRC(m.SSRC); }); #endif @@ -244,8 +244,7 @@ int Abaddon::StartGTK() { } #ifdef WITH_VOICE - m_audio = std::make_unique(); - if (!m_audio->OK()) { + if (!m_audio.OK()) { Gtk::MessageDialog dlg(*m_main_window, "The audio engine could not be initialized!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dlg.set_position(Gtk::WIN_POS_CENTER); dlg.run(); @@ -441,13 +440,13 @@ void Abaddon::DiscordOnThreadUpdate(const ThreadUpdateData &data) { #ifdef WITH_VOICE void Abaddon::OnVoiceConnected() { - m_audio->StartCaptureDevice(); + m_audio.StartCaptureDevice(); ShowVoiceWindow(); } void Abaddon::OnVoiceDisconnected() { - m_audio->StopCaptureDevice(); - m_audio->RemoveAllSSRCs(); + m_audio.StopCaptureDevice(); + m_audio.RemoveAllSSRCs(); if (m_voice_window != nullptr) { m_voice_window->close(); } @@ -461,25 +460,25 @@ void Abaddon::ShowVoiceWindow() { wnd->signal_mute().connect([this](bool is_mute) { m_discord.SetVoiceMuted(is_mute); - m_audio->SetCapture(!is_mute); + m_audio.SetCapture(!is_mute); }); wnd->signal_deafen().connect([this](bool is_deaf) { m_discord.SetVoiceDeafened(is_deaf); - m_audio->SetPlayback(!is_deaf); + m_audio.SetPlayback(!is_deaf); }); wnd->signal_gate().connect([this](double gate) { - m_audio->SetCaptureGate(gate); + m_audio.SetCaptureGate(gate); }); wnd->signal_gain().connect([this](double gain) { - m_audio->SetCaptureGain(gain); + m_audio.SetCaptureGain(gain); }); 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); + m_audio.SetMuteSSRC(*ssrc, is_mute); } }); @@ -1080,7 +1079,7 @@ EmojiResource &Abaddon::GetEmojis() { #ifdef WITH_VOICE AudioManager &Abaddon::GetAudio() { - return *m_audio; + return m_audio; } #endif diff --git a/src/abaddon.hpp b/src/abaddon.hpp index 5256cd5..08070ae 100644 --- a/src/abaddon.hpp +++ b/src/abaddon.hpp @@ -12,6 +12,7 @@ #include "imgmanager.hpp" #include "emojis.hpp" #include "notifications/notifications.hpp" +#include "audio/manager.hpp" #define APP_TITLE "Abaddon" @@ -173,7 +174,7 @@ private: EmojiResource m_emojis; #ifdef WITH_VOICE - std::unique_ptr m_audio; + AudioManager m_audio; Gtk::Window *m_voice_window = nullptr; #endif From f1fb2419d671b1277c2214e645faad6d7a4fded1 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Thu, 1 Jun 2023 15:13:48 -0400 Subject: [PATCH 10/10] update fmt paths --- src/discord/snowflake.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/discord/snowflake.hpp b/src/discord/snowflake.hpp index d63d270..2ced46b 100644 --- a/src/discord/snowflake.hpp +++ b/src/discord/snowflake.hpp @@ -2,8 +2,8 @@ #include #include #include -#include -#include +#include +#include struct Snowflake { Snowflake();