Attribute: Bluetooth Profile Descriptor List
SDP_AddProfileDescriptorList
创建一个属性
本地HF角色的属性
SDP_AddAttribute添加属性
connect_audio
/*******************************************************************************
*
* Function connect_audio
*
* Description create an audio connection
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t connect_audio(const RawAddress* bd_addr) {
btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(*bd_addr);
if (cb == NULL || !is_connected(cb)) return BT_STATUS_FAIL;
CHECK_BTHF_CLIENT_SLC_CONNECTED(cb);
if ((BTIF_HF_CLIENT_FEATURES & BTA_HF_CLIENT_FEAT_CODEC) &&
(cb->peer_feat & BTA_HF_CLIENT_PEER_CODEC)) {
BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_BCC, 0, 0, NULL);
} else {
BTA_HfClientAudioOpen(cb->handle);
}
BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_BCC, 0, 0, NULL);
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
case RFC_STATE_OPENED:
rfc_port_sm_opened(p_port, event, p_data);
case RFC_EVENT_DATA:
/* Send credits in the frame. Pass them in the layer specific member of
* the hdr. */
/* There might be an initial case when we reduced rx_max and credit_rx is
* still */
/* bigger. Make sure that we do not send 255 */
if ((p_port->rfc.p_mcb->flow == PORT_FC_CREDIT) &&
(((BT_HDR*)p_data)->len < p_port->peer_mtu) &&
(!p_port->rx.user_fc) &&
(p_port->credit_rx_max > p_port->credit_rx)) {
((BT_HDR*)p_data)->layer_specific =
(uint8_t)(p_port->credit_rx_max - p_port->credit_rx);
p_port->credit_rx = p_port->credit_rx_max;
} else {
((BT_HDR*)p_data)->layer_specific = 0;
}
rfc_send_buf_uih(p_port->rfc.p_mcb, p_port->dlci, (BT_HDR*)p_data);
L2CA_DataWrite(p_mcb->lcid, p_buf);
事件:
/*******************************************************************************
*
* Function bta_hf_client_rfc_do_open
*
* Description Open an RFCOMM connection to the peer device.
*
*
* Returns void
*
******************************************************************************/
void bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA* p_data) {
tBTA_HF_CLIENT_CB* client_cb =
bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
if (client_cb == NULL) {
APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__,
p_data->hdr.layer_specific);
return;
}
BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_HF_HANDSFREE,
client_cb->cli_sec_mask, BT_PSM_RFCOMM,
BTM_SEC_PROTO_RFCOMM, client_cb->peer_scn);
if (RFCOMM_CreateConnection(UUID_SERVCLASS_HF_HANDSFREE, client_cb->peer_scn,
false, BTA_HF_CLIENT_MTU, client_cb->peer_addr,
&(client_cb->conn_handle),
bta_hf_client_mgmt_cback) == PORT_SUCCESS) {
bta_hf_client_setup_port(client_cb->conn_handle);
APPL_TRACE_DEBUG("bta_hf_client_rfc_do_open : conn_handle = %d",
client_cb->conn_handle);
}
/* RFCOMM create connection failed; send ourselves RFCOMM close event */
else {
bta_hf_client_sm_execute(BTA_HF_CLIENT_RFC_CLOSE_EVT, p_data);
}
}
/*******************************************************************************
*
* Function bta_hf_client_setup_port
*
* Description Setup RFCOMM port for use by HF Client.
*
*
* Returns void
*
******************************************************************************/
void bta_hf_client_setup_port(uint16_t handle) {
PORT_SetEventMask(handle, PORT_EV_RXCHAR);
PORT_SetEventCallback(handle, bta_hf_client_port_cback);
}
/*******************************************************************************
*
* Function bta_hf_client_rfc_data
*
* Description Read and process data from RFCOMM.
*
*
* Returns void
*
******************************************************************************/
void bta_hf_client_rfc_data(tBTA_HF_CLIENT_DATA* p_data) {
tBTA_HF_CLIENT_CB* client_cb =
bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
if (client_cb == NULL) {
APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__,
p_data->hdr.layer_specific);
return;
}
uint16_t len;
char buf[BTA_HF_CLIENT_RFC_READ_MAX];
memset(buf, 0, sizeof(buf));
/* read data from rfcomm; if bad status, we're done */
while (PORT_ReadData(client_cb->conn_handle, buf, BTA_HF_CLIENT_RFC_READ_MAX,
&len) == PORT_SUCCESS) {
/* if no data, we're done */
if (len == 0) {
break;
}
bta_hf_client_at_parse(client_cb, buf, len);
/* no more data to read, we're done */
if (len < BTA_HF_CLIENT_RFC_READ_MAX) {
break;
}
}
}
bta_hf_client_at_parse(client_cb, buf, len);
队列里的HF client函数处理表:由void bta_hf_client_sm_execute(uint16_t event, tBTA_HF_CLIENT_DATA* p_data) 调度处理
/* action functions table, indexed with action enum */
const tBTA_HF_CLIENT_ACTION bta_hf_client_action[] = {
/* BTA_HF_CLIENT_RFC_DO_CLOSE */ bta_hf_client_rfc_do_close,
/* BTA_HF_CLIENT_START_CLOSE */ bta_hf_client_start_close,
/* BTA_HF_CLIENT_START_OPEN */ bta_hf_client_start_open,
/* BTA_HF_CLIENT_RFC_ACP_OPEN */ bta_hf_client_rfc_acp_open,
/* BTA_HF_CLIENT_SCO_LISTEN */ NULL,
/* BTA_HF_CLIENT_SCO_CONN_OPEN */ bta_hf_client_sco_conn_open,
/* BTA_HF_CLIENT_SCO_CONN_CLOSE*/ bta_hf_client_sco_conn_close,
/* BTA_HF_CLIENT_SCO_OPEN */ bta_hf_client_sco_open,
/* BTA_HF_CLIENT_SCO_CLOSE */ bta_hf_client_sco_close,
/* BTA_HF_CLIENT_FREE_DB */ bta_hf_client_free_db,
/* BTA_HF_CLIENT_OPEN_FAIL */ bta_hf_client_open_fail,
/* BTA_HF_CLIENT_RFC_OPEN */ bta_hf_client_rfc_open,
/* BTA_HF_CLIENT_RFC_FAIL */ bta_hf_client_rfc_fail,
/* BTA_HF_CLIENT_DISC_INT_RES */ bta_hf_client_disc_int_res,
/* BTA_HF_CLIENT_RFC_DO_OPEN */ bta_hf_client_rfc_do_open,
/* BTA_HF_CLIENT_DISC_FAIL */ bta_hf_client_disc_fail,
/* BTA_HF_CLIENT_RFC_CLOSE */ bta_hf_client_rfc_close,
/* BTA_HF_CLIENT_RFC_DATA */ bta_hf_client_rfc_data,
/* BTA_HF_CLIENT_DISC_ACP_RES */ bta_hf_client_disc_acp_res,
/* BTA_HF_CLIENT_SVC_CONN_OPEN */ bta_hf_client_svc_conn_open,
/* BTA_HF_CLIENT_SEND_AT_CMD */ bta_hf_client_send_at_cmd,
};
01-01 08:40:00.215 900 1290 D HeadsetClientStateMachine: Connected process message: 100
01-01 08:40:00.216 900 1290 D HeadsetClientStateMachine: Connected: event type: 16
01-01 08:40:00.216 900 1290 D HeadsetClientStateMachine: Connected: command result: 0 queuedAction: 50
01-01 08:40:00.216 900 1290 D HeadsetClientStateMachine: queryCallsDone
01-01 08:40:00.217 900 1290 D HeadsetClientStateMachine: currCallIdSet [] newCallIdSet [1] callAddedIds [1] callRemovedIds [] callRetainedIds []
01-01 08:40:00.217 900 1290 D HeadsetClientStateMachine: ADJUST: currCallIdSet [] newCallIdSet [1] callAddedIds [1] callRemovedIds [] callRetainedIds []
01-01 08:40:00.218 900 1290 D HeadsetClientStateMachine: sendCallChangedIntent BluetoothHeadsetClientCall{mDevice: 331361095, mId: 1, mUUID: d13e321f-b7dd-4015-98d3-f4c2c2d8fa4c, mState: ALERTING, mNumber: 46730415, mMultiParty: false, mOutgoing: true}
01-01 08:40:00.224 900 900 D HfpClientConnService: onReceive Intent { act=android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED flg=0x10000010 (has extras) }
01-01 08:40:00.225 900 900 D HfpClientConnService: Finding block for device 50:8F:4C:F9:F1:67 blocks {50:8F:4C:F9:F1:67=com.android.bluetooth.hfpclient.connserv.HfpClientDeviceBlock@f6f925c}
01-01 08:40:00.225 900 900 D HfpClientDeviceBlock.50:8F:4C:F9:F1:67: Got call BluetoothHeadsetClientCall{mDevice: 50:8F:4C:F9:F1:67, mId: 1, mUUID: d13e321f-b7dd-4015-98d3-f4c2c2d8fa4c, mState: ALERTING, mNumber: 10086, mMultiParty: false, mOutgoing: true}
01-01 08:40:00.225 900 900 D HfpClientDeviceBlock.50:8F:4C:F9:F1:67: findConnectionKey local key set {}
01-01 08:40:00.226 900 900 D HfpClientDeviceBlock.50:8F:4C:F9:F1:67: Creating connection on 50:8F:4C:F9:F1:67 for BluetoothHeadsetClientCall{mDevice: 331361095, mId: 1, mUUID: d13e321f-b7dd-4015-98d3-f4c2c2d8fa4c, mState: ALERTING, mNumber: 46730415, mMultiParty: false, mOutgoing: true}/null
01-01 08:40:00.234 900 900 D HfpClientConnection: Got call state change to 3
01-01 08:40:00.235 900 900 D BluetoothHeadsetClient: getCurrentCalls()
01-01 08:40:00.243 900 900 D HeadsetClientService: Found SM for device 50:8F:4C:F9:F1:67
AG_CALL_CHANGED
case StackEvent.STACK_EVENT:
Intent intent = null;
StackEvent event = (StackEvent) message.obj;
if (DBG) {
Log.d(TAG, "Connected: event type: " + event.type);
}
|
case StackEvent.EVENT_TYPE_CMD_RESULT:
Pair queuedAction = mQueuedActions.poll();
// should not happen but...
if (queuedAction == null || queuedAction.first == NO_ACTION) {
clearPendingAction();
break;
}
if (DBG) {
Log.d(TAG, "Connected: command result: " + event.valueInt
+ " queuedAction: " + queuedAction.first);
}
switch (queuedAction.first) {
case QUERY_CURRENT_CALLS:
queryCallsDone();
break;
default:
Log.w(TAG, "Unhandled AT OK " + event);
break;
}
break;
private void sendCallChangedIntent(BluetoothHeadsetClientCall c) {
Log.d(TAG, "Enter sendCallChangedIntent()");
if (DBG) {
Log.d(TAG, "sendCallChangedIntent " + c);
}
Intent intent = new Intent(BluetoothHeadsetClient.ACTION_CALL_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(BluetoothHeadsetClient.EXTRA_CALL, c);
mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM);
Log.d(TAG, "Exit sendCallChangedIntent()");
}
|
作为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_data==>PORT_ReadData bta_hf_client_at_parse==>bta_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的版本号**
diff --git a/system/bt/bta/hf_client/bta_hf_client_sdp.cc b/system/bt/bta/hf_client/bta_hf_client_sdp.cc
index 475ce16..8ae2a36 100644
--- a/system/bt/bta/hf_client/bta_hf_client_sdp.cc
+++ b/system/bt/bta/hf_client/bta_hf_client_sdp.cc
@@ -117,7 +117,7 @@ bool bta_hf_client_add_record(const char* p_service_name, uint8_t scn,
/* add profile descriptor list */
profile_uuid = UUID_SERVCLASS_HF_HANDSFREE;
- version = HFP_VERSION_1_6;
+ version = HFP_VERSION_1_5;
result &= SDP_AddProfileDescriptorList(sdp_handle, profile_uuid, version);
修改HF的feature
./btif/src/btif_hf_client.cc
#ifndef BTIF_HF_CLIENT_FEATURES
#define BTIF_HF_CLIENT_FEATURES \
(BTA_HF_CLIENT_FEAT_ECNR | BTA_HF_CLIENT_FEAT_3WAY | \
BTA_HF_CLIENT_FEAT_CLI | BTA_HF_CLIENT_FEAT_VREC | BTA_HF_CLIENT_FEAT_VOL | \
BTA_HF_CLIENT_FEAT_ECS | BTA_HF_CLIENT_FEAT_ECC | BTA_HF_CLIENT_FEAT_CODEC)
#endif
https://blog.csdn.net/jcxxxxx55/article/details/52847291
安卓蓝牙支持苹果耳机,需要定制,如电池电量 AT+IPHONEACCEV
描述:报告耳机的状态变更
发起者:耳机
格式:AT+IPHONEACCEV=[Number of key/value pairs ],[key1 ],[val1 ],[key2 ],[val2 ],...
参数:
Number of key/value pairs : 接下来参数的数量
key: 被报告状态变化的类型
1 = 电量等级
2 = 暂停状态
val: 更改的值
Battery events:0-9之间数字的字符串 A string value between '0' and '9'.
Dock state: 0 = undocked, 1 = docked.
Example: AT+IPHONEACCEV=1,1,3
如
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->
打电话:
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的断开
将从对端的数据放在队列中
void btu_hci_msg_process(BT_HDR* p_msg) {
/* Determine the input message type. */
switch (p_msg->event & BT_EVT_MASK) {
case BT_EVT_TO_BTU_HCI_ACL:
/* All Acl Data goes to L2CAP */
l2c_rcv_acl_data(p_msg);
break;
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->
case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */
if ((p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_DataInd_Cb))
(*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid,
(BT_HDR*)p_data);
break;
数据从l2cap 的BT_PSM_RFCOMM通道中上来
p_l2c->pL2CA_DataInd_Cb = RFCOMM_BufDataInd;
L2CA_Register(BT_PSM_RFCOMM, p_l2c);
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);
case RFC_STATE_OPENED:
rfc_port_sm_opened(p_port, event, p_data);
rfc_port_sm_opened->
case RFC_EVENT_UIH:
rfc_port_uplink_data(p_port, (BT_HDR*)p_data);
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;
//在
bta_hf_client_do_disc ->
db_inited = SDP_ServiceSearchAttributeRequest2(
client_cb->peer_addr, client_cb->p_disc_db, bta_hf_client_sdp_cback,
(void*)client_cb);
bta_hf_client_sdp_cback-> event = BTA_HF_CLIENT_DISC_INT_RES_EVT;
bta_hf_client_disc_int_res-> event = BTA_HF_CLIENT_DISC_OK_EVT;
/* DISC_OK_EVT */ {BTA_HF_CLIENT_RFC_DO_OPEN, BTA_HF_CLIENT_IGNORE,
BTA_HF_CLIENT_OPENING_ST},
bta_hf_client_rfc_do_open->
PORT_SetEventCallback(handle, bta_hf_client_port_cback);中注册
-------------------------------------------------------------
即 p_port->p_callback = bta_hf_client_port_cback
/* RFC_DATA_EVT */ {BTA_HF_CLIENT_RFC_DATA, BTA_HF_CLIENT_IGNORE,
BTA_HF_CLIENT_OPEN_ST},
搜索BTA_HF_CLIENT_RFC_DATA
bta_hf_client_main.cc (bta\hf_client) line 96 : /* BTA_HF_CLIENT_RFC_DATA */ bta_hf_client_rfc_data,
bta_hf_client_rfc_data ->
hf AG:
bta_ag_rfc_data
hf CLIENT:
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->
static const tBTA_HF_CLIENT_PARSER_CALLBACK bta_hf_client_parser_cb[] = {
bta_hf_client_parse_ok, bta_hf_client_parse_error,
bta_hf_client_parse_ring, bta_hf_client_parse_brsf,
bta_hf_client_parse_cind, bta_hf_client_parse_ciev,
bta_hf_client_parse_chld, bta_hf_client_parse_bcs,
bta_hf_client_parse_bsir, bta_hf_client_parse_cmeerror,
bta_hf_client_parse_vgm, bta_hf_client_parse_vgme,
bta_hf_client_parse_vgs, bta_hf_client_parse_vgse,
bta_hf_client_parse_bvra, bta_hf_client_parse_clip,
bta_hf_client_parse_ccwa, bta_hf_client_parse_cops,
bta_hf_client_parse_binp, bta_hf_client_parse_clcc,
bta_hf_client_parse_cnum, bta_hf_client_parse_btrh,
bta_hf_client_parse_busy, bta_hf_client_parse_delayed,
bta_hf_client_parse_no_carrier, bta_hf_client_parse_no_answer,
bta_hf_client_parse_blacklisted, bta_hf_client_skip_unknown};
HeadsetClientStateMachine.java
processConnectionEvent
case HeadsetClientHalConstants.CONNECTION_STATE_SLC_CONNECTED:
sendMessage(HeadsetClientStateMachine.SUBSCRIBER_INFO);
if (NativeInterface.retrieveSubscriberInfoNative(getByteAddress(mCurrentDevice))) {
addQueuedAction(SUBSCRIBER_INFO);
}
sBluetoothHfpClientInterface->retrieve_subscriber_info
static bt_status_t retrieve_subscriber_info(const RawAddress* bd_addr) {
btif_hf_client_cb_t* cb = btif_hf_client_get_cb_by_bda(*bd_addr);
if (cb == NULL || !is_connected(cb)) return BT_STATUS_FAIL;
CHECK_BTHF_CLIENT_SLC_CONNECTED(cb);
BTA_HfClientSendAT(cb->handle, BTA_HF_CLIENT_AT_CMD_CNUM, 0, 0, NULL);
return BT_STATUS_SUCCESS;
}
这样hf client就发送命令出去了
手机这边接收到命令后
/* AT command interpreter table for HFP */
const tBTA_AG_AT_CMD bta_ag_hfp_cmd[] = {
{"A", BTA_AG_AT_A_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
{"D", BTA_AG_AT_D_EVT, BTA_AG_AT_NONE | BTA_AG_AT_FREE, BTA_AG_AT_STR, 0,
0},
{"+VGS", BTA_AG_SPK_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
{"+VGM", BTA_AG_MIC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
{"+CCWA", BTA_AG_LOCAL_EVT_CCWA, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
/* Consider CHLD as str to take care of indexes for ECC */
{"+CHLD", BTA_AG_AT_CHLD_EVT, BTA_AG_AT_SET | BTA_AG_AT_TEST, BTA_AG_AT_STR,
0, 4},
{"+CHUP", BTA_AG_AT_CHUP_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
{"+CIND", BTA_AG_AT_CIND_EVT, BTA_AG_AT_READ | BTA_AG_AT_TEST,
BTA_AG_AT_STR, 0, 0},
{"+CLIP", BTA_AG_LOCAL_EVT_CLIP, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
{"+CMER", BTA_AG_LOCAL_EVT_CMER, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
{"+VTS", BTA_AG_AT_VTS_EVT, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
{"+BINP", BTA_AG_AT_BINP_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 1, 1},
{"+BLDN", BTA_AG_AT_BLDN_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
{"+BVRA", BTA_AG_AT_BVRA_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
{"+BRSF", BTA_AG_LOCAL_EVT_BRSF, BTA_AG_AT_SET, BTA_AG_AT_INT, 0,
BTA_AG_CMD_MAX_VAL},
{"+NREC", BTA_AG_AT_NREC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 0},
{"+CNUM", BTA_AG_AT_CNUM_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
{"+BTRH", BTA_AG_AT_BTRH_EVT, BTA_AG_AT_READ | BTA_AG_AT_SET, BTA_AG_AT_INT,
0, 2},
{"+CLCC", BTA_AG_AT_CLCC_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
{"+COPS", BTA_AG_AT_COPS_EVT, BTA_AG_AT_READ | BTA_AG_AT_SET, BTA_AG_AT_STR,
0, 0},
{"+CMEE", BTA_AG_LOCAL_EVT_CMEE, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
{"+BIA", BTA_AG_LOCAL_EVT_BIA, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 20},
{"+CBC", BTA_AG_AT_CBC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 100},
{"+BCC", BTA_AG_LOCAL_EVT_BCC, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
{"+BCS", BTA_AG_AT_BCS_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0,
BTA_AG_CMD_MAX_VAL},
{"+BIND", BTA_AG_AT_BIND_EVT,
BTA_AG_AT_SET | BTA_AG_AT_READ | BTA_AG_AT_TEST, BTA_AG_AT_STR, 0, 0},
{"+BIEV", BTA_AG_AT_BIEV_EVT, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
{"+BAC", BTA_AG_AT_BAC_EVT, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
/* End-of-table marker used to stop lookup iteration */
{"", 0, 0, 0, 0, 0}};
case BTA_AG_AT_CNUM_EVT:
HAL_CBACK(bt_hf_callbacks, cnum_cmd_cb, &btif_hf_cb[idx].connected_bda);
static bthf_callbacks_t sBluetoothHfpCallbacks = {
sizeof(sBluetoothHfpCallbacks),
connection_state_callback,
audio_state_callback,
voice_recognition_callback,
answer_call_callback,
hangup_call_callback,
volume_control_callback,
dial_call_callback,
dtmf_cmd_callback,
noice_reduction_callback,
wbs_callback,
at_chld_callback,
at_cnum_callback,
at_cind_callback,
at_cops_callback,
at_clcc_callback,
unknown_at_callback,
at_bind_callback,
at_biev_callback,
key_pressed_callback};
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);
}
case EVENT_TYPE_SUBSCRIBER_NUMBER_REQUEST:
processSubscriberNumberRequest(event.device);
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
case BTA_HFP_HS_SERVICE_ID: {
btif_hf_client_execute_service(b_enable);
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_setup_port(bta_hf_client_cb_arr.serv_handle);
void bta_hf_client_setup_port(uint16_t handle) {
PORT_SetEventMask(handle, PORT_EV_RXCHAR);
PORT_SetEventCallback(handle, bta_hf_client_port_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在SLC连接成功后为true
SLC连接成功了
bta_hf_client_svc_conn_open->
BTA_HF_CLIENT_CONN_EVT
case BTA_HF_CLIENT_CONN_EVT:
cb->peer_feat = p_data->conn.peer_feat;
cb->chld_feat = p_data->conn.chld_feat;
cb->state = BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED;
HAL_CBACK(bt_hf_client_callbacks, connection_state_cb, &cb->peer_bda,
cb->state, cb->peer_feat, cb->chld_feat);
从日志分析,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 {
/* these events are handled by the state machine */
BTA_HF_CLIENT_API_OPEN_EVT = BTA_SYS_EVT_START(BTA_ID_HS),
BTA_HF_CLIENT_API_CLOSE_EVT,
01-02 14:03:14.417387 7674 7713 I bt_btif : bta_sys_event: Event 0x1b01
01-02 14:03:14.417480 7674 7713 D bt_btif : bta_hf_client_hdl_event: BTA_HF_CLIENT_API_CLOSE_EVT (0x1b01)
01-02 14:03:14.417532 7674 7713 I bt_btif : HF Client evt : State 2 (BTA_HF_CLIENT_OPEN_ST), Event 0x1b01 (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
其中
/* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_CLOSE, BTA_HF_CLIENT_IGNORE,bta_hf_client_rfc_close
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}
12-16 10:43:52.167 897 1290 D HeadsetClientStateMachine: ADJUST: currCallIdSet [1] newCallIdSet [1] callAddedIds [] callRemovedIds [] callRetainedIds [1]
12-16 10:43:52.167 897 1290 D HeadsetClientStateMachine: sendCallChangedIntent BluetoothHeadsetClientCall{mDevice: 12668044, mId: 1, mUUID: cb3fc521-a8d5-4ff0-90d9-627bfd276a68, mState: INCOMING, mNumber: -1567968462, mMultiParty: false, mOutgoing: false}
12-16 10:43:52.676 897 1290 D HeadsetClientStateMachine: AudioOn process message: 50
12-16 10:43:52.676 897 1290 D HeadsetClientStateMachine: Connected process message: 50
12-16 10:43:52.676 897 1290 D HeadsetClientStateMachine: queryCallsStart
12-16 10:43:52.798 897 1290 D HeadsetClientStateMachine: AudioOn process message: 100
12-16 10:43:52.798 897 1290 D HeadsetClientStateMachine: AudioOn: event type: 14
12-16 10:43:52.798 897 1290 D HeadsetClientStateMachine: Connected process message: 100
12-16 10:43:52.798 897 1290 D HeadsetClientStateMachine: Connected: event type: 14
12-16 10:43:52.798 897 1290 D HeadsetClientStateMachine: queryCallsUpdate: 1
12-16 10:43:52.801 897 1290 D HeadsetClientStateMachine: AudioOn process message: 100
12-16 10:43:52.801 897 1290 D HeadsetClientStateMachine: AudioOn: event type: 16
12-16 10:43:52.801 897 1290 D HeadsetClientStateMachine: Connected process message: 100
12-16 10:43:52.801 897 1290 D HeadsetClientStateMachine: Connected: event type: 16
12-16 10:43:52.801 897 1290 D HeadsetClientStateMachine: Connected: command result: 0 queuedAction: 50
12-16 10:43:52.801 897 1290 D HeadsetClientStateMachine: queryCallsDone
12-16 10:43:52.801 897 1290 D HeadsetClientStateMachine: currCallIdSet [1] newCallIdSet [1] callAddedIds [] callRemovedIds [] callRetainedIds [1]
12-16 10:43:52.801 897 1290 D HeadsetClientStateMachine: ADJUST: currCallIdSet [1] newCallIdSet [1] callAddedIds [] callRemovedIds [] callRetainedIds [1]
12-16 10:43:52.802 897 1290 D HeadsetClientStateMachine: sendCallChangedIntent BluetoothHeadsetClientCall{mDevice: 12668044, mId: 1, mUUID: cb3fc521-a8d5-4ff0-90d9-627bfd276a68, mState: INCOMING, mNumber: -1567968462, mMultiParty: false, mOutgoing: false}
12-16 10:43:53.256 897 1290 D HeadsetClientStateMachine: AudioOn process message: 100
12-16 10:43:53.256 897 1290 D HeadsetClientStateMachine: AudioOn: event type: 10
12-16 10:43:53.256 897 1290 D HeadsetClientStateMachine: Connected process message: 100
12-16 10:43:53.256 897 1290 D HeadsetClientStateMachine: Connected: event type: 10
12-16 10:43:53.256 897 1290 D HeadsetClientStateMachine: AudioOn process message: 50
12-16 10:43:53.256 897 1290 D HeadsetClientStateMachine: Connected process message: 50
12-16 10:43:53.256 897 1290 D HeadsetClientStateMachine: queryCallsStart
12-16 10:43:53.340 897 1290 D HeadsetClientStateMachine: AudioOn process message: 100
12-16 10:43:53.340 897 1290 D HeadsetClientStateMachine: AudioOn: event type: 16
12-16 10:43:53.340 897 1290 D HeadsetClientStateMachine: Connected process message: 100
12-16 10:43:53.340 897 1290 D HeadsetClientStateMachine: Connected: event type: 16
12-16 10:43:53.340 897 1290 D HeadsetClientStateMachine: Connected: command result: 0 queuedAction: 50
12-16 10:43:53.340 897 1290 D HeadsetClientStateMachine: queryCallsDone
12-16 10:43:53.340 897 1290 D HeadsetClientStateMachine: currCallIdSet [1] newCallIdSet [] callAddedIds [] callRemovedIds [1] callRetainedIds []
12-16 10:43:53.341 897 1290 D HeadsetClientStateMachine: ADJUST: currCallIdSet [1] newCallIdSet [] callAddedIds [] callRemovedIds [1] callRetainedIds []
12-16 10:43:53.341 897 1290 D HeadsetClientStateMachine: sendCallChangedIntent BluetoothHeadsetClientCall{mDevice: 12668044, mId: 1, mUUID: cb3fc521-a8d5-4ff0-90d9-627bfd276a68, mState: TERMINATED, mNumber: -1567968462, mMultiParty: false, mOutgoing: false}
12-16 10:43:55.390 897 1290 D HeadsetClientStateMachine: AudioOn process message: 100
12-16 10:43:55.390 897 1290 D HeadsetClientStateMachine: AudioOn: event type: 2
12-16 10:43:55.390 897 1290 D HeadsetClientStateMachine: AudioOn audio state changed38:71:DE:2B:46:2B: 0
12-16 10:43:55.390 897 1290 D HeadsetClientStateMachine: hfp_enable=false
12-16 10:43:55.549 897 1290 D HeadsetClientStateMachine: Audio state 38:71:DE:2B:46:2B: 2->0
12-16 10:43:55.549 897 1290 D HeadsetClientStateMachine: Exit AudioOn: 100
12-16 10:43:55.549 897 1290 D HeadsetClientStateMachine: Exit Connected: 100
12-16 10:43:55.549 897 1290 D HeadsetClientStateMachine: Enter Connected: 100
12-16 10:43:55.573 897 1290 D HeadsetClientStateMachine: Connected process message: 100
12-16 10:43:55.573 897 1290 D HeadsetClientStateMachine: Connected: event type: 6
12-16 10:44:21.919 897 1290 D HeadsetClientStateMachine: Connected process message: 100