mumble-voip_mumble/src/mumble/AudioWizard.cpp

779 lines
22 KiB
C++

// Copyright 2007-2023 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
#include "AudioWizard.h"
#include "Accessibility.h"
#include "AudioInput.h"
#include "AudioOutputToken.h"
#include "Log.h"
#include "MainWindow.h"
#include "Utils.h"
#include "Global.h"
#include "GlobalShortcut.h"
#include "GlobalShortcutButtons.h"
#include <QtGui/QMouseEvent>
#include <QtWidgets/QGraphicsEllipseItem>
#include <cmath>
AudioWizard::AudioWizard(QWidget *p) : QWizard(p) {
bInit = true;
bLastActive = false;
Global::get().bInAudioWizard = true;
ticker = new QTimer(this);
ticker->setObjectName(QLatin1String("Ticker"));
setupUi(this);
Mumble::Accessibility::fixWizardButtonLabels(this);
Mumble::Accessibility::setDescriptionFromLabel(qgbInput, qliInputText);
Mumble::Accessibility::setDescriptionFromLabel(qgbOutput, qliOutputText);
Mumble::Accessibility::setDescriptionFromLabel(qrbQualityLow, qlQualityLow);
Mumble::Accessibility::setDescriptionFromLabel(qrbQualityBalanced, qlQualityBalanced);
Mumble::Accessibility::setDescriptionFromLabel(qrbQualityUltra, qlQualityUltra);
Mumble::Accessibility::setDescriptionFromLabel(qrbQualityCustom, qlQualityCustom);
// Done
qcbUsage->setChecked(Global::get().s.bUsage);
// Device
if (AudioInputRegistrar::qmNew) {
foreach (AudioInputRegistrar *air, *AudioInputRegistrar::qmNew) {
qcbInput->addItem(air->name);
if (air->name == AudioInputRegistrar::current) {
qcbInput->setCurrentIndex(qcbInput->count() - 1);
EchoCancelOptionID echoCancelOptionId = firstUsableEchoCancellation(air, qcbOutput->currentText());
if (echoCancelOptionId != EchoCancelOptionID::DISABLED) {
qcbEcho->setEnabled(true);
qcbEcho->setChecked(Global::get().s.echoOption != EchoCancelOptionID::DISABLED);
}
}
QList< audioDevice > ql = air->getDeviceChoices();
}
}
if (qcbInput->count() < 2) {
qcbInput->setEnabled(false);
}
if (AudioOutputRegistrar::qmNew) {
foreach (AudioOutputRegistrar *aor, *AudioOutputRegistrar::qmNew) {
qcbOutput->addItem(aor->name);
if (aor->name == AudioOutputRegistrar::current) {
qcbOutput->setCurrentIndex(qcbOutput->count() - 1);
bDelay = aor->usesOutputDelay();
qcbAttenuateOthers->setEnabled(aor->canMuteOthers());
}
QList< audioDevice > ql = aor->getDeviceChoices();
}
}
if (qcbOutput->count() < 2) {
qcbOutput->setEnabled(false);
}
qcbHighContrast->setChecked(Global::get().s.bHighContrast);
on_qcbHighContrast_clicked(Global::get().s.bHighContrast);
#ifdef Q_OS_WIN
// On windows we can autodetect this
qcbHighContrast->setVisible(false);
#endif
// Settings
if (Global::get().s.iQuality == 16000 && Global::get().s.iFramesPerPacket == 6)
qrbQualityLow->setChecked(true);
else if (Global::get().s.iQuality == 40000 && Global::get().s.iFramesPerPacket == 2)
qrbQualityBalanced->setChecked(true);
else if (Global::get().s.iQuality == 72000 && Global::get().s.iFramesPerPacket == 1)
qrbQualityUltra->setChecked(true);
else
qrbQualityCustom->setChecked(true);
#ifdef USE_NO_TTS
qrbNotificationCustom->setChecked(false);
qrbNotificationCustom->setDisabled(true);
qrbNotificationTTS->setChecked(false);
qrbNotificationTTS->setDisabled(true);
qrbNotificationSounds->setChecked(true);
#else
quint32 iMessage = Settings::LogNone;
for (int i = Log::firstMsgType; i <= Log::lastMsgType; ++i) {
iMessage |= (Global::get().s.qmMessages[i] & (Settings::LogSoundfile | Settings::LogTTS));
}
if (iMessage == Settings::LogTTS && Global::get().s.bTTS)
qrbNotificationTTS->setChecked(true);
else if (iMessage == Settings::LogSoundfile)
qrbNotificationSounds->setChecked(true);
else // If we find mixed message types or only tts with main tts disable assume custom
qrbNotificationCustom->setChecked(true);
qrbNotificationCustom->setVisible(qrbNotificationCustom->isChecked());
#endif
qrbQualityCustom->setVisible(qrbQualityCustom->isChecked());
qlQualityCustom->setVisible(qrbQualityCustom->isChecked());
qcbPositional->setChecked(Global::get().s.bPositionalAudio);
qcbAttenuateOthers->setChecked(Global::get().s.bAttenuateOthers);
on_qcbInput_activated(qcbInput->currentIndex());
on_qcbOutput_activated(qcbOutput->currentIndex());
abAmplify->qcBelow = Qt::blue;
abAmplify->qcInside = Qt::green;
abAmplify->qcAbove = Qt::red;
for (const auto &shortcut : Global::get().s.qlShortcuts) {
if (shortcut.iIndex == Global::get().mw->gsPushTalk->idx) {
pttButtons = shortcut.qlButtons;
break;
}
}
if (Global::get().s.atTransmit == Settings::PushToTalk)
qrPTT->setChecked(true);
else if (Global::get().s.vsVAD == Settings::Amplitude)
qrAmplitude->setChecked(true);
else
qrSNR->setChecked(true);
abVAD->qcBelow = Qt::red;
abVAD->qcInside = Qt::yellow;
abVAD->qcAbove = Qt::green;
qsVAD->setValue(static_cast< int >(Global::get().s.fVADmax * 32767.f + 0.5f));
// Positional
qcbHeadphone->setChecked(Global::get().s.bPositionalHeadphone);
fAngle = 0.0f;
fX = fY = 0.0f;
qgsScene = nullptr;
qgiSource = nullptr;
qgvView->scale(1.0f, -1.0f);
qgvView->viewport()->installEventFilter(this);
qgvView->setRenderHints(QPainter::Antialiasing);
// Volume
qsMaxAmp->setValue(Global::get().s.iMinLoudness);
// Device Tuning
qsOutputDelay->setValue(Global::get().s.iOutputDelay);
on_qsOutputDelay_valueChanged(qsOutputDelay->value());
setOption(QWizard::NoCancelButton, false);
resize(700, 500);
updateTriggerWidgets(qrPTT->isChecked());
sOldSettings = Global::get().s;
Global::get().s.lmLoopMode = Settings::Local;
Global::get().s.dPacketLoss = 0.0;
Global::get().s.dMaxPacketDelay = 0.0;
Global::get().s.bMute = true;
Global::get().s.bDeaf = false;
bTransmitChanged = false;
iMaxPeak = 0;
iTicks = 0;
qpTalkingOn = QPixmap::fromImage(QImage(QLatin1String("skin:talking_on.svg")).scaled(64, 64));
qpTalkingOff = QPixmap::fromImage(QImage(QLatin1String("skin:talking_off.svg")).scaled(64, 64));
bInit = false;
connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(showPage(int)));
ticker->setSingleShot(false);
ticker->start(20);
m_overrideFilter = new OverrideTabOrderFilter(this, this);
installEventFilter(m_overrideFilter);
}
bool AudioWizard::eventFilter(QObject *obj, QEvent *evt) {
if ((evt->type() == QEvent::MouseButtonPress) || (evt->type() == QEvent::MouseMove)) {
QMouseEvent *qme = dynamic_cast< QMouseEvent * >(evt);
if (qme) {
if (qme->buttons() & Qt::LeftButton) {
QPointF qpf = qgvView->mapToScene(qme->pos());
fX = static_cast< float >(qpf.x());
fY = static_cast< float >(qpf.y());
}
}
}
return QWizard::eventFilter(obj, evt);
}
void AudioWizard::on_qcbInput_activated(int) {
qcbInputDevice->clear();
if (!AudioInputRegistrar::qmNew)
return;
AudioInputRegistrar *air = AudioInputRegistrar::qmNew->value(qcbInput->currentText());
QList< audioDevice > ql = air->getDeviceChoices();
foreach (audioDevice d, ql) { qcbInputDevice->addItem(d.first, d.second); }
qcbInputDevice->setEnabled(ql.count() > 1);
on_qcbInputDevice_activated(0);
}
void AudioWizard::on_qcbInputDevice_activated(int) {
if (bInit)
return;
if (!AudioInputRegistrar::qmNew)
return;
Audio::stopInput();
AudioInputRegistrar *air = AudioInputRegistrar::qmNew->value(qcbInput->currentText());
int idx = qcbInputDevice->currentIndex();
if (idx > -1) {
air->setDeviceChoice(qcbInputDevice->itemData(idx), Global::get().s);
}
EchoCancelOptionID echoCancelOptionId = firstUsableEchoCancellation(air, qcbOutput->currentText());
qcbEcho->setEnabled(echoCancelOptionId != EchoCancelOptionID::DISABLED);
Global::get().ai = AudioInputPtr(air->create());
Global::get().ai->start(QThread::HighestPriority);
}
void AudioWizard::on_qcbOutput_activated(int) {
qcbOutputDevice->clear();
if (!AudioOutputRegistrar::qmNew)
return;
AudioOutputRegistrar *aor = AudioOutputRegistrar::qmNew->value(qcbOutput->currentText());
QList< audioDevice > ql = aor->getDeviceChoices();
foreach (audioDevice d, ql) { qcbOutputDevice->addItem(d.first, d.second); }
qcbAttenuateOthers->setEnabled(aor->canMuteOthers());
qcbOutputDevice->setEnabled(ql.count() > 1);
on_qcbOutputDevice_activated(0);
}
void AudioWizard::on_qcbOutputDevice_activated(int) {
if (bInit)
return;
if (!AudioOutputRegistrar::qmNew)
return;
Audio::stopOutput();
AudioOutputRegistrar *aor = AudioOutputRegistrar::qmNew->value(qcbOutput->currentText());
int idx = qcbOutputDevice->currentIndex();
if (idx > -1) {
aor->setDeviceChoice(qcbOutputDevice->itemData(idx), Global::get().s);
bDelay = aor->usesOutputDelay();
}
AudioInputRegistrar *air = AudioInputRegistrar::qmNew->value(qcbInput->currentText());
EchoCancelOptionID echoCancelOptionId = firstUsableEchoCancellation(air, qcbOutput->currentText());
qcbEcho->setEnabled(echoCancelOptionId != EchoCancelOptionID::DISABLED);
Global::get().ao = AudioOutputPtr(aor->create());
Global::get().ao->start(QThread::HighPriority);
}
void AudioWizard::on_qsOutputDelay_valueChanged(int v) {
qlOutputDelay->setText(tr("%1 ms").arg(v * 10));
Global::get().s.iOutputDelay = v;
restartAudio(true);
Mumble::Accessibility::setSliderSemanticValue(qsOutputDelay, QString("%1 %2").arg(v * 10).arg("milliseconds"));
}
void AudioWizard::on_qsMaxAmp_valueChanged(int v) {
Global::get().s.iMinLoudness = qMin(v, 30000);
Mumble::Accessibility::setSliderSemanticValue(qsMaxAmp, Mumble::Accessibility::SliderMode::READ_PERCENT, "%");
}
void AudioWizard::showPage(int pageid) {
if (pageid == -1)
return;
CompletablePage *cp = qobject_cast< CompletablePage * >(currentPage());
AudioOutputPtr ao = Global::get().ao;
if (ao)
ao->wipe();
m_chord = {};
Global::get().bPosTest = false;
if (cp == qwpIntro) {
Global::get().s.bMute = true;
} else if (cp == qwpDone) {
Global::get().s.bMute = true;
} else if (cp == qwpDeviceTuning) {
Global::get().s.bMute = true;
playChord();
} else if (cp == qwpPositional) {
fX = fY = 0.0f;
Global::get().s.bMute = true;
Global::get().bPosTest = true;
if (qgsScene) {
delete qgsScene;
qgiSource = nullptr;
qgsScene = nullptr;
}
playChord();
} else {
Global::get().s.bMute = false;
}
if ((cp == qwpTrigger) || (cp == qwpSettings)) {
if (!bTransmitChanged)
Global::get().s.atTransmit = sOldSettings.atTransmit;
else if (qrPTT->isChecked())
Global::get().s.atTransmit = Settings::PushToTalk;
else
Global::get().s.atTransmit = Settings::VAD;
} else {
Global::get().s.atTransmit = Settings::Continuous;
}
setFocus(Qt::ActiveWindowFocusReason);
QWidget *selectedWidget = Mumble::Accessibility::getFirstFocusableChild(currentPage());
if (selectedWidget) {
m_overrideFilter->focusTarget = selectedWidget;
} else {
m_overrideFilter->focusTarget = button(QWizard::NextButton);
}
}
int AudioWizard::nextId() const {
AudioOutputPtr ao = Global::get().ao;
int nextid = QWizard::nextId();
if (currentPage() == qwpSettings && !Global::get().s.bPositionalAudio)
nextid++;
else if ((currentPage() == qwpDevice) && !bDelay)
nextid++;
return nextid;
}
void AudioWizard::playChord() {
AudioOutputPtr ao = Global::get().ao;
if (!ao || m_chord || bInit) {
return;
}
m_chord = ao->playSample(QLatin1String(":/wb_male.oga"), 1.0f, true);
}
void AudioWizard::restartAudio(bool restartChord) {
m_chord = AudioOutputToken();
Audio::stop();
Global::get().s.qsAudioInput = qcbInput->currentText();
Global::get().s.qsAudioOutput = qcbOutput->currentText();
Audio::start();
if (qgsScene) {
delete qgsScene;
qgiSource = nullptr;
qgsScene = nullptr;
}
if (!restartChord) {
return;
}
if ((currentPage() == qwpPositional) || (currentPage() == qwpDeviceTuning)) {
playChord();
}
}
void AudioWizard::reject() {
Global::get().s = sOldSettings;
Global::get().s.lmLoopMode = Settings::None;
AudioOutputPtr ao = Global::get().ao;
if (ao) {
ao->wipe();
}
ao.reset();
Global::get().bPosTest = false;
restartAudio(false);
Global::get().bInAudioWizard = false;
QWizard::reject();
}
void AudioWizard::accept() {
if (!bTransmitChanged)
Global::get().s.atTransmit = sOldSettings.atTransmit;
else if (qrPTT->isChecked())
Global::get().s.atTransmit = Settings::PushToTalk;
else
Global::get().s.atTransmit = Settings::VAD;
Global::get().s.bMute = sOldSettings.bMute;
Global::get().s.bDeaf = sOldSettings.bDeaf;
Global::get().s.lmLoopMode = Settings::None;
// Switch TTS<->Sounds according to user selection
if (!qrbNotificationCustom->isChecked()) {
Settings::MessageLog mlReplace = qrbNotificationTTS->isChecked() ? Settings::LogSoundfile : Settings::LogTTS;
for (int i = Log::firstMsgType; i <= Log::lastMsgType; ++i) {
if (Global::get().s.qmMessages[i] & static_cast< unsigned int >(mlReplace))
Global::get().s.qmMessages[i] ^= Settings::LogSoundfile | Settings::LogTTS;
}
if (qrbNotificationTTS->isChecked()) {
Global::get().s.bTTS = true;
Global::get().mw->qaAudioTTS->setChecked(true);
}
}
Global::get().s.bUsage = qcbUsage->isChecked();
Global::get().bPosTest = false;
restartAudio(false);
Global::get().bInAudioWizard = false;
QWizard::accept();
}
bool AudioWizard::validateCurrentPage() {
if (currentId() == 1) {
if ((qcbInput->currentIndex() < 0) || (qcbOutput->currentIndex() < 0))
return false;
}
return true;
}
void AudioWizard::on_Ticker_timeout() {
AudioInputPtr ai = Global::get().ai;
AudioOutputPtr ao = Global::get().ao;
if (!ai || !ao)
return;
int iPeak = static_cast< int >(ai->dMaxMic);
if (iTicks++ >= 50) {
iMaxPeak = 0;
iTicks = 0;
}
if (iPeak > iMaxPeak)
iMaxPeak = iPeak;
abAmplify->iBelow = qsMaxAmp->value();
abAmplify->iValue = iPeak;
abAmplify->iPeak = iMaxPeak;
abAmplify->update();
abVAD->iBelow = static_cast< int >(Global::get().s.fVADmin * 32767.0f + 0.5f);
abVAD->iAbove = static_cast< int >(Global::get().s.fVADmax * 32767.0f + 0.5f);
if (Global::get().s.vsVAD == Settings::Amplitude) {
abVAD->iValue = static_cast< int >((32767.f / 96.0f) * (96.0f + ai->dPeakCleanMic) + 0.5f);
} else {
abVAD->iValue = static_cast< int >(ai->fSpeechProb * 32767.0f + 0.5f);
}
abVAD->update();
bool active = ai->isTransmitting();
if (active != bLastActive) {
bLastActive = active;
qlTalkIcon->setPixmap(active ? qpTalkingOn : qpTalkingOff);
}
if (!qgsScene) {
const float baseRadius = 0.5;
unsigned int nspeaker = 0;
// Note: when updating these, make sure the colors in AudioWizard.ui match up.
const QColor skyBlueColor(QLatin1String("#56b4e9"));
const QColor bluishGreenColor(QLatin1String("#009e73"));
const QColor vermillionColor(QLatin1String("#d55e00"));
// Get the directions of the speakers as unit vectors and also the amount of them
const float *spos = ao->getSpeakerPos(nspeaker);
if ((nspeaker > 0) && spos) {
qgsScene = new QGraphicsScene(QRectF(-4.0f, -4.0f, 8.0f, 8.0f), this);
QPen pen;
// A width of 0 will cause it to always use a width
// of exactly 1 pixel
pen.setWidth(0);
QGraphicsEllipseItem *ownPos = qgsScene->addEllipse(
QRectF(-baseRadius, -baseRadius, 2 * baseRadius, 2 * baseRadius), pen, QBrush(skyBlueColor));
ownPos->setPos(0, 0);
// Good for debugging: This draws a cross at the origin
// qgsScene->addLine(QLineF(0,-1,0,1), pen);
// qgsScene->addLine(QLineF(-1,0,1,0), pen);
const float speakerScale = 0.9f;
const float speakerRadius = baseRadius * speakerScale;
// nspeaker is in format [x1,y1,z1, x2,y2,z2, ...]
for (unsigned int i = 0; i < nspeaker; ++i) {
if ((spos[3 * i] != 0.0f) || (spos[3 * i + 1] != 0.0f) || (spos[3 * i + 2] != 0.0f)) {
float x = spos[3 * i];
float z = spos[3 * i + 2];
const float lengthInPlane = std::sqrt(x * x + z * z);
// Scale the vector in the xz plane so that its length is at least enough for
// the speaker icons and the icon for the own pos don't overlap
if ((baseRadius + speakerRadius) < lengthInPlane) {
const float scaleFactor = (baseRadius + speakerRadius) / lengthInPlane;
x *= scaleFactor;
z *= scaleFactor;
}
QGraphicsEllipseItem *ellipse = qgsScene->addEllipse(
QRectF(-speakerRadius, -speakerRadius, 2 * speakerRadius, 2 * speakerRadius), pen,
QBrush(vermillionColor));
ellipse->setPos(x, z);
}
}
const float sourceScale = 0.9f;
const float sourceRadius = baseRadius * sourceScale;
qgiSource = qgsScene->addEllipse(QRectF(-sourceRadius, -sourceRadius, 2 * sourceRadius, 2 * sourceRadius),
pen, QBrush(bluishGreenColor));
qgiSource->setPos(0, (sourceRadius + baseRadius) * 1.5);
qgvView->setScene(qgsScene);
qgvView->fitInView(-4.0f, -4.0f, 8.0f, 8.0f, Qt::KeepAspectRatio);
}
} else if (currentPage() == qwpPositional) {
// This block here is responsible for setting the position of
// the audio source. Unless the user has clicked on the scene,
// the source will rotate around the origin at a radius of 2.
// Once the user has clicked on the scene, the sound source
// is put where (s)he clicked last.
float xp, yp;
if ((fX == 0.0f) && (fY == 0.0f)) {
// increase the angle of the sound source by a certain amount. he higher
// this value is, the faster will the source rotate.
fAngle += 0.02f;
xp = sinf(fAngle) * 2.0f;
yp = cosf(fAngle) * 2.0f;
} else {
xp = fX;
yp = fY;
}
qgiSource->setPos(xp, yp);
if (m_chord) {
ao->setBufferPosition(m_chord, xp, 0, yp);
}
}
}
void AudioWizard::on_qsVAD_valueChanged(int v) {
if (!bInit) {
Global::get().s.fVADmax = static_cast< float >(v) / 32767.0f;
Global::get().s.fVADmin = Global::get().s.fVADmax * 0.9f;
}
Mumble::Accessibility::setSliderSemanticValue(qsVAD, QString("%2 - %3")
.arg(QString::number(Global::get().s.fVADmin, 'f', 2))
.arg(QString::number(Global::get().s.fVADmax, 'f', 2)));
}
void AudioWizard::on_qrSNR_clicked(bool on) {
if (on) {
Global::get().s.vsVAD = Settings::SignalToNoise;
Global::get().s.atTransmit = Settings::VAD;
updateTriggerWidgets(false);
bTransmitChanged = true;
}
}
void AudioWizard::on_qrAmplitude_clicked(bool on) {
if (on) {
Global::get().s.vsVAD = Settings::Amplitude;
Global::get().s.atTransmit = Settings::VAD;
updateTriggerWidgets(false);
bTransmitChanged = true;
}
}
void AudioWizard::on_qrPTT_clicked(bool on) {
if (on) {
Global::get().s.atTransmit = Settings::PushToTalk;
updateTriggerWidgets(true);
bTransmitChanged = true;
}
}
void AudioWizard::on_qpbPTT_clicked() {
GlobalShortcutButtons dialog;
dialog.setButtons(pttButtons);
const auto ret = dialog.exec();
if (ret != Accepted) {
return;
}
pttButtons = dialog.buttons();
if (!pttButtons.isEmpty()) {
qrPTT->setChecked(true);
updateTriggerWidgets(true);
} else if (qrPTT->isChecked()) {
qrAmplitude->setChecked(true);
updateTriggerWidgets(false);
}
bTransmitChanged = true;
QList< Shortcut > shortcuts;
bool found = false;
for (auto &shortcut : Global::get().s.qlShortcuts) {
if (shortcut.iIndex == Global::get().mw->gsPushTalk->idx) {
if (pttButtons.isEmpty()) {
continue;
}
if (!found) {
found = true;
shortcut.qlButtons = pttButtons;
}
}
shortcuts << shortcut;
}
if (!found && !pttButtons.isEmpty()) {
Shortcut shortcut;
shortcut.iIndex = Global::get().mw->gsPushTalk->idx;
shortcut.qlButtons = pttButtons;
shortcut.bSuppress = false;
shortcuts << shortcut;
}
Global::get().s.qlShortcuts = shortcuts;
GlobalShortcutEngine::engine->bNeedRemap = true;
GlobalShortcutEngine::engine->needRemap();
}
void AudioWizard::on_qcbEcho_clicked(bool on) {
if (on) {
AudioInputRegistrar *air = AudioInputRegistrar::qmNew->value(qcbInput->currentText());
Global::get().s.echoOption = firstUsableEchoCancellation(air, qcbOutput->currentText());
} else {
Global::get().s.echoOption = EchoCancelOptionID::DISABLED;
}
restartAudio(true);
}
void AudioWizard::on_qcbHeadphone_clicked(bool on) {
Global::get().s.bPositionalHeadphone = on;
restartAudio(true);
}
void AudioWizard::on_qcbPositional_clicked(bool on) {
Global::get().s.bPositionalAudio = on;
Global::get().s.bTransmitPosition = on;
restartAudio(true);
}
void AudioWizard::updateTriggerWidgets(bool ptt) {
qwVAD->setEnabled(!ptt);
if (pttButtons.count() > 0) {
QString text;
for (const auto &button : pttButtons) {
if (!text.isEmpty()) {
text += ' ';
}
const auto info = GlobalShortcutEngine::engine->buttonInfo(button);
text += QString("'%1%2'").arg(info.devicePrefix, info.name);
}
qpbPTT->setText(text);
qwpTrigger->setComplete(true);
} else {
qpbPTT->setText(tr("No buttons assigned"));
qwpTrigger->setComplete(!ptt);
}
}
void AudioWizard::on_qcbAttenuateOthers_clicked(bool checked) {
Global::get().s.bAttenuateOthers = checked;
}
void AudioWizard::on_qcbHighContrast_clicked(bool on) {
Global::get().s.bHighContrast = on;
qliAmpTuningText->setVisible(!Global::get().s.bHighContrast);
qliAmpTuningTextHC->setVisible(Global::get().s.bHighContrast);
qliVolumeTuningText->setVisible(!Global::get().s.bHighContrast);
qliVolumeTuningTextHC->setVisible(Global::get().s.bHighContrast);
qliVadTuningText->setVisible(!Global::get().s.bHighContrast);
qliVadTuningTextHC->setVisible(Global::get().s.bHighContrast);
}
void AudioWizard::on_qrbQualityLow_clicked() {
Global::get().s.iQuality = 16000;
Global::get().s.iFramesPerPacket = 6;
restartAudio(true);
}
void AudioWizard::on_qrbQualityBalanced_clicked() {
Global::get().s.iQuality = 40000;
Global::get().s.iFramesPerPacket = 2;
restartAudio(true);
}
void AudioWizard::on_qrbQualityUltra_clicked() {
Global::get().s.iQuality = 72000;
Global::get().s.iFramesPerPacket = 1;
restartAudio(true);
}
void AudioWizard::on_qrbQualityCustom_clicked() {
Global::get().s.iQuality = sOldSettings.iQuality;
Global::get().s.iFramesPerPacket = sOldSettings.iFramesPerPacket;
restartAudio(true);
}
EchoCancelOptionID AudioWizard::firstUsableEchoCancellation(AudioInputRegistrar *air, const QString outputSys) {
for (EchoCancelOptionID ecoid : air->echoOptions) {
if (air->canEcho(ecoid, outputSys)) {
return ecoid;
}
}
return EchoCancelOptionID::DISABLED;
}