Raspberry Pi Bluetooth Speaker

Raspbian Wheezy Installation Guide

From a fresh installation of Wheezyrun the following as the default user pi:

pi@raspberrypi ~ $ sudo apt-get install bluez pulseaudio-module-bluetooth python-gobject python-gobject-2 alsa-utils

Add the user pi to the group lp. This is so the user pi can get access to the bluetooth daemon. If this isn’t done, the bluez source will not show up in pulse audio.

pi@raspberrypi ~ $ sudo usermod -a -G lp pi

The bluetooth stack has to be configured for A2DP.

pi@raspberrypi ~ $ sudo nano /etc/bluetooth/audio.conf

Add the following line after [General]:

Enable=Source,Sink,Media,Socket

Change the resampling algorithm for pulse audio

pi@raspberrypi ~ $ sudo nano /etc/pulse/daemon.conf
; resample-method = speex-float-3
resample-method = trivial ; ADD THIS LINE

Reboot at this point!

pi@raspberrypi ~ $ sudo reboot

NOTE: Do not run these with sudo… Run as pi!

Boot up, log-in, and run:

pi@raspberrypi ~ $ sudo hciconfig hci0 piscan

Makes the Pi BT discoverable

pi@raspberrypi ~ $ bluez-simple-agent

Connect with your smart phone and enter pin / authorize.
After authorization is complete, CTRL-C out.

You can then trust the phone by using the command:

pi@raspberrypi ~ $ bluez-test-device trusted B8:C6:8E:52:E8:CA yes

It shouldn’t ask for a pin in the future…

After the phone is connected, list the sources. A bluez source should show up:
Note: This command will start the PulseAudio daemon in per-user mode if it is not already running!

pi@raspberrypi ~ $ pactl list sources short

0    alsa_output.platform-bcm2835_AUD0.0.analog-stereo.monitor    module-alsa-card.c    s16le 2ch 44100Hz    SUSPENDED
1    bluez_source.B8_C6_8E_52_E8_CA    module-bluetooth-device.c    s16le 2ch 44100Hz    SUSPENDED

List the sinks. An ALSA sink for the BCM codec should show up:

pi@raspberrypi ~ $ pactl list sinks short

0    alsa_output.platform-bcm2835_AUD0.0.analog-stereo    module-alsa-card.c    s16le 2ch 44100Hz    SUSPENDED

Connect the source to the sink manaual as a test:

pi@raspberrypi ~ $ pactl load-module module-loopback source=bluez_source.B8_C6_8E_52_E8_CA sink=alsa_output.platform-bcm2835_AUD0.0.analog-stereo

If you play the song on the phone, it should be played on the connected speakers. If not, maybe the default output isn’t the line out jack or the volume is muted or too low.

The audio defaults to the HDMI output. I wanted it to play over the headphone jack.
Here is the command to set the source to headphone jack:

pi@raspberrypi ~ $ amixer cset numid=3 1

turn up the ALSA volume:

pi@raspberrypi ~ $ amixer set Master 100%

Also turn up the PulseAudio volume:

pi@raspberrypi ~ $ pacmd set-sink-volume 0 65537

The 0 is the sink channel number for alsa_output.platform-bcm2835_AUD0.0.analog-stereo as found with the command: “pactl list sinks short”.

Script to automate this when a bluetooth device attaches

To trigger the udev script when a new device connects create (or modify) an even handler in /etc/udev/rules.d/99-input.rules adding the following content rules

SUBSYSTEM="input", GROUP="input", MODE="0660"
KERNEL=="input[0-9]*", RUN+="/usr/lib/udev/bluetooth"

Now let’s actually save that script that the above rule file is referencing. First check to see if a udev/ directory exists. Do sudo ls –la /usr/lib/udev . If it doesn’t exist go ahead and create it like so: sudo mkdir /usr/lib/udev

sudo nano /usr/lib/udev/bluetooth
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/bin/bash
# This script belongs in /usr/lib/udev/bluetooth and should be executable

#PA_SINK='alsa_output.platform-bcm2835_AUD0.0.analog-stereo'
#Change SINK to 0 as name of sink changes on hardware change. 0 Is default
PA_SINK=0
LOG_FILE=/var/log/bluetooth_a2dp
MAC=$(echo "$NAME" | sed 's/:/_/g' | sed 's/"//g')

# Set the user you want to run as, 'pi' would be fine for most.
BT_USER=pi

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
        echo "Validated new source: $1" >> "$LOG_FILE"
        echo "$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
}

echo "Change for device $MAC detected, running $ACTION" >> "$LOG_FILE"

if [ "$ACTION" = "add" ]
then
    incoming=bluez_source."$MAC"
    if [ ! -z $(checkSource "$incoming") ] ; then
        connect "$incoming"
        setVolume
    fi
fi

disable timeouts by adding a line in ‘/etc/pulse/client.conf’

extra-arguments = --exit-idle-time=-1 --log-target=syslog

The Pi User has to be logged in for this to work. In a headless setup you can get the Pi to auto login by editing the /etc/inittab file and replacing the line

1:2345:respawn:/sbin/getty 115200 tty1

with

1:2345:respawn:/bin/login -f pi tty1 /dev/tty1 2>&1

Also forget about auto pairing, not going to happen. BLUEZ 4 onwards disabled this as a security measure. Your gonna have to SSH in and pair your devices