HF 笔记手机音箱「HF 笔记」 - 文章中心
HF 笔记手机音箱「HF 笔记」
2025-02-17

Attribute: Bluetooth Profile Descriptor List
SDP_AddProfileDescriptorList 
在这里插入图片描述
创建一个属性在这里插入图片描述
本地HF角色的属性
在这里插入图片描述
在这里插入图片描述
SDP_AddAttribute添加属性

connect_audio

 
 

bta_hf_client_send_at_bcc

bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_BCC, buf, strlen(buf));

PORT_WriteData

port_write

RFCOMM_DataReq

rfc_port_sm_execute

 
 
 

事件

 
 
 
 

队列里的HF client函数处理表:由void bta_hf_client_sm_execute(uint16_t event, tBTA_HF_CLIENT_DATA* p_data) 调度处理

 
 
 

AG_CALL_CHANGED

在这里插入图片描述

 

 


queryCallsDone

在这里插入图片描述|

 
 
 

作为AG角色:接收发送命令的接口
处理HF角色发来的命令
在这里插入图片描述
bta_ag_reg =>> bta_ag_hdl_event ==>> bta_ag_sm_execute ==>>bta_ag_rfc_data ==>>bta_ag_at_parse ==>>bta_ag_process_at
调用注册的callback函数 bta_ag_at_hfp_cback

发送消息给HF **
这个处理函数中调用的大多为
bta_ag_send_result**,然后bta_ag_send_result调用PORT_WriteData向rfcomm给对方传数据

作为HF 角色:接收发送命令的接口
发送命令给AG : bta_hf_client_send_at 
处理来自AG角色发来的命令bta_hf_client_rfc_dataPORT_ReadData bta_hf_client_at_parsebta_hf_client_at_parse_start=>
bta_hf_client_parser_cb
在这里插入图片描述
如处理CIEV事件
bta_hf_client_parse_ciev
>bta_hf_client_handle_ciev
>bta_hf_client_ind
>bta_hf_client_app_callback(BTA_HF_CLIENT_IND_EVT, &evt);
btif_hf_client_upstreams_evt可以查看到很多抛到上层的事件
 process_ind_evt(&p_data->ind);
 在这里插入图片描述

 
 

修改HF的feature
https://blog.csdn.net/u010481276/article/details/btif/src/btif_hf_client.cc

 
 

在这里插入图片描述
Android状态栏显示蓝牙耳机电量
在这里插入图片描述

安卓蓝牙支持苹果耳机,需要定制,如电池电量 AT+IPHONEACCEV

 


AT+XAPL
+XAPL
AT+IPHONEACCEV
在这里插入图片描述
命令当作一个错误上抛到应用层处理
bta_ag_at_err_cback-》BTA_AG_AT_UNAT_EVT:unknown_at_cmd_cb-》unknown_at_callback-》onUnknownAt-》processUnknownAt->processVendorSpecificAt->broadcastVendorSpecificEventIntent->onVendorSpecificHeadsetEvent->
VENDOR_SPECIFIC_HEADSET_EVENT_IPHONEACCEV:getBatteryLevelFromAppleBatteryVsc->updateBatteryLevel->
sendBatteryLevelChangedBroadcast->ACTION_BATTERY_LEVEL_CHANGED->BatteryLevelChangedHandler->

在这里插入图片描述
在这里插入图片描述
默认HFP协议中是AG给HF电量,profile中是没有定义HF给AG电量,所以各家都有扩展,QCC是扩展的BIEV,然后iphone是扩展的AT+IPHONEACCEV,各个耳机遵循的不同,看方案·
在这里插入图片描述
处理BIEV的流程

 

processAtBiev
sendIndicatorIntent
onHfIndicatorValueChanged
updateBatteryLevel
打电话
BluetoothHeadsetClientCall dial
HeadsetClientService BluetoothHeadsetClientCall dial(BluetoothDevice device, String number)
mNativeInterface.dialNative 发给对方手机
然后发送sendMessage(QUERY_CURRENT_CALLS);检测手机的通话状态,最后将手机的电话状态HfpClientConnection告诉本地的手机c通讯模块

HCI_Disconnection_Complete断开事件有一个connect handle,如果是esco断开它采用的connect handle与基于acl的connnect handle断开两者的connect handle是不同的,与此来判断是sco断开还是acl断开 ,下面是sco生成的handle
在这里插入图片描述正常通讯的handle
在这里插入图片描述
由上可知不同,也由此可知以下的断开是esco的断开,而非acl的断开
在这里插入图片描述

将从对端的数据放在队列中

 

l2c_rcv_acl_data

l2c_csm_execute(p_ccb, L2CEVT_L2CAP_DATA, p_msg);

case CST_OPEN:
l2c_csm_open(p_ccb, event, p_data);

l2c_csm_open->

 
 

RFCOMM_BufDataInd

rfc_parse_data解析事件类型

if (event == RFC_EVENT_UIH) {
if (p_buf->len > 0)
rfc_port_sm_execute(p_port, event, p_buf);
else
osi_free(p_buf);

 

rfc_port_sm_opened->

 

rfc_port_uplink_data
->PORT_DataInd-> fixed_queue_enqueue(p_port->rx.queue, p_buf);
-> if (p_port->p_callback && events) p_port->p_callback(events, p_port->inx);通知上层读数据

上层取从队列中数据

p_port->p_callback接口注册流程

HF CLIENT:

bta_hf_client_port_cback-> p_buf->hdr.event = BTA_HF_CLIENT_RFC_DATA_EVT;

 

即 p_port->p_callback = bta_hf_client_port_cback

在这里插入图片描述
搜索部分RFC_DATA得到结果

{BTA_HF_CLIENT_RFC_DATA, BTA_HF_CLIENT_IGNORE,
BTA_HF_CLIENT_OPEN_ST},

搜索BTA_HF_CLIENT_RFC_DATA
bta_hf_client_main.cc (btahf_client) line 96 : bta_hf_client_rfc_data,

bta_hf_client_rfc_data ->

 

PORT_Read ->
p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_port->rx.queue);

解析命令,再回传给上层
bta_hf_client_at_parse(client_cb, buf, len);->bta_hf_client_at_parse_start->bta_hf_client_parser_cb->

 
 

HeadsetClientStateMachine.java

processConnectionEvent

case HeadsetClientHalConstants.CONNECTION_STATE_SLC_CONNECTED:
sendMessage(HeadsetClientStateMachine.SUBSCRIBER_INFO);

 

sBluetoothHfpClientInterface->retrieve_subscriber_info

 

这样hf client就发送命令出去了

手机这边接收到命令后

 

case BTA_AG_AT_CNUM_EVT:
HAL_CBACK(bt_hf_callbacks, cnum_cmd_cb, &btif_hf_cb[idx].connected_bda);

 

at_cnum_callback

HeadsetStateMachine.java
private void onAtCnum(byte[] address) {
StackEvent event = new StackEvent(EVENT_TYPE_SUBSCRIBER_NUMBER_REQUEST);
event.device = getDevice(address);
sendMessage(STACK_EVENT, event);
}

 

processSubscriberNumberRequest
在这里插入图片描述

SLC连接建立
https://blog.csdn.net/shichaog/article/details/52123439
BTA_EnableBluetooth->BTA_DM_API_ENABLE_EVT

bta_dm_enable

btif_dm_upstreams_evt
case BTA_DM_ENABLE_EVT: {
btif_in_execute_service_request

 

BTA_HfClientEnable

bta_hf_client_api_enable

bta_hf_client_start_server
RFCOMM_CreateConnection(
UUID_SERVCLASS_HF_HANDSFREE, bta_hf_client_cb_arr.scn, true,
BTA_HF_CLIENT_MTU, RawAddress::kAny, &(bta_hf_client_cb_arr.serv_handle),
bta_hf_client_mgmt_cback);

 
 

在这里插入图片描述
处理BTA_HF_CLIENT_RFC_DATA_EVT
在这里插入图片描述rfcomm连接上执行call函数bta_hf_client_mgmt_cback

bta_hf_client_mgmt_cback

bta_hf_client_rfc_acp_open

bta_hf_client_rfc_open
bta_sys_conn_open
bta_hf_client_slc_seq刚开始初始值为BTA_HF_CLIENT_AT_NONE
在这里插入图片描述
一次对话过后有一个OK返回,由bta_hf_client_handle_ok处理,启动下一次命令
在这里插入图片描述
client_cb->svc_conn在C连接成功后为true
在这里插入图片描述
SLC连接成功了
bta_hf_client_svc_conn_open
BTA_HF_CLIENT_CONN_EVT

 

在这里插入图片描述
从日志分析,at+cmer+at+chld执行完后就slc建立成功了
在这里插入图片描述

disconnect->BTA_HfClientClose->BTA_HF_CLIENT_API_CLOSE_EVT->bta_hf_client_start_close

查找方法,正常情況下工作是open狀態,根据BTA_ID_HS找注册函数 先找准状态,再此找事件为对应状态的下标BTA_HF_CLIENT_API_CLOSE_EVT即第二个,则为API_CLOSE_EVT,查找BTA_HF_CLIENT_START_CLOSE其实换成小写就是,即bta_hf_client_start_close
enum {

BTA_HF_CLIENT_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_HS),
BTA_HF_CLIENT_API_CLOSE_EVT,

在这里插入图片描述

 

bta_hf_client_start_close 
bta_hf_client_rfc_do_close->
RFCOMM_RemoveConnection
BTA_HF_CLIENT_RFC_CLOSE_EVT
SDP_CancelServiceSearch
其中

 

bta_hf_client_rfc_close
bta_hf_client_at_reset
bta_sys_conn_close
bta_hf_client_sco_shutdown>bta_hf_client_sco_remove>BTM_RemoveSco
bta_sys_sco_unuse在这里插入图片描述

来电状态判断
跟据发送的ACTION_CALL_CHANGED所携带的BluetoothHeadsetClientCall状态来判断通话情况
HeadsetClientStateMachine: sendCallChangedIntent BluetoothHeadsetClientCall{mDevice: 12668044, mId: 1, mUUID: cb3fc521-a8d5-4ff0-90d9-627bfd276a68, mState: INCOMING, mNumber: -1567968462, mMultiParty: false, mOutgoing: false}

  I   II   III   IV