Bluetooth蓝牙架构
架构图
image.png
image.png
蓝牙应用通过binder和系统蓝牙Service进行通讯 ,然后通过JNI与蓝牙HAL层进行通讯.
Android的硬件抽象层,简单来说,就是对Linux内核驱动程序的封装,向上提供接口
Bluetooth的kernel层 linux系统上Bluetooth的核心代码,包括驱动
源码目录
java层
frameworks/base/core/java/android/bluetooth/
jni层
frameworks/base/core/jni/android_bluetooth_开头的文件
packages/apps/Bluetooth/jni/
主要是为Bluetooth的JAVA类提供一些底层API支持(C++实现)。如gatt等。
编译完成后生成libbluetooth_jni.so,供Bluetooth.apk使用。
运用蓝牙API,Android应用程序可以完成如下操作:
(1)扫描其他Bluetooth设备。
(2)查询配对Bluetooth设备的本地Bluetooth适配器。
(3)建立RFCOMM通道。
(4)通过服务探索连接到其他设备。
(5)与其他设备进行数据传输。
(6)管理多个连接
BluetoothAdapter主要提供蓝牙的基本操作,比如enable, disable, discovery, pair, unpair, createRfcomm等,其他的就都是Profile的各自的Service了;
大多的事情都是在Bluedroid层里面做的,上层只管去Call和Callback就是了
配对和连接是两个不同的概念:
配对意思是两个设备相互意识到对方的存在,共享一个用来鉴别身份的链路键(link-key),能够与对方建立一个加密的连接。
连接意思是两个设备现在共享一个RFCOMM信道,能够相互传输数据。
Devicediscovery(设备搜索)是一个扫描搜索本地已使能Bluetooth设备并且从搜索到的设备请求一些信息的过程
RFCOMM是一个仿真有线链路的无线数据仿真协议,符合ETSI标准的TS07.10串口仿真协议,它在蓝牙基带上仿真RS-232的控制和数据信号,为原先使用串行连接的上层业务提供传送能力。
RFCOMM连接会阻塞直到用户成功将设备配对(如果用户拒绝配对或者配对超时了连接会失败)。
startDiscovery() 该函数时异步的,调用后立即返回,返回值表示搜索是否成功开始。搜索处理通常包括一个12秒钟的查询扫描
然后通过广播接收数据:BroadcastReceiver ACTION_FOUND EXTRA_DEVICE
Bluetooth
1,基本蓝牙功能:打开/关闭/扫描/配对/连接
2,蓝牙协议功能: 传输文件/蓝牙同步联系人等等
(1)BluetoothAdapter BluetoothDevice BluetoothSocket
https://blog.csdn.net/edmond999/article/details/82495379
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
aidl = =》》 BluetoothAdapterService
IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);
配对完成和连接是有区别的,配对意味着设备双方都知道对方的存在并且有一个共享的link-key用于授权。并且双方能否建立加密连接。连接意味着设备当前共享一个RFCOMM通道并且双方能够传递数据。
使用BluetoothDevice,通过调用createRfcommSocketToServiceRecord(UUID)获得BluetoothSocket
mmSocket.connect();
bytes = mmInStream.read(buffer);
mmOutStream.write(bytes);
(2)BluetoothProfile 协议栈
https://blog.csdn.net/u012439416/article/details/52599790
HFP协议
HFP (Hands-free Profile),让蓝⽛设备(如蓝⽛⽿机)可以控制电话,如接听、挂断、拒接、语⾳拨号 等,拒接、语⾳拨号要看蓝⽛⽿机及电话是否⽀持。
mBluetoothAdapter.getProfileProxy(getApplicationContext(),new ServiceListener() {
onServiceConnected
mHfpClient= (BluetoothHeadsetClient) proxy;
与通话相关的操作主要有4个:
BluetoothHeadsetClient是一个api,由第三方apk直接调用,可以进行拨号/接听/拒接/挂断操作,对应的方法依次为dial()/acceptCall()/rejectCall()/terminateCall().
HeadsetClientService是一个服务
HeadsetClientService 根据不同的方法给状态机发送不同的消息,最后通过HeadsetClientStateMachine根据JNI机制调用
com_android_bluetooth_hfpclient.cpp对应的方法,最后调用底层C/C++ 来真正的实现拨号/接听/拒接/挂断操作。
使用profile
profile是两个设备基于蓝牙通信的无线接口规范。
mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET);
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEADSET) {
mBluetoothHeadset = (BluetoothHeadset) proxy;
aidl = =》》 BluetoothHeadsetService
BluetoothHeadsetClient.java主要负责蓝牙通话的相关动作,比如接听等等
BluetoothHeadsetClientCall.java主要负责蓝牙通话的状态,比如是来电还是去电等等。
https://blog.csdn.net/u012439416/article/details/54348772
a2dp协议
全称:Advanced Audio Distribution Profile 蓝牙音频传输协议
输入客户端: BluetoothA2dpSink.java
输入接口好像只能获取连接的状态,远程蓝牙地址还有判断是否在正在传输音频以外,其它的貌似啥也做不了。
假如手机和蓝牙耳机连接,手机除了可以调节声音输出的大小之外,还能要求耳机做什么呢?这样的输入接口也合情合理。
想象一下这种场景,主设备和从设备通过蓝牙连接并正在放歌,如何通过从设备来调整主设备声音的大小,以及上一首下一首等,这就需要avrcp协议出场了。
PBAP协议
使用场景:智能车载中同步联系人 通话记录等信息。
-
构造BluetoothPbapClient对象,
-
调用BluetoothPbapClient对象方法,处理对应的回调消息。
- public static final String ICH_PATH = "telecom/ich.vcf"; // 手机来电记录
- public static final String OCH_PATH = "telecom/och.vcf"; // 手机去电记录
- public static final String MCH_PATH = "telecom/mch.vcf";// 手机未接电话记录
- public static final String CCH_PATH = "telecom/cch.vcf"; // 所有通话记录
- public static final String PB_PATH = "telecom/pb.vcf"; // 手机联系人
mPbapClient. pullPhoneBook(PATH);
pullPhoneBook = (ArrayList<VCardEntry>) msg.obj;
VCardEntry可以保存联系人/通话记录的各种信息,看枚举EntryLabel
参考文章:
https://blog.csdn.net/u012408797/article/details/84991903
https://blog.csdn.net/u012408797/article/details/109766608
https://blog.csdn.net/weixin_45534242/category_11754600.html
https://blog.csdn.net/edmond999/article/details/82495379
https://blog.csdn.net/u012439416/category_6475898.html