mirror of
https://github.com/celisej567/abaddon.git
synced 2026-09-06 20:15:19 +03:00
add window to change more stuff with opus
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
125
src/windows/voicesettingswindow.cpp
Normal file
125
src/windows/voicesettingswindow.cpp
Normal file
@@ -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
|
||||
25
src/windows/voicesettingswindow.hpp
Normal file
25
src/windows/voicesettingswindow.hpp
Normal file
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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)>;
|
||||
|
||||
Reference in New Issue
Block a user