Bessere Audioqualität für Mikrofone mit PulseAudio, WebRTC und RNNoise

Update 2022: Die meisten Distributionen nutzen nun PipeWire oder sind dabei darauf umzustellen. Für PipeWire können einfach Filter Chains benutzt werden.

Mein Audiosetup für die meisten Veranstaltungen ist ein 1€ Ansteckmikrofon mit einer 5€ USB-Soundkarte. Das man davon nicht das beste erwarten kann ist jedem klar, aber mit ein bisschen Weiterverarbeitung lässt sich die Qualität deutlich verbessern. PulseAudio bietet viele verschiedene Module um Audio in (fast) Echtzeit zu verändern und ein paar von diesen machen wir uns hier zu nutze.

Hinweis: Wer nur RNNoise nutzen möchte kann auch NoiseTorch verwenden. Dies bietet eine einfache GUI für die PulseAudio Konfiguration.

Automatische Lautstärkeregelung und Echo-/Rauschunterdrückung mit WebRTC

Dafür nutzen wir das Modul module-echo-cancel für Echo-/Rauschunterdrückung, aber auch besonders um die automatische Lautstärkeregelung zu aktivieren. Der zweite Punkt ist für mich besonders wichtig, weil mein Mikrofon sonst zu leise ist.

Als erstes finden wir den Namen unseres Mikrofons mit pactl list sources short heraus. Dies sieht dann z.B. so aus:

0	alsa_output.usb-C-Media_Electronics_Inc._USB_Audio_Device-00.analog-stereo.monitor	module-alsa-card.c	s16le 2ch 44100Hz	SUSPENDED
1	alsa_input.usb-C-Media_Electronics_Inc._USB_Audio_Device-00.mono-fallback	module-alsa-card.c	s16le 1ch 48000Hz	RUNNING
2	alsa_output.pci-0000_00_1f.3.analog-stereo.monitor	module-alsa-card.c	s16le 2ch 48000Hz	IDLE
3	alsa_input.pci-0000_00_1f.3.analog-stereo	module-alsa-card.c	s16le 2ch 44100Hz	SUSPENDED

In meinem Falle ist es alsa_input.usb-C-Media_Electronics_Inc._USB_Audio_Device-00.mono-fallback.

Nun können wir das Modul module-echo-cancel wie folgt laden. Dabei muss <your_mic_here> mit den Namen von eben ersetzt werden.

pacmd load-module module-echo-cancel source_master=<your_mic_here> aec_method=webrtc aec_args="analog_gain_control=0 digital_gain_control=1" source_name=WebRTC_source

Damit haben wir eine Source angelegt die unser Mikrofon nimmt und dieses dann mit WebRTC filtert. Diese heißt z.B. in den GNOME Einstellungen Audio Adapter (Unitek Y-247A) Mono (echo cancelled with Internes Audio Analog Stereo) und kann nun zum Testen verwendet werden.

Wer mit den Einstellungen für WebRTC rumspielen möchte findet die Dokumentation der meisten Parameter hier: https://wiki.archlinux.org/index.php/PulseAudio/Troubleshooting#Possible_'aec_args'_for_'aec_method=webrtc'.

Filtern von Hintergrundgeräuschen mit RNNoise

RTX Voice steht unter Linux  nicht zu Verfügung, aber eine erstaunlich gute Alternative ist RNNoise. Dies erlaubt das Filtern von Hintergrundgeräuschen in Echtzeit mit Unterstützung von neuronalen Netzen.

Um diese Technologie für ein Mikrofon zu verwenden, kann das LADSPA Plugin für RNNoise von Werman benutzt werden. Es ist in der AUR (Arch Linux) zu finden und für Fedora gibt es eine Copr Repository. Alterntativ kann es auch vom Source Code selbst gebaut werden.
Leider macht es uns PulseAudio hier nicht ganz so einfach, da LADSPA-Plugins nur auf Sinks (Ausgänge) angewendet werden können. Also legen wir als erstes eine Sink an und legen darauf RNNoise als LADSPA-Filter.

pacmd load-module module-null-sink sink_name=mic_denoised_out rate=4800
pacmd load-module module-ladspa-sink sink_name=mic_raw_in sink_master=mic_denoised_out label=noise_suppressor_mono plugin=librnnoise_ladspa control=50

Danach geben wir mithilfe des Moduls module-loopback das Mikrofon auf dieser Sink aus.

pacmd load-module module-loopback latency_msec=25 source=WebRTC_source sink=mic_raw_in channels=1 source_dont_move=true sink_dont_move=true

latency_msec=25 kann auch auf  latency_msec=1 gesetzt werden, nur auf  meinem Rechner hat PulseAudio regelmäßig die Latenz auf 20ms oder mehr hoch gesetzt, daher ist dies für mich ein guter Standardwert. Alles bis 100ms klingt für die meisten Menschen in Ordnung.

Die von uns angelegte Sink besitzt einen Monitor Ausgang, über den wir das mit RNNoise gefilterte Mikrofon ausgeben können. Leider lassen sich Monitor Ausgänge z.B. im Chrome nicht als Mikrofon verwenden. Um dieses Problem zu lösen, erstellen wir eine Source (virtuelles Mikrofon), die den Monitor Ausgang als Eingang nimmt.

pacmd load-module module-remap-source source_name=denoised master=mic_denoised_out.monitor channels=1 source_properties='device.description="Filtered USB Mic"'

Wenn alles geklappt hat, taucht Filtered USB Mic als Mikrofon auf. Einige Anwendungen müssen erst neugestartet werden, damit das Mikrofon erkannt wird.

Konfiguration

Damit die diese Einstellungen permanent sind, kann folgende Konfiguration nun einfach zur /etc/pulse/default.pa  oder zu seiner lokalen PulseAudio Konfiguration hinzufügen. Dabei muss <your_mic_here> wieder durch den Namen des Mikrofons ersetzt werden.

### Enable Noise-Cancelation with WebRTC and RNNoise
load-module module-echo-cancel source_master=<your_mic_here> aec_method=webrtc aec_args="analog_gain_control=0 digital_gain_control=1" source_name=WebRTC_source


load-module module-null-sink sink_name=mic_denoised_out rate=48000
load-module module-ladspa-sink sink_name=mic_raw_in sink_master=mic_denoised_out label=noise_suppressor_mono plugin=librnnoise_ladspa control=50
load-module module-loopback latency_msec=25 source=WebRTC_source sink=mic_raw_in channels=1 source_dont_move=true sink_dont_move=true
load-module module-remap-source source_name=denoised master=mic_denoised_out.monitor channels=1 source_properties='device.description="Filtered USB Mic"'
set-default-source denoised

Nun kann PulseAudio mit z.B. systemctl --user restart pulseaudio.service  neugestartet werden damit diese Konfiguration geladen wird.

Erfahrungen

Folgende Sachen sind mir bei Benutzung dieses Setups aufgefallen.

  • Alleine die Benutzung von module-echo-cancel bringt schon viel. Wenn dies reicht kann die Nutzung von RNNoise auch weggelassen werden. Wenn die Qualität des Mikrofons schon gut ist und keine automatische Lautstärkeregulung gebraucht wird, reicht auch nur RNNoise.
  • Die Kombination von WebRTC und RNNoise filtert das (50Hz) Brummen, was durch Stromleitungen gerne verursacht wird komplett raus.
  • Man hat relativ viele neue Audioquellen in seinen Einstellungen. Leider gibt es meines Wissens nach keine Möglichkeit diese zu verstecken.
  • PulseAudio erzeugt eine höhere CPU-Last als normal. Dies ist aber bis jetzt aber nicht problematisch geworden.

Sonstiges

RNNoise lässt sich auch mit z.B. mpv nutzen. Hier kann man auch die verschiedenen Modelle probieren die hier zu finden sind: https://github.com/GregorR/rnnoise-models

# Mit dem LADSPA plugin
mpv --af=lavfi='[ladspa=librnnoise_ladspa:p=noise_suppressor_mono]' datei.mp4
# Oder direkt über libav
mpv --af="arnndn=m=/path/to/model.rnnn" datei.mp4

Dies ist besonders hilfreich, wenn man Vorlesungen hat die verrauscht sind.

THS

Quellen und Weiterführende Links