feat: integrate Opus codec into lib/libopus + voice messages in chatgui
- Add lib/libopus/ (opus v1.6.1 embedded source: CELT 18 .c, SILK 77 .c, SILK float 28 .c, OPUS core 14 .c) - Add lib/opus_codec.h/.c (wrapper: encoder, decoder, raw PCM int16) - Add tests/test_opus_codec.c (7 tests: silence, sine, compression, PLC, null, defaults, multi-frame) - chatgui: AudioRecorder (miniaudio capture, 48kHz mono) - chatgui: VoiceEncoder (PCM→Opus file with custom container) - chatgui: VoicePlayer (Opus→PCM playback via SoundManager) - chatgui: PTT button in InputBar, voice message send/receive in MessageList - chatgui: AudioDeviceSettingsPage (device selection, persisted in ui_state) - chatgui: MessageDelegate voice message rendering (play button + duration) - Update autotools: configure.ac, Makefile.am, src/Makefile.am, tests/Makefile.am - Update CMake: chatgui CMakeLists.txt, libutun CMakeLists.txt (link libopus_internal.a)
This commit is contained in:
1 parent
4a23593020
commit
4fde0b0325
260 files changed
+72665
-16
No files matched your search
@@ -0,0 +1,95 @@
|
||||
#include "audiodevicesettingspage.h"
|
||||
#include "sound_manager.h"
|
||||
#include "../db/db_manager.h"
|
||||
#include "../transport/gui_bridge.h"
|
||||
#include "../../lib/mem.h"
|
||||
extern "C" {
|
||||
#include "../transport/chat_core.h"
|
||||
}
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QFormLayout>
|
||||
#include <QDebug>
|
||||
|
||||
AudioDeviceSettingsPage::AudioDeviceSettingsPage(DbManager* db, QWidget* parent)
|
||||
: QWidget(parent), m_db(db)
|
||||
{
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 12, 0, 0);
|
||||
|
||||
auto* infoLabel = new QLabel("Select audio devices for playback and recording.\nChanges take effect after restart.", this);
|
||||
infoLabel->setWordWrap(true);
|
||||
infoLabel->setStyleSheet("color: palette(text); font-size: 12px;");
|
||||
layout->addWidget(infoLabel);
|
||||
|
||||
auto* formLayout = new QFormLayout();
|
||||
formLayout->setContentsMargins(0, 16, 0, 0);
|
||||
formLayout->setSpacing(10);
|
||||
|
||||
auto* outLabel = new QLabel("Playback device:", this);
|
||||
m_outputCombo = new QComboBox(this);
|
||||
m_outputCombo->setStyleSheet(
|
||||
"QComboBox { border: 1px solid palette(mid); border-radius: 4px;"
|
||||
" padding: 6px 10px; font-size: 13px; background: palette(base); }");
|
||||
formLayout->addRow(outLabel, m_outputCombo);
|
||||
|
||||
auto* inLabel = new QLabel("Recording device:", this);
|
||||
m_inputCombo = new QComboBox(this);
|
||||
m_inputCombo->setStyleSheet(m_outputCombo->styleSheet());
|
||||
formLayout->addRow(inLabel, m_inputCombo);
|
||||
|
||||
layout->addLayout(formLayout);
|
||||
layout->addStretch();
|
||||
}
|
||||
|
||||
void AudioDeviceSettingsPage::loadFromDb() {
|
||||
auto playbackDevs = SoundManager::enumeratePlaybackDevices();
|
||||
auto captureDevs = SoundManager::enumerateCaptureDevices();
|
||||
|
||||
m_outputCombo->clear();
|
||||
for (int i = 0; i < playbackDevs.size(); i++) {
|
||||
QString label = playbackDevs[i].name;
|
||||
if (playbackDevs[i].isDefault) label += " (default)";
|
||||
m_outputCombo->addItem(label, i);
|
||||
if (playbackDevs[i].isDefault && m_savedOutputIdx < 0) m_savedOutputIdx = i;
|
||||
}
|
||||
|
||||
m_inputCombo->clear();
|
||||
for (int i = 0; i < captureDevs.size(); i++) {
|
||||
QString label = captureDevs[i].name;
|
||||
if (captureDevs[i].isDefault) label += " (default)";
|
||||
m_inputCombo->addItem(label, i);
|
||||
if (captureDevs[i].isDefault && m_savedInputIdx < 0) m_savedInputIdx = i;
|
||||
}
|
||||
|
||||
if (m_db) {
|
||||
m_savedOutputIdx = m_db->getUiStateInt("audio_output_device", m_savedOutputIdx);
|
||||
m_savedInputIdx = m_db->getUiStateInt("audio_input_device", m_savedInputIdx);
|
||||
}
|
||||
|
||||
if (m_savedOutputIdx >= 0 && m_savedOutputIdx < m_outputCombo->count())
|
||||
m_outputCombo->setCurrentIndex(m_savedOutputIdx);
|
||||
if (m_savedInputIdx >= 0 && m_savedInputIdx < m_inputCombo->count())
|
||||
m_inputCombo->setCurrentIndex(m_savedInputIdx);
|
||||
}
|
||||
|
||||
void AudioDeviceSettingsPage::applyAndSave() {
|
||||
int outIdx = m_outputCombo->currentData().toInt();
|
||||
int inIdx = m_inputCombo->currentData().toInt();
|
||||
|
||||
auto saveKey = [](const char* key, int val) {
|
||||
QByteArray v = QByteArray::number(val);
|
||||
size_t klen = strlen(key), vlen = (size_t)v.size();
|
||||
size_t total = klen + 1 + vlen + 1;
|
||||
void* arg = u_malloc(total);
|
||||
memcpy(arg, key, klen + 1);
|
||||
memcpy((char*)arg + klen + 1, v.constData(), vlen + 1);
|
||||
gui_bridge_post_uasync_fn(chat_core_save_ui_state_trampoline, arg);
|
||||
};
|
||||
saveKey("audio_output_device", outIdx);
|
||||
saveKey("audio_input_device", inIdx);
|
||||
|
||||
m_savedOutputIdx = outIdx;
|
||||
m_savedInputIdx = inIdx;
|
||||
qDebug("AudioDeviceSettings: saved output=%d input=%d", outIdx, inIdx);
|
||||
}
|
||||
Reference in new issue
Block a user