DEV Community

Cover image for Switch between HSP/HFP and A2DP from system tray

Posted on

Switch between HSP/HFP and A2DP from system tray

This is going to be about Linux and Pulseaudio, you can stop reading now if you don't use those.

So you have a Bluetooth headset and are wondering what is HSP/HFP and A2DP?

A2DP mode is a high fidelity mode for listening to music. But? You can't use the headset's microphone. Basically in this mode your headset becomes just headphones.

If you want to use the mic you need to switch to the HSP/HFP mode, also know as "hands free mode" But the catch is that it is limited to 8000Hz frequency range, which, I guess, is OK for voice but is totally unbearable for listening to music.

So we need to switch between these 2 modes depending on whether we want to listen to music or have a conversation with someone on some telecommunications application like Skype or Zoom.

If you are using a GNU/Linux distribution your audio is most likely managed by Pulseaudio. It is a network-capable sound server program distributed via the project. It is capable of routing sound via Bluetooth using the pulseaudio-bluetooth module.

Now, we can tell Pulseaudio to switch between HSP/HFP and A2DP depending on the context.

We do this by editing the /etc/pulse/ configuration file. Find the load-module module-bluetooth-policy
line and append auto_switch=2 to it.

Restart the Pulseaudio daemon and now our headset should switch to the HSP/HFP mode when some application activates the microphone and it should switch back to the A2DP mode when the microphone is released and no longer needed.

This sounds fine in theory and works well. But what happens when you want to use an audio editor? Most audio editors will invoke the microphone. So are we going to edit our audio in 8000hz fidelity or do we want to force our headset back to the A2DP mode?

What if we want to use an external mic and keep the high fidelity mode temporarily? What if we are in a listen only Zoom meeting and don't really need the microphone as we are not going to say anything really.

There is a solution, we can switch the audio profiles using the Pulseaudio utility pactl as described next.

First we need to find the address of our Bluetooth card. We can do this by executing the following command.

$ pactl list cards | grep Name
        Name: alsa_card.pci-0000_00_1b.0
        Name: bluez_card.F4_0E_11_7E_93_EB
Enter fullscreen mode Exit fullscreen mode

Here we see our Bluetooth headset bluez_card.F4_0E_11_7E_93_EB. Now having this, we can use pactl to force whatever mode we want.

Set the A2DP mode like this:

pactl set-card-profile bluez_card.F4_0E_11_7E_93_EB a2dp_sink
Enter fullscreen mode Exit fullscreen mode

Set the HSP/HFP mode like this:

pactl set-card-profile bluez_card.F4_0E_11_7E_93_EB headset_head_unit
Enter fullscreen mode Exit fullscreen mode

Ok, so that gets the job done and we can make shorter aliases in our shell of choice. But what if we don't want to pop up the terminal emulator each time we want to force a specific mode?

Well, for this I wrote a little graphical utility that sits in the system tray and let's you switch the profiles from your desktop. It is just a little wrapper around pactl but it gets the job done.

It is called bt_profile and can be found here

It looks like this when it is running:


We start this utility by giving it the Bluetooth headset's Pulseaudio address we obtained earlier. Like this:

$ bt_profile -sink "bluez_card.F4_0E_11_7E_93_EB"
Enter fullscreen mode Exit fullscreen mode

We can now put this in our desktop's start up scripts. On KDE you go in System Settings -> Autostart and add the command.

That's it, I hope this is useful for some :)

Discussion (1)

c1p0 profile image

Thanks for this article! I ended up just binding some keyboard shortcuts to each pactl command, but it was still very useful.