Skip to content

Instantly share code, notes, and snippets.

@jason-costello
Forked from oleq/_README.md
Created August 5, 2017 02:19
Show Gist options
  • Select an option

  • Save jason-costello/c8c936ddb2b537d3d9b6cbba1d48d260 to your computer and use it in GitHub Desktop.

Select an option

Save jason-costello/c8c936ddb2b537d3d9b6cbba1d48d260 to your computer and use it in GitHub Desktop.
A2DP audio streaming using Raspberry PI (Raspbian Jessie)
#!/bin/bash
PA_SINK="alsa_output.0.analog-stereo"
LOG_FILE=/var/log/a2dp-autoconnect
MAC=$(echo "$NAME" | sed 's/:/_/g' | sed 's/\"//g')
BT_USER=pi
function log {
echo "[$(date)]: $*" >> $LOG_FILE
}
function checkSource {
# Get the current sources
local _sources=$(sudo -u "$BT_USER" pactl list sources short)
# Check if any sources are currently running
# and that our new device is valid.
if [[ ! "$_sources" =~ RUNIING ]] && [[ "$_sources" =~ "$1" ]] ; then
log "Validated new source: $1"
log "$1"
fi
}
function setVolume {
# Set our volume to max
sudo -u "$BT_USER" pacmd set-sink-volume 0 65537
sudo -u "$BT_USER" amixer set Master 100%
}
function connect {
# Connect source to sink
sudo -u "$BT_USER" pactl load-module module-loopback \
source="$1" sink="$PA_SINK" rate=44100 adjust_time=0
}
log "Change for device $MAC detected, running $ACTION"
if [ "$ACTION" = "add" ]
then
incoming=bluez_source."$MAC"
if [ ! -z $(checkSource "$incoming") ] ; then
connect "$incoming"
setVolume
else
log "Source $incoming invalid or some source already running."
fi
fi

Initial setup

Raspberry PI running Raspbian Jessie.

Make sure PI is up–to–date:

sudo apt-get update
sudo apt-get upgrade

Install required packages:

http://www.instructables.com/id/Enhance-your-Raspberry-Pi-media-center-with-Blueto/?ALLSTEPS

sudo apt-get install alsa-utils bluez bluez-tools pulseaudio-module-bluetooth python-gobject python-gobject-2

Not quite sure it's really needed (?), but it doesn't hurt:

sudo usermod -a -G lp pi

Obtaining hardware

I used external USB audio interface Creative Sound Blaster Play. The on–board audio produces low–quality, noisy output, so I decided to use something better.

As for Bluetooth dongle, I used Digitus Tiny USB-Adapter, which is discovered as Cambridge Silicon Radio, Ltd Bluetooth Dongle.

Note: I used another dongle (different manufacturer) also discovered as Cambridge Silicon Radio... but unable to stream audio. So beware, because different manufacturers use the same hardware in a different way. Or pretend to use the same hardware for some (compatibility?) reasons. This way or another, if you get garbled audio or no audio at all but everything else is alright, then try another dongle – it's cheap.

See RPi USB Bluetooth adapters for buying recommendations. Trial and error is another option, since most devices cost below $10.

pi@raspberrypi:~ $ lsusb
...
Bus 001 Device 008: ID 041e:30d3 Creative Technology, Ltd Sound Blaster Play!
...
Bus 001 Device 012: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
...

Setup PulseAudio

http://www.crazy-audio.com/2014/09/pulseaudio-on-the-raspbery-pi/

pi@raspberrypi:~ $ cat /etc/pulse/daemon.conf
...
enable-remixing = no
enable-lfe-remixing = no
default-sample-format = s32le
default-sample-rate = 192000
alternate-sample-rate = 176000
default-sample-channels = 2
exit-idle-time = -1
...

Reboot PI:

sudo reboot

Configure USB Audio

The problem is that on–board audio ouput is prefered over USB audio interface:

pi@raspberrypi:~ $ cat /proc/asound/modules
 0 snd_bcm2835
 1 snd_usb_audio

Some configuration does the trick and from now on RPI uses USB Audio as default:

http://raspberrypi.stackexchange.com/questions/40831/how-do-i-configure-my-sound-for-jasper-on-raspbian-jessie

pi@raspberrypi:~ $ cat /etc/modprobe.d/alsa-base.conf
# This sets the index value of the cards but doesn't reorder.
options snd_usb_audio index=0
options snd_bcm2835 index=1

# Does the reordering.
options snd slots=snd-usb-audio,snd-bcm2835

Reboot the device:

sudo reboot

See snd_usb_audio as a preferred output:

pi@raspberrypi:~ $ cat /proc/asound/modules
 0 snd_usb_audio
 1 snd_bcm2835

Setup Bluetooth

pi@raspberrypi:~ $ cat /etc/bluetooth/audio.conf
[General]
Class = 0x20041C
Enable = Source,Sink,Media,Socket

Reboot PI:

sudo reboot

Pair devices (phones, tablets, PCs) with PI:

bluetoothctl
[bluetooth]# list
Controller 00:1A:7D:DA:71:06 raspberrypi [default]
[bluetooth]# agent on
[bluetooth]# default-agent
[bluetooth]# discoverable on
[bluetooth]# scan on

Then, for each device:

pair XX:XX:XX:XX:XX:XX
trust XX:XX:XX:XX:XX:XX

Setup auto connecting

pi@raspberrypi:~ $ pactl list sources short
0   alsa_output.0.analog-stereo.monitor module-alsa-card.c  s16le 2ch 48000Hz   IDLE
1   alsa_input.0.analog-mono    module-alsa-card.c  s16le 1ch 48000Hz   IDLE
4   bluez_source.A8_88_08_11_AB_4B  module-bluez5-device.c  s16le 2ch 44100Hz   RUNNING

pi@raspberrypi:~ $ pactl list sinks short
0   alsa_output.0.analog-stereo module-alsa-card.c  s16le 2ch 48000Hz   RUNNING

The whole trick to make a2dp work is to redirect a right source (like iPhone) to the right sink (ALSA).

In this example it would be bluez_source.A8_88_08_11_AB_4B -> alsa_output.0.analog-stereo, given that the phone is already paired and connected to PI.

Add udev rule which executes a2dp-autoconnect script each time a bluetooth device is connected

pi@raspberrypi:~ $ sudo cat /etc/udev/rules.d/99-input.rules
KERNEL=="input[0-9]*", RUN+="/home/pi/a2dp-autoconnect"

The script is an extended version of http://blog.mrverrall.co.uk/2013/01/raspberry-pi-a2dp-bluetooth-audio.html. It redirects a new bluetooth device to the right sink and sets the right volume level.

I located it in /home/pi/a2dp-autoconnect, then set it executable:

pi@raspberrypi:~ $ chmod +x a2dp-autoconnect

To observe connection log "live":

pi@raspberrypi:~ $ tail -f /var/log/a2dp-autoconnect
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment