Attempting to use Calls with a USB headset (or other USB audio devices) attached to the Librem 5 presents me with a couple of related issues…
- When the call connects, the input (headset mic) volume drops to a very low level, so low that the call recipient can either barely hear you or simply can’t hear you at all.
- Raising the input volume manually from g-c-c invariably triggers automatic gain control which then steps up the volume to 100% or close to it over a short period of time resulting in the volume being too loud at the recipient’s end to such an extent the audio becomes unclear.
I had a cumbersome hack workaround which I detailed in the Internal mic fix? thread, this works but is not practical for everyday usage.
I spent some more time on it and have come up with a “set and forget” solution which allows for USB headsets to be the simple plug ‘n’ play devices they’re supposed to be while being able to be used by Calls
without having their input volumes messed around with.
I’m using udev to detect the devices being attached, this also triggers a systemd user unit which in turn adds a filter definition to the device properties. It’s the same filter definition as is added to the internal audio hardware at boot so when a call connects the echo-cancel module is loaded, the filter is applied and input volumes remain unchanged.
The files required will be placed in system locations so you will require root permissions. to write to those file locations
For udev, I create the file…
/etc/udev/rules.d/99-usb-audio-devices.rules
…with the following contents…
# USB audio devices requiring echo cancellation filter definition
ACTION=="change", SUBSYSTEM=="sound", \
ENV{ID_TYPE}=="audio", \
ENV{ID_BUS}=="usb", \
ENV{SOUND_INITIALIZED}=="1", \
ENV{ID_SERIAL}=="?*", \
ENV{ECHO_CANCEL}!="0", \
TAG+="systemd", \
SYMLINK+="snd/audio-device_%E{ID_SERIAL}", \
ENV{SYSTEMD_USER_WANTS}="echo-cancel-filter@%E{ID_SERIAL}.service"
This triggers when a USB audio device is plugged in to the Librem 5 and in turn triggers the systemd user unit passing the “ID_SERIAL” value to the unit. From the devices I have tested with, they all use the “ID_SERIAL” string to form part of the card name as used by ALSA and pulseaudio so it appears to be a good choice to aid IDing the devices in the config script.
The udev rule includes a check for an “ECHO_CANCEL” value, this provides a mechanism for disabling the echo cancellation filter config on any devices if needs be.
For the systemd user unit, I create the file…
/etc/systemd/user/echo-cancel-filter@.service
…the “@” in the file name is important, and I place the following contents into the file…
[Unit]
Description=Echo cancellation filter for audio devices
Requiste=pulseaudio.service
After=pulseaudio.service
After=dev-snd-audio\x2ddevice_%i.device
[Service]
Type=oneshot
ExecStart=/usr/bin/echo-cancel %i
…the Requiste and Afters are probably redundant but “belt and braces” and all that. The %i is the “ID_SERIAL” string from the previous udev rule. This unit file just triggers the script and passes the “ID_SERIAL” value along to it, the script does the actual work of adding the filter parameters to the device.
For the script I create the file…
/usr/bin/echo-cancel
With the following contents…
#!/bin/bash
ECF_PARAMS='"'
ECF_PARAMS+='use_master_format=1 '
ECF_PARAMS+='aec_args=\"'
ECF_PARAMS+='analog_gain_control=0 '
ECF_PARAMS+='voice_detection=0 '
ECF_PARAMS+='high_pass_filter=0 '
ECF_PARAMS+='noise_suppression=0'
ECF_PARAMS+='\"'
ECF_PARAMS+='"'
for TYPES in sources sinks; do
IDX=$(pactl list short ${TYPES} \
| awk -v DAC="${1}" '$2 ~ DAC \
&& $2 !~ /\.monitor$/ \
&& $2 !~ /\.echo-cancel$/ { print $1 }')
if [[ ! -z ${IDX} ]]; then
pacmd update-${TYPES%?}-proplist ${IDX} \
filter.apply.echo-cancel.parameters=${ECF_PARAMS}
fi
done
… the script requires to be made executable…
sudo chmod +x /usr/bin/echo-cancel
The tricky part of the script was working out a formatting of the parameters string that pacmd
would parse properly.
After rebooting, the rules will be in place and plugging in any USB audio device will now have the required filter definition automatically added and will be usable with Calls
.
If you don’t want to reboot to test, you can simply reload the udev rules…
sudo udevadm control --reload-rules
So far I have tested with the following hardware…
- Beyerdynamic MMX 150 a dedicated USB headset.
- UGREEN USB C to 3.5mm adapter providing connectivity for Beyerdynamic MMX 300 analog headset.
- THX Onyx also providing connectivity for Beyerdynamic MMX 300 analog headset.
- Jabra Evolve 65 with Jabra Link 360 a standard wireless telephony headset.
-
Samson G-Track Pro a USB desktop microphone, I used this in a couple of configurations.
- As mic input while the phone was set to speakerphone.
- As both mic input and speaker output as it has an inbuilt monitor feature which can take the phone output as it’s monitor input.
These all work fine.