Skip to content

Instantly share code, notes, and snippets.

@oleq
Last active September 7, 2024 13:11
Show Gist options
  • Save oleq/24e09112b07464acbda1 to your computer and use it in GitHub Desktop.
Save oleq/24e09112b07464acbda1 to your computer and use it in GitHub Desktop.
A2DP audio streaming using Raspberry PI (Raspbian Jessie)

What is this all about?

This tutorial will turn your Raspberry PI into a simple Bluetooth audio receiver, which plays music through connected speakers. It's like a regular car audio system, but it can be used anywhere and it's a good value.

   Audio source (i.e. smartphone) 
                |
                v
 (((  Wireless Bluetooth Channel  )))
                |
                v
           Raspberry PI
                |
                v
       USB Audio Interface
                |
                v
             Speakers

The Bluetooth profile which does the magic is called A2DP.

Obtaining peripherals

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)
...

Audio interface

The on–board audio produces low–quality, noisy output, so I decided to use something better. I chose external USB Creative Sound Blaster Play! interface. It costs ~$20.

Bluetooth dongle

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 they 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, don't worry, just 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.

USB Hub

Raspberry PI offers limited power to USB devices (and limited number of ports). You'll need some active (powered) USB Hub to keep USB devices stable and working (USB Audio, USB Bluettoth and optional USB WiFi). Google to learn more, it's a very common topic when using Raspberry PI.

Initial setup

I'm using Raspberry PI 1 Model B, running Raspbian Jessie. Make sure your system is up–to–date first:

sudo apt-get update
sudo apt-get upgrade

Note: It usually takes a while. Get some tee and sandwiches.

Then install required packages (related article):

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

Setup PulseAudio

Use the following configuration to get most of PulseAudio (related article):

pi@raspberrypi:~ $ cat /etc/pulse/daemon.conf
...
resample-method=ffmpeg
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

Note: PA is pretty CPU–consuming. With the following configuration it uses ~30% of my PI's CPU. So if you expect PI to do something else beside A2DP and avoid sound glitches, reasearch different resample-method.

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 (related article):

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 PI:

sudo reboot

From now on RPI uses USB Audio as default:

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

Setup Bluetooth

Make sure Bluetooth audio is working and discovered as a car audio system

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

I'm not quite sure if the following is also needed. But I added it anyway:

pi@raspberrypi:~ $ cat /etc/bluetooth/main.conf
[General]
...
Name = raspberrypi
Class = 0x20041C
...

Reboot PI:

sudo reboot

Pair devices (phones, tablets, PCs) with PI using bluetoothctl utility:

pi@raspberrypi:~ $ bluetoothctl

See that your USB dongle is here:

[bluetooth]# list
Controller 00:1A:7D:DA:71:06 raspberrypi [default]

Prepare for pairing:

[bluetooth]# agent on
[bluetooth]# default-agent
[bluetooth]# discoverable on
[bluetooth]# scan on

Then, for each device:

pair XX:XX:XX:XX:XX:XX
...
    Go through pairing process.
...
trust XX:XX:XX:XX:XX:XX

CTRL(CMD)+D to exit bluetoothctl.

Setup auto connecting

Given that your device is already paired and connected to PI, run the following:

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

and

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

The whole trick is to redirect the right source (i.e. smartphone) the right sink (ALSA) each time a new Bluetooth device is connected. In the above case, it would be bluez_source.A8_88_08_11_AB_4B to alsa_output.0.analog-stereo.

The good news that it can be automated. Add udev rule which executes a2dp-autoconnect script each time a Bluetooth device is connected:

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

The script I used is an extended version of http://blog.mrverrall.co.uk/2013/01/raspberry-pi-a2dp-bluetooth-audio.html. It's pretty straightforward: it redirects a new Bluetooth audio source to the right sink and sets output volume level.

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

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

Note: Observe connection log "live" to debug connection issues:

pi@raspberrypi:~ $ tail -f /var/log/a2dp-autoconnect

Auto–login

Some people complained that the whole configuration does not work after reboot, unless pi user is logged in.

Auto–login can be enabled using raspi–config utility

pi@raspberrypi:~ $ sudo raspi-config

in "Boot Options" -> "Console Auto–login".

Enjoy!

If your device is already paired, simply connect it to Raspberry PI and select Bluetooth audio output. Enjoy your tunes!

Tested with iPhone, MacbookPro and Windows laptop.

#!/bin/bash
# The original script: http://blog.mrverrall.co.uk/2013/01/raspberry-pi-a2dp-bluetooth-audio.html.
# Find the right sink with `pactl list sources short`.
PA_SINK="alsa_output.0.analog-stereo"
BT_MAC=$(echo "$NAME" | sed 's/:/_/g' | sed 's/\"//g')
BT_USER=pi
function log {
echo "[$(date)]: $*" >> /var/log/a2dp-autoconnect
}
function checkSource {
# Get the current sources
local _sources=$(sudo su - "$BT_USER" -c "pactl list sources short")
# Check if any sources are currently running and that our new device is valid.
if [[ "$_sources" =~ RUNIING ]]; then
log "Source is already RUNNING. Available sources:"
log "$_sources"
return
fi
if [[ ! "$_sources" =~ "$1" ]] ; then
log "Unrecognized source. Available sources:"
log "\n$_sources"
return
fi
log "Validated new source: $1."
echo "$1"
}
function setVolume {
log "Setting volume levels."
# Set our volume to max
sudo su - "$BT_USER" -c "pacmd set-sink-volume 0 65537"
sudo su - "$BT_USER" -c "amixer set Master 100%"
}
function connect {
log "Connecting $1."
# Connect source to sink
sudo su - "$BT_USER" -c 'pactl load-module module-loopback source="$1" sink="$PA_SINK" rate=44100 adjust_time=0'
}
log "Change for device $BT_MAC detected, running $ACTION."
if [ "$ACTION" = "add" ]
then
incoming=bluez_source."$BT_MAC"
if [ ! -z $(checkSource "$incoming") ] ; then
connect "$incoming"
setVolume
fi
fi
@Playsky
Copy link

Playsky commented Jun 4, 2016

Hello !
Is this system work with a raspberry 3 ? Without a Bluetooth dongle but just with the raspberry 3 Bluetooth ? Because I can't connect my iPhone with Bluetoothctl si may be I need a Bluetooth dongle ?
Thank !

@RikuKawai
Copy link

RikuKawai commented Jun 15, 2016

I've followed this guide and it works, but I'm noticing two issues.

Most important issue is changing the volume on my phone has no effect on the Pi output, it's always the same, and too low for my amp to run at full power. Edit: Now it's incredibly loud, noisy, and constantly cuts out. The cutting out may or may not be my phone.

Less important issue, but a minor annoyance, is my name setting isn't having any effect, I set the name to Jazukure but it still shows up as raspberrypi on my phone.

I've fixed the name issue by changing my hostname. Volume control now works, or rather worked. The entire setup worked properly once, and once only. After a reboot no amount of repairing will get my laptop to actually stay connected to the Pi. I'm using a Raspberry Pi B+ (first generation).

@sbisbilo
Copy link

Hello
Playsky did you success with the on board raspberry 3 bluetooth ?
Thanks

@ccrisan
Copy link

ccrisan commented Oct 1, 2016

The connect function has an error at line 46. It should be something like:

sudo su - "$BT_USER" -c "pactl load-module module-loopback source=\"$1\" sink=\"$PA_SINK\" rate=44100 adjust_time=0"

@joelalock
Copy link

joelalock commented Oct 16, 2016

i can get as far as verifying the password from my galazy s5 and the pi actually shows me as connected but then it kicks the connection and my phone says that it cant communicate with the pi.

i can trust the source from "bluetoothctl" but if i try to pair from there it wont allow it and says it already exists.

google has not helped .

any ideas? anybody?

[bluetooth]# agent on
Agent registered
[bluetooth]# default-agent
Default agent request successful
[bluetooth]# discoverable on
Changing discoverable on succeeded
[CHG] Controller 00:1A:7D:DA:71:0B Discoverable: yes
[bluetooth]# scan on
Discovery started
[CHG] Controller 00:1A:7D:DA:71:0B Discovering: yes
[CHG] Device 28:27:BF:FB:4E:EB RSSI: -55
[CHG] Device C4:57:6E:2E:9E:3C RSSI: -70
[CHG] Device 28:27:BF:FB:4E:EB RSSI: -46
[CHG] Device 98:D3:31:20:44:06 LegacyPairing: yes
[CHG] Device 98:D3:31:20:44:06 RSSI: -24
[bluetooth]# pair 28:27:BF:FB:4E:EB
Device 28:27:BF:FB:4E:EB not available
[CHG] Device 28:27:BF:FB:4E:EB RSSI: -55
[CHG] Device 28:27:BF:FB:4E:EB RSSI: -47
[bluetooth]# pair 28:27:BF:FB:4E:EB
Device 28:27:BF:FB:4E:EB not available
[bluetooth]# bluetoothctl
Invalid command
[bluetooth]# exit
Agent unregistered
[DEL] Controller 00:1A:7D:DA:71:0B retropie [default]
pi@retropie:~ $ bluetoothctl
[NEW] Controller 00:1A:7D:DA:71:0B retropie [default]
[NEW] Device 28:27:BF:FB:4E:EB SAMSUNG-SM-G900V
[NEW] Device C4:57:6E:2E:9E:3C [TV]Samsung LED55
[NEW] Device 98:D3:31:20:44:06 BC04-B
[bluetooth]# pair 28:27:BF:FB:4E:EB
Attempting to pair with 28:27:BF:FB:4E:EB
Failed to pair: org.bluez.Error.AlreadyExists
[CHG] Device 28:27:BF:FB:4E:EB Connected: yes
[CHG] Device 28:27:BF:FB:4E:EB Connected: no
[bluetooth]#

and another attempt:

[bluetooth]# list
Controller 00:1A:7D:DA:71:0B retropie [default]
[bluetooth]# agent on
Agent registered
[bluetooth]# default-agent
Default agent request successful
[bluetooth]# discoverable on
Changing discoverable on succeeded
[CHG] Controller 00:1A:7D:DA:71:0B Discoverable: yes
[bluetooth]# scan on
Discovery started
[CHG] Controller 00:1A:7D:DA:71:0B Discovering: yes
[CHG] Device C4:57:6E:2E:9E:3C RSSI: -71
[CHG] Device 28:27:BF:FB:4E:EB RSSI: -46
[CHG] Device 98:D3:31:20:44:06 RSSI: -25
[CHG] Device 28:27:BF:FB:4E:EB RSSI: -54
[CHG] Device 28:27:BF:FB:4E:EB RSSI: -46
[CHG] Device 28:27:BF:FB:4E:EB RSSI: -57
[CHG] Device 28:27:BF:FB:4E:EB RSSI: -46
[CHG] Device 28:27:BF:FB:4E:EB RSSI: -55
[bluetooth]# pair 28:27:BF:FB:4E:EB
Device 28:27:BF:FB:4E:EB not available
[CHG] Device 28:27:BF:FB:4E:EB RSSI: -45
[CHG] Device 28:27:BF:FB:4E:EB RSSI: -59
[CHG] Device 28:27:BF:FB:4E:EB RSSI: -49
[CHG] Device 28:27:BF:FB:4E:EB Connected: yes
Request confirmation
[agent] Confirm passkey 774981 (yes/no): y
[CHG] Device 28:27:BF:FB:4E:EB Connected: no

again:

[CHG] Device C4:57:6E:2E:9E:3C RSSI: -77
[CHG] Device 28:27:BF:FB:4E:EB Connected: yes
Request confirmation
[agent] Confirm passkey 420804 (yes/no): yes
[CHG] Device 28:27:BF:FB:4E:EB RSSI: -58
[CHG] Device C4:57:6E:2E:9E:3C RSSI: -69
[CHG] Device 28:27:BF:FB:4E:EB Connected: no
[CHG] Device 28:27:BF:FB:4E:EB RSSI: -48

@ozzieone
Copy link

Yeah this an one

Are the phone buttons working volume up/down ? i have iphone 6
I have sound only max of nothing (i can set it with CLI i dont want that)

@BalzGuenat
Copy link

@ozzieone I have the same problem. Have you found anything?

@ValdikSS
Copy link

@ozzieone, @BalzGuenat you either use global hotkey daemon like triggerhappy or load pulseaudio module module-mmkbd-evdev with corresponding Bluetooth input device from /dev/input/

@BillyCallahan
Copy link

First of all, great tutorial that works fine thanks !
Just one issue: I'm using a Raspberry Pi W (bluetooth embedded) but the sound is cuting every 1-2 seconds...Even when the phone is really close.

@joealcorn
Copy link

Same issue as @AudricManaud, with and without a powered USB hub. Did you make any progress?

@joealcorn
Copy link

@AudricManaud So it turned out my issue seems to be caused by my android phone, as audio works without stuttering when using a macbook. Some googling reveals this is a long standing issue with android, but I've had good results with bluetooth audio a couple months ago with the same phone, so I wonder if there's something I can do.

@BillyCallahan
Copy link

@joealcorn Nop couldn't resolve my issue :(
My phone always worked out fine...
I checked my Pi's CPU, it remains normal.

@BillyCallahan
Copy link

Hey :)
Just found this: raspberrypi/linux#1402
It seems that the problem comes from using wifi & bluetooth simultaneously.
I disabled the wifi, and it worked fine. However I still got some stutters from time to time :/
And I need the wifi, otherwise what's the point of using RPi...

@dmth
Copy link

dmth commented Jun 10, 2017

@oleq Thank you very much for sharing this.

sudo usermod -a -G lp pi

from what I see, this add the user pi to the group lp. This group is usually used for to printing.
It really should not be necessary.

@Khoa-NT
Copy link

Khoa-NT commented Aug 8, 2017

Hi,
I don't have much knowledge in bluetooth. Would you mind if I ask some questions ?

1/ In section What is this all about? doesn't mention the usb bluetooth 4.0. Does this project need it ?
2/ Does this project help connect Bluetooth Headset To Raspberry Pi 3 (A2DP & HSP) ?
What I want is connect raspberry Pi with my bluetooth module. So that Raspberry pi can get input sound from my bluetooth module and output sound to it.
Currently I can send sound from raspberry pi to my bluetooth module but raspberry pi doesn't receive any sound from it.

Would you mind helping me ?
Thanks

@tomwadley
Copy link

Instead of the script that loads module-loopback, you can also use module-bluetooth-policy which does exactly that. From the docs [0]:

Load module-loopback automatically for A2DP and HFGW sources, so that the received audio is automatically played back to some output.

Personally, I have a line like this in my /etc/pulse/system.pa:

load-module module-bluetooth-policy

[0] https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/Modules/#index36h3

@theunbal
Copy link

I dont see any bluetooth sources when i run pact list sources short. i only get this:
0 alsa_output.usb-GeneralPlus_USB_Audio_Device-00.analog-stereo.monitor module-alsa-card.c s16le 2ch 44100Hz SUSPENDED
1 alsa_input.usb-GeneralPlus_USB_Audio_Device-00.analog-mono module-alsa-card.c s16le 1ch 44100Hz SUSPENDED
2 alsa_output.platform-soc_audio.analog-stereo.monitor module-alsa-card.c s16le 2ch 44100Hz SUSPENDED

any suggestions? My phone shows connected to the pi.

@svenkkkk
Copy link

do you have any ideea why, when i run
pactl list sources short
I get ONLY
pi@raspberrypi:~ $ pactl list sinks short
0 alsa_output.platform-soc_audio.analog-stereo module-alsa-card.c s16le 2ch 44100Hz SUSPENDED

although the phone is connected?
Thank you!

@BrettStuart014
Copy link

@svenkkkk did you ever find why you cant bluez in the list of sources, I have the same issue

Copy link

ghost commented Dec 23, 2017

@BrettStuart014 i had the same problem with my iPhone. When i start the connection vom iphone site. So now my steps to solved the problem.

[bluetooth]# agent on
[bluetooth]# default-agent
[bluetooth]# discoverable on
[bluetooth]# scan on

[bluetooth]# pair XX:XX:XX:XX:XX:XX
[CHG] Device XX:XX:XX:XX:XX:XX Connected: yes
Request PIN code
[agent] Enter PIN code: 0000
[CHG] Device XX:XX:XX:XX:XX:XX Modalias: bluetooth:v004Cp6F0Ad0B20
[CHG] Device XX:XX:XX:XX:XX:XX UUIDs:
00000000-deca-fade-deca-deafdecacafe
00001000-0000-1000-8000-00805f9b34fb
0000110a-0000-1000-8000-00805f9b34fb
0000110c-0000-1000-8000-00805f9b34fb
0000110e-0000-1000-8000-00805f9b34fb
00001116-0000-1000-8000-00805f9b34fb
0000111f-0000-1000-8000-00805f9b34fb
0000112f-0000-1000-8000-00805f9b34fb
00001132-0000-1000-8000-00805f9b34fb
00001200-0000-1000-8000-00805f9b34fb
02030302-1d19-415f-86f2-22a2106a0a77
[CHG] Device XX:XX:XX:XX:XX:XX Paired: yes
Pairing successful
[CHG] Device XX:XX:XX:XX:XX:XX Connected: no
[CHG] Device XX:XX:XX:XX:XX:XXRSSI: -52

So now it was paired but not connected !! before i made the issue that i start connection from phone site.
But last time i used
[bluetooth]# connect XX:XX:XX:XX:XX:XX
Attempting to connect to XX:XX:XX:XX:XX:XX
[CHG] Device XX:XX:XX:XX:XX:XX RSSI: -52
[CHG] Device XX:XX:XX:XX:XX:XX RSSI: -44
[CHG] Device XX:XX:XX:XX:XX:XX Connected: yes
Connection successful

and after that i hear musik on the speakers. and when i start
pactl list sources short i see booth
0 alsa_output.platform-soc_audio.analog-stereo.monitor module-alsa-card.c s16le 2ch 44100Hz SUSPENDED
1 bluez_source.XX:XX:XX:XX:XX:XX module-bluez5-device.c s16le 2ch 44100Hz SUSPENDED

i hope it helps you.

Copy link

ghost commented Dec 24, 2017

Hi one post again. After start pi in the morning i get connection problems but this solved my problem

https://goo.gl/5Xoos9

now my iphone links fine with raspi. So all is testet with debian jessie. I dont no is it runnning on stretch too.

@akshitgandhi
Copy link

Hi, I am not able to get the logs of the a2dp-autoconnect file by running tail -f /var/log/a2dp-autoconnect. And maybe because of this whenever I reboot the pi I have to set the source and sink before playing music. Any help?

@davthomaspilot
Copy link

I'm trying to use a Pi Zero W as a Bluetooth device. I'm using a PHAT-DAC to get I2S audio. The idea is to Bluetooth connect from Ipad to the Pi zero, then stream audio from the Ipad to the Rpi.

I think this thread tries to do something similar, except with an RPI-3. Should it work for a Pi Zero W?

I can't get past missing bluetooth and pulseaudio packages. No installation candidates....

@chadi8
Copy link

chadi8 commented Apr 27, 2018

Hello,
when i run pactl list sources short
I get ONLY
pi@raspberrypi:~ $ pactl list sinks short
0 alsa_output.platform-soc_audio.analog-stereo module-alsa-card.c s16le 2ch 44100Hz SUSPENDED
but my phone is connected, and trusted

i tried pactl load-module module-bluetooth-discover,
but nothing works !!
any help would be appreciated thanks!

@mmmatjaz
Copy link

Is anyone using this on banana pi? I'm using it with raspbian and every 10s the sound becomes distorted, then returns to normal again, and so on ... "top" shows that pulseaudio is using 35% of CPU when bluetooth is connected, whether anything is playing or not. I have the same issue with both an android phone and a windows laptop. Both of these stream just fine to other bluetooth receivers. Any tips?

@myRaspber
Copy link

Hi,

Everythings Work fine but Bluetooth Connection always stop át 30 min..
How can set up always connection??

@JOchoaBE
Copy link

For those that have the problem of bluez not showing up in pactl list sources even though bluetooth device is connected and playing, it usually means that the PulseAudio bluetooth modules need to be restarted. Could be a bug. Restart PulseAudio and connect bluetooth device again. Then it should then show up in pactl list sources.

@milnepe
Copy link

milnepe commented Dec 12, 2020

@oleq Thank you very much for sharing this.

sudo usermod -a -G lp pi

from what I see, this add the user pi to the group lp. This group is usually used for to printing.
It really should not be necessary.

You probably do need this or group bluetooth, if your user wants to be able to communicate with bluetoothd. /etc/dbus-1/system.d/bluetooth.conf defines which groups have access, by default bluetooth & lp - if you are not a member of either of these groups pulseaudio (which must be run per-user) will not be able to load the A2DP profiles to connect BT devices that need them!

  <!-- allow users of bluetooth group to communicate -->
  <policy group="bluetooth">
    <allow send_destination="org.bluez"/>
  </policy>

  <policy at_console="true">
    <allow send_destination="org.bluez"/>
  </policy>

  <!-- allow users of lp group (printing subsystem) to 
       communicate with bluetoothd -->
  <policy group="lp">
    <allow send_destination="org.bluez"/>
  </policy>

@novafurry
Copy link

Is it possible to get song info, or control the media?

@991026lk
Copy link

酸Q

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