bluetooth在linux应用开发

linuxBluetooth的协议栈为BlueZhttp://www.bluez.org/4.46上,BlueZ实现了对A2DP Sink的支持,而以前的版本只支持A2DP Sourcephp


主机实现到HCI层,底层由蓝牙芯片实现。HCI层实现的是蓝牙芯片与主机通信的方式。目前通常是串口或者USB通信。所谓的USB也不是真正意义上的USB通信,而是相似与USB转串口的方式,即经过驱动模拟USB设备实现串口通信。目前USB蓝牙适配器基本都是这种设备模式。PC端实现了L2CAP, SDP, RFCOMM协议,以及USB转串口的驱动。Windows XP SP2操做系统以上版本的都内置了这些协议栈,还有如WIDCOMM等公司提供的第三方协议栈。html

实际中只需在市场上购买这种蓝牙适配器(USB接口),而后经过配置内核蓝牙的接口驱动(即上图中的HCI层驱动),这样相应的蓝牙协议(linux官方版本是bluez)就已经在内核中了,这就至关于内核驱动中已经支持了相应的蓝牙协议(SDP,RFCOMM...),有了驱动就须要接口库提供给应用程序使用,这里用到的接口库是开源的bluez,其实就是要在内核之上移植bluez及工具bluez-utilslinux

bluez分为两部分:内核代码和用户态程序及工具集。api

内核部分

内核代码:bluez核心协议和驱动程序等模块组成。自从linux2.4.6开始linux内核集成bluez安全

HCI. 这个是最底层的了,称为 Host Control Interface. 之因此称为 HCI 是源于蓝牙的应用模型的。蓝牙是链接智能外设的无线接口,接口的一侧是设备,另外一侧就是主机 (Host) 了,采用相似记法的还有 USB, IEEE1394,因此,从设计初衷来看,这几个东东都是针对差很少的市场的,固然,各有所长了。一个蓝牙适配器是否能被驱动起来,就看 HCI 的支持性了。最多见的蓝牙适配器就是笔者持有的这类 USB 接口的了,对于大部分标准的蓝牙设备,它的驱动模块是: hci-usb,对于咱们的 2.6 内核,插入这个适配器,该模块就被自动加载了。服务器

L2CAP之上有两个协议被较广地使用着:RFCOMMBNEP,前者用于取代传统的串行口,包括串行口上的各类应用,好比,传真和拨号上网、打印机、文件图片等数据传输;后者则能够提供一个以太网接口,更适于计算机组网。天然地,对于手机和计算机之间,RFCOMM 老是更常被用到。网络

内核蓝牙配置:less

[*] Networking support --->

<*> Bluetooth subsystem support ---> //蓝牙子系统必须选择

<*> L2CAP protocol suppor //逻辑链路控制和适配协议。

<*> SCO links support //蓝牙语音和耳机支持

<*> RFCOMM protocol suppor //面向流的传输协议,支持拨号网络等
 [*] RFCOMM TTY support // 
<*> BNEP protocol support //蓝牙网络封装协议,自组网支持
 [*] Multicast filter support //蓝牙多播,支持BNEP
 [*] Protocol filter support <*> HIDP protocol support //基本支持协议
 Bluetooth device drivers --->

<*> HCI USB driver //USB蓝牙模块支持

<M>HCI UART driver //基于串口,CF卡或PCMCIA的蓝牙

<*> HCI BlueFRITZ! USB driver <*> HCI VHCI (Virtual HCI device) driver

此外,在Bluetooth device drivers里选上你所须要支持的Bluetooth设备。若使用CSRchip,经过串口和cpu通信的,芯片默认使用BCSP做为通信协议,因此选择HCI UART driverBCSP protocol support socket

如果经过usb接口使用蓝牙适配器,须要选择HCI USB driver。ide

用户态部分

用户态程序及工具集:应用程序接口和bluez工具集。

bluez软件包名称:bluez,提供bluetoothd守护进程。

bluez工具集:bluez-utils,提供bluetoothctl命令。

可用bluetoothctl完成蓝牙设备配对,步骤以下:

  1. (optional) Select a default controller with select MAC_address.

  2. Enter power on to turn the power to the controller on. It is off by default and will turn off again each reboot, see #Auto power-on after boot.

  3. Enter devices to get the MAC Address of the device with which to pair.

  4. Enter device discovery mode with scan on command if device is not yet on the list.

  5. Turn the agent on with agent on or choose a specific agent: if you press tab twice after agent you should see a list of available agents, e.g. DisplayOnly KeyboardDisplay NoInputNoOutput DisplayYesNo KeyboardOnly off on.

  6. Enter pair MAC_address to do the pairing (tab completion works).

  7. If using a device without a PIN, one may need to manually trust the device before it can reconnect successfully. Enter trust MAC_address to do so.

  8. Enter connect MAC_address to establish a connection.

一个操做示例以下,链接蓝牙音箱:

select 48:51:B7:DE:56:DD //48:51:B7:DE:56:DD为网关蓝牙模块的地址
 power off power on agent on default-agent scan on //搜索蓝牙设备,等待,直到待链接设备被搜索到
 pair FC:58:FA:5B:7E:DD //配对
 connect FC:58:FA:5B:7E:DD //链接,会提示链接成功
 exit //退出bluetoothctl

蓝牙音频Audio

蓝牙profile

蓝牙profile协议概览.pdf   

Bluetooth的一个很重要特性,就是全部的Bluetooth产品都无须实现所有的Bluetooth规范。为了更容易的保持Bluetooth设备之间的兼容,Bluetooth规范中定义了ProfileProfile定义了设备如何实现一种链接或者应用,你能够把Profile理解为链接层或者应用层协议

好比,若是一家公司但愿它们的Bluetooth芯片支援全部的Bluetooth耳机,那么它只要支持HeadSet Profile便可,而无须考虑该芯片与其它Bluetooth设备的通信与兼容性问题。若是你想购买Bluetooth产品,你应该了解你的应用须要哪些Profile来完成,而且确保你购买的Bluetooth产品支持这些Profile

之因此把Profile翻译为配置文件,是为避免和JavaME中的简表混淆,配置文件也是蓝牙 SIG官方网站给出的标准翻译。

想要使用蓝牙无线技术,设备必须可以翻译特定蓝牙配置文件,配置文件定义了可能的应用。蓝牙配置文件表达了通常行为,蓝牙设备能够经过这些行为与其余设备进行通讯。

蓝牙技术定义了普遍的配置文件,描述了许多不一样类型的使用安全。按蓝牙规格中提供的指导,开发商可建立应用程序以用来与其余符合蓝牙规格的设备协同工做。在最低限度下,各配置文件规格应包含下列主题的相关信息:

1)与其余配置文件的相关性。

2)建议的用户界面格式。

3)配置文件使用的蓝牙协议堆栈的特定部分。

为执行其任务,每一个配置文件都使用堆栈各层上的特定选项和参数。若须要,也可包括必需的服务记录概要。

在全部的Profile中,有四种是基本的Profile,这些Profile会被其它的Profile使用。它们是:

GAP Profile: Generic Access Profile,该Profile保证不一样的Bluetooth产品能够互相发现对方并创建链接。

SDAP Profile: Service Discovery Application Profile,经过该Profile,一个Bluetooth设备能够找到其它Bluetooth设备提供的服务,以及查询相关的信息。

SPP Profile: Serial Port Profile,模拟串口通信。

GOEP Profile: Generic Object Exchange Profile,通用对象交换。这个Profile的名字有些费解,它定义的是数据的传输,包括同步,文件传输,或者推送其它的数据。你能够把它理解为内容无关的传输层协议,能够被任何应用用来传输本身定义的数据对象

Bluetooth还定义了9种应用(usage)Profile

CTP Profile: Cordless Telephone Profile,无绳电话。

IP Profile: Intercom Profile,这是在两个设备之间创建语音链接,换句话说,把两个昂贵的蓝牙设备变成廉价的对讲机。

HS Profile: HeadSet Profile,用于链接耳机。

DNP Profile: Dial-up Networking Profile,用于为PC提供拨号网络功能。

FP Profile: Fax Profile,传真功能。

LAP Profile: LAN Access Profile,使用PPP协议创建局域网。

OPP Profile: Object Push Profile,用于设备之间传输数据对象。

FTP Profile: File Transfer Profile,用于文件传输。

SP Profile: Synchronization Profile,用于不一样的Bluetooth设备同步,保持数据的一致性。

目前经常使用的配置蓝牙配置(profile)是A2DP

A2DP全名是Advanced Audio Distribution Profile 高级音频分发配置文件,描述了立体声音频如何从媒体输出(source)传输至输入(sink)。A2DP是可以采用耳机内的芯片来堆栈数据,达到声音的高清晰度。然而并不是支持A2DP的耳机就是蓝牙立体声耳机,立体声实现的基本要求是双声道,因此单声道的蓝牙耳机是不能实现立体声的。

使用场景:简单来讲,对于一个蓝牙音乐播放器(MP3),音频输出是音乐播放器,而音频输入是无线耳机或无线立体声音响。

此配置文件定义了音频设备的两个角色:输出和输入。

输出(SRCsource):音频的输入端对音频数据进行编码,发送到Sink端。

输入(SNKsink):接收到音频数据后,进行解码操做还原出音频。

A2DP定义了在ACL信道实现高品质音频内容的单声道或立体声分发协议和程序。 所以, 高级音频蓝牙音频应该区别开来,后者是指根据基带规格定义的SCO信道中分发窄幅波段的语音。

此配置文件创建在GAVDP基础上。它包括对复杂程度低的次频宽编解码技术(SBC)的必备支持和对MPEG-1,2音频、 MPEG-2,4 AAC和自适应声学转换编码技术(ATRAC)的可选支持。

音频数据按适当的格式进行压缩后能在有限频宽中正常使用。环绕声的分发不在此配置文件的范围。

PulseAudio

https://www.freedesktop.org/wiki/Software/PulseAudio/

Bluetooth的音频应使用软件pulseaudio,要使用蓝牙耳机或音响的话要先安装pulseaudio-bluetoothpulseaudio-module-bluetoothPulseAudio 5.x 开始默认支持 A2DP

PulseAudio是一个开源的、跨平台的、支持网络的sound server声音服务器基本上就是您的声音应用的代理者。它能够支持从一个或多个source(进程或音频采集设备)输入声音并重定向它到一个或多个sink(声卡,远程网络PulseAudio server或其余进程)。PulseAudio的目的之一就是经过它来reroute全部的音频流。

为了支持Bluetooth audio sourcePulseAuido还实现了动态检测蓝牙音频设备的功能。这个功能和BlueZ A2DP Sink都是由João Paulo实现的,能够在它的blogBlueZ now has A2DP Sink support》中找到相关信息。

PulseAudio如何从BlueZ获得音频数据

虽然BlueZ内部对A2DP Sink的实现较为复杂,可是暴露给外部的数据接口确很是简单。在bluez/audio/ipc.c中实现了三个bt_audio_service函数。PulseAudio使用bt_audio_service_open()打开一个socket,而后调用bt_audio_service_get_data_fd()获得音频数据文件描述符fd。这个fd是经过那个socketBlueZ的进程传递到PulseAudio的进程的。最后,使用完毕,调用bt_audio_service_close()来关闭socketPulseAudio经过D-busBlueZ进行通讯,进行参数的读取和设置,决定合适的读取时机,发送读取的状态。

PulseAudiofd读出的音频数据流是通过SBC压缩编码的(对于采用其余编码,如MPEG-1,的状况,本文不作讨论),PulseAudio还须要对这些音频数据流进行解码。在BlueZ中已经实现了SBC编解码,源文件位于bluez/sbcPluseAudio直接使用了这些源代码,把它们放在pulseadio/src/modules/bluetooth/sbc中。

sudo apt install pulseaudio-module-bluetooth Reading package lists... Done Building dependency tree Reading state information... Done The following additional packages will be installed: libasound2-plugins libpulsedsp libspeexdsp1 pulseaudio pulseaudio-utils rtkit Suggested packages: pavumeter pavucontrol paman paprefs The following NEW packages will be installed: libasound2-plugins libpulsedsp libspeexdsp1 pulseaudio pulseaudio-module-bluetooth pulseaudio-utils rtkit 0 upgraded, 7 newly installed, 0 to remove and 238 not upgraded. Need to get 32.2 kB/1,387 kB of archives. After this operation, 6,764 kB of additional disk space will be used. Do you want to continue? [Y/n] Get:1 http://mirrors.ustc.edu.cn/raspbian/raspbian stretch/main armhf rtkit armhf 0.11-4+deb9u1 [32.2 kB]
 Fetched 32.2 kB in 0s (112 kB/s) Selecting previously unselected package libspeexdsp1:armhf. (Reading database ... 126798 files and directories currently installed.) Preparing to unpack .../0-libspeexdsp1_1.2~rc1.2-1_armhf.deb ... Unpacking libspeexdsp1:armhf (1.2~rc1.2-1) ....................................................] Selecting previously unselected package libasound2-plugins:armhf...............................] Preparing to unpack .../1-libasound2-plugins_1.1.1-1_armhf.deb ... Unpacking libasound2-plugins:armhf (1.1.1-1) ..................................................] Selecting previously unselected package libpulsedsp:armhf......................................] Preparing to unpack .../2-libpulsedsp_10.0-1+deb9u1_armhf.deb ... Unpacking libpulsedsp:armhf (10.0-1+deb9u1) ...................................................] Selecting previously unselected package pulseaudio-utils.......................................] Preparing to unpack .../3-pulseaudio-utils_10.0-1+deb9u1_armhf.deb ... Unpacking pulseaudio-utils (10.0-1+deb9u1) ....................................................] Selecting previously unselected package pulseaudio.............................................] Preparing to unpack .../4-pulseaudio_10.0-1+deb9u1_armhf.deb ... Unpacking pulseaudio (10.0-1+deb9u1) ...#####..................................................] Selecting previously unselected package rtkit.####.............................................] Preparing to unpack .../5-rtkit_0.11-4+deb9u1_armhf.deb ... Unpacking rtkit (0.11-4+deb9u1) ...#################...........................................] Selecting previously unselected package pulseaudio-module-bluetooth............................] Preparing to unpack .../6-pulseaudio-module-bluetooth_10.0-1+deb9u1_armhf.deb ... Unpacking pulseaudio-module-bluetooth (10.0-1+deb9u1) ...#.....................................] Setting up libpulsedsp:armhf (10.0-1+deb9u1) ...##############.................................] Setting up pulseaudio-utils (10.0-1+deb9u1) ...####################............................] Setting up rtkit (0.11-4+deb9u1) ...###################################........................] Created symlink /etc/systemd/system/graphical.target.wants/rtkit-daemon.service → /lib/systemd/system/rtkit-daemon.service. Processing triggers for man-db (2.7.6.1-2) ...#############################....................] Processing triggers for dbus (1.10.26-0+deb9u1) ... Setting up libspeexdsp1:armhf (1.2~rc1.2-1) ... Setting up libasound2-plugins:armhf (1.1.1-1) ...###############################...............] Setting up pulseaudio (10.0-1+deb9u1) ...###########################################...........] Adding user pulse to group audio######################################################.........] Setting up pulseaudio-module-bluetooth (10.0-1+deb9u1) ...##############################.......] Processing triggers for dbus (1.10.26-0+deb9u1) ...#########################################...]

启动pulseaudio:

/usr/bin/pulseaudio --start --log-target=syslog 

pulseaudio安装完成后,蓝牙音响设备pair/connect完成后,能够经过其提供的命令pactl查看蓝牙设备,pacmd设置profile、sink等。

#pactl list cards Card #0 Name: bluez_card.FC_58_FA_5B_7E_DD Driver: module-bluez5-device.c Owner Module: 20 Properties: device.description = "A3" device.string = "FC:58:FA:5B:7E:DD" device.api = "bluez" device.class = "sound" device.bus = "bluetooth" device.form_factor = "headset" bluez.path = "/org/bluez/hci0/dev_FC_58_FA_5B_7E_DD" bluez.class = "0x260404" bluez.alias = "A3" device.icon_name = "audio-headset-bluetooth" device.intended_roles = "phone" Profiles: headset_head_unit: Headset Head Unit (HSP/HFP) (sinks: 1, sources: 1, priority: 20, available: yes) a2dp_sink: High Fidelity Playback (A2DP Sink) (sinks: 1, sources: 0, priority: 10, available: yes) off: Off (sinks: 0, sources: 0, priority: 0, available: yes) Active Profile: headset_head_unit Ports: headset-output: Headset (priority: 0, latency offset: 0 usec) Part of profile(s): headset_head_unit, a2dp_sink headset-input: Headset (priority: 0, latency offset: 0 usec) Part of profile(s): headset_head_unit # pactl list sinks Sink #1 State: SUSPENDED Name: bluez_sink.FC_58_FA_5B_7E_DD Description: A3 Driver: module-bluez5-device.c Sample Specification: s16le 1ch 8000Hz Channel Map: mono Owner Module: 20 Mute: no Volume: mono: 65536 / 100% balance 0.00 Base Volume: 65536 / 100% Monitor Source: bluez_sink.FC_58_FA_5B_7E_56.monitor Latency: 0 usec, configured 0 usec Flags: HARDWARE HW_VOLUME_CTRL LATENCY Properties: bluetooth.protocol = "headset_head_unit" device.intended_roles = "phone" device.description = "A3" device.string = "FC:58:FA:5B:7E:DD" device.api = "bluez" device.class = "sound" device.bus = "bluetooth" device.form_factor = "headset" bluez.path = "/org/bluez/hci0/dev_FC_58_FA_5B_7E_DD" bluez.class = "0x260404" bluez.alias = "A3" device.icon_name = "audio-headset-bluetooth" Ports: headset-output: Headset (priority: 0) Active Port: headset-output Formats: pcm

pacmd获取到音响card索引号和sink索引号后,可经过pactl设置profile和默认输出:

pacmd set-card-profile 0 a2dp_sink        // Card #0
pacmd set-default-sink 1                  // Sink #1

设置完成后,可用pulseaudio自带的paplay播放wav格式音频文件:

paplay test.wav

至此,蓝牙音响可播放出声音。

 

参考:

    1. 嵌入式linux开发板使用pulseaudio链接蓝牙耳机播放音频文件

    2. bluetooth archlinux wiki

    3. 蓝牙核心技术概述(一):蓝牙概述

    4. 蓝牙设备开发的三种方式

    5. 对蓝牙profile的理解

    6. ARM平台上蓝牙协议栈Bluez的移植使用和配置

    7. UbuntuBluetooth A2DP receiver实现分析

    8. Bluetooth headset (简体中文)

    9. Turn Your Raspberry Pi Into a Wireless Portable Bluetooth Audio System A2DP

    10. 用树莓派玩转蓝牙

    11. Playing Audio over Bluetooth on Rasbperry Pi (Using Bluealsa, Command Line)

    12. 树莓派链接天猫精灵蓝牙音箱-1

相关文章
相关标签/搜索