How to keep the audio profile at A2DP while using a mic with Bluetooth headset? (Push-to-talk)

Ondra, there is a very long pulse audio merge request discussion that contains most of the information.

tl;dr; to get things working pulse audio, bluez and kernel need to be updated (not trivially). As well a separate daemon hsphfpd is necessary.

Kernel updates are not progressing and user input to maintainers would be helpful in pushing things forward. Think about providing such. See here.

Without the kernel patches, using headphones' mic leads to terrible audio quality (HSP/HFP mode of operation).

But there is chance that only Pulse patches (and support from your headphones) can enable A2DP bi-directional audio which should be alright for most purposes.

And that patch is progressing well at the moment. More feedback on it shouldn't hurt.

Update: THings in above mentioned pull request escalated very quickly and seems like PulseAudio may never implement proper bluetooth support. Lets hope for Pipewire which already has some patches.


I was about to return the headset and wait for Bluetooth 5.0 headset, but then realized, that's the best functionality I can get with my BT 4.0 laptop. So I kept them.

Still, listening to a French guy over 16 bit 8000 Hz audio wasn't really the right way to have a meeting. For few days, I was switching between the two modes using Ubuntu's sound settings dialog, but that's really, really annoying as you can imagine.

So I wrote this script leveraging pacmd which toggles between the 2 modes:

  • Crappy audio, microphone on
  • Near-CD quality audio, microphone off

It is not polished, has some dead code, and I use my own phones ID's, but it may be an inspiration for your own script. Latest version here.

#!/bin/bash

####  Restart Bluetooth
if [ "$1" == "resetBT" ] ; then
  sudo rfkill block bluetooth && sleep 0.1 && sudo rfkill unblock bluetooth;
  exit;
fi;

#### Toggle listen/speak
if [ "$1" == "" -o "$1" == "toggle" ] ; then
  LINE=`pacmd list-sinks  | grep '\(name:\|alias\)' | grep -B1 F5A  | head -1`
  if [ "$LINE" == "" ] ; then echo "F5A headset not found"; exit; fi

  SINK_NAME="bluez_sink.00_19_5D_25_6F_6C.a2dp_sink"
  if $(echo "$LINE" | grep $SINK_NAME &> /dev/null) ; then
    echo "Detected quality sound output, that means we can't speak; switch that."
    $0 speak;
  else
    echo "Quality sound not found, switch to the good sound."
    $0 listen;
  fi
fi

#### Change the output to F5A
if [ "$1" == "listen" ] ; then
  LINE=`pacmd list-sinks  | grep '\(name:\|alias\)' | grep -B1 F5A  | head -1`
  if [ "$LINE" == "" ] ; then echo "F5A phones not found"; exit; fi
  #        name: <bluez_sink.00_19_5D_25_6F_6C.headset_head_unit>

  ## Get what's between <...>
  SINK_NAME=`echo "$LINE" | tr '>' '<' | cut -d'<' -f2`;

  ## The above gives an ID according to the active profile.
  ## To set manually:
  #SINK_NAME="bluez_sink.00_19_5D_25_6F_6C.headset_head_unit"
  #SINK_NAME="bluez_sink.00_19_5D_25_6F_6C.a2dp_sink"

  ## Switch the output to that.
  echo "Switching audio output to $SINK_NAME";
  pacmd set-default-sink "$SINK_NAME"

  #### Change profile to quality output + no mic. From `pacmd list-cards`:
  CARD="bluez_card.00_19_5D_25_6F_6C"
  PROFILE="a2dp_sink"   
  echo "Switching audio profile to $PROFILE";
  pacmd set-card-profile $CARD $PROFILE
  exit;
fi;

#### Input
if [ "$1" == "speak" ] ; then
  ## Change profile to crappy output + mic. From `pacmd list-cards`:
  CARD="bluez_card.00_19_5D_25_6F_6C"
  pacmd set-card-profile $CARD headset_head_unit

  LINE=`pacmd list-sources | grep '\(name:\|alias\)' | grep -B1 F5A  | head -1`
  if [ "$LINE" == "" ] ; then echo "F5A mic not found"; exit; fi
  SOURCE_NAME=`echo "$LINE" | tr '>' '<' | cut -d'<' -f2`;
  #SOURCE_NAME="bluez_source.00_19_5D_25_6F_6C.headset_head_unit"
  #SOURCE_NAME="bluez_sink.00_19_5D_25_6F_6C.a2dp_sink.monitor"
  echo "Switching audio input to $SOURCE_NAME";
  pacmd set-default-source "$SOURCE_NAME" || echo 'Try `pacmd list-sources`.';
fi;


####  Resources:

##  Why this is needed
# https://jimshaver.net/2015/03/31/going-a2dp-only-on-linux/

##  My original question
# https://askubuntu.com/questions/1004712/audio-profile-changes-automatically-to-hsp-bad-quality-when-i-change-input-to/1009156#1009156

##  Script to monitor plugged earphones and switch when unplugged (Ubuntu does that, but nice script):
# https://github.com/freundTech/linux-helper-scripts/blob/master/padevswitch/padevswitch

Hope this helps someone :)


Based on this article I fear that Bluetooth won't give me the pleasure of hearing a quality sound and speak over the headset at the same time. :/

Not accepting this answer though, I am still hoping someone will come up with some way to do so.