That would have been my first suggestion - always check that the Profile of the device is correct!
Noise suppression
Almost all built-in microphones are going to struggle for quality. On many laptops, for example, they are too close to speakers or fans - and they usually have a fairly wide pattern (meaning all sorts of background noise is picked up). On webcams (when they have a built in mic), the microphone is usually quite small, has a wide pattern, and hence also isn't good.
I've been messing about a lot with PipeWire/WirePlumber and LV2 (or LADSPA) plugins; but there's no user-friendly way to set them up. Nor can they cure all ills. But ...
PipeWire can use the rnnoise plugin for noise suppression;
The plugin itself can be downloaded the from the releases. The LADSPA variant can be extracted and placed in ~/.ladspa
.
An example configuration to use the plugin within PipeWire is supplied in the plugin's README, along with instructions for the configuration location (e.g. ~/.config/pipewire/pipewire.conf.d
).
To connect the plugin automatically, we can set the target.object
value in the capture.props
argument of the configuration. The correct value for target.object
can be found via wpctl status
and wpctl inspect
, as I'll explain.
Let's say we want to use a headset (Razer Barracuda X). First we look for its id
for PipeWire using wpctl
(from WirePlumber):
# ids are listed under the 'Sources' section of the output
# so lets look at the first few lines of the section:
wpctl status | grep 'Sources' -A3
with output:
├─ Sources:
│ * 39. UMC202HD 192 voice filters [vol: 1.00]
│ 70. Razer Barracuda X Mono [vol: 1.41]
│
The id
is 70
. Now we get the node.name
of this source node which should be a stable-enough value for target.object
:
wpctl inspect 70 | grep 'node\.name'
with output:
* node.name = "alsa_input.usb-1532_Razer_Barracuda_X_R002000000-01.mono-fallback"
Putting this together we have the final (example) configuration:
context.modules = [
{ name = libpipewire-module-filter-chain
args = {
node.description = "Noise Canceling source"
media.name = "Noise Canceling source"
filter.graph = {
nodes = [
{
type = ladspa
name = rnnoise
plugin = /path/to/librnnoise_ladspa.so
label = noise_suppressor_mono
control = {
"VAD Threshold (%)" = 50.0
"VAD Grace Period (ms)" = 200
"Retroactive VAD Grace (ms)" = 0
}
}
]
}
capture.props = {
node.name = "capture.rnnoise_source"
node.passive = true
audio.rate = 48000
}
playback.props = {
node.name = "rnnoise_source"
media.class = Audio/Source
audio.rate = 48000
target.object = "alsa_input.usb-1532_Razer_Barracuda_X_R002000000-01.mono-fallback"
}
}
}
]
Then we can restart the audio via systemctl restart --user pipewire.{service,socket} wireplumber.service
(sometimes web pages or other apps that use audio need to be refreshed, depends on the browser/app).