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