HF 笔记

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<Integer, Object> 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;


queryCallsDone

在这里插入图片描述|

    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()");
    }
|

终于发出了ACTION_CALL_CHANGED

接收广播
在这里插入图片描述

进入outgoing电话
在这里插入图片描述手机连接车机,车机打电话的的流程

车机通过ATD10086告诉手机车机要打的号码,通过手机后手机向外打电话,手机返回ok后,车机开机查询手机的通话状态或者手机通过ciev事件告诉车机状态
在这里插入图片描述
两个角色互发数据的数据流程

作为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

去掉BTA_HF_CLIENT_FEAT_CODEC,不支持编解码协商,结合hf1.5,车机端默认为cvsd解码
在这里插入图片描述
电量显示支持

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

安卓蓝牙支持苹果耳机,需要定制,如电池电量 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->

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

Bluetooth\src\com\android\bluetooth\hfp\HeadsetStateMachine.java

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的断开
在这里插入图片描述

rfcomm接收数据

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

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得到结果

/* 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建立成功了
在这里插入图片描述

hf client disconnect

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

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值