介绍:

BT ,bluetooth ,硬件的厂家有 realtek , Broadcom, csr ,rad 等,我了解到的,前两者在 arm android 上集成的比较多,如 rockchip 平台上rtl8723bs ,ap6212,ap6210, ap6335.等。后者 csr rda 没怎么接触过,听说终端设备上用的比较多。

 

硬件:

Arm adroid 机子上的蓝牙的硬件几乎都是以模块的形式出现,一般同时封装了 WiFi 和 蓝牙,有的甚至还封装了FM. 管脚为 44pin

Android 蓝牙音箱曲线调节 蓝牙音箱调试方法_Android 蓝牙音箱曲线调节

 

 

蓝牙和主控的连接是串口,需要用到串口的流控:cts rts ,(有的例外,如 realtek rtl8723 可把 芯片cts 接地)。

并且上电,复位和 wake 的几个 gpio 要配置正确,同时,32k 的慢时钟是需要的,不然有可能造成蓝牙打不开的情况,32k 的时钟,一般在 rtc (8563),或者pmu ,或者其他地方取。

在蓝牙用到实时通话(hfp , hfp client)的过程中,还需要pcm/i2s 的连接,注意 in 和 out 多分析一下,容易反,其标识容易混淆。

软件:

 

蓝牙软件实现比较复杂,对比了一下 android5.1 和 android6.0 发现很大的区别,由于项目需要,把 android5.1 的蓝牙部分移植到了 6.0上,花了相当大的经历。

 

Android6.0 上蓝牙相关代码位置介绍一下:

1 package/app/blutooth

这里不仅仅是蓝牙的app 层的东西,还有和蓝牙协议栈通信的 Jni , 和 api 通信的service

Android 蓝牙音箱曲线调节 蓝牙音箱调试方法_串口_02

 

 

2 frame/base/core/java/android/bluetooth/

这里是 api 的一些东西,实现和 蓝牙 service 通信的 aidl 接口也是在这实现的。

3 system/bt

蓝牙协议栈,android5.1 放在 externel/bluedroid 里面的

4 device/common/bluetooth/libbt

libbt-vendor 不同厂家私有的一些蓝牙定义。

5 ./hardware/libhardware/include/hardware/bluetooth.h

蓝牙的一些头文件。

6 内核的 dts 以及蓝牙rfkill 的电源的支持。

 

移植过程:

蓝牙在android 上连耳机,连手机电脑的功能,实现比较简单,差不多底层移植好后就能实现了,由android 本身移植好了。

 

主要是移植音响的功能,也就是做为设备端,让手机连。使设备播放音乐。

 

到这里的时候就会去查看蓝牙的一些场景:专业术语叫 profile

 

如手机,平板功能,都是用的 a2dp, hfp, avrcp 等 profile ,而做为音响,耳机的时候是 a2dp sink , avrcp , hfp client 的profile .,另外还一些我没用过的 profile 如: SPP ,HID

 

这里需要说明的一点,目前蓝牙对一些 profile 的硬件通路,很多没做过蓝牙的人几乎会犯错:

   A2dp / A2dp sink :虽然是播放音乐用的,但是他并没有走 pcm 接口,而是走的串口。这时很多人会计算串口波特率,觉得播放音乐完全不够用,以为串口是 115200 为最高波特率,但是实际在蓝牙串口上,波特率设置在3m左右,一般在蓝牙芯片公司给出的 config 文件里可以看到。

  Hfp / Hfp client : 实时语音通话,这个时候是走的pcm (软件中有 SCO 的字样)

 

A2dp sink 的移植看起来比较简单,不需要考虑硬件通路,反正走串口,只需要讲蓝牙过来的音频数据播放到喇叭就可以。

 

  1. 在哪取蓝牙过来的音频数据,怎么能让蓝牙进入音频数据过来的模式?

   答案是这部分android 已经做好了。我们只需要配置一下 packages/apps/Bluetooth/res/values/config.xml 里的profile_supported_a2dp_sink  为 true 就可以了

他会模拟出一个 app 可以用声音源: AudioSource.BLUETOOTH_A2DP ,我们只需要用new AudioRecord(AudioSource.BLUETOOTH_A2DP,xxxx), 我这边没有用 AudioSource.BLUETOOTH_A2DP 这个名字,直接用的数字11代替,因为要用到这个 AudioSource.BLUETOOTH_A2DP ,其他地方要改很多东西。

 

2 蓝牙音频数据的播放如何实现?

  这个得自己写,我这边主控公司给出的技术支持,写了2个线程的方法,一个线程负责录音,一个线程负责播放。

 

这个时候,很多人很问一个问题,蓝牙是串口过来的东西,怎么可以直接用AudioRecord 来读数据呢?对这个问题,如果不深入理解,都是迷茫的。后查资料并读 system/bt 协议栈会发现,协议栈通过 audio_a2dp_hw.c btif_media_task.c等实现声卡的模拟,对上层来说就是多了一个蓝牙声卡,可以对它读写控制。蓝牙声卡的模拟实现的数据传输方式是:socket 。Socket 文件地址 /data/misc/bluedroid/.a2dp_ctrl 和 /data/misc/bluedroid/.a2dp_data

  

实现录音播放后,a2dp sink 是可以听到手机传过来的声音了。

 

 

HFP client 移植主要考虑入口 和线程实现,还有 pcm 接口的配置

1 如何进入 hfp client 的profile ,进入后怎么把数据丢到硬件pcm 上去?

  同样是配置

packages/apps/Bluetooth/res/values/config.xml 的 profile_supported_hfpclient 为true ,android 已经实现了它的功能。

我们在 java 的找到接口(hfp_enable)后

./packages/apps/Bluetooth/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java:2145:                    mAudioManager.setParameters("hfp_enable=true");

在hardware 层来实现其功能,我这里还是主控厂家给的补丁。写了4个线程,2个收2个发:流程如下:

 

downlink 表示 , 远端电话语音信号-> 手机蓝牙-> AP6212 -> 3368 I2S1 PCM_IN 8K- > 3368 I2S0 I2S_SDO 48K-> ES8316  DAC

uplink表示 ,  CX20921 ADC->3368 I2S0 I2S_SDI  48K -> 3368 I2S1 PCM_OUT 8K  -> AP6212 -> 手机蓝牙->远端电话语音信号

 

2 硬件上怎么设计能出声音?

 硬件设计有几种方式

1,拿主控的一路 i2s/pcm 出来,直接接到蓝牙 pcm 。这个直接读写这一路 i2s

2,蓝牙pcm 接到 主控的codec 上。这个切换 codec 的通路。

 我们用的第一种方式

 

3 pcm 参数的配置:可能是个人以前很少用到 pcm 格式,只知道 i2s 的几种格式,如 标准 i2s ,左右对其什么的。

 Pcm 也有几种格式,1time delay ,2 time delay 等等。得注意主控 i2s 和 pcm 的配置。当然这个时候示波器是相当重要的,可以查一下配置是否正确,

Pcm 的格式4线的定义是 clk ,sync ,in ,out . clk 一般在256K ,sync 8k ,sync 的波形是差不多一个 slot 的高电平,其余是低电平。

I2s 的格式4线的定义是 ,bclk .lrclk ,in ,out . clk 一般在2.82m ,lrclk 为采样率,44.1k ,8k 都有

 

4 蓝牙pcm 采样率和播放到喇叭 codec 采样率不一致,怎么调?

  采用重采样,直接采用 externel/speex 的 speex 做重采样。

 

5 通道数不一致,有的通道有杂音,声音不能调大小?

 还是在 hardware 层做算法处理,如丢弃声道,mix 声道,大小按规律去更修改 pcm 数据的大小。

 

AVRCP 的控制

 

这个简单,直接调用 api ,发送一个play pause 等命令

 

 

另外再说一下,花时间最多的问题: android 6.0 上。A2dp sink 老是出 system crash. 查了很久。因为它是偶现的,比如两个小时才出一次,不管是用 addr2line 定位文件位置,还是看 /data/tombstone 文件查看都没有进展,有兴趣的话可以帮查一下问题:

05-07 17:15:46.901  2474  2501 F libc    : Fatal signal 11 (SIGSEGV), code 1, fault addr 0xfb0b1ff8 in tid 2501 (bluedroid wake/)

05-07 17:15:47.006   229   229 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

05-07 17:15:47.006   229   229 F DEBUG   : Build fingerprint: 'Android/rk3368_64/rk3368:6.0.1/MOB30J/user.wade.20180507.150808:userdebug/test-keys'

05-07 17:15:47.007   229   229 F DEBUG   : Revision: '0'

05-07 17:15:47.007   229   229 F DEBUG   : ABI: 'arm'

05-07 17:15:47.008   229   229 F DEBUG   : pid: 2474, tid: 2501, name: bluedroid wake/  >>> com.android.bluetooth <<<

05-07 17:15:47.008   229   229 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xfb0b1ff8

05-07 17:15:47.046   229   229 F DEBUG   :     r0 aaeb0ed8  r1 00000000  r2 00000108  r3 aaeb1258

05-07 17:15:47.046   229   229 F DEBUG   :     r4 aaeb1ba0  r5 00000380  r6 fffffc80  r7 00ef0004

05-07 17:15:47.046   229   229 F DEBUG   :     r8 f74f1eb8  r9 aaeb0ee8  sl f74f1eb8  fp f4249aac

05-07 17:15:47.046   229   229 F DEBUG   :     ip 00000000  sp e2892288  lr 00ef0050  pc f74bc394  cpsr a00e0030

05-07 17:15:47.055   229   229 F DEBUG   :

05-07 17:15:47.055   229   229 F DEBUG   : backtrace:

05-07 17:15:47.055   229   229 F DEBUG   :     #00 pc 0002f394  /system/lib/libc.so (dlmalloc_real+1303)

05-07 17:15:47.055   229   229 F DEBUG   :     #01 pc 000fc241  /system/lib/hw/bluetooth.default.so (osi_malloc+8)

05-07 17:15:47.055   229   229 F DEBUG   :     #02 pc 0009c469  /system/lib/hw/bluetooth.default.so (GKI_getbuf+6)

05-07 17:15:47.056   229   229 F DEBUG   :     #03 pc 0005bc91  /system/lib/hw/bluetooth.default.so (btif_media_sink_enque_buf+72)

05-07 17:15:47.056   229   229 F DEBUG   :     #04 pc 0003cf17  /system/lib/hw/bluetooth.default.so

05-07 17:15:47.056   229   229 F DEBUG   :     #05 pc 0008d8f7  /system/lib/hw/bluetooth.default.so (bta_av_stream_data_cback+162)

05-07 17:15:47.056   229   229 F DEBUG   :     #06 pc 000da5df  /system/lib/hw/bluetooth.default.so (avdt_scb_event+70)

05-07 17:15:47.056   229   229 F DEBUG   :     #07 pc 000dac75  /system/lib/hw/bluetooth.default.so (avdt_ad_tc_data_ind+64)

05-07 17:15:47.057   229   229 F DEBUG   :     #08 pc 000eb5c7  /system/lib/hw/bluetooth.default.so (l2c_csm_execute+3486)

05-07 17:15:47.057   229   229 F DEBUG   :     #09 pc 000e600f  /system/lib/hw/bluetooth.default.so (l2c_rcv_acl_data+4018)

05-07 17:15:47.057   229   229 F DEBUG   :     #10 pc 000fe96b  /system/lib/hw/bluetooth.default.so

05-07 17:15:47.057   229   229 F DEBUG   :     #11 pc 000ff93f  /system/lib/hw/bluetooth.default.so

05-07 17:15:47.057   229   229 F DEBUG   :     #12 pc 000415af  /system/lib/libc.so (_ZL15__pthread_startPv+30)

05-07 17:15:47.058   229   229 F DEBUG   :     #13 pc 0001918b  /system/lib/libc.so (__start_thread+6)

05-07 17:15:47.532   229   229 F DEBUG   :

05-07 17:15:47.532   229   229 F DEBUG   : Tombstone written to: /data/tombstones/tombstone_05

05-07 17:15:47.532   229   229 E DEBUG   : AM write failed: Broken pipe

05-07 17:15:47.539   564   595 I BootReceiver: Copying /data/tombstones/tombstone_05 to Dr

 

最后解决这个问题的办法,我采取了把 5.1 的蓝牙部分全部移植到 6.0上。测试没有问题。难道是 android 6.0 对a2dp sink 的支持还不到位?