1 /******************************************************************************
2 *
3 * Copyright (c) 2016 The Android Open Source Project
4 * Copyright 2003-2012 Broadcom Corporation
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at:
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 ******************************************************************************/
19
20 #include <cstdint>
21 #include <cstdio>
22
23 #include "bta/hf_client/bta_hf_client_int.h"
24 #include "bta/include/utl.h"
25 #include "osi/include/allocator.h"
26 #include "osi/include/osi.h" // UNUSED_ATTR
27 #include "stack/include/bt_hdr.h"
28 #include "stack/include/btm_api.h"
29 #include "types/raw_address.h"
30
31 #include <base/logging.h>
32
33 static const char* bta_hf_client_evt_str(uint16_t event);
34 static const char* bta_hf_client_state_str(uint8_t state);
35 void bta_hf_client_cb_init(tBTA_HF_CLIENT_CB* client_cb, uint16_t handle);
36
37 /* state machine states */
38 enum {
39 BTA_HF_CLIENT_INIT_ST,
40 BTA_HF_CLIENT_OPENING_ST,
41 BTA_HF_CLIENT_OPEN_ST,
42 BTA_HF_CLIENT_CLOSING_ST
43 };
44
45 /* state machine action enumeration list */
46 enum {
47 BTA_HF_CLIENT_RFC_DO_CLOSE,
48 BTA_HF_CLIENT_START_CLOSE,
49 BTA_HF_CLIENT_START_OPEN,
50 BTA_HF_CLIENT_RFC_ACP_OPEN,
51 BTA_HF_CLIENT_SCO_LISTEN,
52 BTA_HF_CLIENT_SCO_CONN_OPEN,
53 BTA_HF_CLIENT_SCO_CONN_CLOSE,
54 BTA_HF_CLIENT_SCO_OPEN,
55 BTA_HF_CLIENT_SCO_CLOSE,
56 BTA_HF_CLIENT_FREE_DB,
57 BTA_HF_CLIENT_OPEN_FAIL,
58 BTA_HF_CLIENT_RFC_OPEN,
59 BTA_HF_CLIENT_RFC_FAIL,
60 BTA_HF_CLIENT_DISC_INT_RES,
61 BTA_HF_CLIENT_RFC_DO_OPEN,
62 BTA_HF_CLIENT_DISC_FAIL,
63 BTA_HF_CLIENT_RFC_CLOSE,
64 BTA_HF_CLIENT_RFC_DATA,
65 BTA_HF_CLIENT_DISC_ACP_RES,
66 BTA_HF_CLIENT_SVC_CONN_OPEN,
67 BTA_HF_CLIENT_SEND_AT_CMD,
68 BTA_HF_CLIENT_NUM_ACTIONS,
69 };
70
71 #define BTA_HF_CLIENT_IGNORE BTA_HF_CLIENT_NUM_ACTIONS
72
73 /* type for action functions */
74 typedef void (*tBTA_HF_CLIENT_ACTION)(tBTA_HF_CLIENT_DATA* p_data);
75
76 /* action functions table, indexed with action enum */
77 const tBTA_HF_CLIENT_ACTION bta_hf_client_action[] = {
78 /* BTA_HF_CLIENT_RFC_DO_CLOSE */ bta_hf_client_rfc_do_close,
79 /* BTA_HF_CLIENT_START_CLOSE */ bta_hf_client_start_close,
80 /* BTA_HF_CLIENT_START_OPEN */ bta_hf_client_start_open,
81 /* BTA_HF_CLIENT_RFC_ACP_OPEN */ bta_hf_client_rfc_acp_open,
82 /* BTA_HF_CLIENT_SCO_LISTEN */ NULL,
83 /* BTA_HF_CLIENT_SCO_CONN_OPEN */ bta_hf_client_sco_conn_open,
84 /* BTA_HF_CLIENT_SCO_CONN_CLOSE*/ bta_hf_client_sco_conn_close,
85 /* BTA_HF_CLIENT_SCO_OPEN */ bta_hf_client_sco_open,
86 /* BTA_HF_CLIENT_SCO_CLOSE */ bta_hf_client_sco_close,
87 /* BTA_HF_CLIENT_FREE_DB */ bta_hf_client_free_db,
88 /* BTA_HF_CLIENT_OPEN_FAIL */ bta_hf_client_open_fail,
89 /* BTA_HF_CLIENT_RFC_OPEN */ bta_hf_client_rfc_open,
90 /* BTA_HF_CLIENT_RFC_FAIL */ bta_hf_client_rfc_fail,
91 /* BTA_HF_CLIENT_DISC_INT_RES */ bta_hf_client_disc_int_res,
92 /* BTA_HF_CLIENT_RFC_DO_OPEN */ bta_hf_client_rfc_do_open,
93 /* BTA_HF_CLIENT_DISC_FAIL */ bta_hf_client_disc_fail,
94 /* BTA_HF_CLIENT_RFC_CLOSE */ bta_hf_client_rfc_close,
95 /* BTA_HF_CLIENT_RFC_DATA */ bta_hf_client_rfc_data,
96 /* BTA_HF_CLIENT_DISC_ACP_RES */ bta_hf_client_disc_acp_res,
97 /* BTA_HF_CLIENT_SVC_CONN_OPEN */ bta_hf_client_svc_conn_open,
98 /* BTA_HF_CLIENT_SEND_AT_CMD */ bta_hf_client_send_at_cmd,
99 };
100
101 /* state table information */
102 #define BTA_HF_CLIENT_ACTIONS 2 /* number of actions */
103 #define BTA_HF_CLIENT_NEXT_STATE 2 /* position of next state */
104 #define BTA_HF_CLIENT_NUM_COLS 3 /* number of columns in state tables */
105
106 /* state table for init state */
107 const uint8_t bta_hf_client_st_init[][BTA_HF_CLIENT_NUM_COLS] = {
108 /* Event Action 1 Action 2
109 Next state */
110 /* API_OPEN_EVT */ {BTA_HF_CLIENT_START_OPEN, BTA_HF_CLIENT_IGNORE,
111 BTA_HF_CLIENT_OPENING_ST},
112 /* API_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
113 BTA_HF_CLIENT_INIT_ST},
114 /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
115 BTA_HF_CLIENT_INIT_ST},
116 /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
117 BTA_HF_CLIENT_INIT_ST},
118 /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_RFC_ACP_OPEN, BTA_HF_CLIENT_IGNORE,
119 BTA_HF_CLIENT_OPEN_ST},
120 /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
121 BTA_HF_CLIENT_INIT_ST},
122 /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
123 BTA_HF_CLIENT_INIT_ST},
124 /* RFC_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
125 BTA_HF_CLIENT_INIT_ST},
126 /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_FREE_DB, BTA_HF_CLIENT_IGNORE,
127 BTA_HF_CLIENT_INIT_ST},
128 /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
129 BTA_HF_CLIENT_INIT_ST},
130 /* DISC_OK_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
131 BTA_HF_CLIENT_INIT_ST},
132 /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
133 BTA_HF_CLIENT_INIT_ST},
134 /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
135 BTA_HF_CLIENT_INIT_ST},
136 /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
137 BTA_HF_CLIENT_INIT_ST},
138 /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
139 BTA_HF_CLIENT_INIT_ST},
140 };
141
142 /* state table for opening state */
143 const uint8_t bta_hf_client_st_opening[][BTA_HF_CLIENT_NUM_COLS] = {
144 /* Event Action 1 Action 2
145 Next state */
146 /* API_OPEN_EVT */ {BTA_HF_CLIENT_OPEN_FAIL, BTA_HF_CLIENT_IGNORE,
147 BTA_HF_CLIENT_OPENING_ST},
148 /* API_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_DO_CLOSE, BTA_HF_CLIENT_IGNORE,
149 BTA_HF_CLIENT_CLOSING_ST},
150 /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
151 BTA_HF_CLIENT_OPENING_ST},
152 /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
153 BTA_HF_CLIENT_OPENING_ST},
154 /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_RFC_OPEN, BTA_HF_CLIENT_IGNORE,
155 BTA_HF_CLIENT_OPEN_ST},
156 /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_FAIL, BTA_HF_CLIENT_IGNORE,
157 BTA_HF_CLIENT_INIT_ST},
158 /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
159 BTA_HF_CLIENT_OPENING_ST},
160 /* RFC_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
161 BTA_HF_CLIENT_OPENING_ST},
162 /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
163 BTA_HF_CLIENT_OPENING_ST},
164 /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_DISC_INT_RES, BTA_HF_CLIENT_IGNORE,
165 BTA_HF_CLIENT_OPENING_ST},
166 /* DISC_OK_EVT */ {BTA_HF_CLIENT_RFC_DO_OPEN, BTA_HF_CLIENT_IGNORE,
167 BTA_HF_CLIENT_OPENING_ST},
168 /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_DISC_FAIL, BTA_HF_CLIENT_IGNORE,
169 BTA_HF_CLIENT_INIT_ST},
170 /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
171 BTA_HF_CLIENT_OPENING_ST},
172 /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
173 BTA_HF_CLIENT_OPENING_ST},
174 /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
175 BTA_HF_CLIENT_OPENING_ST},
176 };
177
178 /* state table for open state */
179 const uint8_t bta_hf_client_st_open[][BTA_HF_CLIENT_NUM_COLS] = {
180 /* Event Action 1 Action 2
181 Next state */
182 /* API_OPEN_EVT */ {BTA_HF_CLIENT_OPEN_FAIL, BTA_HF_CLIENT_IGNORE,
183 BTA_HF_CLIENT_OPEN_ST},
184 /* API_CLOSE_EVT */ {BTA_HF_CLIENT_START_CLOSE, BTA_HF_CLIENT_IGNORE,
185 BTA_HF_CLIENT_CLOSING_ST},
186 /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_SCO_OPEN, BTA_HF_CLIENT_IGNORE,
187 BTA_HF_CLIENT_OPEN_ST},
188 /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_SCO_CLOSE, BTA_HF_CLIENT_IGNORE,
189 BTA_HF_CLIENT_OPEN_ST},
190 /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
191 BTA_HF_CLIENT_OPEN_ST},
192 /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_CLOSE, BTA_HF_CLIENT_IGNORE,
193 BTA_HF_CLIENT_INIT_ST},
194 /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
195 BTA_HF_CLIENT_OPEN_ST},
196 /* RFC_DATA_EVT */ {BTA_HF_CLIENT_RFC_DATA, BTA_HF_CLIENT_IGNORE,
197 BTA_HF_CLIENT_OPEN_ST},
198 /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_DISC_ACP_RES, BTA_HF_CLIENT_IGNORE,
199 BTA_HF_CLIENT_OPEN_ST},
200 /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
201 BTA_HF_CLIENT_OPEN_ST},
202 /* DISC_OK_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
203 BTA_HF_CLIENT_OPEN_ST},
204 /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
205 BTA_HF_CLIENT_OPEN_ST},
206 /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_SCO_CONN_OPEN, BTA_HF_CLIENT_IGNORE,
207 BTA_HF_CLIENT_OPEN_ST},
208 /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_SCO_CONN_CLOSE, BTA_HF_CLIENT_IGNORE,
209 BTA_HF_CLIENT_OPEN_ST},
210 /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_SEND_AT_CMD, BTA_HF_CLIENT_IGNORE,
211 BTA_HF_CLIENT_OPEN_ST},
212 };
213
214 /* state table for closing state */
215 const uint8_t bta_hf_client_st_closing[][BTA_HF_CLIENT_NUM_COLS] = {
216 /* Event Action 1 Action 2
217 Next state */
218 /* API_OPEN_EVT */ {BTA_HF_CLIENT_OPEN_FAIL, BTA_HF_CLIENT_IGNORE,
219 BTA_HF_CLIENT_CLOSING_ST},
220 /* API_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
221 BTA_HF_CLIENT_CLOSING_ST},
222 /* API_AUDIO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
223 BTA_HF_CLIENT_CLOSING_ST},
224 /* API_AUDIO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
225 BTA_HF_CLIENT_CLOSING_ST},
226 /* RFC_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
227 BTA_HF_CLIENT_CLOSING_ST},
228 /* RFC_CLOSE_EVT */ {BTA_HF_CLIENT_RFC_CLOSE, BTA_HF_CLIENT_IGNORE,
229 BTA_HF_CLIENT_INIT_ST},
230 /* RFC_SRV_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
231 BTA_HF_CLIENT_CLOSING_ST},
232 /* RFC_DATA_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
233 BTA_HF_CLIENT_CLOSING_ST},
234 /* DISC_ACP_RES_EVT */ {BTA_HF_CLIENT_FREE_DB, BTA_HF_CLIENT_IGNORE,
235 BTA_HF_CLIENT_CLOSING_ST},
236 /* DISC_INT_RES_EVT */ {BTA_HF_CLIENT_FREE_DB, BTA_HF_CLIENT_IGNORE,
237 BTA_HF_CLIENT_INIT_ST},
238 /* DISC_OK_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
239 BTA_HF_CLIENT_CLOSING_ST},
240 /* DISC_FAIL_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
241 BTA_HF_CLIENT_CLOSING_ST},
242 /* SCO_OPEN_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
243 BTA_HF_CLIENT_CLOSING_ST},
244 /* SCO_CLOSE_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
245 BTA_HF_CLIENT_CLOSING_ST},
246 /* SEND_AT_CMD_EVT */ {BTA_HF_CLIENT_IGNORE, BTA_HF_CLIENT_IGNORE,
247 BTA_HF_CLIENT_CLOSING_ST},
248 };
249
250 /* type for state table */
251 typedef const uint8_t (*tBTA_HF_CLIENT_ST_TBL)[BTA_HF_CLIENT_NUM_COLS];
252
253 /* state table */
254 const tBTA_HF_CLIENT_ST_TBL bta_hf_client_st_tbl[] = {
255 bta_hf_client_st_init, bta_hf_client_st_opening, bta_hf_client_st_open,
256 bta_hf_client_st_closing};
257
258 /* HF Client control block */
259 tBTA_HF_CLIENT_CB_ARR bta_hf_client_cb_arr;
260
261 /* Event handler for the state machine */
262 static const tBTA_SYS_REG bta_hf_client_reg = {bta_hf_client_hdl_event,
263 BTA_HfClientDisable};
264
265 /*******************************************************************************
266 *
267 * Function bta_hf_client_cb_arr_init
268 *
269 * Description Initialize entire control block array set
270 *
271 *
272 * Returns void
273 *
274 ******************************************************************************/
bta_hf_client_cb_arr_init()275 void bta_hf_client_cb_arr_init() {
276 memset(&bta_hf_client_cb_arr, 0, sizeof(tBTA_HF_CLIENT_CB_ARR));
277
278 // reset the handles and make the CBs non-allocated
279 for (int i = 0; i < HF_CLIENT_MAX_DEVICES; i++) {
280 // Allocate the handles in increasing order of indices
281 bta_hf_client_cb_init(&(bta_hf_client_cb_arr.cb[i]), i);
282 bta_hf_client_cb_arr.cb[i].handle = BTA_HF_CLIENT_CB_FIRST_HANDLE + i;
283 }
284 }
285
286 /*******************************************************************************
287 *
288 * Function bta_hf_client_cb_init
289 *
290 * Description Initialize an HF_Client service control block. Assign the
291 * handle to cb->handle.
292 *
293 *
294 *
295 * Returns void
296 *
297 ******************************************************************************/
bta_hf_client_cb_init(tBTA_HF_CLIENT_CB * client_cb,uint16_t handle)298 void bta_hf_client_cb_init(tBTA_HF_CLIENT_CB* client_cb, uint16_t handle) {
299 APPL_TRACE_DEBUG("%s", __func__);
300
301 // Free any memory we need to explicity release
302 alarm_free(client_cb->collision_timer);
303
304 // release unique pointers
305 client_cb->enabled_hf_indicators.clear();
306 client_cb->peer_hf_indicators.clear();
307
308 // Memset the rest of the block
309 // memset(client_cb, 0, sizeof(tBTA_HF_CLIENT_CB));
310 *client_cb = {};
311
312 // Re allocate any variables required
313 client_cb->collision_timer = alarm_new("bta_hf_client.scb_collision_timer");
314 client_cb->handle = handle;
315 client_cb->sco_idx = BTM_INVALID_SCO_INDEX;
316 }
317
318 /*******************************************************************************
319 *
320 * Function bta_hf_client_resume_open
321 *
322 * Description Resume opening process.
323 *
324 *
325 * Returns void
326 *
327 ******************************************************************************/
bta_hf_client_resume_open(tBTA_HF_CLIENT_CB * client_cb)328 void bta_hf_client_resume_open(tBTA_HF_CLIENT_CB* client_cb) {
329 APPL_TRACE_DEBUG("%s", __func__);
330
331 /* resume opening process. */
332 if (client_cb->state == BTA_HF_CLIENT_INIT_ST) {
333 client_cb->state = BTA_HF_CLIENT_OPENING_ST;
334 tBTA_HF_CLIENT_DATA msg;
335 msg.hdr.layer_specific = client_cb->handle;
336 msg.api_open.bd_addr = client_cb->peer_addr;
337 bta_hf_client_start_open(&msg);
338 }
339 }
340
341 /*******************************************************************************
342 *
343 * Function bta_hf_client_collision_timer_cback
344 *
345 * Description HF Client connection collision timer callback
346 *
347 *
348 * Returns void
349 *
350 ******************************************************************************/
bta_hf_client_collision_timer_cback(void * data)351 static void bta_hf_client_collision_timer_cback(void* data) {
352 APPL_TRACE_DEBUG("%s", __func__);
353 tBTA_HF_CLIENT_CB* client_cb = (tBTA_HF_CLIENT_CB*)data;
354
355 /* If the peer haven't opened connection, restart opening process */
356 bta_hf_client_resume_open(client_cb);
357 }
358
359 /*******************************************************************************
360 *
361 * Function bta_hf_client_collision_cback
362 *
363 * Description Get notified about collision.
364 *
365 *
366 * Returns void
367 *
368 ******************************************************************************/
bta_hf_client_collision_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status,uint8_t id,UNUSED_ATTR uint8_t app_id,const RawAddress & peer_addr)369 void bta_hf_client_collision_cback(UNUSED_ATTR tBTA_SYS_CONN_STATUS status,
370 uint8_t id, UNUSED_ATTR uint8_t app_id,
371 const RawAddress& peer_addr) {
372 tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_bda(peer_addr);
373 if (client_cb != NULL && client_cb->state == BTA_HF_CLIENT_OPENING_ST) {
374 if (id == BTA_ID_SYS) /* ACL collision */
375 {
376 APPL_TRACE_WARNING("HF Client found collision (ACL) ...");
377 } else if (id == BTA_ID_HS) /* RFCOMM collision */
378 {
379 APPL_TRACE_WARNING("HF Client found collision (RFCOMM) ...");
380 } else {
381 APPL_TRACE_WARNING("HF Client found collision (\?\?\?) ...");
382 }
383
384 client_cb->state = BTA_HF_CLIENT_INIT_ST;
385
386 /* Cancel SDP if it had been started. */
387 if (client_cb->p_disc_db) {
388 (void)SDP_CancelServiceSearch(client_cb->p_disc_db);
389 osi_free_and_reset((void**)&client_cb->p_disc_db);
390 }
391
392 /* reopen registered server */
393 /* Collision may be detected before or after we close servers. */
394 bta_hf_client_start_server();
395
396 /* Start timer to handle connection opening restart */
397 alarm_set_on_mloop(client_cb->collision_timer,
398 BTA_HF_CLIENT_COLLISION_TIMER_MS,
399 bta_hf_client_collision_timer_cback, (void*)client_cb);
400 }
401 }
402
403 /*******************************************************************************
404 *
405 * Function bta_hf_client_api_enable
406 *
407 * Description Handle an API enable event.
408 *
409 *
410 * Returns void
411 *
412 ******************************************************************************/
bta_hf_client_api_enable(tBTA_HF_CLIENT_CBACK * p_cback,tBTA_HF_CLIENT_FEAT features,const char * p_service_name)413 tBTA_STATUS bta_hf_client_api_enable(tBTA_HF_CLIENT_CBACK* p_cback,
414 tBTA_HF_CLIENT_FEAT features,
415 const char* p_service_name) {
416 /* If already registered then return error */
417 if (bta_sys_is_register(BTA_ID_HS)) {
418 APPL_TRACE_ERROR("BTA HF Client is already enabled, ignoring ...");
419 return BTA_FAILURE;
420 }
421
422 /* register with BTA system manager */
423 bta_sys_register(BTA_ID_HS, &bta_hf_client_reg);
424
425 /* reset the control blocks */
426 bta_hf_client_cb_arr_init();
427
428 bta_hf_client_cb_arr.p_cback = p_cback;
429 bta_hf_client_cb_arr.features = features;
430
431 /* create SDP records */
432 bta_hf_client_create_record(&bta_hf_client_cb_arr, p_service_name);
433
434 /* set same setting as AG does */
435 BTM_WriteVoiceSettings(AG_VOICE_SETTINGS);
436
437 bta_sys_collision_register(BTA_ID_HS, bta_hf_client_collision_cback);
438
439 /* Set the Audio service class bit */
440 tBTA_UTL_COD cod = {
441 .minor = BTM_COD_MINOR_UNCLASSIFIED,
442 .major = BTM_COD_MAJOR_UNCLASSIFIED,
443 .service = BTM_COD_SERVICE_AUDIO,
444 };
445 utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS);
446
447 /* start RFCOMM server */
448 bta_hf_client_start_server();
449
450 return BTA_SUCCESS;
451 }
452
453 /*******************************************************************************
454 *
455 * Function bta_hf_client_find_cb_by_handle
456 *
457 * Description Finds the control block by handle provided
458 *
459 * handle: Handle as obtained from BTA_HfClientOpen call
460 *
461 *
462 * Returns Control block corresponding to the handle and NULL if
463 * none exists
464 *
465 ******************************************************************************/
bta_hf_client_find_cb_by_handle(uint16_t handle)466 tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_handle(uint16_t handle) {
467 // Handles are limited from 1 through HF_CLIENT_MAX_DEVICES
468 if (handle < 1 || handle > HF_CLIENT_MAX_DEVICES) {
469 APPL_TRACE_ERROR("%s: handle out of range (%d, %d) %d", __func__, 1,
470 HF_CLIENT_MAX_DEVICES, handle);
471 return NULL;
472 }
473
474 // Check if the associated index is allocated. Index is (handle - 1).
475 if (bta_hf_client_cb_arr.cb[handle - 1].is_allocated)
476 return &(bta_hf_client_cb_arr.cb[handle - 1]);
477
478 APPL_TRACE_ERROR("%s: block not found for handle %d", __func__, handle);
479 return NULL;
480 }
481
482 /*******************************************************************************
483 *
484 * Function bta_hf_client_find_cb_by_bda
485 *
486 * Description Finds the control block by handle provided
487 *
488 * bda: address of the device to find the handle for.
489 * Since there can only be one HF connection for a device
490 * we should always find a unique block
491 *
492 * Returns Control block corresponding to the address and NULL if
493 * none exists
494 *
495 ******************************************************************************/
bta_hf_client_find_cb_by_bda(const RawAddress & peer_addr)496 tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_bda(const RawAddress& peer_addr) {
497 for (int i = 0; i < HF_CLIENT_MAX_DEVICES; i++) {
498 // Check if the associated index is allocated and that BD ADDR matches
499 tBTA_HF_CLIENT_CB* client_cb = &bta_hf_client_cb_arr.cb[i];
500 if (client_cb->is_allocated && peer_addr == client_cb->peer_addr) {
501 return client_cb;
502 } else {
503 APPL_TRACE_WARNING("%s: bdaddr mismatch for handle %d alloc %d", __func__,
504 i, client_cb->is_allocated);
505 }
506 }
507 APPL_TRACE_ERROR("%s: block not found", __func__);
508 return NULL;
509 }
510
511 /*******************************************************************************
512 *
513 * Function bta_hf_client_find_cb_by_rfc_handle
514 *
515 * Description Finds the control block by RFC handle provided.
516 *
517 * handle: RFC handle for the established connection
518 *
519 *
520 * Returns Control block corresponding to the handle and NULL if none
521 * exists
522 *
523 ******************************************************************************/
bta_hf_client_find_cb_by_rfc_handle(uint16_t handle)524 tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_rfc_handle(uint16_t handle) {
525 for (int i = 0; i < HF_CLIENT_MAX_DEVICES; i++) {
526 tBTA_HF_CLIENT_CB* client_cb = &bta_hf_client_cb_arr.cb[i];
527 bool is_allocated = client_cb->is_allocated;
528 uint16_t conn_handle = client_cb->conn_handle;
529
530 APPL_TRACE_DEBUG("%s: cb rfc_handle %d alloc %d conn_handle %d", __func__,
531 handle, is_allocated, conn_handle);
532
533 if (is_allocated && conn_handle == handle) {
534 return client_cb;
535 }
536
537 APPL_TRACE_WARNING("%s: no cb yet %d alloc %d conn_handle %d", __func__,
538 handle, is_allocated, conn_handle);
539 }
540
541 APPL_TRACE_ERROR("%s: no cb found for rfc handle %d", __func__, handle);
542 return NULL;
543 }
544
545 /*******************************************************************************
546 *
547 * Function bta_hf_client_find_cb_by_sco_handle
548 *
549 * Description Finds the control block by sco handle provided
550 *
551 * handle: sco handle
552 *
553 *
554 * Returns Control block corresponding to the sco handle and
555 * none if none exists
556 *
557 ******************************************************************************/
bta_hf_client_find_cb_by_sco_handle(uint16_t handle)558 tBTA_HF_CLIENT_CB* bta_hf_client_find_cb_by_sco_handle(uint16_t handle) {
559 for (int i = 0; i < HF_CLIENT_MAX_DEVICES; i++) {
560 tBTA_HF_CLIENT_CB* client_cb = &bta_hf_client_cb_arr.cb[i];
561 if (client_cb->is_allocated && client_cb->sco_idx == handle) {
562 return client_cb;
563 }
564 }
565 APPL_TRACE_ERROR("%s: block not found for handle %d", __func__, handle);
566 return NULL;
567 }
568
569 /*******************************************************************************
570 *
571 * Function bta_hf_client_allocate_handle
572 *
573 * Description Allocates a handle for the new BD ADDR that needs a new RF
574 * channel for HF connection. If the channel cannot be created
575 * for a reason then false is returned
576 *
577 * bd_addr: Address of the device for which this block is
578 * being created. Single device can only have one block.
579 * p_handle: OUT variable to store the outcome of allocate. If
580 * allocate failed then value is not valid
581 *
582 *
583 * Returns true if the creation of p_handle succeeded, false otherwise
584 *
585 ******************************************************************************/
bta_hf_client_allocate_handle(const RawAddress & bd_addr,uint16_t * p_handle)586 bool bta_hf_client_allocate_handle(const RawAddress& bd_addr,
587 uint16_t* p_handle) {
588 tBTA_HF_CLIENT_CB* existing_cb = bta_hf_client_find_cb_by_bda(bd_addr);
589 if (existing_cb != NULL) {
590 BTIF_TRACE_ERROR("%s: cannot allocate handle since BDADDR already exists",
591 __func__);
592 return false;
593 }
594 /* Check that we do not have a request to for same device in the control
595 * blocks */
596 for (int i = 0; i < HF_CLIENT_MAX_DEVICES; i++) {
597 tBTA_HF_CLIENT_CB* client_cb = &bta_hf_client_cb_arr.cb[i];
598 if (client_cb->is_allocated) {
599 APPL_TRACE_WARNING("%s: control block already used index %d", __func__,
600 i);
601 continue;
602 }
603
604 // Reset the client control block
605 bta_hf_client_cb_init(client_cb, client_cb->handle);
606
607 *p_handle = client_cb->handle;
608 APPL_TRACE_DEBUG("%s: marking CB handle %d to true", __func__,
609 client_cb->handle);
610
611 client_cb->is_allocated = true;
612 client_cb->peer_addr = bd_addr;
613 bta_hf_client_at_init(client_cb);
614 return true;
615 }
616
617 return false;
618 APPL_TRACE_ERROR("%s: all control blocks in use!", __func__);
619 }
620
621 /*******************************************************************************
622 *
623 * Function bta_hf_client_app_callback
624 *
625 * Description Calls the application callback
626 *
627 *
628 * Returns Void
629 *
630 ******************************************************************************/
bta_hf_client_app_callback(uint16_t event,tBTA_HF_CLIENT * data)631 void bta_hf_client_app_callback(uint16_t event, tBTA_HF_CLIENT* data) {
632 if (bta_hf_client_cb_arr.p_cback != NULL) {
633 bta_hf_client_cb_arr.p_cback(event, data);
634 }
635 }
636
637 /*******************************************************************************
638 *
639 * Function bta_hf_client_api_disable
640 *
641 * Description Handle an API disable event.
642 *
643 *
644 * Returns void
645 *
646 ******************************************************************************/
bta_hf_client_api_disable()647 void bta_hf_client_api_disable() {
648 if (!bta_sys_is_register(BTA_ID_HS)) {
649 APPL_TRACE_WARNING("BTA HF Client is already disabled, ignoring ...");
650 return;
651 }
652
653 /* Remove the collision handler */
654 bta_sys_collision_register(BTA_ID_HS, NULL);
655
656 bta_hf_client_cb_arr.deregister = true;
657
658 /* remove sdp record */
659 bta_hf_client_del_record(&bta_hf_client_cb_arr);
660
661 /* remove rfcomm server */
662 bta_hf_client_close_server();
663
664 /* reinit the control block */
665 for (int i = 0; i < HF_CLIENT_MAX_DEVICES; i++) {
666 if (bta_hf_client_cb_arr.cb[i].is_allocated) {
667 bta_hf_client_cb_init(&(bta_hf_client_cb_arr.cb[i]), i);
668 }
669 }
670
671 /* De-register with BTA system manager */
672 bta_sys_deregister(BTA_ID_HS);
673 }
674
675 /*******************************************************************************
676 *
677 * Function bta_hf_client_hdl_event
678 *
679 * Description Data HF Client main event handling function.
680 *
681 *
682 * Returns bool
683 *
684 ******************************************************************************/
bta_hf_client_hdl_event(BT_HDR_RIGID * p_msg)685 bool bta_hf_client_hdl_event(BT_HDR_RIGID* p_msg) {
686 APPL_TRACE_DEBUG("%s: %s (0x%x)", __func__,
687 bta_hf_client_evt_str(p_msg->event), p_msg->event);
688 bta_hf_client_sm_execute(p_msg->event, (tBTA_HF_CLIENT_DATA*)p_msg);
689 return true;
690 }
691
692 /*******************************************************************************
693 *
694 * Function bta_hf_client_sm_execute
695 *
696 * Description State machine event handling function for HF Client
697 *
698 *
699 * Returns void
700 *
701 ******************************************************************************/
bta_hf_client_sm_execute(uint16_t event,tBTA_HF_CLIENT_DATA * p_data)702 void bta_hf_client_sm_execute(uint16_t event, tBTA_HF_CLIENT_DATA* p_data) {
703 tBTA_HF_CLIENT_CB* client_cb =
704 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
705 if (client_cb == NULL) {
706 APPL_TRACE_ERROR("%s: cb not found for handle %d", __func__,
707 p_data->hdr.layer_specific);
708 return;
709 }
710
711 tBTA_HF_CLIENT_ST_TBL state_table;
712 uint8_t action;
713 int i;
714
715 uint16_t in_event = event;
716 uint8_t in_state = client_cb->state;
717
718 /* Ignore displaying of AT results when not connected (Ignored in state
719 * machine) */
720 if (client_cb->state == BTA_HF_CLIENT_OPEN_ST) {
721 APPL_TRACE_EVENT("HF Client evt : State %d (%s), Event 0x%04x (%s)",
722 client_cb->state,
723 bta_hf_client_state_str(client_cb->state), event,
724 bta_hf_client_evt_str(event));
725 }
726
727 event &= 0x00FF;
728 if (event >= (BTA_HF_CLIENT_MAX_EVT & 0x00FF)) {
729 APPL_TRACE_ERROR("HF Client evt out of range, ignoring...");
730 return;
731 }
732
733 /* look up the state table for the current state */
734 state_table = bta_hf_client_st_tbl[client_cb->state];
735
736 /* set next state */
737 client_cb->state = state_table[event][BTA_HF_CLIENT_NEXT_STATE];
738
739 /* execute action functions */
740 for (i = 0; i < BTA_HF_CLIENT_ACTIONS; i++) {
741 action = state_table[event][i];
742 if (action != BTA_HF_CLIENT_IGNORE) {
743 (*bta_hf_client_action[action])(p_data);
744 } else {
745 break;
746 }
747 }
748
749 /* If the state has changed then notify the app of the corresponding change */
750 if (in_state != client_cb->state) {
751 VLOG(1) << __func__ << ": notifying state change to " << in_state << " -> "
752 << client_cb->state << " device " << client_cb->peer_addr;
753 tBTA_HF_CLIENT evt;
754 memset(&evt, 0, sizeof(evt));
755 evt.bd_addr = client_cb->peer_addr;
756 if (client_cb->state == BTA_HF_CLIENT_INIT_ST) {
757 bta_hf_client_app_callback(BTA_HF_CLIENT_CLOSE_EVT, &evt);
758 APPL_TRACE_DEBUG("%s: marking CB handle %d to false", __func__, client_cb->handle);
759 client_cb->is_allocated = false;
760 } else if (client_cb->state == BTA_HF_CLIENT_OPEN_ST) {
761 evt.open.handle = client_cb->handle;
762 bta_hf_client_app_callback(BTA_HF_CLIENT_OPEN_EVT, &evt);
763 }
764 }
765
766 VLOG(2) << __func__ << ": device " << client_cb->peer_addr
767 << "state change: [" << bta_hf_client_state_str(in_state) << "] -> ["
768 << bta_hf_client_state_str(client_cb->state) << "] after Event ["
769 << bta_hf_client_evt_str(in_event) << "]";
770 }
771
send_post_slc_cmd(tBTA_HF_CLIENT_CB * client_cb)772 static void send_post_slc_cmd(tBTA_HF_CLIENT_CB* client_cb) {
773 client_cb->at_cb.current_cmd = BTA_HF_CLIENT_AT_NONE;
774
775 tBTA_HF_CLIENT_DATA p_data;
776 p_data.hdr.layer_specific = client_cb->handle;
777 bta_hf_client_sco_listen(&p_data);
778 bta_hf_client_send_at_bia(client_cb);
779 bta_hf_client_send_at_ccwa(client_cb, true);
780 bta_hf_client_send_at_cmee(client_cb, true);
781 bta_hf_client_send_at_cops(client_cb, false);
782 bta_hf_client_send_at_btrh(client_cb, true, 0);
783 bta_hf_client_send_at_clip(client_cb, true);
784 }
785
786 /*******************************************************************************
787 *
788 * Function bta_hf_client_slc_seq
789 *
790 * Description Handles AT commands sequence required for SLC creation
791 *
792 *
793 * Returns void
794 *
795 ******************************************************************************/
bta_hf_client_slc_seq(tBTA_HF_CLIENT_CB * client_cb,bool error)796 void bta_hf_client_slc_seq(tBTA_HF_CLIENT_CB* client_cb, bool error) {
797 APPL_TRACE_DEBUG("bta_hf_client_slc_seq cmd: %u",
798 client_cb->at_cb.current_cmd);
799
800 if (error) {
801 /* SLC establishment error, sent close rfcomm event */
802 APPL_TRACE_ERROR(
803 "HFPClient: Failed to create SLC due to AT error, disconnecting (%u)",
804 client_cb->at_cb.current_cmd);
805
806 tBTA_HF_CLIENT_DATA msg;
807 msg.hdr.layer_specific = client_cb->handle;
808 bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, &msg);
809 return;
810 }
811
812 if (client_cb->svc_conn) {
813 APPL_TRACE_WARNING("%s: SLC already connected for CB handle %d", __func__,
814 client_cb->handle);
815 return;
816 }
817
818 switch (client_cb->at_cb.current_cmd) {
819 case BTA_HF_CLIENT_AT_NONE:
820 bta_hf_client_send_at_brsf(client_cb, bta_hf_client_cb_arr.features);
821 break;
822
823 case BTA_HF_CLIENT_AT_BRSF:
824 if ((bta_hf_client_cb_arr.features & BTA_HF_CLIENT_FEAT_CODEC) &&
825 (client_cb->peer_features & BTA_HF_CLIENT_PEER_CODEC)) {
826 bta_hf_client_send_at_bac(client_cb);
827 break;
828 }
829
830 bta_hf_client_send_at_cind(client_cb, false);
831 break;
832
833 case BTA_HF_CLIENT_AT_BAC:
834 bta_hf_client_send_at_cind(client_cb, false);
835 break;
836
837 case BTA_HF_CLIENT_AT_CIND:
838 bta_hf_client_send_at_cind(client_cb, true);
839 break;
840
841 case BTA_HF_CLIENT_AT_CIND_STATUS:
842 bta_hf_client_send_at_cmer(client_cb, true);
843 break;
844
845 case BTA_HF_CLIENT_AT_CMER:
846 if (client_cb->peer_features & BTA_HF_CLIENT_PEER_FEAT_3WAY &&
847 bta_hf_client_cb_arr.features & BTA_HF_CLIENT_FEAT_3WAY) {
848 bta_hf_client_send_at_chld(client_cb, '?', 0);
849 } else if (bta_hf_client_cb_arr.features & BTA_HF_CLIENT_FEAT_HF_IND &&
850 client_cb->peer_features & BTA_HF_CLIENT_PEER_HF_IND) {
851 bta_hf_client_send_at_bind(client_cb, 0);
852 } else {
853 tBTA_HF_CLIENT_DATA msg;
854 msg.hdr.layer_specific = client_cb->handle;
855 bta_hf_client_svc_conn_open(&msg);
856 send_post_slc_cmd(client_cb);
857 }
858 break;
859
860 case BTA_HF_CLIENT_AT_CHLD:
861 if (bta_hf_client_cb_arr.features & BTA_HF_CLIENT_FEAT_HF_IND &&
862 client_cb->peer_features & BTA_HF_CLIENT_PEER_HF_IND) {
863 bta_hf_client_send_at_bind(client_cb, 0);
864 } else {
865 tBTA_HF_CLIENT_DATA msg;
866 msg.hdr.layer_specific = client_cb->handle;
867 bta_hf_client_svc_conn_open(&msg);
868 send_post_slc_cmd(client_cb);
869 }
870 break;
871
872 case BTA_HF_CLIENT_AT_BIND_SET_IND:
873 bta_hf_client_send_at_bind(client_cb, 1);
874 break;
875
876 case BTA_HF_CLIENT_AT_BIND_READ_SUPPORTED_IND:
877 bta_hf_client_send_at_bind(client_cb, 2);
878 break;
879
880 case BTA_HF_CLIENT_AT_BIND_READ_ENABLED_IND:
881 tBTA_HF_CLIENT_DATA msg;
882 msg.hdr.layer_specific = client_cb->handle;
883 bta_hf_client_svc_conn_open(&msg);
884 send_post_slc_cmd(client_cb);
885 break;
886
887 default: {
888 /* If happen there is a bug in SLC creation procedure... */
889 APPL_TRACE_ERROR(
890 "HFPClient: Failed to create SLCdue to unexpected AT command, "
891 "disconnecting (%u)",
892 client_cb->at_cb.current_cmd);
893
894 tBTA_HF_CLIENT_DATA msg;
895 msg.hdr.layer_specific = client_cb->handle;
896 bta_hf_client_sm_execute(BTA_HF_CLIENT_API_CLOSE_EVT, &msg);
897 break;
898 }
899 }
900 }
901
902 #ifndef CASE_RETURN_STR
903 #define CASE_RETURN_STR(const) \
904 case const: \
905 return #const;
906 #endif
907
bta_hf_client_evt_str(uint16_t event)908 static const char* bta_hf_client_evt_str(uint16_t event) {
909 switch (event) {
910 CASE_RETURN_STR(BTA_HF_CLIENT_API_OPEN_EVT)
911 CASE_RETURN_STR(BTA_HF_CLIENT_API_CLOSE_EVT)
912 CASE_RETURN_STR(BTA_HF_CLIENT_API_AUDIO_OPEN_EVT)
913 CASE_RETURN_STR(BTA_HF_CLIENT_API_AUDIO_CLOSE_EVT)
914 CASE_RETURN_STR(BTA_HF_CLIENT_RFC_OPEN_EVT)
915 CASE_RETURN_STR(BTA_HF_CLIENT_RFC_CLOSE_EVT)
916 CASE_RETURN_STR(BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT)
917 CASE_RETURN_STR(BTA_HF_CLIENT_RFC_DATA_EVT)
918 CASE_RETURN_STR(BTA_HF_CLIENT_DISC_ACP_RES_EVT)
919 CASE_RETURN_STR(BTA_HF_CLIENT_DISC_INT_RES_EVT)
920 CASE_RETURN_STR(BTA_HF_CLIENT_DISC_OK_EVT)
921 CASE_RETURN_STR(BTA_HF_CLIENT_DISC_FAIL_EVT)
922 CASE_RETURN_STR(BTA_HF_CLIENT_API_ENABLE_EVT)
923 CASE_RETURN_STR(BTA_HF_CLIENT_API_DISABLE_EVT)
924 CASE_RETURN_STR(BTA_HF_CLIENT_SCO_OPEN_EVT)
925 CASE_RETURN_STR(BTA_HF_CLIENT_SCO_CLOSE_EVT)
926 CASE_RETURN_STR(BTA_HF_CLIENT_SEND_AT_CMD_EVT)
927 default:
928 return "Unknown HF Client Event";
929 }
930 }
931
bta_hf_client_state_str(uint8_t state)932 static const char* bta_hf_client_state_str(uint8_t state) {
933 switch (state) {
934 CASE_RETURN_STR(BTA_HF_CLIENT_INIT_ST)
935 CASE_RETURN_STR(BTA_HF_CLIENT_OPENING_ST)
936 CASE_RETURN_STR(BTA_HF_CLIENT_OPEN_ST)
937 CASE_RETURN_STR(BTA_HF_CLIENT_CLOSING_ST)
938 default:
939 return "Unknown HF Client State";
940 }
941 }
942
bta_hf_client_dump_statistics(int fd)943 void bta_hf_client_dump_statistics(int fd) {
944 dprintf(fd, "\nBluetooth HF Client BTA Statistics\n");
945
946 // We dump statistics for all control blocks
947 for (int i = 0; i < HF_CLIENT_MAX_DEVICES; i++) {
948 tBTA_HF_CLIENT_CB* client_cb = &bta_hf_client_cb_arr.cb[i];
949 if (!client_cb->is_allocated) {
950 // Skip the blocks which are not allocated
951 continue;
952 }
953
954 dprintf(fd, " Control block #%d\n", i + 1);
955
956 uint8_t* a = client_cb->peer_addr.address;
957 // Device name
958 dprintf(fd, " Peer Device: %02x:%02x:%02x:%02x:%02x:%02x\n", a[0], a[1],
959 a[2], a[3], a[4], a[5]);
960
961 // State machine state
962 dprintf(fd, " State Machine State: %s\n",
963 bta_hf_client_state_str(client_cb->state));
964
965 // Local RFC channelfor communication
966 dprintf(fd, " RFCOMM Channel (local) %d\n", client_cb->conn_handle);
967
968 // BTA Handle shared between BTA and client (ex BTIF)
969 dprintf(fd, " BTA Generated handle %d\n", client_cb->handle);
970 }
971 }
972