basic volume meters

This commit is contained in:
ouwou
2022-10-16 23:12:26 -04:00
parent 17e7478bb4
commit 621beb1344
4 changed files with 90 additions and 2 deletions

View File

@@ -7,6 +7,7 @@
#include "manager.hpp"
#include <array>
#include <glibmm/main.h>
#define MINIAUDIO_IMPLEMENTATION
#include <miniaudio.h>
#include <opus.h>
@@ -107,6 +108,8 @@ AudioManager::AudioManager() {
char device_name[MA_MAX_DEVICE_NAME_LENGTH + 1];
ma_device_get_name(&m_capture_device, ma_device_type_capture, device_name, sizeof(device_name), nullptr);
printf("using %s for capture\n", device_name);
Glib::signal_timeout().connect(sigc::mem_fun(*this, &AudioManager::DecayVolumeMeters), 40);
}
AudioManager::~AudioManager() {
@@ -158,6 +161,7 @@ void AudioManager::FeedMeOpus(uint32_t ssrc, const std::vector<uint8_t> &data) {
int decoded = opus_decode(it->second.second, opus_encoded, static_cast<opus_int32>(payload_size), pcm.data(), 120 * 48, 0);
if (decoded <= 0) {
} else {
UpdateReceiveVolume(ssrc, pcm.data(), decoded);
auto &buf = it->second.first;
buf.insert(buf.end(), pcm.begin(), pcm.begin() + decoded * 2);
}
@@ -191,6 +195,8 @@ void AudioManager::SetVolumeSSRC(uint32_t ssrc, double volume) {
void AudioManager::OnCapturedPCM(const int16_t *pcm, ma_uint32 frames) {
if (m_opus_buffer == nullptr || !m_should_capture) return;
UpdateCaptureVolume(pcm, frames);
int payload_len = opus_encode(m_encoder, pcm, 480, static_cast<unsigned char *>(m_opus_buffer), 1275);
if (payload_len < 0) {
printf("encoding error: %d\n", payload_len);
@@ -199,10 +205,53 @@ void AudioManager::OnCapturedPCM(const int16_t *pcm, ma_uint32 frames) {
}
}
void AudioManager::UpdateReceiveVolume(uint32_t ssrc, const int16_t *pcm, int frames) {
std::lock_guard<std::mutex> _(m_vol_mtx);
auto &meter = m_volumes[ssrc];
for (int i = 0; i < frames * 2; i += 2) {
const int amp = std::abs(pcm[i]);
meter = std::max(meter, std::abs(amp) / 32768.0);
}
}
void AudioManager::UpdateCaptureVolume(const int16_t *pcm, ma_uint32 frames) {
for (ma_uint32 i = 0; i < frames * 2; i += 2) {
const int amp = std::abs(pcm[i]);
m_capture_peak_meter = std::max(m_capture_peak_meter.load(std::memory_order_relaxed), amp);
}
}
bool AudioManager::DecayVolumeMeters() {
m_capture_peak_meter -= 300;
if (m_capture_peak_meter < 0) m_capture_peak_meter = 0;
std::lock_guard<std::mutex> _(m_vol_mtx);
for (auto &[ssrc, meter] : m_volumes) {
meter -= 0.01;
if (meter < 0.0) meter = 0.0;
}
return true;
}
bool AudioManager::OK() const {
return m_ok;
}
double AudioManager::GetCaptureVolumeLevel() const noexcept {
return m_capture_peak_meter / 32768.0;
}
double AudioManager::GetSSRCVolumeLevel(uint32_t ssrc) const noexcept {
std::lock_guard<std::mutex> _(m_vol_mtx);
if (const auto it = m_volumes.find(ssrc); it != m_volumes.end()) {
return it->second;
}
return 0.0;
}
AudioManager::type_signal_opus_packet AudioManager::signal_opus_packet() {
return m_signal_opus_packet;
}

View File

@@ -35,9 +35,18 @@ public:
[[nodiscard]] bool OK() const;
[[nodiscard]] double GetCaptureVolumeLevel() const noexcept;
[[nodiscard]] double GetSSRCVolumeLevel(uint32_t ssrc) const noexcept;
private:
void OnCapturedPCM(const int16_t *pcm, ma_uint32 frames);
void UpdateReceiveVolume(uint32_t ssrc, const int16_t *pcm, int frames);
void UpdateCaptureVolume(const int16_t *pcm, ma_uint32 frames);
std::atomic<int> m_capture_peak_meter = 0;
bool DecayVolumeMeters();
friend void data_callback(ma_device *, void *, const void *, ma_uint32);
friend void capture_data_callback(ma_device *, void *, const void *, ma_uint32);
@@ -52,7 +61,7 @@ private:
ma_device m_capture_device;
ma_device_config m_capture_config;
std::mutex m_mutex;
mutable std::mutex m_mutex;
std::unordered_map<uint32_t, std::pair<std::deque<int16_t>, OpusDecoder *>> m_sources;
OpusEncoder *m_encoder;
@@ -65,6 +74,9 @@ private:
std::unordered_set<uint32_t> m_muted_ssrcs;
std::unordered_map<uint32_t, double> m_volume_ssrc;
mutable std::mutex m_vol_mtx;
std::unordered_map<uint32_t, double> m_volumes;
public:
using type_signal_opus_packet = sigc::signal<void(int payload_size)>;
type_signal_opus_packet signal_opus_packet();

View File

@@ -5,6 +5,7 @@
#include "voicewindow.hpp"
#include "components/lazyimage.hpp"
#include "abaddon.hpp"
#include "audio/manager.hpp"
// clang-format on
class VoiceWindowUserListEntry : public Gtk::ListBoxRow {
@@ -30,6 +31,7 @@ public:
m_horz.add(m_mute);
m_main.add(m_horz);
m_main.add(m_volume);
m_main.add(m_meter);
add(m_main);
show_all_children();
@@ -47,6 +49,10 @@ public:
});
}
void SetVolumeMeter(double frac) {
m_meter.set_fraction(frac);
}
private:
Gtk::Box m_main;
Gtk::Box m_horz;
@@ -54,6 +60,7 @@ private:
Gtk::Label m_name;
Gtk::CheckButton m_mute;
Gtk::Scale m_volume;
Gtk::ProgressBar m_meter;
public:
using type_signal_mute_cs = sigc::signal<void(bool)>;
@@ -98,9 +105,12 @@ VoiceWindow::VoiceWindow(Snowflake channel_id)
m_controls.add(m_mute);
m_controls.add(m_deafen);
m_main.add(m_controls);
m_main.add(m_capture_volume);
m_main.add(m_scroll);
add(m_main);
show_all_children();
Glib::signal_timeout().connect(sigc::mem_fun(*this, &VoiceWindow::UpdateVoiceMeters), 40);
}
void VoiceWindow::SetUsers(const std::unordered_set<Snowflake> &user_ids) {
@@ -130,6 +140,17 @@ void VoiceWindow::OnDeafenChanged() {
m_signal_deafen.emit(m_deafen.get_active());
}
bool VoiceWindow::UpdateVoiceMeters() {
m_capture_volume.set_fraction(Abaddon::Get().GetAudio().GetCaptureVolumeLevel());
for (auto [id, row] : m_rows) {
const auto ssrc = Abaddon::Get().GetDiscordClient().GetSSRCOfUser(id);
if (ssrc.has_value()) {
row->SetVolumeMeter(Abaddon::Get().GetAudio().GetSSRCVolumeLevel(*ssrc));
}
}
return true;
}
void VoiceWindow::OnUserConnect(Snowflake user_id, Snowflake to_channel_id) {
if (m_channel_id == to_channel_id) {
if (auto it = m_rows.find(user_id); it == m_rows.end()) {

View File

@@ -6,11 +6,13 @@
#include <gtkmm/box.h>
#include <gtkmm/checkbutton.h>
#include <gtkmm/listbox.h>
#include <gtkmm/progressbar.h>
#include <gtkmm/scrolledwindow.h>
#include <gtkmm/window.h>
#include <unordered_set>
// clang-format on
class VoiceWindowUserListEntry;
class VoiceWindow : public Gtk::Window {
public:
VoiceWindow(Snowflake channel_id);
@@ -26,6 +28,8 @@ private:
void OnMuteChanged();
void OnDeafenChanged();
bool UpdateVoiceMeters();
Gtk::Box m_main;
Gtk::Box m_controls;
@@ -35,9 +39,11 @@ private:
Gtk::ScrolledWindow m_scroll;
Gtk::ListBox m_user_list;
Gtk::ProgressBar m_capture_volume;
Snowflake m_channel_id;
std::unordered_map<Snowflake, Gtk::ListBoxRow *> m_rows;
std::unordered_map<Snowflake, VoiceWindowUserListEntry *> m_rows;
public:
using type_signal_mute = sigc::signal<void(bool)>;