summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorouwou <26526779+ouwou@users.noreply.github.com>2024-04-13 22:34:50 -0400
committerouwou <26526779+ouwou@users.noreply.github.com>2024-04-13 22:34:50 -0400
commit02fd49b0736f74cc22dc3c9b16d904334d017dce (patch)
tree4257dba34b011163fb0abb0af096c3982958aa8c /src
parent565213450a891d728b3b46102e3c485cdfa86844 (diff)
parent5e382b11dce3892a3b6d2ea42bc3be0db79c2ef5 (diff)
downloadabaddon-portaudio-02fd49b0736f74cc22dc3c9b16d904334d017dce.tar.gz
abaddon-portaudio-02fd49b0736f74cc22dc3c9b16d904334d017dce.zip
Merge branch 'master' into stages
Diffstat (limited to 'src')
-rw-r--r--src/abaddon.cpp2
-rw-r--r--src/audio/jitterbuffer.hpp82
-rw-r--r--src/audio/manager.cpp22
-rw-r--r--src/audio/manager.hpp3
-rw-r--r--src/emojis.cpp96
-rw-r--r--src/emojis.hpp11
-rw-r--r--src/settings.cpp2
-rw-r--r--src/settings.hpp2
8 files changed, 42 insertions, 178 deletions
diff --git a/src/abaddon.cpp b/src/abaddon.cpp
index 486d526..fb8cc89 100644
--- a/src/abaddon.cpp
+++ b/src/abaddon.cpp
@@ -53,7 +53,7 @@ void macOSThemeChangedCallback(CFNotificationCenterRef center, void *observer, C
Abaddon::Abaddon()
: m_settings(Platform::FindConfigFile())
, m_discord(GetSettings().UseMemoryDB) // stupid but easy
- , m_emojis(GetResPath("/emojis.bin"))
+ , m_emojis(GetResPath("/emojis.db"))
#ifdef WITH_VOICE
, m_audio(GetSettings().Backends)
#endif
diff --git a/src/audio/jitterbuffer.hpp b/src/audio/jitterbuffer.hpp
deleted file mode 100644
index 3da3594..0000000
--- a/src/audio/jitterbuffer.hpp
+++ /dev/null
@@ -1,82 +0,0 @@
-#pragma once
-#include <chrono>
-#include <cstdint>
-#include <deque>
-
-// very simple non-RTP-based jitter buffer. does not handle out-of-order
-template<typename SampleFormat>
-class JitterBuffer {
-public:
- /*
- * desired_latency: how many milliseconds before audio can be drawn from buffer
- * maximum_latency: how many milliseconds before old audio starts to be discarded
- */
- JitterBuffer(int desired_latency, int maximum_latency, int channels, int sample_rate)
- : m_desired_latency(desired_latency)
- , m_maximum_latency(maximum_latency)
- , m_channels(channels)
- , m_sample_rate(sample_rate)
- , m_last_push(std::chrono::steady_clock::now()) {
- }
-
- [[nodiscard]] size_t Available() const noexcept {
- return m_samples.size();
- }
-
- bool PopSamples(SampleFormat *ptr, size_t amount) {
- CheckBuffering();
- if (m_buffering || Available() < amount) return false;
- std::copy(m_samples.begin(), m_samples.begin() + amount, ptr);
- m_samples.erase(m_samples.begin(), m_samples.begin() + amount);
- return true;
- }
-
- void PushSamples(SampleFormat *ptr, size_t amount) {
- m_samples.insert(m_samples.end(), ptr, ptr + amount);
- m_last_push = std::chrono::steady_clock::now();
- const auto buffered = MillisBuffered();
- if (buffered > m_maximum_latency) {
- const auto overflow_ms = MillisBuffered() - m_maximum_latency;
- const auto overflow_samples = overflow_ms * m_channels * m_sample_rate / 1000;
- m_samples.erase(m_samples.begin(), m_samples.begin() + overflow_samples);
- }
- }
-
-private:
- [[nodiscard]] size_t MillisBuffered() const {
- return m_samples.size() * 1000 / m_channels / m_sample_rate;
- }
-
- void CheckBuffering() {
- // if we arent buffering but the buffer is empty then we should be
- if (m_samples.empty()) {
- if (!m_buffering) {
- m_buffering = true;
- }
- return;
- }
-
- if (!m_buffering) return;
-
- // if we reached desired latency, we are sufficiently buffered
- const auto millis_buffered = MillisBuffered();
- if (millis_buffered >= m_desired_latency) {
- m_buffering = false;
- }
- // if we havent buffered to desired latency but max latency has elapsed, exit buffering so it doesnt get stuck
- const auto now = std::chrono::steady_clock::now();
- const auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_last_push).count();
- if (millis >= m_maximum_latency) {
- m_buffering = false;
- }
- }
-
- int m_desired_latency;
- int m_maximum_latency;
- int m_channels;
- int m_sample_rate;
- bool m_buffering = true;
- std::chrono::time_point<std::chrono::steady_clock> m_last_push;
-
- std::deque<SampleFormat> m_samples;
-};
diff --git a/src/audio/manager.cpp b/src/audio/manager.cpp
index f9ffdd5..33730d9 100644
--- a/src/audio/manager.cpp
+++ b/src/audio/manager.cpp
@@ -26,7 +26,6 @@ const uint8_t *StripRTPExtensionHeader(const uint8_t *buf, int num_bytes, size_t
return buf;
}
-// frameCount is configured to be 480 samples per channel
void data_callback(ma_device *pDevice, void *pOutput, const void *pInput, ma_uint32 frameCount) {
AudioManager *mgr = reinterpret_cast<AudioManager *>(pDevice->pUserData);
if (mgr == nullptr) return;
@@ -38,14 +37,12 @@ void data_callback(ma_device *pDevice, void *pOutput, const void *pInput, ma_uin
if (const auto vol_it = mgr->m_volume_ssrc.find(ssrc); vol_it != mgr->m_volume_ssrc.end()) {
volume = vol_it->second;
}
-
- static std::array<int16_t, 480 * 2> buf;
-
- if (!pair.first.PopSamples(buf.data(), 480 * 2)) continue;
-
- for (size_t i = 0; i < 480 * 2; i++) {
+ auto &buf = pair.first;
+ const size_t n = std::min(static_cast<size_t>(buf.size()), static_cast<size_t>(frameCount * 2ULL));
+ for (size_t i = 0; i < n; i++) {
pOutputF32[i] += volume * buf[i] / 32768.F;
}
+ buf.erase(buf.begin(), buf.begin() + n);
}
}
@@ -205,14 +202,7 @@ void AudioManager::AddSSRC(uint32_t ssrc) {
int error;
if (m_sources.find(ssrc) == m_sources.end()) {
auto *decoder = opus_decoder_create(48000, 2, &error);
- auto &s = Abaddon::Get().GetSettings();
- m_sources.insert(std::make_pair(ssrc, std::make_pair(
- JitterBuffer<int16_t>(
- s.JitterDesiredLatency,
- s.JitterMaximumLatency,
- 2,
- 48000),
- decoder)));
+ m_sources.insert(std::make_pair(ssrc, std::make_pair(std::deque<int16_t> {}, decoder)));
}
}
@@ -252,7 +242,7 @@ void AudioManager::FeedMeOpus(uint32_t ssrc, const std::vector<uint8_t> &data) {
} else {
UpdateReceiveVolume(ssrc, pcm.data(), decoded);
auto &buf = it->second.first;
- buf.PushSamples(pcm.data(), decoded * 2);
+ buf.insert(buf.end(), pcm.begin(), pcm.begin() + decoded * 2);
}
}
}
diff --git a/src/audio/manager.hpp b/src/audio/manager.hpp
index 56882fd..5716fc5 100644
--- a/src/audio/manager.hpp
+++ b/src/audio/manager.hpp
@@ -21,7 +21,6 @@
#endif
#include "devices.hpp"
-#include "jitterbuffer.hpp"
// clang-format on
class AudioManager {
@@ -137,7 +136,7 @@ private:
mutable std::mutex m_rnn_mutex;
#endif
- std::unordered_map<uint32_t, std::pair<JitterBuffer<int16_t>, OpusDecoder *>> m_sources;
+ std::unordered_map<uint32_t, std::pair<std::deque<int16_t>, OpusDecoder *>> m_sources;
OpusEncoder *m_encoder;
diff --git a/src/emojis.cpp b/src/emojis.cpp
index 7e33949..a8d571e 100644
--- a/src/emojis.cpp
+++ b/src/emojis.cpp
@@ -5,90 +5,48 @@
#include <gdkmm/pixbufloader.h>
-#ifdef ABADDON_IS_BIG_ENDIAN
-/* Allows processing emojis.bin correctly on big-endian systems. */
-int emojis_int32_correct_endian(int little_endian_in) {
- /* this does the same thing as __bswap_32() but can be done without
- non-standard headers. */
- return ((little_endian_in >> 24) & 0xff) | // move byte 3 to byte 0
- ((little_endian_in << 8) & 0xff0000) | // move byte 1 to byte 2
- ((little_endian_in >> 8) & 0xff00) | // move byte 2 to byte 1
- ((little_endian_in << 24) & 0xff000000); // byte 0 to byte 3
-}
-#else
-int emojis_int32_correct_endian(int little_endian_in) {
- return little_endian_in;
-}
-#endif
-
EmojiResource::EmojiResource(std::string filepath)
: m_filepath(std::move(filepath)) {}
-bool EmojiResource::Load() {
- m_fp = std::fopen(m_filepath.c_str(), "rb");
- if (m_fp == nullptr) return false;
-
- int index_offset;
- std::fread(&index_offset, 4, 1, m_fp);
- index_offset = emojis_int32_correct_endian(index_offset);
- std::fseek(m_fp, index_offset, SEEK_SET);
-
- int emojis_count;
- std::fread(&emojis_count, 4, 1, m_fp);
- emojis_count = emojis_int32_correct_endian(emojis_count);
- for (int i = 0; i < emojis_count; i++) {
- std::vector<std::string> shortcodes;
-
- int shortcodes_count;
- std::fread(&shortcodes_count, 4, 1, m_fp);
- shortcodes_count = emojis_int32_correct_endian(shortcodes_count);
- for (int j = 0; j < shortcodes_count; j++) {
- int shortcode_length;
- std::fread(&shortcode_length, 4, 1, m_fp);
- shortcode_length = emojis_int32_correct_endian(shortcode_length);
- std::string shortcode(shortcode_length, '\0');
- std::fread(shortcode.data(), shortcode_length, 1, m_fp);
- shortcodes.push_back(std::move(shortcode));
- }
-
- int surrogates_count;
- std::fread(&surrogates_count, 4, 1, m_fp);
- surrogates_count = emojis_int32_correct_endian(surrogates_count);
- std::string surrogates(surrogates_count, '\0');
- std::fread(surrogates.data(), surrogates_count, 1, m_fp);
- m_patterns.emplace_back(surrogates);
+EmojiResource::~EmojiResource() {
+ sqlite3_finalize(m_get_emoji_stmt);
+ sqlite3_close(m_db);
+}
- int data_size, data_offset;
- std::fread(&data_size, 4, 1, m_fp);
- data_size = emojis_int32_correct_endian(data_size);
- std::fread(&data_offset, 4, 1, m_fp);
- data_offset = emojis_int32_correct_endian(data_offset);
- m_index[surrogates] = { data_offset, data_size };
+bool EmojiResource::Load() {
+ if (sqlite3_open(m_filepath.c_str(), &m_db) != SQLITE_OK) return false;
- for (const auto &shortcode : shortcodes)
- m_shortcode_index[shortcode] = surrogates;
+ if (sqlite3_prepare_v2(m_db, "SELECT data FROM emoji_data WHERE emoji = ?", -1, &m_get_emoji_stmt, nullptr) != SQLITE_OK) return false;
- m_pattern_shortcode_index[surrogates] = std::move(shortcodes);
+ sqlite3_stmt *stmt;
+ if (sqlite3_prepare_v2(m_db, "SELECT * FROM emoji_shortcodes", -1, &stmt, nullptr) != SQLITE_OK) return false;
+ while (sqlite3_step(stmt) == SQLITE_ROW) {
+ std::string shortcode = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0));
+ std::string emoji = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1));
+ m_shortcode_index[shortcode] = emoji;
+ m_pattern_shortcode_index[emoji].push_back(shortcode);
}
+ sqlite3_finalize(stmt);
std::sort(m_patterns.begin(), m_patterns.end(), [](const Glib::ustring &a, const Glib::ustring &b) {
return a.size() > b.size();
});
+
return true;
}
Glib::RefPtr<Gdk::Pixbuf> EmojiResource::GetPixBuf(const Glib::ustring &pattern) {
- const auto it = m_index.find(pattern);
- if (it == m_index.end()) return {};
- const int pos = it->second.first;
- const int len = it->second.second;
- std::fseek(m_fp, pos, SEEK_SET);
- std::vector<uint8_t> data(len);
- std::fread(data.data(), len, 1, m_fp);
- auto loader = Gdk::PixbufLoader::create();
- loader->write(static_cast<const guint8 *>(data.data()), data.size());
- loader->close();
- return loader->get_pixbuf();
+ if (sqlite3_reset(m_get_emoji_stmt) != SQLITE_OK) return {};
+ if (sqlite3_bind_text(m_get_emoji_stmt, 1, pattern.c_str(), -1, nullptr) != SQLITE_OK) return {};
+ if (sqlite3_step(m_get_emoji_stmt) != SQLITE_ROW) return {};
+ if (const void *blob = sqlite3_column_blob(m_get_emoji_stmt, 0)) {
+ const int bytes = sqlite3_column_bytes(m_get_emoji_stmt, 0);
+ auto loader = Gdk::PixbufLoader::create();
+ loader->write(static_cast<const guint8 *>(blob), bytes);
+ loader->close();
+ return loader->get_pixbuf();
+ }
+ return {};
}
void EmojiResource::ReplaceEmojis(Glib::RefPtr<Gtk::TextBuffer> buf, int size) {
diff --git a/src/emojis.hpp b/src/emojis.hpp
index a41b8ac..c0de316 100644
--- a/src/emojis.hpp
+++ b/src/emojis.hpp
@@ -8,11 +8,13 @@
#include <gdkmm/pixbuf.h>
#include <gtkmm/textbuffer.h>
-// shoutout to gtk for only supporting .svg's sometimes
+#include <sqlite3.h>
class EmojiResource {
public:
EmojiResource(std::string filepath);
+ ~EmojiResource();
+
bool Load();
Glib::RefPtr<Gdk::Pixbuf> GetPixBuf(const Glib::ustring &pattern);
const std::map<std::string, std::string> &GetShortCodes() const;
@@ -21,9 +23,10 @@ public:
private:
std::unordered_map<std::string, std::vector<std::string>> m_pattern_shortcode_index;
- std::map<std::string, std::string> m_shortcode_index; // shortcode -> pattern
- std::unordered_map<std::string, std::pair<int, int>> m_index; // pattern -> [pos, len]
- FILE *m_fp = nullptr;
+ std::map<std::string, std::string> m_shortcode_index; // shortcode -> pattern
std::string m_filepath;
std::vector<Glib::ustring> m_patterns;
+
+ sqlite3 *m_db = nullptr;
+ sqlite3_stmt *m_get_emoji_stmt = nullptr;
};
diff --git a/src/settings.cpp b/src/settings.cpp
index 6dab229..fc76ddb 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -130,8 +130,6 @@ void SettingsManager::DefineSettings() {
AddSetting("voice", "vad", "gate"s, &Settings::VAD);
#endif
AddSetting("voice", "backends", ""s, &Settings::Backends);
- AddSetting("voice", "jitter_latency_desired", 50, &Settings::JitterDesiredLatency);
- AddSetting("voice", "jitter_latency_maximum", 200, &Settings::JitterMaximumLatency);
}
void SettingsManager::ReadSettings() {
diff --git a/src/settings.hpp b/src/settings.hpp
index 0b0f6e2..5805452 100644
--- a/src/settings.hpp
+++ b/src/settings.hpp
@@ -52,8 +52,6 @@ public:
// [voice]
std::string VAD;
std::string Backends;
- int JitterDesiredLatency;
- int JitterMaximumLatency;
// [windows]
bool HideConsole;