add basic combobox to choose output device, start using spdlog
This commit is contained in:
@@ -90,6 +90,9 @@ if (Fontconfig_FOUND)
|
|||||||
target_link_libraries(abaddon Fontconfig::Fontconfig)
|
target_link_libraries(abaddon Fontconfig::Fontconfig)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
find_package(spdlog REQUIRED)
|
||||||
|
target_link_libraries(abaddon spdlog::spdlog)
|
||||||
|
|
||||||
target_link_libraries(abaddon ${SQLite3_LIBRARIES})
|
target_link_libraries(abaddon ${SQLite3_LIBRARIES})
|
||||||
target_link_libraries(abaddon ${GTKMM_LIBRARIES})
|
target_link_libraries(abaddon ${GTKMM_LIBRARIES})
|
||||||
target_link_libraries(abaddon ${CURL_LIBRARIES})
|
target_link_libraries(abaddon ${CURL_LIBRARIES})
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
#include <gtkmm.h>
|
#include <gtkmm.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <spdlog/cfg/env.h>
|
||||||
|
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "platform.hpp"
|
#include "platform.hpp"
|
||||||
@@ -1098,6 +1101,11 @@ int main(int argc, char **argv) {
|
|||||||
if (buf[0] != '1')
|
if (buf[0] != '1')
|
||||||
SetEnvironmentVariableA("GTK_CSD", "0");
|
SetEnvironmentVariableA("GTK_CSD", "0");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
spdlog::cfg::load_env_levels();
|
||||||
|
auto log_audio = spdlog::stdout_color_mt("audio");
|
||||||
|
auto log_voice = spdlog::stdout_color_mt("voice");
|
||||||
|
|
||||||
Gtk::Main::init_gtkmm_internals(); // why???
|
Gtk::Main::init_gtkmm_internals(); // why???
|
||||||
return Abaddon::Get().StartGTK();
|
return Abaddon::Get().StartGTK();
|
||||||
}
|
}
|
||||||
|
33
src/audio/devices.cpp
Normal file
33
src/audio/devices.cpp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#include "devices.hpp"
|
||||||
|
|
||||||
|
AudioDevices::AudioDevices()
|
||||||
|
: m_playback(Gtk::ListStore::create(m_playback_columns)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Glib::RefPtr<Gtk::ListStore> AudioDevices::GetPlaybackDeviceModel() {
|
||||||
|
return m_playback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioDevices::SetDevices(ma_device_info *pPlayback, ma_uint32 playback_count, ma_device_info *pCapture, ma_uint32 capture_count) {
|
||||||
|
m_playback->clear();
|
||||||
|
|
||||||
|
for (ma_uint32 i = 0; i < playback_count; i++) {
|
||||||
|
auto &d = pPlayback[i];
|
||||||
|
auto row = *m_playback->append();
|
||||||
|
row[m_playback_columns.Name] = d.name;
|
||||||
|
row[m_playback_columns.DeviceID] = d.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<ma_device_id> AudioDevices::GetDeviceIDFromModel(const Gtk::TreeModel::iterator &iter) {
|
||||||
|
if (iter) {
|
||||||
|
return static_cast<ma_device_id>((*iter)[m_playback_columns.DeviceID]);
|
||||||
|
} else {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioDevices::PlaybackColumns::PlaybackColumns() {
|
||||||
|
add(Name);
|
||||||
|
add(DeviceID);
|
||||||
|
}
|
26
src/audio/devices.hpp
Normal file
26
src/audio/devices.hpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtkmm/liststore.h>
|
||||||
|
#include <miniaudio.h>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
class AudioDevices {
|
||||||
|
public:
|
||||||
|
AudioDevices();
|
||||||
|
|
||||||
|
Glib::RefPtr<Gtk::ListStore> GetPlaybackDeviceModel();
|
||||||
|
|
||||||
|
void SetDevices(ma_device_info *pPlayback, ma_uint32 playback_count, ma_device_info *pCapture, ma_uint32 capture_count);
|
||||||
|
std::optional<ma_device_id> GetDeviceIDFromModel(const Gtk::TreeModel::iterator &iter);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PlaybackColumns : public Gtk::TreeModel::ColumnRecord {
|
||||||
|
public:
|
||||||
|
PlaybackColumns();
|
||||||
|
|
||||||
|
Gtk::TreeModelColumn<Glib::ustring> Name;
|
||||||
|
Gtk::TreeModelColumn<ma_device_id> DeviceID;
|
||||||
|
};
|
||||||
|
PlaybackColumns m_playback_columns;
|
||||||
|
Glib::RefPtr<Gtk::ListStore> m_playback;
|
||||||
|
};
|
@@ -8,6 +8,7 @@
|
|||||||
#include "manager.hpp"
|
#include "manager.hpp"
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <glibmm/main.h>
|
#include <glibmm/main.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
#define MINIAUDIO_IMPLEMENTATION
|
#define MINIAUDIO_IMPLEMENTATION
|
||||||
#include <miniaudio.h>
|
#include <miniaudio.h>
|
||||||
#include <opus.h>
|
#include <opus.h>
|
||||||
@@ -58,12 +59,20 @@ AudioManager::AudioManager() {
|
|||||||
int err;
|
int err;
|
||||||
m_encoder = opus_encoder_create(48000, 2, OPUS_APPLICATION_VOIP, &err);
|
m_encoder = opus_encoder_create(48000, 2, OPUS_APPLICATION_VOIP, &err);
|
||||||
if (err != OPUS_OK) {
|
if (err != OPUS_OK) {
|
||||||
printf("failed to initialize opus encoder: %d\n", err);
|
spdlog::get("audio")->error("failed to initialize opus encoder: {}", err);
|
||||||
m_ok = false;
|
m_ok = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
opus_encoder_ctl(m_encoder, OPUS_SET_BITRATE(64000));
|
opus_encoder_ctl(m_encoder, OPUS_SET_BITRATE(64000));
|
||||||
|
|
||||||
|
if (ma_context_init(nullptr, 0, nullptr, &m_context) != MA_SUCCESS) {
|
||||||
|
spdlog::get("audio")->error("failed to initialize context");
|
||||||
|
m_ok = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Enumerate();
|
||||||
|
|
||||||
m_device_config = ma_device_config_init(ma_device_type_playback);
|
m_device_config = ma_device_config_init(ma_device_type_playback);
|
||||||
m_device_config.playback.format = ma_format_f32;
|
m_device_config.playback.format = ma_format_f32;
|
||||||
m_device_config.playback.channels = 2;
|
m_device_config.playback.channels = 2;
|
||||||
@@ -72,13 +81,13 @@ AudioManager::AudioManager() {
|
|||||||
m_device_config.pUserData = this;
|
m_device_config.pUserData = this;
|
||||||
|
|
||||||
if (ma_device_init(nullptr, &m_device_config, &m_device) != MA_SUCCESS) {
|
if (ma_device_init(nullptr, &m_device_config, &m_device) != MA_SUCCESS) {
|
||||||
puts("open playback fail");
|
spdlog::get("audio")->error("failed to initialize playback device");
|
||||||
m_ok = false;
|
m_ok = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ma_device_start(&m_device) != MA_SUCCESS) {
|
if (ma_device_start(&m_device) != MA_SUCCESS) {
|
||||||
puts("failed to start playback");
|
spdlog::get("audio")->error("failed to start playback");
|
||||||
ma_device_uninit(&m_device);
|
ma_device_uninit(&m_device);
|
||||||
m_ok = false;
|
m_ok = false;
|
||||||
return;
|
return;
|
||||||
@@ -93,14 +102,14 @@ AudioManager::AudioManager() {
|
|||||||
m_capture_config.pUserData = this;
|
m_capture_config.pUserData = this;
|
||||||
|
|
||||||
if (ma_device_init(nullptr, &m_capture_config, &m_capture_device) != MA_SUCCESS) {
|
if (ma_device_init(nullptr, &m_capture_config, &m_capture_device) != MA_SUCCESS) {
|
||||||
puts("open capture fail");
|
spdlog::get("audio")->error("failed to initialize capture device");
|
||||||
m_ok = false;
|
m_ok = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char device_name[MA_MAX_DEVICE_NAME_LENGTH + 1];
|
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);
|
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);
|
spdlog::get("audio")->info("using {} as capture device", device_name);
|
||||||
|
|
||||||
Glib::signal_timeout().connect(sigc::mem_fun(*this, &AudioManager::DecayVolumeMeters), 40);
|
Glib::signal_timeout().connect(sigc::mem_fun(*this, &AudioManager::DecayVolumeMeters), 40);
|
||||||
}
|
}
|
||||||
@@ -108,6 +117,7 @@ AudioManager::AudioManager() {
|
|||||||
AudioManager::~AudioManager() {
|
AudioManager::~AudioManager() {
|
||||||
ma_device_uninit(&m_device);
|
ma_device_uninit(&m_device);
|
||||||
ma_device_uninit(&m_capture_device);
|
ma_device_uninit(&m_capture_device);
|
||||||
|
ma_context_uninit(&m_context);
|
||||||
RemoveAllSSRCs();
|
RemoveAllSSRCs();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +139,7 @@ void AudioManager::RemoveSSRC(uint32_t ssrc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AudioManager::RemoveAllSSRCs() {
|
void AudioManager::RemoveAllSSRCs() {
|
||||||
puts("remove all ssrc");
|
spdlog::get("audio")->info("removing all ssrc");
|
||||||
std::lock_guard<std::mutex> _(m_mutex);
|
std::lock_guard<std::mutex> _(m_mutex);
|
||||||
for (auto &[ssrc, pair] : m_sources) {
|
for (auto &[ssrc, pair] : m_sources) {
|
||||||
opus_decoder_destroy(pair.second);
|
opus_decoder_destroy(pair.second);
|
||||||
@@ -163,13 +173,45 @@ void AudioManager::FeedMeOpus(uint32_t ssrc, const std::vector<uint8_t> &data) {
|
|||||||
|
|
||||||
void AudioManager::StartCaptureDevice() {
|
void AudioManager::StartCaptureDevice() {
|
||||||
if (ma_device_start(&m_capture_device) != MA_SUCCESS) {
|
if (ma_device_start(&m_capture_device) != MA_SUCCESS) {
|
||||||
puts("failed to start capture");
|
spdlog::get("audio")->error("Failed to start capture device");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioManager::StopCaptureDevice() {
|
void AudioManager::StopCaptureDevice() {
|
||||||
if (ma_device_stop(&m_capture_device) != MA_SUCCESS) {
|
if (ma_device_stop(&m_capture_device) != MA_SUCCESS) {
|
||||||
puts("failed to stop capture");
|
spdlog::get("audio")->error("Failed to stop capture device");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioManager::SetPlaybackDevice(const Gtk::TreeModel::iterator &iter) {
|
||||||
|
spdlog::get("audio")->debug("Setting new playback device");
|
||||||
|
|
||||||
|
const auto device_id = m_devices.GetDeviceIDFromModel(iter);
|
||||||
|
if (!device_id) {
|
||||||
|
spdlog::get("audio")->error("Requested ID from iterator is invalid");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_playback_id = *device_id;
|
||||||
|
|
||||||
|
ma_device_uninit(&m_device);
|
||||||
|
|
||||||
|
m_device_config = ma_device_config_init(ma_device_type_playback);
|
||||||
|
m_device_config.playback.format = ma_format_f32;
|
||||||
|
m_device_config.playback.channels = 2;
|
||||||
|
m_device_config.playback.pDeviceID = &m_playback_id;
|
||||||
|
m_device_config.sampleRate = 48000;
|
||||||
|
m_device_config.dataCallback = data_callback;
|
||||||
|
m_device_config.pUserData = this;
|
||||||
|
|
||||||
|
if (ma_device_init(&m_context, &m_device_config, &m_device) != MA_SUCCESS) {
|
||||||
|
spdlog::get("audio")->error("Failed to initialize new device");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ma_device_start(&m_device) != MA_SUCCESS) {
|
||||||
|
spdlog::get("audio")->error("Failed to start new device");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,6 +247,29 @@ void AudioManager::SetVolumeSSRC(uint32_t ssrc, double volume) {
|
|||||||
m_volume_ssrc[ssrc] = (std::exp(volume) - 1) / (E - 1);
|
m_volume_ssrc[ssrc] = (std::exp(volume) - 1) / (E - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioManager::Enumerate() {
|
||||||
|
ma_device_info *pPlaybackDeviceInfo;
|
||||||
|
ma_uint32 playbackDeviceCount;
|
||||||
|
ma_device_info *pCaptureDeviceInfo;
|
||||||
|
ma_uint32 captureDeviceCount;
|
||||||
|
|
||||||
|
spdlog::get("audio")->debug("Enumerating devices");
|
||||||
|
|
||||||
|
if (ma_context_get_devices(
|
||||||
|
&m_context,
|
||||||
|
&pPlaybackDeviceInfo,
|
||||||
|
&playbackDeviceCount,
|
||||||
|
&pCaptureDeviceInfo,
|
||||||
|
&captureDeviceCount) != MA_SUCCESS) {
|
||||||
|
spdlog::get("audio")->error("Failed to enumerate devices");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
spdlog::get("audio")->debug("Found {} playback devices and {} capture devices", playbackDeviceCount, captureDeviceCount);
|
||||||
|
|
||||||
|
m_devices.SetDevices(pPlaybackDeviceInfo, playbackDeviceCount, pCaptureDeviceInfo, captureDeviceCount);
|
||||||
|
}
|
||||||
|
|
||||||
void AudioManager::OnCapturedPCM(const int16_t *pcm, ma_uint32 frames) {
|
void AudioManager::OnCapturedPCM(const int16_t *pcm, ma_uint32 frames) {
|
||||||
if (m_opus_buffer == nullptr || !m_should_capture) return;
|
if (m_opus_buffer == nullptr || !m_should_capture) return;
|
||||||
|
|
||||||
@@ -222,7 +287,7 @@ void AudioManager::OnCapturedPCM(const int16_t *pcm, ma_uint32 frames) {
|
|||||||
|
|
||||||
int payload_len = opus_encode(m_encoder, new_pcm.data(), 480, static_cast<unsigned char *>(m_opus_buffer), 1275);
|
int payload_len = opus_encode(m_encoder, new_pcm.data(), 480, static_cast<unsigned char *>(m_opus_buffer), 1275);
|
||||||
if (payload_len < 0) {
|
if (payload_len < 0) {
|
||||||
printf("encoding error: %d\n", payload_len);
|
spdlog::get("audio")->error("encoding error: {}", payload_len);
|
||||||
} else {
|
} else {
|
||||||
m_signal_opus_packet.emit(payload_len);
|
m_signal_opus_packet.emit(payload_len);
|
||||||
}
|
}
|
||||||
@@ -275,6 +340,10 @@ double AudioManager::GetSSRCVolumeLevel(uint32_t ssrc) const noexcept {
|
|||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioDevices &AudioManager::GetDevices() {
|
||||||
|
return m_devices;
|
||||||
|
}
|
||||||
|
|
||||||
AudioManager::type_signal_opus_packet AudioManager::signal_opus_packet() {
|
AudioManager::type_signal_opus_packet AudioManager::signal_opus_packet() {
|
||||||
return m_signal_opus_packet;
|
return m_signal_opus_packet;
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include <gtkmm/treemodel.h>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
#include <miniaudio.h>
|
#include <miniaudio.h>
|
||||||
#include <opus.h>
|
#include <opus.h>
|
||||||
#include <sigc++/sigc++.h>
|
#include <sigc++/sigc++.h>
|
||||||
|
#include "devices.hpp"
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
class AudioManager {
|
class AudioManager {
|
||||||
@@ -30,6 +32,8 @@ public:
|
|||||||
void StartCaptureDevice();
|
void StartCaptureDevice();
|
||||||
void StopCaptureDevice();
|
void StopCaptureDevice();
|
||||||
|
|
||||||
|
void SetPlaybackDevice(const Gtk::TreeModel::iterator &iter);
|
||||||
|
|
||||||
void SetCapture(bool capture);
|
void SetCapture(bool capture);
|
||||||
void SetPlayback(bool playback);
|
void SetPlayback(bool playback);
|
||||||
|
|
||||||
@@ -39,11 +43,15 @@ public:
|
|||||||
void SetMuteSSRC(uint32_t ssrc, bool mute);
|
void SetMuteSSRC(uint32_t ssrc, bool mute);
|
||||||
void SetVolumeSSRC(uint32_t ssrc, double volume);
|
void SetVolumeSSRC(uint32_t ssrc, double volume);
|
||||||
|
|
||||||
|
void Enumerate();
|
||||||
|
|
||||||
[[nodiscard]] bool OK() const;
|
[[nodiscard]] bool OK() const;
|
||||||
|
|
||||||
[[nodiscard]] double GetCaptureVolumeLevel() const noexcept;
|
[[nodiscard]] double GetCaptureVolumeLevel() const noexcept;
|
||||||
[[nodiscard]] double GetSSRCVolumeLevel(uint32_t ssrc) const noexcept;
|
[[nodiscard]] double GetSSRCVolumeLevel(uint32_t ssrc) const noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]] AudioDevices &GetDevices();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnCapturedPCM(const int16_t *pcm, ma_uint32 frames);
|
void OnCapturedPCM(const int16_t *pcm, ma_uint32 frames);
|
||||||
|
|
||||||
@@ -63,10 +71,13 @@ private:
|
|||||||
// playback
|
// playback
|
||||||
ma_device m_device;
|
ma_device m_device;
|
||||||
ma_device_config m_device_config;
|
ma_device_config m_device_config;
|
||||||
|
ma_device_id m_playback_id;
|
||||||
// capture
|
// capture
|
||||||
ma_device m_capture_device;
|
ma_device m_capture_device;
|
||||||
ma_device_config m_capture_config;
|
ma_device_config m_capture_config;
|
||||||
|
|
||||||
|
ma_context m_context;
|
||||||
|
|
||||||
mutable std::mutex m_mutex;
|
mutable std::mutex m_mutex;
|
||||||
std::unordered_map<uint32_t, std::pair<std::deque<int16_t>, OpusDecoder *>> m_sources;
|
std::unordered_map<uint32_t, std::pair<std::deque<int16_t>, OpusDecoder *>> m_sources;
|
||||||
|
|
||||||
@@ -86,6 +97,8 @@ private:
|
|||||||
mutable std::mutex m_vol_mtx;
|
mutable std::mutex m_vol_mtx;
|
||||||
std::unordered_map<uint32_t, double> m_volumes;
|
std::unordered_map<uint32_t, double> m_volumes;
|
||||||
|
|
||||||
|
AudioDevices m_devices;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using type_signal_opus_packet = sigc::signal<void(int payload_size)>;
|
using type_signal_opus_packet = sigc::signal<void(int payload_size)>;
|
||||||
type_signal_opus_packet signal_opus_packet();
|
type_signal_opus_packet signal_opus_packet();
|
||||||
|
@@ -4,6 +4,8 @@
|
|||||||
#include "voiceclient.hpp"
|
#include "voiceclient.hpp"
|
||||||
#include "json.hpp"
|
#include "json.hpp"
|
||||||
#include <sodium.h>
|
#include <sodium.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <spdlog/fmt/bin_to_hex.h>
|
||||||
#include "abaddon.hpp"
|
#include "abaddon.hpp"
|
||||||
#include "audio/manager.hpp"
|
#include "audio/manager.hpp"
|
||||||
|
|
||||||
@@ -127,11 +129,11 @@ DiscordVoiceClient::DiscordVoiceClient() {
|
|||||||
sodium_init();
|
sodium_init();
|
||||||
|
|
||||||
m_ws.signal_open().connect([this]() {
|
m_ws.signal_open().connect([this]() {
|
||||||
puts("vws open");
|
spdlog::get("voice")->info("Websocket open");
|
||||||
});
|
});
|
||||||
|
|
||||||
m_ws.signal_close().connect([this](uint16_t code) {
|
m_ws.signal_close().connect([this](uint16_t code) {
|
||||||
printf("vws close %u\n", code);
|
spdlog::get("voice")->info("Websocket closed with code {}", code);
|
||||||
Stop();
|
Stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -258,9 +260,9 @@ void DiscordVoiceClient::HandleGatewayReady(const VoiceGatewayMessage &m) {
|
|||||||
m_port = d.Port;
|
m_port = d.Port;
|
||||||
m_ssrc = d.SSRC;
|
m_ssrc = d.SSRC;
|
||||||
if (std::find(d.Modes.begin(), d.Modes.end(), "xsalsa20_poly1305") == d.Modes.end()) {
|
if (std::find(d.Modes.begin(), d.Modes.end(), "xsalsa20_poly1305") == d.Modes.end()) {
|
||||||
puts("xsalsa20_poly1305 not in encryption modes");
|
spdlog::get("voice")->error("xsalsa20_poly1305 not in encryption modes");
|
||||||
}
|
}
|
||||||
printf("connect to %s:%u ssrc %u\n", m_ip.c_str(), m_port, m_ssrc);
|
spdlog::get("voice")->info("connect to {}:{} ssrc {}", m_ip, m_port, m_ssrc);
|
||||||
|
|
||||||
m_udp.Connect(m_ip, m_port);
|
m_udp.Connect(m_ip, m_port);
|
||||||
m_keepalive_thread = std::thread(&DiscordVoiceClient::KeepaliveThread, this);
|
m_keepalive_thread = std::thread(&DiscordVoiceClient::KeepaliveThread, this);
|
||||||
@@ -270,11 +272,7 @@ void DiscordVoiceClient::HandleGatewayReady(const VoiceGatewayMessage &m) {
|
|||||||
|
|
||||||
void DiscordVoiceClient::HandleGatewaySessionDescription(const VoiceGatewayMessage &m) {
|
void DiscordVoiceClient::HandleGatewaySessionDescription(const VoiceGatewayMessage &m) {
|
||||||
VoiceSessionDescriptionData d = m.Data;
|
VoiceSessionDescriptionData d = m.Data;
|
||||||
printf("receiving with %s secret key: ", d.Mode.c_str());
|
spdlog::get("voice")->debug("receiving with {}, secret key: {:ns}", d.Mode, spdlog::to_hex(std::begin(d.SecretKey), std::end(d.SecretKey)));
|
||||||
for (auto b : d.SecretKey) {
|
|
||||||
printf("%02X", b);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
VoiceSpeakingMessage msg;
|
VoiceSpeakingMessage msg;
|
||||||
msg.Delay = 0;
|
msg.Delay = 0;
|
||||||
@@ -330,10 +328,10 @@ void DiscordVoiceClient::Discovery() {
|
|||||||
if (response.size() >= 74 && response[0] == 0x00 && response[1] == 0x02) {
|
if (response.size() >= 74 && response[0] == 0x00 && response[1] == 0x02) {
|
||||||
const char *our_ip = reinterpret_cast<const char *>(&response[8]);
|
const char *our_ip = reinterpret_cast<const char *>(&response[8]);
|
||||||
uint16_t our_port = (response[73] << 8) | response[74];
|
uint16_t our_port = (response[73] << 8) | response[74];
|
||||||
printf("we are %s:%u\n", our_ip, our_port);
|
spdlog::get("voice")->debug("IP address discovered: {}:{}\n", our_ip, our_port);
|
||||||
SelectProtocol(our_ip, our_port);
|
SelectProtocol(our_ip, our_port);
|
||||||
} else {
|
} else {
|
||||||
puts("received non-discovery packet after discovery");
|
spdlog::get("voice")->error("Received non-discovery packet after discovery");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,7 +353,7 @@ void DiscordVoiceClient::OnUDPData(std::vector<uint8_t> data) {
|
|||||||
static std::array<uint8_t, 24> nonce = {};
|
static std::array<uint8_t, 24> nonce = {};
|
||||||
std::memcpy(nonce.data(), data.data(), 12);
|
std::memcpy(nonce.data(), data.data(), 12);
|
||||||
if (crypto_secretbox_open_easy(payload, payload, data.size() - 12, nonce.data(), m_secret_key.data())) {
|
if (crypto_secretbox_open_easy(payload, payload, data.size() - 12, nonce.data(), m_secret_key.data())) {
|
||||||
puts("decrypt fail");
|
// spdlog::get("voice")->trace("UDP payload decryption failure");
|
||||||
} else {
|
} else {
|
||||||
Abaddon::Get().GetAudio().FeedMeOpus(ssrc, { payload, payload + data.size() - 12 - crypto_box_MACBYTES });
|
Abaddon::Get().GetAudio().FeedMeOpus(ssrc, { payload, payload + data.size() - 12 - crypto_box_MACBYTES });
|
||||||
}
|
}
|
||||||
|
@@ -121,6 +121,17 @@ VoiceWindow::VoiceWindow(Snowflake channel_id)
|
|||||||
m_signal_gain.emit(val / 100.0);
|
m_signal_gain.emit(val / 100.0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
auto *renderer = Gtk::make_managed<Gtk::CellRendererText>();
|
||||||
|
m_playback_combo.set_valign(Gtk::ALIGN_END);
|
||||||
|
m_playback_combo.set_hexpand(true);
|
||||||
|
m_playback_combo.set_halign(Gtk::ALIGN_FILL);
|
||||||
|
m_playback_combo.set_model(Abaddon::Get().GetAudio().GetDevices().GetPlaybackDeviceModel());
|
||||||
|
m_playback_combo.pack_start(*renderer);
|
||||||
|
m_playback_combo.add_attribute(*renderer, "text", 0);
|
||||||
|
m_playback_combo.signal_changed().connect([this]() {
|
||||||
|
Abaddon::Get().GetAudio().SetPlaybackDevice(m_playback_combo.get_active());
|
||||||
|
});
|
||||||
|
|
||||||
m_scroll.add(m_user_list);
|
m_scroll.add(m_user_list);
|
||||||
m_controls.add(m_mute);
|
m_controls.add(m_mute);
|
||||||
m_controls.add(m_deafen);
|
m_controls.add(m_deafen);
|
||||||
@@ -129,6 +140,7 @@ VoiceWindow::VoiceWindow(Snowflake channel_id)
|
|||||||
m_main.add(m_capture_gate);
|
m_main.add(m_capture_gate);
|
||||||
m_main.add(m_capture_gain);
|
m_main.add(m_capture_gain);
|
||||||
m_main.add(m_scroll);
|
m_main.add(m_scroll);
|
||||||
|
m_main.add(m_playback_combo);
|
||||||
add(m_main);
|
add(m_main);
|
||||||
show_all_children();
|
show_all_children();
|
||||||
|
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
#include "discord/snowflake.hpp"
|
#include "discord/snowflake.hpp"
|
||||||
#include <gtkmm/box.h>
|
#include <gtkmm/box.h>
|
||||||
#include <gtkmm/checkbutton.h>
|
#include <gtkmm/checkbutton.h>
|
||||||
|
#include <gtkmm/combobox.h>
|
||||||
#include <gtkmm/listbox.h>
|
#include <gtkmm/listbox.h>
|
||||||
#include <gtkmm/progressbar.h>
|
#include <gtkmm/progressbar.h>
|
||||||
#include <gtkmm/scale.h>
|
#include <gtkmm/scale.h>
|
||||||
@@ -45,6 +46,8 @@ private:
|
|||||||
Gtk::Scale m_capture_gate;
|
Gtk::Scale m_capture_gate;
|
||||||
Gtk::Scale m_capture_gain;
|
Gtk::Scale m_capture_gain;
|
||||||
|
|
||||||
|
Gtk::ComboBox m_playback_combo;
|
||||||
|
|
||||||
Snowflake m_channel_id;
|
Snowflake m_channel_id;
|
||||||
|
|
||||||
std::unordered_map<Snowflake, VoiceWindowUserListEntry *> m_rows;
|
std::unordered_map<Snowflake, VoiceWindowUserListEntry *> m_rows;
|
||||||
|
Reference in New Issue
Block a user