Skip to content

Instantly share code, notes, and snippets.

@ragusa87
Last active January 30, 2020 19:08
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save ragusa87/6687903 to your computer and use it in GitHub Desktop.
Save ragusa87/6687903 to your computer and use it in GitHub Desktop.
Enable bluetooth A2DP on Raspberry-PI via pulseaudio. To install, edit /etc/udev/rules.d/99-input.rules and add the line: SUBSYSTEM=="bluetooth", RUN+="/usr/lib/udev/bluetooth" Then save this script as /usr/lib/udev/bluetooth and set it executable. Bluetooth devices must be linked first.
#!/bin/bash
# This script is called by udev when you link a bluetooth device with your computer
# It's called to add or remove the device from pulseaudio
#
#
# Output to this file
LOGFILE="/var/log/bluetooth_dev"
# Name of the local sink in this computer
# You can get it by calling : pactl list short sinks
AUDIOSINK="alsa_output.platform-bcm2835_AUD0.0.analog-stereo"
# User used to execute pulseaudio, an active session must be open to avoid errors
USER="pi"
# Audio Output for raspberry-pi
# 0=auto, 1=headphones, 2=hdmi.
AUDIO_OUTPUT=1
# If on, this computer is not discovearable when an audio device is connected
# 0=off, 1=on
ENABLE_BT_DISCOVER=1
echo "For output see $LOGFILE"
## This function add the pulseaudio loopback interface from source to sink
## The source is set by the bluetooth mac address using XX_XX_XX_XX_XX_XX format.
## param: XX_XX_XX_XX_XX_XX
## return 0 on success
add_from_mac(){
if [ -z "$1" ] # zero params
then
echo "Mac not found" >> $LOGFILE
else
mac=$1 # Mac is parameter-1
# Setting source name
bluez_dev=bluez_source.$mac
echo "bluez source: $mac" >> $LOGFILE
# This script is called early, we just wait to be sure that pulseaudio discovered the device
sleep 1
# Very that the source is present
CONFIRM=`sudo -u pi pactl list short | grep $bluez_dev`
if [ ! -z "$CONFIRM" ]
then
echo "Adding the loopback interface: $bluez_dev" >> $LOGFILE
echo "sudo -u $USER pactl load-module module-loopback source=$bluez_dev sink=$AUDIOSINK rate=44100 adjust_time=0" >> $LOGFILE
# This command route audio from bluetooth source to the local sink..
# it's the main goal of this script
sudo -u $USER pactl load-module module-loopback source=$bluez_dev sink=$AUDIOSINK rate=44100 adjust_time=0 >> $LOGFILE
return $?
else
echo "Unable to find a bluetooth device compatible with pulsaudio using the following device: $bluez_dev" >> $LOGFILE
return -1
fi
fi
}
## This function set volume to maximum and choose the right output
## return 0 on success
volume_max(){
# Set the audio OUTPUT on raspberry pi
# amixer cset numid=3 <n>
# where n is 0=auto, 1=headphones, 2=hdmi.
amixer cset numid=3 $AUDIO_OUTPUT >> $LOGFILE
# Set volume level to 100 percent
amixer set Master 100% >> $LOGFILE
pacmd set-sink-volume 0 65537 >> $LOGFILE
return $?
}
## This function will detect the bluetooth mac address from input device and configure it.
## Lots of devices are seen as input devices. But Mac OS X is not detected as input
## return 0 on success
detect_mac_from_input(){
ERRORCODE=-1
echo "Detecting mac from input devices" >> $LOGFILE
for dev in $(find /sys/devices/virtual/input/ -name input*)
do
if [ -f "$dev/name" ]
then
mac=$(cat "$dev/name" | sed 's/:/_/g')
add_from_mac $mac
# Endfor if the command is successfull
ERRORCODE=$?
if [ $ERRORCODE -eq 0]; then
return 0
fi
fi
done
# Error
return $ERRORCODE
}
## This function will detect the bt mac address from dev-path and configure it.
## Devpath is set by udev on device link
## return 0 on success
detect_mac_from_devpath(){
ERRORCODE=-1
if [ ! -z "$DEVPATH" ]; then
echo "Detecting mac from DEVPATH" >> $LOGFILE
for dev in $(find /sys$DEVPATH -name address)
do
mac=$(cat "$dev" | sed 's/:/_/g')
add_from_mac $mac
# Endfor if the command is successfull
ERRORCODE=$?
if [ $ERRORCODE -eq 0]; then
return 0
fi
done
return $ERRORCODE;
else
echo "DEVPATH not set, wrong bluetooth device? " >> $LOGFILE
return -2
fi
return $ERRORCODE
}
## Detecting if an action is set
if [ -z "$ACTION" ]; then
echo "The script must be called from udev." >> $LOGFILE
exit -1;
fi
## Getting the action
ACTION=$(expr "$ACTION" : "\([a-zA-Z]\+\).*")
# Switch case
case "$ACTION" in
"add")
# Turn off bluetooth discovery before connecting existing BT device to audio
if [ $ENABLE_BT_DISCOVER -eq 1]; then
echo "Stet computer as hidden" >> $LOGFILE
hciconfig hci0 noscan
fi
# Turn volume to max
volume_max
# Detect BT Mac Address from input devices
detect_mac_from_input
OK=$?
# Detect BT Mac address from device path on a bluetooth event
if [ $OK != 0 ]; then
if [ "$SUBSYSTEM" == "bluetooth" ]; then
detect_mac_from_devpath
OK=$?
fi
fi
# Check if the add was successfull, otherwise display all available sources
if [ $OK != 0 ]; then
echo "Your bluetooth device is not detected !" >> $LOGFILE
echo "Available sources are:" >> $LOGFILE
sudo -u $USER pactl list short sources >> $LOGFILE
else
echo "Device successfully added " >> $LOGFILE
fi
;;
"remove")
# Turn on bluetooth discovery if device disconnects
if [ $ENABLE_BT_DISCOVER -eq 1]; then
echo "Set computer as visible" >> $LOGFILE
sudo hciconfig hci0 piscan
fi
echo "Removed" >> $LOGFILE
;;
#
*)
echo "Unsuported action $action" >> $LOGFILE
;;
esac
echo "--" >> $LOGFILE
@ssj71
Copy link

ssj71 commented Jan 11, 2018

Thanks for this script!

I just put the script in my home directory with some changes since I'm not using pulseaudio. Its working, but the logfile isn't being created so I'm having a hard time troubleshooting. Does it have to run from /usr/lib/udev to make the log or something?

@malteos
Copy link

malteos commented Mar 22, 2018

My bluetooth device is not getting detected. Any hints how to solve this?

Unable to find a bluetooth device compatible with pulsaudio using the following device: bluez_source.XX_XX_XX_XX_XX
Your bluetooth device is not detected !
Available sources are:
0	alsa_output.platform-soc_audio.analog-stereo.monitor	module-alsa-card.c	s16le 2ch 44100Hz	IDLE
--

@00xBIT
Copy link

00xBIT commented Aug 14, 2018

@mschwarzer
I have same problem.

@m-karbowski
Copy link

m-karbowski commented Jan 31, 2019

@malteos @00xBIT
This check is done by sudo -u $USER pactl list short sources and under sudo sources are not shown:

$ pactl list short sources
0	alsa_output.usb-Burr-Brown_from_TI_USB_Audio_DAC-00.analog-stereo.monitor
24	bluez_source.xx_xx_xx_xx_xx_xx.a2dp_source
$ sudo -u openhabian pactl list short sources
0	alsa_output.usb-Burr-Brown_from_TI_USB_Audio_DAC-00.analog-stereo.monitor

I haven't found solution for this problem, but I found out that audio is routing correctly without this script (probably newer pulseaudio or bluez is smarter). The only thing that I had to configure is setting default sink in /etc/pulse/client.conf:

; default-sink = alsa_output.usb-Burr-Brown_from_TI_USB_Audio_DAC-00.analog-stereo

My setup:

Operating System: Raspbian GNU/Linux 9 (stretch)
Kernel: Linux 4.14.94-v7+

Package: pulseaudio
Version: 10.0-1+deb9u1

Package: bluez
Version: 5.43-2+rpt2+deb9u2

@ragusa87
Copy link
Author

There is a nice up to date project that you can use instead: https://github.com/nicokaiser/rpi-audio-receiver

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment