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

相關文章
相關標籤/搜索