Flawless Bluetooth Headset (MDR-100ABN) on Linux

When I first got my headset, I kept having problems where A2DP wouldn’t work right upon connecting to bluetooth. I could get it to work by reconnecting occasionally, but nothing worked consistently. I googled around and found https://askubuntu.com/questions/765233/pulseaudio-fails-to-set-card-profile-to-a2dp-sink-how-can-i-see-the-logs-and, from this thread I found a few different solutions, some which worked. However, I wasn’t happy with manually running some sort of a2dp-fix script each time I plugged my headset in, so I set out to automate it. The main issue I had was that bluetoothctl wouldn’t work when running from a udev rule. After looking at some examples and digging into the source code, I figured out how to use dbus to accomplish the same. I now finally have it working using the following scripts:



bt_device_addr=$(pacmd list-cards | grep -i 'name:.*bluez_card' | sed -E 's/.*<?bluez_card\.([A-Z0-9_]+)>?/\1/')
device_mac=$(echo $bt_device_addr | sed 's/_/:/g')

a2dp_available=$(pacmd list-cards | grep -A30 bluez | grep "A2DP Sink" | sed -E 's/.* available: ([a-z]+)\)/\1/g')

if [[ "$a2dp_available" == "no" ]] || [[ "$a2dp_available" == "unknown" ]]
dbus-send --system --dest=org.bluez --print-reply /org/bluez/hci0/dev_$bt_device_addr org.bluez.Device1.Connect

pacmd set-card-profile bluez_card.$bt_device_addr off
pacmd set-card-profile bluez_card.$bt_device_addr a2dp_sink
pacmd set-default-sink bluez_sink.$bt_device_addr.a2dp_sink

This is the main script, which does the heavy lifting. Before trying to automate this, see if running this script fixes A2DP for you. If it does, then create the next couple of scripts to automate it.


ACTION=="add", SUBSYSTEM=="bluetooth", RUN+="/usr/local/bin/a2dp-fix-wrapper"

That is the rule that triggers the fix upon connecting the headset. This could probably be improved to be a bit more strict, but I don’t see the harm on running every time some bluetooth device is connected.


#!/bin/bashfor PID in $(pgrep pulseaudio); do
USER=$(grep -z USER= /proc/$PID/environ | sed 's/.*=//' | tr -d '\0')
USER_ID=$(id -u $USER)
HOME=$(echo $(getent passwd $USER )| cut -d : -f 6)
export XDG_RUNTIME_DIR=/run/user/$USER_ID
export XAUTHORITY=$HOME/.Xauthority
export DISPLAY=:0
sleep 5
if [[ ! -z $USER ]]; then
sudo -u $USER -E /usr/local/bin/a2dp-fix

This script sets up all the necessary variables for a2dp-fix to work correctly when launched by udev.

With these 3 files, you should have A2DP available every time you connect your headset. However, I also find myself wanting to switch to headset mode for meetings and such. In order to make that easier, I wrote the following script and bound it to a key-shortcut


#!/bin/shset_a2dp() {
pacmd set-card-profile bluez_card.$BT_DEVICE_ADDR a2dp_sink
pacmd set-default-sink bluez_sink.$BT_DEVICE_ADDR.a2dp_sink
set_headset() {
pacmd set-card-profile bluez_card.$BT_DEVICE_ADDR headset_head_unit
pacmd set-default-sink bluez_sink.$BT_DEVICE_ADDR.headset_head_unit
pacmd set-default-source bluez_source.$BT_DEVICE_ADDR.headset_head_unit
BT_SINK=$(pacmd list-sinks | grep 'name:.*bluez_sink' | sed -E 's/.*<(.*)>/\1/')
if [[ $BT_SINK =~ $regex ]]
if [[ $BT_PROFILE == "headset_head_unit" ]]
then set_a2dp
else set_headset

Now my headset works correctly whenever I connect it, and I can easily switch between A2DP and headset modes with a single keybinding :)

Edit 01/27/19: Small fix in `/usr/local/bin/a2dp-fix` thanks to https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/525#note_108750

I’m Diego Fernández Giraldo, a Freelance Data Science Engineer looking to help your business succeed by ensuring you are leveraging data to its full potential.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store