Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15531786
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类:

2009-12-08 16:33:22

Description

This page contains audio service usage examples. The API description is available at .

Note that there are a few approaches for a2dp (alsa, gstreamer, pulse?), maybe two for sco (alsa, pulse?). Alsa is the simplest and should support the greater variety of audio clients directly.

Basic steps

(these are valid for bluez-utils-3.16 or newer)

Note: you will not need bluetooth-alsa, plugz, btsco or the like for audio to work. They are obsolete.

  1. Make sure the audio service is installed
  2. modify your ~/.asoundrc to contain
    pcm.bluetooth {
    type bluetooth
    device 00:11:22:33:44:55
    }
    where 00:11:22:33:44:55 is the Bluetooth address of your headset (use for example hcitool scan to find it)
  3. configure your audio application to use the alsa device "bluetooth". See for some examples.
  4. start playing :)

Tips

  • There's a tool called dbus-viewer (apt-get install dbus-viewer; dbus-viewer --system) which is very helpful in using D-Bus interfaces as long as there are no convenient scripts or GUIs available for them. A newer similar tool for GTK+ is called . In kubuntu try qdbusviewer from the qt4-dev-tools package.

Known issues

  • You may get choppiness with a2dp. An hcid.conf with "lm accept,master;" and "lp hold,sniff,park;" will be more robust. For BlueZ 4.x, which has no hcid.conf, you will have to do something like 'hciconfig hci0 lm master; hciconfig hci0 lp hold,sniff,park' after bluetoothd starts up (or write a patch ;).
  • If you get messages in the kernel log like "sco packet for unknown connection" then you may need to apply a kernel patch (several versions of the fix are circulating around bluez-dev but no one solution seems right)
  • xmms with broadcom based headsets produces choppy sound at times (actually xmms in general seems to have a little bit buggy alsa usage). We recommend using some other player, e.g. audacious.
    • e.g. the Logitech freepulse and Etymotic Research ety8 headphones are broadcom based
  • vlc pause/unpause doesn't work (no sound after unpause)
  • Skype at version 2.0.0.72 may not work out of the box with your headset. It seems like this may be due to Skype not handling the sampling rate your headset is fixed at. A workaround is to create a plug device so resampling can be done transparently. You can do this in your .asoundrc file, for example:
pcm.bluetoothraw {
type bluetooth
device 00:11:22:33:44:55
}
pcm.bluetooth {
type plug
slave {
pcm bluetoothraw
}
}

Alsa Plugin

Configuration

Append this lines to ~/.asoundrc:

pcm.bluetooth {
type bluetooth
device "XX:XX:XX:XX:XX:XX" #optional, connects to specific device instead the default one
profile "auto" #optional, supported profiles are: auto, hifi and voice
}

See also the workaround in the previous section.

Supported Players

aplay and arecord

arecord -D bluetooth -f S16_LE | aplay -D bluetooth -f S16_LE

gst-launch

gst-launch -v alsasrc device=bluetooth ! audioconvert ! audioresample ! alsasink device=bluetooth sync=false

audacious

options->preferences->Audio->Current Output Plugin->ALSA
Output Plugin Preferences->Device Settings->audio device: "bluetooth"

if you can't see the audio device form there, you can force the bluetooth output by modifying your audacious property file

~/.config/audacious/config. Modify the "pcm_device" value by "pcm_device=bluetooth"

xmms

xmms is known to have some issues, please use its successor audacious instead

options->preferences->Output Plugin->Configure: "bluetooth"

beep-media-player

preferences->Plugins->Output->Select ALSA->Preferences->Audio device: "bluetooth"->Advanced->disable mmap mode

mplayer

mplayer -ao alsa:device=bluetooth

play

play --device=bluetooth file.mp3

amarok

Amarok configuration -> Engine -> Select: "alsa"

then

replace "default" with "bluetooth" in either "mono" or "stereo" field

banshee, rhythmbox and totem

to route the sound to bluetooth:

gconftool -t string -s /system/gstreamer/0.10/default/musicaudiosink "alsasink device=bluetooth"

to route the sound to normal speakers:

gconftool -t string -s /system/gstreamer/0.10/default/musicaudiosink "autoaudiosink"

Kaffeine

Menu Settings -> xine Engine Parameters -> audio -> Expert Options tab
Change "device.alsa_default_device" (mono) and "device.alsa_front_device" (stereo) from "default" to "bluetooth"

GStreamer Plugin

Currently only available for a2dp.

Configuration

It is not necessary to create a virtual device as in alsa, configuration can be change via element properties:

a2dpsink

Element Properties:
name : The name of the object
flags: readable, writable
String. Default: null Current: "a2dpsink0"
preroll-queue-len : Number of buffers to queue during preroll
flags: readable, writable
Unsigned Integer. Range: 0 - 4294967295 Default: 0 Current: 0
sync : Sync on the clock
flags: readable, writable
Boolean. Default: true Current: true
max-lateness : Maximum number of nanoseconds that a buffer can be late before it is dropped (-1 unlimited)
flags: readable, writable
Integer64. Range: -1 - 9223372036854775807 Default: -1 Current: -1
qos : Generate Quality-of-Service events upstream
flags: readable, writable
Boolean. Default: false Current: false
device : Bluetooth remote device address
flags: readable, writable
String. Default: null Current: null

sbcenc

Element Properties:
name : The name of the object
flags: readable, writable
String. Default: null Current: "sbcenc0"
mode : Encoding mode
flags: readable, writable
Enum "GstSbcMode" Current: 0, "auto"
(0): auto - Auto
(1): mono - Mono
(2): dual - Dual Channel
(3): stereo - Stereo
(4): joint - Joint Stereo
allocation : Allocation mode
flags: readable, writable
Enum "GstSbcAllocation" Current: 0, "auto"
(0): auto - Auto
(1): loudness - Loudness
(2): snr - SNR
blocks : Blocks
flags: readable, writable
Integer. Range: 0 - 2147483647 Default: 0 Current: 0
subbands : Sub Bands
flags: readable, writable
Integer. Range: 0 - 2147483647 Default: 0 Current: 0

Supported Players

gst-launch

To transmit with SBC

gst-launch -v ... ! decodebin ! audioconvert ! audioresample ! sbcenc ! a2dpsink device=XX:XX:XX:XX:XX:XX

To send mp3 data directly

gst-launch filesrc location= ! mp3parse ! a2dpsink device=XX:XX:XX:XX:XX:XX

Sending mp3 data directly is preferable on low powered systems, such as embedded devices, rather than decoding from mp3 and re-encoding as sbc. (To diagnose problems, try passing --gst-debug a2dpsink:5,avdtpsink:5 to gst-launch. Sometimes the mp3parse element from the gst-plugins-ugly package is incompatible with bluez due to the way it reports channels. Different versions and/or manual patching may be required)

banshee, rhythmbox and totem

to route the sound to bluetooth:

gconftool -t string -s /system/gstreamer/0.10/default/musicaudiosink "sbcenc ! a2dpsink device=XX:XX:XX:XX:XX:XX"

to route the sound to normal speakers:

gconftool -t string -s /system/gstreamer/0.10/default/musicaudiosink "autoaudiosink"

Pulseaudio

Pulse using ALSA plugin

Older versions of pulse without the native bluetooth module can use the alsa plugin:

Make audio service autostart. (Autostart=true in /etc/bluetooth/audio.service) (not required for bluez 4.x)

.asoundrc:

pcm.headset {
type bluetooth
device "XX:XX:XX:XX:XX:XX"
profile "voice"
}

Manually run:

pactl load-module module-alsa-sink device=headset
pactl load-module module-alsa-source device=headset

Then use pavucontrol to make the headset sink/source the default

Pulse native Bluetooth sink

Newer versions of pulse have a native Bluetooth sink which works *only* with Bluez 4.x. You need pulse 0.9.14 (FIXME: maybe 0.9.13 works too?) and later, and they have to have module-bluetooth-discover and module-bluetooth-device compiled, and they have to match the version of BlueZ you are running.

That last point is so important it's worth repeating: You *must* have matching bluez and pulseaudio versions, because the API for communicating between pulse and bluez is still under active development. If you fail to do this, everything will seem to work up to the point of making "beep" sounds as your headset is connected...except there will be error messages instead of audio.

Here's a compatibility table to get you started:

bluez 4.0-26:   FIXME:  not sure when pulse/bluez starts working...0.9.13?  4.18?
bluez 4.27-33: pulse 0.9.14
bluez 4.34-38: pulse 0.9.15
bluez 4.39+: FIXME: if these versions are released, please test and update this page! Thanks in advance!

You'll also need a non-ancient kernel (2.6.24 works, and it's older than anything the BlueZ developers are willing to support), the kernel needs to be built with Bluetooth support, you'll need a compatible bluetooth adapter, and you need to pair your headset first...which you'll need for the ALSA and gstreamer plugins as well.

Also, it is a good idea to make sure pulse is working properly with a more conventional sound device on your setup, and strip down your Pulse configuration to the bare minimum set of modules that you actually use before attempting to use it with Bluetooth. Chances are good that if an obscure Pulse module bug causes your pulseaudio daemon to crash with an ordinary sound card, it'll continue to make your pulseaudio daemon crash with a bluetooth audio device.

There are two ways to get the bluetooth sink running in pulse: automatic detection with module-bluetooth-discover, or manually with module-bluetooth-device.

Manually using module-bluetooth-device

The manual method: from pacmd, the pulseaudio -C command line, or from .pulse/default.pa:

# $HOME/.pulse/default.pa
# Load the sink module. We use the name "fred" here, but any valid Pulse sink name will work.
# Also note we've set the default profile to 'a2dp'. Use 'hsp' for headset (telephone) audio.
load-module module-bluetooth-device profile=a2dp sink_name=fred address=XX:XX:XX:XX:XX:XX
# Make the module default (you can do this with any other pulse tool as well, e.g. pavucontrol)
set-default-sink fred
# Set the card profile (in case you left out profile= above - pulse 0.9.15 only)
set-card-profile fred a2dp

Some important notes about the manual method:

  • It sets up one connection to the headset. That means if the headset isn't powered on, isn't connectable, is connected but to a cell phone or other Bluetooth device, or is out of range when pulse starts, there will be no bluetooth sink in Pulse. Also, if the headset goes out of range, gets turned off, battery dies, or disconnects, the bluetooth sink will disappear from Pulse. You can repeat the load-module command to reconnect the headset.
  • Depending on the pulse version and on the firmware in your headset, module-bluetooth-discover may interfere with your connection attempts. You may need to remove (or not load in the first place) module-bluetooth-discover.

Automatically with module-bluetooth-discover

The automatic method: Load module-bluetooth-discover, then connect with gnome-bluetooth or dbus commands.

# $HOME/.pulse/default.pa
# Load module-bluetooth-discover
load-module module-bluetooth-discover
# Note we do NOT have to load-module module-bluetooth-device here.

Once the pulseaudio daemon is configured and running with module-bluetooth-device, you can (in theory) connect to the headset any way you like: use gnome-bluetooth, press the "connect" button on the headset, etc. Pulseaudio should detect the headset connection and automatically create a pulseaudio sink. You then use pavucontrol or similar to configure it as the default sink and/or move streams to it.

# Use dbus-send from the command line to connect to the headset:
$ dbus-send --print-reply --system --dest=org.bluez / org.bluez.Manager.DefaultAdapter
method return sender=:1.18141 -> dest=:1.18218 reply_serial=2
object path "/org/bluez/4189/hci0"
$ dbus-send --print-reply --system --dest=org.bluez /org/bluez/4189/hci0 org.bluez.Adapter.FindDevice string:00:15:0E:A0:6C:C8
method return sender=:1.18141 -> dest=:1.18221 reply_serial=2
object path "/org/bluez/4189/hci0/dev_00_15_0E_A0_6C_C8"
$ dbus-send --print-reply --system --dest=org.bluez /org/bluez/4189/hci0/dev_00_15_0E_A0_6C_C8 org.bluez.AudioSink.Connect
method return sender=:1.18141 -> dest=:1.18226 reply_serial=2

# Use pacmd to set the default sink and enable a2dp
$ pacmd "set-default-sink bluez_sink.00_15_0E_A0_6C_C8"
$ pacmd "set-card-profile bluez_sink.00_15_0E_A0_6C_C8 a2dp"

Depending on what profile you want, the interface name in the last dbus-send command will be different:

org.bluez.AudioSink.Connect - connects via A2DP (stereo audio)
org.bluez.Headset.Connect - connects via HSP/HFP (mono headset with mic)
org.bluez.Audio.Connect - connects to both (select which to use via the pulse card profile)

Regardless of which method you use, after the Connect call, module-bluetooth-discover in the pulseaudio daemon should automatically load the module-bluetooth-device module. Pulse 0.9.13 and 0.9.14 used a name based on the "friendly name" of the device (which is a string like "TRI_BH102 v2.2"). Pulse 0.9.15 uses a name based on the Bluetooth address such as "bluez_sink.00_15_0E_A0_6C_C8".

Pulse 0.9.15 probably won't work until you set the card profile.

Advanced examples for programatically setting up audio devices

The examples from here to the end of the page are only for programmers who need to automate device creation, service startup, etc. Stop reading now if you're just trying to get the basics working.

Service Activation

Note this section does not apply to bluez 4.x, where the audio service is a plugin that runs in bluetoothd.

When a client wants to start the audio service or discover the audio service bus "id", the ActivateService method should be called.

import dbus
bus = dbus.SystemBus()
bmgr = dbus.Interface(bus.get_object('org.bluez', '/org/bluez'), 'org.bluez.Manager')
bus_id = bmgr.ActivateService('audio')

# All serial service messages should be sent to this address
print bus_id

Service activation from command line:

$dbus-send --system --type=method_call --print-reply --dest=org.bluez \
/org/bluez org.bluez.Manager.ActivateService string:audio

A2DP

Note that much of this section does not apply to bluez 4.x, which uses org.bluez..Connect.

A2DP (Advanced Audio Distribution Profile) is intended for high quality stereo audio applications.

For A2DP there is no need to specifically request a "playing" state. The bluetooth alsa plugin will automatically do this when some application tries to use it. If no device is connected, the default device will be connected to, otherwise the first found connected device will be used.

python

import dbus
bus = dbus.SystemBus()
manager = dbus.Interface(bus.get_object('org.bluez', '/org/bluez'), 'org.bluez.Manager')
bus_id = manager.ActivateService('audio')
audio = dbus.Interface(bus.get_object(bus_id, '/org/bluez/audio'), 'org.bluez.audio.Manager')

path = audio.CreateDevice('00:11:22:33:44:55')
#audio.ChangeDefaultDevice(path) #change the device to be used by default
sink = dbus.Interface (bus.get_object(bus_id, path), 'org.bluez.audio.Sink')
sink.Connect()

Command line

The ":X.Y" in the following examples is the unique bus name of the audio service. You get it in the reply to the ActivateService method call:

$dbus-send --system --print-reply --dest=org.bluez /org/bluez org.bluez.Manager.ActivateService string:audio

* CreateDevice:

$dbus-send --system --type=method_call --print-reply --dest=":X.Y" \
/org/bluez/audio org.bluez.audio.Manager.CreateDevice string:00:11:22:33:44:55

* Connect (replace device_object_path with return value from last call):

$dbus-send --system --type=method_call --print-reply --dest=":X.Y" \
"device_object_path" org.bluez.audio.Sink.Connect

Headset Profile

Note this section does not apply to bluez 4.x, which uses org.bluez.Headset.Connect.

The Headset Profile is intended for two-way low-latency audio applications such as VoIP.

python

import dbus
bus = dbus.SystemBus()
manager = dbus.Interface(bus.get_object('org.bluez', '/org/bluez'), 'org.bluez.Manager')
bus_id = manager.ActivateService('audio')
audio = dbus.Interface(bus.get_object(bus_id, '/org/bluez/audio'), 'org.bluez.audio.Manager')

path = audio.CreateHeadset('00:11:22:33:44:55')
#audio.ChangeDefaultHeadset(path) #change the device to be used by default
headset = dbus.Interface (bus.get_object(bus_id, path), 'org.bluez.audio.Headset')
#Connect and Play are not required in PCM mode
headset.Connect()
headset.Play()

Command line

* CreateHeadset:

$dbus-send --system --type=method_call --print-reply --dest=":X.Y" \
/org/bluez/audio org.bluez.audio.Manager.CreateHeadset string:00:11:22:33:44:55

* Connect:

$dbus-send --system --type=method_call --print-reply --dest=":X.Y" \
"device_object_path" org.bluez.audio.Headset.Connect

* Play:

$dbus-send --system --type=method_call --print-reply --dest=":X.Y" \
"device_object_path" org.bluez.audio.Headset.Play
阅读(7049) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~