|
|
|
|
@ -14,6 +14,7 @@ extern "C" {
|
|
|
|
|
#include "../../lib/mem.h" |
|
|
|
|
extern "C" { |
|
|
|
|
#include "chat/chat_core.h" |
|
|
|
|
#include "call/call_video_rate.h" |
|
|
|
|
} |
|
|
|
|
#include <QVBoxLayout> |
|
|
|
|
#include <QHBoxLayout> |
|
|
|
|
@ -22,6 +23,8 @@ extern "C" {
|
|
|
|
|
#include <QFrame> |
|
|
|
|
#include <QDebug> |
|
|
|
|
#include <QDoubleSpinBox> |
|
|
|
|
#include <QSpinBox> |
|
|
|
|
#include <QMessageBox> |
|
|
|
|
#include <cmath> |
|
|
|
|
|
|
|
|
|
AudioDeviceSettingsPage::AudioDeviceSettingsPage(DbManager* db, AudioRecorder* recorder, QWidget* parent) |
|
|
|
|
@ -163,7 +166,24 @@ AudioDeviceSettingsPage::AudioDeviceSettingsPage(DbManager* db, AudioRecorder* r
|
|
|
|
|
m_jitterReserveSpin->setSuffix(QCoreApplication::translate("ChatGui", " s")); |
|
|
|
|
m_jitterReserveSpin->setToolTip(QCoreApplication::translate("ChatGui", "Maximum adaptive jitter reserve for calls. Applies to the next call.")); |
|
|
|
|
callForm->addRow(QCoreApplication::translate("ChatGui", "Call: maximum jitter reserve"), m_jitterReserveSpin); |
|
|
|
|
m_videoMinimumSpin = new QSpinBox(this); |
|
|
|
|
m_videoMaximumSpin = new QSpinBox(this); |
|
|
|
|
for (auto* spin : {m_videoMinimumSpin, m_videoMaximumSpin}) { |
|
|
|
|
spin->setRange(CALL_VIDEO_RATE_MIN_BPS / 1000, CALL_VIDEO_RATE_MAX_BPS / 1000); |
|
|
|
|
spin->setSingleStep(100); |
|
|
|
|
spin->setSuffix(QCoreApplication::translate("ChatGui", " kbit/s")); |
|
|
|
|
} |
|
|
|
|
m_videoMinimumSpin->setValue(CALL_VIDEO_RATE_MIN_BPS / 1000); |
|
|
|
|
m_videoMaximumSpin->setValue(CALL_VIDEO_RATE_MAX_BPS / 1000); |
|
|
|
|
connect(m_videoMinimumSpin, QOverload<int>::of(&QSpinBox::valueChanged), m_videoMaximumSpin, &QSpinBox::setMinimum); |
|
|
|
|
connect(m_videoMaximumSpin, QOverload<int>::of(&QSpinBox::valueChanged), m_videoMinimumSpin, &QSpinBox::setMaximum); |
|
|
|
|
callForm->addRow(QCoreApplication::translate("ChatGui", "Call video: minimum bitrate"), m_videoMinimumSpin); |
|
|
|
|
callForm->addRow(QCoreApplication::translate("ChatGui", "Call video: maximum bitrate"), m_videoMaximumSpin); |
|
|
|
|
layout->addLayout(callForm); |
|
|
|
|
auto* videoHint = new QLabel(QCoreApplication::translate("ChatGui", |
|
|
|
|
"Video bitrate adapts to the connection within this range. Default: 300–4000 kbit/s."), this); |
|
|
|
|
videoHint->setWordWrap(true); |
|
|
|
|
layout->addWidget(videoHint); |
|
|
|
|
|
|
|
|
|
buildCompressorUI(layout); |
|
|
|
|
|
|
|
|
|
@ -211,6 +231,12 @@ void AudioDeviceSettingsPage::loadFromDb() {
|
|
|
|
|
m_savedCompressorMaxGainDb = m_db->getUiStateInt("compressor_max_gain_db", 25); |
|
|
|
|
m_savedCompressorRiseRate = m_db->getUiStateInt("compressor_rise_rate", 10); |
|
|
|
|
m_jitterReserveSpin->setValue(m_db->getUiStateInt("call_jitter_max_reserve_ms", 1000) / 1000.0); |
|
|
|
|
QByteArray range = m_db->getUiState("call_video_bitrate_range_kbps").toUtf8(); |
|
|
|
|
uint32_t minimum = CALL_VIDEO_RATE_MIN_BPS, maximum = CALL_VIDEO_RATE_MAX_BPS; |
|
|
|
|
if (!range.isEmpty()) call_video_rate_parse_range(range.constData(), &minimum, &maximum); |
|
|
|
|
m_videoMinimumSpin->setValue(CALL_VIDEO_RATE_MIN_BPS / 1000); |
|
|
|
|
m_videoMaximumSpin->setValue(maximum / 1000); |
|
|
|
|
m_videoMinimumSpin->setValue(minimum / 1000); |
|
|
|
|
m_savedAecEnabled = m_db->getUiStateInt("aec_enabled", 1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -245,6 +271,21 @@ void AudioDeviceSettingsPage::loadFromDb() {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void AudioDeviceSettingsPage::applyAndSave() { |
|
|
|
|
const char* rangeKey = "call_video_bitrate_range_kbps"; |
|
|
|
|
QString range = QStringLiteral("%1:%2").arg(m_videoMinimumSpin->value()).arg(m_videoMaximumSpin->value()); |
|
|
|
|
if (!m_configPath.isEmpty() && !config_update_option(m_configPath, "chatserver", rangeKey, range)) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video bitrate range config save failed path=%s", qPrintable(m_configPath)); |
|
|
|
|
QMessageBox::warning(this, QCoreApplication::translate("ChatGui", "Settings"), |
|
|
|
|
QCoreApplication::translate("ChatGui", "Could not save the call video bitrate range.")); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
auto* rangeArg = static_cast<chat_setting_arg*>(u_calloc(1, sizeof(chat_setting_arg))); |
|
|
|
|
if (!rangeArg) { DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video bitrate range command allocation failed"); return; } |
|
|
|
|
rangeArg->inst = gui_bridge_get_inst(); |
|
|
|
|
memcpy(rangeArg->data, rangeKey, strlen(rangeKey) + 1); |
|
|
|
|
QByteArray rangeBytes = range.toUtf8(); |
|
|
|
|
memcpy(rangeArg->data + strlen(rangeKey) + 1, rangeBytes.constData(), rangeBytes.size() + 1); |
|
|
|
|
gui_bridge_post_uasync_fn(chat_core_set_setting_trampoline, rangeArg); |
|
|
|
|
QString outputId = m_outputCombo->currentData().toString(); |
|
|
|
|
QString inputId = m_inputCombo->currentData().toString(); |
|
|
|
|
int codecPreset = m_codecPresetCombo->currentData().toInt(); |
|
|
|
|
@ -261,13 +302,13 @@ void AudioDeviceSettingsPage::applyAndSave() {
|
|
|
|
|
memcpy(arg->data + klen + 1, v.constData(), vlen + 1); |
|
|
|
|
gui_bridge_post_uasync_fn(chat_core_save_ui_state_trampoline, arg); |
|
|
|
|
}; |
|
|
|
|
auto saveDevice = [](const char* key, const QString& id) { |
|
|
|
|
auto saveText = [](const char* key, const QString& id) { |
|
|
|
|
QByteArray value = id.toUtf8(); |
|
|
|
|
size_t keyLen = strlen(key), valueLen = value.size(); |
|
|
|
|
auto* arg = static_cast<save_ui_state_arg*>(u_calloc(1, sizeof(save_ui_state_arg))); |
|
|
|
|
if (!arg) return; |
|
|
|
|
if (!arg) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "settings save allocation failed key=%s", key); return; } |
|
|
|
|
if (keyLen + valueLen + 2 > sizeof(arg->data)) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "audio: device ID too long bytes=%zu", valueLen); |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "settings value too long key=%s bytes=%zu", key, valueLen); |
|
|
|
|
u_free(arg); return; |
|
|
|
|
} |
|
|
|
|
arg->inst = gui_bridge_get_inst(); |
|
|
|
|
@ -275,8 +316,9 @@ void AudioDeviceSettingsPage::applyAndSave() {
|
|
|
|
|
memcpy(arg->data + keyLen + 1, value.constData(), valueLen + 1); |
|
|
|
|
gui_bridge_post_uasync_fn(chat_core_save_ui_state_trampoline, arg); |
|
|
|
|
}; |
|
|
|
|
saveDevice("audio_output_id", outputId); |
|
|
|
|
saveDevice("audio_input_id", inputId); |
|
|
|
|
saveText("audio_output_id", outputId); |
|
|
|
|
saveText("audio_input_id", inputId); |
|
|
|
|
saveText(rangeKey, range); |
|
|
|
|
SoundManager::instance()->setDevices(outputId, inputId); |
|
|
|
|
saveKey("opus_codec_preset", codecPreset); |
|
|
|
|
|
|
|
|
|
|