diff options
author | ouwou <26526779+ouwou@users.noreply.github.com> | 2022-11-14 01:28:07 -0500 |
---|---|---|
committer | ouwou <26526779+ouwou@users.noreply.github.com> | 2022-11-14 01:28:07 -0500 |
commit | 38c5230a1d194cb2fc4cf36fb6b417fdefb32788 (patch) | |
tree | 53a3c8985a6d0a90f05e84ed60257bbed3871fcd | |
parent | e2784cd97bd9a4b5995c556d35bd4f08a2f4bad7 (diff) | |
download | abaddon-portaudio-38c5230a1d194cb2fc4cf36fb6b417fdefb32788.tar.gz abaddon-portaudio-38c5230a1d194cb2fc4cf36fb6b417fdefb32788.zip |
add window to change more stuff with opus
-rw-r--r-- | src/audio/manager.cpp | 62 | ||||
-rw-r--r-- | src/audio/manager.hpp | 9 | ||||
-rw-r--r-- | src/windows/voicesettingswindow.cpp | 125 | ||||
-rw-r--r-- | src/windows/voicesettingswindow.hpp | 25 | ||||
-rw-r--r-- | src/windows/voicewindow.cpp | 14 | ||||
-rw-r--r-- | src/windows/voicewindow.hpp | 6 |
6 files changed, 240 insertions, 1 deletions
diff --git a/src/audio/manager.cpp b/src/audio/manager.cpp index fcfa9f2..1a7bda5 100644 --- a/src/audio/manager.cpp +++ b/src/audio/manager.cpp @@ -301,6 +301,66 @@ void AudioManager::SetVolumeSSRC(uint32_t ssrc, double volume) { m_volume_ssrc[ssrc] = (std::exp(volume) - 1) / (E - 1); } +void AudioManager::SetEncodingApplication(int application) { + std::lock_guard<std::mutex> _(m_enc_mutex); + int prev_bitrate = 64000; + if (int err = opus_encoder_ctl(m_encoder, OPUS_GET_BITRATE(&prev_bitrate)); err != OPUS_OK) { + spdlog::get("audio")->error("Failed to get old bitrate when reinitializing: {}", err); + } + opus_encoder_destroy(m_encoder); + int err = 0; + m_encoder = opus_encoder_create(48000, 2, application, &err); + if (err != OPUS_OK) { + spdlog::get("audio")->critical("opus_encoder_create failed: {}", err); + return; + } + + if (int err = opus_encoder_ctl(m_encoder, OPUS_SET_BITRATE(prev_bitrate)); err != OPUS_OK) { + spdlog::get("audio")->error("Failed to set bitrate when reinitializing: {}", err); + } +} + +int AudioManager::GetEncodingApplication() { + std::lock_guard<std::mutex> _(m_enc_mutex); + int temp = OPUS_APPLICATION_VOIP; + if (int err = opus_encoder_ctl(m_encoder, OPUS_GET_APPLICATION(&temp)); err != OPUS_OK) { + spdlog::get("audio")->error("opus_encoder_ctl(OPUS_GET_APPLICATION) failed: {}", err); + } + return temp; +} + +void AudioManager::SetSignalHint(int signal) { + std::lock_guard<std::mutex> _(m_enc_mutex); + if (int err = opus_encoder_ctl(m_encoder, OPUS_SET_SIGNAL(signal)); err != OPUS_OK) { + spdlog::get("audio")->error("opus_encoder_ctl(OPUS_SET_SIGNAL) failed: {}", err); + } +} + +int AudioManager::GetSignalHint() { + std::lock_guard<std::mutex> _(m_enc_mutex); + int temp = OPUS_AUTO; + if (int err = opus_encoder_ctl(m_encoder, OPUS_GET_SIGNAL(&temp)); err != OPUS_OK) { + spdlog::get("audio")->error("opus_encoder_ctl(OPUS_GET_SIGNAL) failed: {}", err); + } + return temp; +} + +void AudioManager::SetBitrate(int bitrate) { + std::lock_guard<std::mutex> _(m_enc_mutex); + if (int err = opus_encoder_ctl(m_encoder, OPUS_SET_BITRATE(bitrate)); err != OPUS_OK) { + spdlog::get("audio")->error("opus_encoder_ctl(OPUS_SET_BITRATE) failed: {}", err); + } +} + +int AudioManager::GetBitrate() { + std::lock_guard<std::mutex> _(m_enc_mutex); + int temp = 64000; + if (int err = opus_encoder_ctl(m_encoder, OPUS_GET_BITRATE(&temp)); err != OPUS_OK) { + spdlog::get("audio")->error("opus_encoder_ctl(OPUS_GET_BITRATE) failed: {}", err); + } + return temp; +} + void AudioManager::Enumerate() { ma_device_info *pPlaybackDeviceInfo; ma_uint32 playbackDeviceCount; @@ -339,7 +399,9 @@ void AudioManager::OnCapturedPCM(const int16_t *pcm, ma_uint32 frames) { if (m_capture_peak_meter / 32768.0 < m_capture_gate) return; + m_enc_mutex.lock(); int payload_len = opus_encode(m_encoder, new_pcm.data(), 480, static_cast<unsigned char *>(m_opus_buffer), 1275); + m_enc_mutex.unlock(); if (payload_len < 0) { spdlog::get("audio")->error("encoding error: {}", payload_len); } else { diff --git a/src/audio/manager.hpp b/src/audio/manager.hpp index 7516918..dbb0b6e 100644 --- a/src/audio/manager.hpp +++ b/src/audio/manager.hpp @@ -44,6 +44,13 @@ public: void SetMuteSSRC(uint32_t ssrc, bool mute); void SetVolumeSSRC(uint32_t ssrc, double volume); + void SetEncodingApplication(int application); + [[nodiscard]] int GetEncodingApplication(); + void SetSignalHint(int signal); + [[nodiscard]] int GetSignalHint(); + void SetBitrate(int bitrate); + [[nodiscard]] int GetBitrate(); + void Enumerate(); [[nodiscard]] bool OK() const; @@ -81,6 +88,8 @@ private: ma_context m_context; mutable std::mutex m_mutex; + mutable std::mutex m_enc_mutex; + std::unordered_map<uint32_t, std::pair<std::deque<int16_t>, OpusDecoder *>> m_sources; OpusEncoder *m_encoder; diff --git a/src/windows/voicesettingswindow.cpp b/src/windows/voicesettingswindow.cpp new file mode 100644 index 0000000..c009cbf --- /dev/null +++ b/src/windows/voicesettingswindow.cpp @@ -0,0 +1,125 @@ +#ifdef WITH_VOICE + +// clang-format off + +#include "voicesettingswindow.hpp" +#include "abaddon.hpp" +#include "audio/manager.hpp" +#include <spdlog/spdlog.h> + +// clang-format on + +VoiceSettingsWindow::VoiceSettingsWindow() + : m_main(Gtk::ORIENTATION_VERTICAL) { + get_style_context()->add_class("app-window"); + set_default_size(300, 300); + + m_encoding_mode.append("Voice"); + m_encoding_mode.append("Music"); + m_encoding_mode.append("Restricted"); + m_encoding_mode.set_tooltip_text( + "Sets the coding mode for the Opus encoder\n" + "Voice - Optimize for voice quality\n" + "Music - Optimize for non-voice signals incl. music\n" + "Restricted - Optimize for non-voice, low latency. Not recommended"); + + const auto mode = Abaddon::Get().GetAudio().GetEncodingApplication(); + if (mode == OPUS_APPLICATION_VOIP) { + m_encoding_mode.set_active(0); + } else if (mode == OPUS_APPLICATION_AUDIO) { + m_encoding_mode.set_active(1); + } else if (mode == OPUS_APPLICATION_RESTRICTED_LOWDELAY) { + m_encoding_mode.set_active(2); + } + + m_encoding_mode.signal_changed().connect([this]() { + const auto mode = m_encoding_mode.get_active_text(); + auto &audio = Abaddon::Get().GetAudio(); + spdlog::get("audio")->debug("Chose encoding mode: {}", mode.c_str()); + if (mode == "Voice") { + audio.SetEncodingApplication(OPUS_APPLICATION_VOIP); + } else if (mode == "Music") { + spdlog::get("audio")->debug("music/audio"); + audio.SetEncodingApplication(OPUS_APPLICATION_AUDIO); + } else if (mode == "Restricted") { + audio.SetEncodingApplication(OPUS_APPLICATION_RESTRICTED_LOWDELAY); + } + }); + + m_signal.append("Auto"); + m_signal.append("Voice"); + m_signal.append("Music"); + m_signal.set_tooltip_text( + "Signal hint. Tells Opus what the current signal is\n" + "Auto - Let Opus figure it out\n" + "Voice - Tell Opus it's a voice signal\n" + "Music - Tell Opus it's a music signal"); + + const auto signal = Abaddon::Get().GetAudio().GetSignalHint(); + if (signal == OPUS_AUTO) { + m_signal.set_active(0); + } else if (signal == OPUS_SIGNAL_VOICE) { + m_signal.set_active(1); + } else if (signal == OPUS_SIGNAL_MUSIC) { + m_signal.set_active(2); + } + + m_signal.signal_changed().connect([this]() { + const auto signal = m_signal.get_active_text(); + auto &audio = Abaddon::Get().GetAudio(); + spdlog::get("audio")->debug("Chose signal hint: {}", signal.c_str()); + if (signal == "Auto") { + audio.SetSignalHint(OPUS_AUTO); + } else if (signal == "Voice") { + audio.SetSignalHint(OPUS_SIGNAL_VOICE); + } else if (signal == "Music") { + audio.SetSignalHint(OPUS_SIGNAL_MUSIC); + } + }); + + // exponential scale for bitrate because higher bitrates dont sound much different + constexpr static auto MAX_BITRATE = 128000.0; + constexpr static auto MIN_BITRATE = 2400.0; + const auto bitrate_scale = [this](double value) -> double { + value /= 100.0; + return (MAX_BITRATE - MIN_BITRATE) * value * value * value + MIN_BITRATE; + }; + + const auto bitrate_scale_r = [this](double value) -> double { + return 100.0 * std::cbrt((value - MIN_BITRATE) / (MAX_BITRATE - MIN_BITRATE)); + }; + + m_bitrate.set_range(0.0, 100.0); + m_bitrate.set_value_pos(Gtk::POS_TOP); + m_bitrate.set_value(bitrate_scale_r(Abaddon::Get().GetAudio().GetBitrate())); + m_bitrate.signal_format_value().connect([this, bitrate_scale](double value) { + const auto scaled = bitrate_scale(value); + if (value <= 99.9) { + return Glib::ustring(std::to_string(static_cast<int>(scaled))); + } else { + return Glib::ustring("MAX"); + } + }); + m_bitrate.signal_value_changed().connect([this, bitrate_scale]() { + const auto value = m_bitrate.get_value(); + const auto scaled = bitrate_scale(value); + if (value <= 99.9) { + Abaddon::Get().GetAudio().SetBitrate(static_cast<int>(scaled)); + } else { + Abaddon::Get().GetAudio().SetBitrate(OPUS_BITRATE_MAX); + } + }); + + m_main.add(m_encoding_mode); + m_main.add(m_signal); + m_main.add(m_bitrate); + add(m_main); + show_all_children(); + + // no need to bring in ManageHeapWindow, no user menu + signal_hide().connect([this]() { + delete this; + }); +} + +#endif diff --git a/src/windows/voicesettingswindow.hpp b/src/windows/voicesettingswindow.hpp new file mode 100644 index 0000000..cf6b477 --- /dev/null +++ b/src/windows/voicesettingswindow.hpp @@ -0,0 +1,25 @@ +#pragma once +#ifdef WITH_VOICE + +// clang-format off + +#include <gtkmm/box.h> +#include <gtkmm/comboboxtext.h> +#include <gtkmm/scale.h> +#include <gtkmm/window.h> + +// clang-format on + +class VoiceSettingsWindow : public Gtk::Window { +public: + VoiceSettingsWindow(); + + Gtk::Box m_main; + Gtk::ComboBoxText m_encoding_mode; + Gtk::ComboBoxText m_signal; + Gtk::Scale m_bitrate; + +private: +}; + +#endif diff --git a/src/windows/voicewindow.cpp b/src/windows/voicewindow.cpp index 7b574e4..7c90e96 100644 --- a/src/windows/voicewindow.cpp +++ b/src/windows/voicewindow.cpp @@ -6,6 +6,7 @@ #include "components/lazyimage.hpp" #include "abaddon.hpp" #include "audio/manager.hpp" +#include "voicesettingswindow.hpp" // clang-format on class VoiceWindowUserListEntry : public Gtk::ListBoxRow { @@ -83,7 +84,9 @@ VoiceWindow::VoiceWindow(Snowflake channel_id) , m_controls(Gtk::ORIENTATION_HORIZONTAL) , m_mute("Mute") , m_deafen("Deafen") - , m_channel_id(channel_id) { + , m_channel_id(channel_id) + , m_menu_view("View") + , m_menu_view_settings("More _Settings", true) { get_style_context()->add_class("app-window"); set_default_size(300, 300); @@ -145,9 +148,18 @@ VoiceWindow::VoiceWindow(Snowflake channel_id) Abaddon::Get().GetAudio().SetCaptureDevice(m_capture_combo.get_active()); }); + m_menu_bar.append(m_menu_view); + m_menu_view.set_submenu(m_menu_view_sub); + m_menu_view_sub.append(m_menu_view_settings); + m_menu_view_settings.signal_activate().connect([this]() { + auto *window = new VoiceSettingsWindow; + window->show(); + }); + m_scroll.add(m_user_list); m_controls.add(m_mute); m_controls.add(m_deafen); + m_main.add(m_menu_bar); m_main.add(m_controls); m_main.add(m_capture_volume); m_main.add(m_capture_gate); diff --git a/src/windows/voicewindow.hpp b/src/windows/voicewindow.hpp index f9ea23f..805d94a 100644 --- a/src/windows/voicewindow.hpp +++ b/src/windows/voicewindow.hpp @@ -8,6 +8,7 @@ #include <gtkmm/checkbutton.h> #include <gtkmm/combobox.h> #include <gtkmm/listbox.h> +#include <gtkmm/menubar.h> #include <gtkmm/progressbar.h> #include <gtkmm/scale.h> #include <gtkmm/scrolledwindow.h> @@ -53,6 +54,11 @@ private: std::unordered_map<Snowflake, VoiceWindowUserListEntry *> m_rows; + Gtk::MenuBar m_menu_bar; + Gtk::MenuItem m_menu_view; + Gtk::Menu m_menu_view_sub; + Gtk::MenuItem m_menu_view_settings; + public: using type_signal_mute = sigc::signal<void(bool)>; using type_signal_deafen = sigc::signal<void(bool)>; |