Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/dev/build-instructions/cmake_options.md
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,11 @@ All warnings are treated as errors.
Build support for WASAPI.
(Default: ON)

### webrtc-audio-processing

Use WebRTC audio processing for various dsp features.
(Default: OFF)

### xboxinput

Build support for global shortcuts from Xbox controllers via the XInput DLL.
Expand Down
78 changes: 69 additions & 9 deletions src/mumble/AudioConfigDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "AudioOutputSample.h"
#include "AudioOutputToken.h"
#include "NetworkConfig.h"
#include "Settings.h"
#include "Utils.h"
#include "Global.h"

Expand Down Expand Up @@ -127,10 +128,24 @@ void AudioInputDialog::load(const Settings &r) {
loadSlider(qsDoublePush, static_cast< int >(static_cast< float >(r.uiDoublePush) / 1000.f + 0.5f));
loadSlider(qsPTTHold, static_cast< int >(r.pttHold));

if (r.vsVAD == Settings::Amplitude)
qrbAmplitude->setChecked(true);
else
qrbSNR->setChecked(true);
#ifdef USE_WEBRTC_AUDIO_PROCESSING
loadSlider(qsWebRTCAggressiveness, r.fVADWebRTCAggressiveness);
qrbWebRTC->show();
#endif

switch (r.vsVAD) {
case Settings::Amplitude:
qrbAmplitude->setChecked(true);
break;
#ifdef USE_WEBRTC_AUDIO_PROCESSING
case Settings::WebRTC:
qrbWebRTC->setChecked(true);
break;
#endif
default:
qrbSNR->setChecked(true);
break;
}

loadCheckBox(qcbPushWindow, r.bShowPTTButtonWindow);
loadCheckBox(qcbEnableCuePTT, r.audioCueEnabledPTT);
Expand Down Expand Up @@ -241,11 +256,22 @@ void AudioInputDialog::save() const {
s.noiseCancelMode = Settings::NoiseCancelSpeex;
}

s.iMinLoudness = 18000 - qsAmp->value() + 2000;
s.iVoiceHold = qsTransmitHold->value();
s.fVADmin = static_cast< float >(qsTransmitMin->value()) / 32767.0f;
s.fVADmax = static_cast< float >(qsTransmitMax->value()) / 32767.0f;
s.vsVAD = qrbSNR->isChecked() ? Settings::SignalToNoise : Settings::Amplitude;
s.iMinLoudness = 18000 - qsAmp->value() + 2000;
s.iVoiceHold = qsTransmitHold->value();
s.fVADmin = static_cast< float >(qsTransmitMin->value()) / 32767.0f;
s.fVADmax = static_cast< float >(qsTransmitMax->value()) / 32767.0f;

s.fVADWebRTCAggressiveness = qsWebRTCAggressiveness->value();

if (qrbAmplitude->isChecked())
s.vsVAD = Settings::Amplitude;
#ifdef USE_WEBRTC_AUDIO_PROCESSING
else if (qrbWebRTC->isChecked())
s.vsVAD = Settings::WebRTC;
#endif
else
s.vsVAD = Settings::SignalToNoise;

s.iFramesPerPacket = qsFrames->value();
s.iFramesPerPacket = (s.iFramesPerPacket == 1) ? 1 : ((s.iFramesPerPacket - 1) * 2);
s.uiDoublePush = static_cast< unsigned int >(qsDoublePush->value() * 1000);
Expand Down Expand Up @@ -354,6 +380,20 @@ void AudioInputDialog::on_qsTransmitMax_valueChanged() {
Mumble::Accessibility::setSliderSemanticValue(qsTransmitMax, Mumble::Accessibility::SliderMode::READ_PERCENT, "%");
}

void AudioInputDialog::updateVad() {
Settings::VADSource vad = Settings::SignalToNoise;

if (qrbAmplitude->isChecked())
vad = Settings::Amplitude;
#ifdef USE_WEBRTC_AUDIO_PROCESSING
else if (qrbWebRTC->isChecked())
vad = Settings::WebRTC;
#endif

AudioInputPtr ai = Global::get().ai;
ai->updateVad(vad);
}

void AudioInputDialog::updateBitrate() {
if (!qsQuality || !qsFrames || !qlBitrate)
return;
Expand Down Expand Up @@ -622,6 +662,26 @@ void AudioInputDialog::on_qrbNoiseSupBoth_toggled(bool checked) {
showSpeexNoiseSuppressionSlider(checked);
}

#ifdef USE_WEBRTC_AUDIO_PROCESSING
void AudioInputDialog::on_qrbWebRTC_toggled(bool checked) {
updateVad();

qliWebRTCAggressiveness->setVisible(checked);
qsWebRTCAggressiveness->setVisible(checked);

qliTransmitMax->setVisible(!checked);
qsTransmitMax->setVisible(!checked);
qliTransmitMin->setVisible(!checked);
qsTransmitMin->setVisible(!checked);
}

void AudioInputDialog::on_qsWebRTCAggressiveness_valueChanged(int aggressiveness) {
AudioInputPtr ai = Global::get().ai;
ai->updateWebrtcAggressiveness(static_cast< webrtc::Vad::Aggressiveness >(aggressiveness));
updateVad();
}
Comment thread
goodspeed34 marked this conversation as resolved.
#endif

void AudioOutputDialog::enablePulseAudioAttenuationOptionsFor(const QString &outputName) {
if (outputName == QLatin1String("PulseAudio")) {
qcbOnlyAttenuateSameOutput->show();
Expand Down
6 changes: 6 additions & 0 deletions src/mumble/AudioConfigDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class AudioInputDialog : public ConfigWidget, public Ui::AudioInput {
Q_DISABLE_COPY(AudioInputDialog)

void updateAudioCueEnabled();
void updateVad();

protected:
QTimer *qtTick;
Expand Down Expand Up @@ -67,6 +68,11 @@ public slots:
void on_qcbIdleAction_currentIndexChanged(int v);
void on_qrbNoiseSupSpeex_toggled(bool checked);
void on_qrbNoiseSupBoth_toggled(bool checked);

#ifdef USE_WEBRTC_AUDIO_PROCESSING
void on_qrbWebRTC_toggled(bool);
void on_qsWebRTCAggressiveness_valueChanged(int);
#endif
};

class AudioOutputDialog : public ConfigWidget, public Ui::AudioOutput {
Expand Down
62 changes: 60 additions & 2 deletions src/mumble/AudioInput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
#include "VoiceRecorder.h"
#include "Global.h"

#ifdef USE_WEBRTC_AUDIO_PROCESSING
#include "WebRTC_Priv.h"
Comment thread
goodspeed34 marked this conversation as resolved.
#endif

#include <opus.h>

#ifdef USE_RNNOISE
Expand All @@ -27,6 +31,7 @@ extern "C" {
#endif

#include <algorithm>
#include <atomic>
#include <cassert>
#include <chrono>
#include <exception>
Expand Down Expand Up @@ -251,6 +256,12 @@ AudioInput::AudioInput()
denoiseState = rnnoise_create(nullptr);
#endif

#ifdef USE_WEBRTC_AUDIO_PROCESSING
m_vadWebrtcAggressiveness = static_cast< webrtc::Vad::Aggressiveness >(Global::get().s.fVADWebRTCAggressiveness);
#endif

updateVad(Global::get().s.vsVAD);

qWarning("AudioInput: %d bits/s, %d hz, %d sample", iAudioQuality, iSampleRate, iFrameSize);
iEchoFreq = iMicFreq = iSampleRate;

Expand Down Expand Up @@ -941,11 +952,28 @@ void AudioInput::encodeAudioFrame(AudioChunk chunk) {
static_cast< std::streamsize >(iFrameSize * sizeof(short)));
}

fSpeechProb = static_cast< float >(m_preprocessor.getSpeechProb()) / 100.0f;
Settings::VADSource currentVad = m_vad.load();

switch (currentVad) {
#ifdef USE_WEBRTC_AUDIO_PROCESSING
case Settings::WebRTC: {
auto webrtcVad = std::atomic_load(&m_vadWebrtc);

if (!webrtcVad) {
break;
}

fSpeechProb = !!webrtcVad->VoiceActivity(psSource, iFrameSize, iSampleRate);
break;
}
#endif
default:
fSpeechProb = static_cast< float >(m_preprocessor.getSpeechProb()) / 100.0f;
}

// clean microphone level: peak of filtered signal attenuated by AGC gain
dPeakCleanMic = qMax(dPeakSignal - static_cast< float >(gainValue), -96.0f);
float level = (Global::get().s.vsVAD == Settings::SignalToNoise) ? fSpeechProb : (1.0f + dPeakCleanMic / 96.0f);
float level = (currentVad == Settings::Amplitude) ? (1.0f + dPeakCleanMic / 96.0f) : fSpeechProb;

bool bIsSpeech = false;

Expand Down Expand Up @@ -1244,5 +1272,35 @@ void AudioInput::updateUserMuteDeafState(const ClientUser *user) {
}
}

void AudioInput::updateVad(Settings::VADSource src) {
#ifdef USE_WEBRTC_AUDIO_PROCESSING
if (src == Settings::WebRTC) {
auto u = webrtc::CreateVad(m_vadWebrtcAggressiveness);
if (!u) {
qWarning() << "AudioInput: Failed to initialize WebRTC VAD, disabled";
}
std::shared_ptr< webrtc::Vad > s = std::move(u);
std::atomic_store(&m_vadWebrtc, std::move(s));
} else {
std::atomic_store(&m_vadWebrtc, std::shared_ptr< webrtc::Vad >(nullptr));
}
#endif
m_vad.store(src);
}

#ifdef USE_WEBRTC_AUDIO_PROCESSING
void AudioInput::updateWebrtcAggressiveness(webrtc::Vad::Aggressiveness aggressiveness) {
m_vadWebrtcAggressiveness = aggressiveness;
if (m_vad.load() == Settings::WebRTC && m_vadWebrtc) {
auto u = webrtc::CreateVad(m_vadWebrtcAggressiveness);
if (!u) {
qWarning() << "AudioInput: Failed to initialize WebRTC VAD, disabled";
}
std::shared_ptr< webrtc::Vad > s = std::move(u);
std::atomic_store(&m_vadWebrtc, std::move(s));
}
}
Comment thread
goodspeed34 marked this conversation as resolved.
#endif

void AudioInput::onUserMutedChanged() {
}
19 changes: 19 additions & 0 deletions src/mumble/AudioInput.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <QThread>

#include <array>
#include <atomic>
#include <cstdint>
#include <fstream>
#include <list>
Expand All @@ -29,6 +30,10 @@
#include "Settings.h"
#include "Timer.h"

#ifdef USE_WEBRTC_AUDIO_PROCESSING
#include "WebRTC_Priv.h"
#endif

class AudioInput;
struct OpusEncoder;
struct DenoiseState;
Expand Down Expand Up @@ -226,6 +231,13 @@ class AudioInput : public QThread {
AudioPreprocessor m_preprocessor;
SpeexEchoState *sesEcho;

std::atomic< Settings::VADSource > m_vad;

#ifdef USE_WEBRTC_AUDIO_PROCESSING
std::shared_ptr< webrtc::Vad > m_vadWebrtc;
webrtc::Vad::Aggressiveness m_vadWebrtcAggressiveness;
#endif

/// bResetEncoder is a flag that notifies
/// our encoder functions that the encoder
/// needs to be reset.
Expand Down Expand Up @@ -313,6 +325,13 @@ class AudioInput : public QThread {
virtual bool isAlive() const;
bool isTransmitting() const;

void updateVad(Settings::VADSource src);

#ifdef USE_WEBRTC_AUDIO_PROCESSING
void updateWebrtcAggressiveness(webrtc::Vad::Aggressiveness);
#endif


void updateUserMuteDeafState(const ClientUser *user);

protected:
Expand Down
56 changes: 56 additions & 0 deletions src/mumble/AudioInput.ui
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,22 @@
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="qrbWebRTC">
<property name="toolTip">
<string>Use WebRTC GMM based speech detection</string>
</property>
<property name="whatsThis">
<string>&lt;b&gt;This sets speech detection to use the WebRTC VAD algorithm.&lt;/b&gt;&lt;br /&gt;In this mode, a configuration-free Gaussian Mixture Model is used to detect speech.</string>
</property>
<property name="visible">
<bool>false</bool>
</property>
<property name="text">
<string>WebRTC GMM</string>
</property>
</widget>
</item>
Comment thread
goodspeed34 marked this conversation as resolved.
</layout>
</item>
<item row="4" column="0">
Expand Down Expand Up @@ -490,6 +506,44 @@
<widget class="QWidget" name="qwContinuous"/>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="qliWebRTCAggressiveness">
<property name="visible">
<bool>false</bool>
</property>
<property name="text">
<string>Aggressiveness</string>
</property>
<property name="buddy">
<cstring>qsWebRTCAggressiveness</cstring>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="SemanticSlider" name="qsWebRTCAggressiveness">
<property name="visible">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Controls aggressiveness of WebRTC VAD</string>
</property>
<property name="whatsThis">
<string>Higher values make the VAD more aggressive in filtering noise.</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>3</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
Expand Down Expand Up @@ -1175,9 +1229,11 @@
<tabstop>qcbTransmit</tabstop>
<tabstop>qrbAmplitude</tabstop>
<tabstop>qrbSNR</tabstop>
<tabstop>qrbWebRTC</tabstop>
<tabstop>qsTransmitHold</tabstop>
<tabstop>qsTransmitMin</tabstop>
<tabstop>qsTransmitMax</tabstop>
<tabstop>qsWebRTCAggressiveness</tabstop>
<tabstop>qsQuality</tabstop>
<tabstop>qsDoublePush</tabstop>
<tabstop>qsPTTHold</tabstop>
Expand Down
Loading
Loading