summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt6
-rw-r--r--README.md22
-rw-r--r--res/fonts/Twemoji-15.0.3.ttfbin0 -> 7409592 bytes
-rw-r--r--res/fonts/TwitterColorEmoji.ttfbin7656676 -> 0 bytes
-rw-r--r--res/fonts/conf.d/10-scale-bitmap-fonts.conf5
-rw-r--r--res/fonts/conf.d/55-emoji-prepend.conf2
-rw-r--r--res/res/emojis.db (renamed from res/res/emojis.bin)bin3434074 -> 4886528 bytes
-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
15 files changed, 62 insertions, 193 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d1b56fc..236dbd2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -38,12 +38,6 @@ if (WIN32)
add_compile_definitions(NOMINMAX)
endif ()
-include(TestBigEndian)
-test_big_endian(IS_BIG_ENDIAN)
-if (IS_BIG_ENDIAN)
- add_compile_definitions(ABADDON_IS_BIG_ENDIAN)
-endif ()
-
configure_file(${PROJECT_SOURCE_DIR}/src/config.h.in ${PROJECT_BINARY_DIR}/config.h)
file(GLOB_RECURSE ABADDON_SOURCES
diff --git a/README.md b/README.md
index 349ab15..c2fab19 100644
--- a/README.md
+++ b/README.md
@@ -87,7 +87,7 @@ the result of fundamental issues with Discord's thread implementation.
#### Linux:
1. Install dependencies
- * On Ubuntu 22.04 (Jammy) and newer:
+ * On Ubuntu 22.04 (Jammy)/Debian 12 (bookworm) and newer:
```Shell
$ sudo apt install g++ cmake libgtkmm-3.0-dev libcurl4-gnutls-dev libsqlite3-dev libssl-dev nlohmann-json3-dev libhandy-1-dev libsecret-1-dev libopus-dev libsodium-dev libspdlog-dev
```
@@ -173,6 +173,9 @@ spam filter's wrath:
### Styling
+<details>
+ <summary>Show all styles</summary>
+
#### CSS selectors
| Selector | Description |
@@ -257,6 +260,8 @@ Used in profile popup:
| `.profile-badges` | Container for badges |
| `.profile-badge` | |
+</details>
+
### Settings
Settings are configured (for now) by editing `abaddon.ini`.
@@ -270,6 +275,9 @@ The format is similar to the standard Windows ini format **except**:
This listing is organized by section.
For example, memory_db would be set by adding `memory_db = true` under the line `[discord]`
+<details>
+ <summary>Show all settings</summary>
+
#### discord
| Setting | Type | Default | Description |
@@ -330,12 +338,10 @@ For example, memory_db would be set by adding `memory_db = true` under the line
#### voice
-| Setting | Type | Default | Description |
-|--------------------------|--------|------------------------------------|----------------------------------------------------------------------------------------------------------------------------|
-| `vad` | string | rnnoise if enabled, gate otherwise | Method used for voice activity detection. Changeable in UI |
-| `backends` | string | empty | Change backend priority when initializing miniaudio: `wasapi;dsound;winmm;coreaudio;sndio;audio4;oss;pulseaudio;alsa;jack` |
-| `jitter_latency_desired` | int | 50 | Desired/Minimum latency for jitter buffer (in milliseconds) |
-| `jitter_latency_maximum` | int | 200 | Maximum latency for jitter buffer before frames are discarded (in milliseconds) |
+| Setting | Type | Default | Description |
+|------------|--------|------------------------------------|----------------------------------------------------------------------------------------------------------------------------|
+| `vad` | string | rnnoise if enabled, gate otherwise | Method used for voice activity detection. Changeable in UI |
+| `backends` | string | empty | Change backend priority when initializing miniaudio: `wasapi;dsound;winmm;coreaudio;sndio;audio4;oss;pulseaudio;alsa;jack` |
#### windows
@@ -349,3 +355,5 @@ For example, memory_db would be set by adding `memory_db = true` under the line
|------------------|------------------------------------------------------------------------------|
| `ABADDON_NO_FC` | (Windows only) don't use custom font config |
| `ABADDON_CONFIG` | change path of configuration file to use. relative to cwd or can be absolute |
+
+</details>
diff --git a/res/fonts/Twemoji-15.0.3.ttf b/res/fonts/Twemoji-15.0.3.ttf
new file mode 100644
index 0000000..402a1d0
--- /dev/null
+++ b/res/fonts/Twemoji-15.0.3.ttf
Binary files differ
diff --git a/res/fonts/TwitterColorEmoji.ttf b/res/fonts/TwitterColorEmoji.ttf
deleted file mode 100644
index 3e41671..0000000
--- a/res/fonts/TwitterColorEmoji.ttf
+++ /dev/null
Binary files differ
diff --git a/res/fonts/conf.d/10-scale-bitmap-fonts.conf b/res/fonts/conf.d/10-scale-bitmap-fonts.conf
index b20b52e..b4e9cb4 100644
--- a/res/fonts/conf.d/10-scale-bitmap-fonts.conf
+++ b/res/fonts/conf.d/10-scale-bitmap-fonts.conf
@@ -12,7 +12,10 @@
<bool>false</bool>
</test>
<edit name="pixelsizefixupfactor" mode="assign">
- <double>0.15</double>
+ <divide>
+ <name target="pattern">pixelsize</name>
+ <name target="font" >pixelsize</name>
+ </divide>
</edit>
</match>
<!--
diff --git a/res/fonts/conf.d/55-emoji-prepend.conf b/res/fonts/conf.d/55-emoji-prepend.conf
index b56cebb..049e6c3 100644
--- a/res/fonts/conf.d/55-emoji-prepend.conf
+++ b/res/fonts/conf.d/55-emoji-prepend.conf
@@ -3,7 +3,7 @@
<fontconfig>
<match>
<edit name="family" mode="prepend" binding="weak">
- <string>Twitter Color Emoji</string>
+ <string>Twemoji 128</string>
</edit>
</match>
</fontconfig> \ No newline at end of file
diff --git a/res/res/emojis.bin b/res/res/emojis.db
index 7694b20..4d34d6f 100644
--- a/res/res/emojis.bin
+++ b/res/res/emojis.db
Binary files differ
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;