One of main advantages of the bluetooth stack is support for multiple profiles. Few years ago there has been developed an A2DP profile („Advanced audio distribution profile”). Sending sound samples over Bluetooth can be difficult due to radio bandwidth limitation. Each second of voice sampled with 16 bits quality and 44100 Hz frequency requires over 1411200 bits, that’s way too much for Bluetooth 1.1/1.2 (max effective transmission speed for two devices is 768kbit/s).

A2DP profile uses low-complexity subband codec SBC.
It allows to send high quality audio over bluetooth devices using standard bandwidth. The SBC codec uses subbands much similar like a MPEG-2 Layer III but less complex algorithm.

ALSA and A2DP.
Advanced Linux Sound Architecture allows add drivers for any sound device. From some point of view A2DP sink (target sound device) can be perceived as sound card, it’s just a matter of driver implementation. The bluetooth-alsa driver is being developed for few years and current version is quite usable.

Yesterday I’ve devided to put alsa-bluetooth and SBC codec into something quite small like Sarge SBC.
I could not find bitbake recipes for libsbc and alsa-a2dpd so I made my own:

Using mplayer I’ve been able to play WAV’s files via alsa:device=a2dpd audio output. It seems that decoding mp3 files
then back encoding to SBC and transmitting over bluetooth takes too much power of SBC.

The SBC doesn’t have bluetooth device onboard but it has USB host controller, so I’ve used my bluetooth dongle.
hciconfig hci0 -a

hci0: Type: USB
BD Address: xx:xx:xx:xx:xx:xx ACL MTU: 192:8 SCO MTU: 64:8
RX bytes:300417 acl:1825 sco:0 events:35730 errors:0
TX bytes:10050082 acl:64004 sco:0 commands:76 errors:0
Features: 0xff 0xff 0x8f 0xf8 0x18 0x18 0x00 0x80
Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3
Link policy:
Name: sarge_at91
Class: 0x000000
Service Classes: Unspecified
Device Class: Miscellaneous,
HCI Ver: 1.1 (0x1) HCI Rev: 0x639 LMP Ver: 1.1 (0x1) LMP Subver: 0x639
Manufacturer: Cambridge Silicon Radio (10)

I’m using alsa 1.0.13. Before using pcm.a2dpd output device alsa needs to be configured:

pcm.headset {

# The Bluetooth device address for target headset, used for Audio Gateway (PC) initiated connections
# Please note that this value is ignored when the connection is Headset initiated
@args.BDADDR {
type string
# default „xx:xx:xx:xx:xx:xx”

# This value represents how long we will try to reach the headset, until we give up.
# Value is in milliseconds
@args.TIMEOUT {
type integer
default 6000

type sco
bdaddr $BDADDR
timeout $TIMEOUT

ctl.headset {
type sco

# A2DPD must be started first
pcm.a2dpd {
type a2dpd

# This entry allows the plugin to appear in mixer applications
# This way, the sound level can be controlled by software outside the player
# This works but unfortunately sound is broken at first sight
# So it needs more study
pcm.a2dpdsoftvol {
type softvol
slave {
pcm „a2dpd”

control {
name „Bluetooth Headset”
card 0
count 1

a2dp daemon config file:

# Rate
# use 32000 if your headset seems to not support 44100 (HP/Logitech works well at 44100, S,4100 is mandatory
# If using SCO, then 8000hz is the value needed.
# if the plugin do not give e 8000hz stream, then the conversion will be done by the daemon
# Until we use a real resample library, we won’t g a good quality, this is prototype software.

# buggy if I remember well
plugin-rate default is the rate used between the plugin and the daemon
# if this value is not 0 then alsa will coert all stream to the specified rate and then send it to the daemon
# if this value is 0, then alsa will do no conrsion at all, the daemon will do it’s own resampling.
# This „features” is disabled because of the crappy qualityf the daemon resampler
# For example, to test a2dpd resampling from 32000 to 44100 use plugin-rate=32000 and rate=100

# Allows to specify the sbc bitpool, this can help reducing bandwith
# 8 Allows to run on 115200 bauds with corresponding quality 😉
# 64 needs USB or 921600 bauds
# Recommended value from Bluetooth spe is 53

# flags that will later be combinable
# 1: display bandwith each seconds.
# 3: current statelags=0

# Recommended

# Automatically connect to selected headset if a stream if started
#ot recommended if running on battery 😉

# Automatically disconnect after a timeout (seconds)

# AVRCP Commands to run
# If these entries are emptied, then some keyboard entry will be sent to /devinput
cmdplay=xmms –play
cmdpause=xmms –pause
cmdprev=xmms –rew
cmdnext=xmms –fwd
cmdnew=xmms –play
cmdstoxmms –stop
#cmdplay=dcop amarok player play
#cmdpause=dcop amarok player pause
#cmdprev=dcop amarok player prev
#dnext=dcop amarok player next
#cmdnew=dcop amarok player play
#cmdstop=dcop amarok player stop

# Put to 0 to igne AVRCP (if your computer freezes when commands are received)

# Audio routing
# If set to 1 (at2dp startup only) a2dp will reread configuration file
#. for audio routing changes each second

# Display debug traces or not

# Redirect stdout to this file

# Poll stdin focontrol commands (‚c’onnect/’s’tart/’p’ause/’d’isconnect/’a’utoconnect)
# Use a2dpd_ctl instead

# 0> Bluetooth A2DP Sink
# 1 => Alsa

# Your bluetooth headset address
# Address of your alsa output (default : plughw:0,0) you have to know what to do

starting a2dpd daemon:

a2dpd –file /home/mcgregor/.a2dpdrc –daemon

The deamon should set headset bdaddr from configuration file but it doesn’t so use the command:

a2dpd_ctl SetAddress bdaddr

playing audio console log:

root@sarge_at91:~$ mplayer -ao alsa:device=a2dpd ./audiodump.wav
MPlayer 1.0rc1-4.1.1 (C) 2000-2006 MPlayer Team

Playing ./audiodump.wav.
Audio file file format detected.
Forced audio codec: mad
Opening audio decoder: [pcm] Uncompressed PCM audio decoder
AUDIO: 44100 Hz, 2 ch, s16le, 1411.2 kbit/100.00% (ratio: 176400->176400)
Selected audio codec: [pcm] afm: pcm (Uncompressed PCM)
PCM.A2DPD[01:19:03.753]: _snd_pcm_a2dpd_open: AlsaVersion=1.0.13, Opened for Playback
AO: [alsa] 44100Hz 2ch s16le (2 bytes per sample)
Video: no video
Starting playback…
alsa-play: write error: Broken pipe2.7% $<50>
alsa-play: trying to reset soundcard
A: 12.1 (12.0) of 72.0 (01:12.0) 1.6% $<50>

Sarge SBC and my Jabra BT620s headset:

One Response to “Bluetooth-alsa”

  1. […] Black Mesa East Âť Bluetooth-alsa Forced audio codec: mad. Opening audio decoder: [pcm] Uncompressed PCM audio decoder. AUDIO: 44100 Hz, 2 ch, s16le, 1411.2 kbit/100.00% (ratio: Black Mesa East Âť Bluetooth-alsa […]

Leave a Reply

You must be logged in to post a comment.