1 /******************************************************************************
2 *
3 * Copyright (c) 2014 The Android Open Source Project
4 * Copyright 2004-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
22 #include "bta/hf_client/bta_hf_client_int.h"
23 #include "bta/include/bta_ag_api.h"
24 #include "device/include/esco_parameters.h"
25 #include "osi/include/allocator.h"
26 #include "stack/include/btm_api.h"
27
28 #define BTA_HF_CLIENT_NO_EDR_ESCO \
29 (ESCO_PKT_TYPES_MASK_NO_2_EV3 | ESCO_PKT_TYPES_MASK_NO_3_EV3 | \
30 ESCO_PKT_TYPES_MASK_NO_2_EV5 | ESCO_PKT_TYPES_MASK_NO_3_EV5)
31
32 enum {
33 BTA_HF_CLIENT_SCO_LISTEN_E,
34 BTA_HF_CLIENT_SCO_OPEN_E, /* open request */
35 BTA_HF_CLIENT_SCO_CLOSE_E, /* close request */
36 BTA_HF_CLIENT_SCO_SHUTDOWN_E, /* shutdown request */
37 BTA_HF_CLIENT_SCO_CONN_OPEN_E, /* SCO opened */
38 BTA_HF_CLIENT_SCO_CONN_CLOSE_E, /* SCO closed */
39 };
40
41 /*******************************************************************************
42 *
43 * Function bta_hf_client_remove_sco
44 *
45 * Description Removes the specified SCO from the system.
46 *
47 * Returns bool - true if SCO removal was started
48 *
49 ******************************************************************************/
bta_hf_client_sco_remove(tBTA_HF_CLIENT_CB * client_cb)50 static bool bta_hf_client_sco_remove(tBTA_HF_CLIENT_CB* client_cb) {
51 bool removed_started = false;
52 tBTM_STATUS status;
53
54 APPL_TRACE_DEBUG("%s", __func__);
55
56 if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
57 status = BTM_RemoveSco(client_cb->sco_idx);
58
59 APPL_TRACE_DEBUG("%s: idx 0x%04x, status:0x%x", __func__,
60 client_cb->sco_idx, status);
61
62 if (status == BTM_CMD_STARTED) {
63 removed_started = true;
64 }
65 /* If no connection reset the SCO handle */
66 else if ((status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR)) {
67 client_cb->sco_idx = BTM_INVALID_SCO_INDEX;
68 }
69 }
70 return removed_started;
71 }
72
73 /*******************************************************************************
74 *
75 * Function bta_hf_client_cback_sco
76 *
77 * Description Call application callback function with SCO event.
78 *
79 *
80 * Returns void
81 *
82 ******************************************************************************/
bta_hf_client_cback_sco(tBTA_HF_CLIENT_CB * client_cb,uint8_t event)83 void bta_hf_client_cback_sco(tBTA_HF_CLIENT_CB* client_cb, uint8_t event) {
84 tBTA_HF_CLIENT evt;
85
86 memset(&evt, 0, sizeof(evt));
87 evt.bd_addr = client_cb->peer_addr;
88
89 /* call app cback */
90 bta_hf_client_app_callback(event, &evt);
91 }
92
93 /*******************************************************************************
94 *
95 * Function bta_hf_client_sco_conn_rsp
96 *
97 * Description Process the SCO connection request
98 *
99 *
100 * Returns void
101 *
102 ******************************************************************************/
bta_hf_client_sco_conn_rsp(tBTA_HF_CLIENT_CB * client_cb,tBTM_ESCO_CONN_REQ_EVT_DATA * p_data)103 static void bta_hf_client_sco_conn_rsp(tBTA_HF_CLIENT_CB* client_cb,
104 tBTM_ESCO_CONN_REQ_EVT_DATA* p_data) {
105 enh_esco_params_t resp;
106 uint8_t hci_status = HCI_SUCCESS;
107
108 APPL_TRACE_DEBUG("%s", __func__);
109
110 if (client_cb->sco_state == BTA_HF_CLIENT_SCO_LISTEN_ST) {
111 if (p_data->link_type == BTM_LINK_TYPE_SCO) {
112 // SCO
113 resp = esco_parameters_for_codec(SCO_CODEC_CVSD_D1);
114 } else if (client_cb->negotiated_codec == BTA_AG_CODEC_MSBC) {
115 // eSCO mSBC
116 resp = esco_parameters_for_codec(ESCO_CODEC_MSBC_T2);
117 } else if (bta_hf_client_cb_arr.features & BTA_HF_CLIENT_FEAT_ESCO_S4) {
118 // eSCO CVSD, HFP 1.7 requires S4
119 resp = esco_parameters_for_codec(ESCO_CODEC_CVSD_S4);
120 } else {
121 // eSCO CVSD, S3 is preferred by default(before HFP 1.7)
122 resp = esco_parameters_for_codec(ESCO_CODEC_CVSD_S3);
123 }
124
125 /* tell sys to stop av if any */
126 bta_sys_sco_use(BTA_ID_HS, 1, client_cb->peer_addr);
127 } else {
128 hci_status = HCI_ERR_HOST_REJECT_DEVICE;
129 }
130
131 BTM_EScoConnRsp(p_data->sco_inx, hci_status, &resp);
132 }
133
134 /*******************************************************************************
135 *
136 * Function bta_hf_client_sco_connreq_cback
137 *
138 * Description BTM eSCO connection requests and eSCO change requests
139 * Only the connection requests are processed by BTA.
140 *
141 * Returns void
142 *
143 ******************************************************************************/
bta_hf_client_esco_connreq_cback(tBTM_ESCO_EVT event,tBTM_ESCO_EVT_DATA * p_data)144 static void bta_hf_client_esco_connreq_cback(tBTM_ESCO_EVT event,
145 tBTM_ESCO_EVT_DATA* p_data) {
146 APPL_TRACE_DEBUG("%s: %d", __func__, event);
147
148 tBTA_HF_CLIENT_CB* client_cb =
149 bta_hf_client_find_cb_by_sco_handle(p_data->conn_evt.sco_inx);
150 if (client_cb == NULL) {
151 APPL_TRACE_ERROR("%s: wrong SCO handle to control block %d", __func__,
152 p_data->conn_evt.sco_inx);
153 return;
154 }
155
156 if (event != BTM_ESCO_CONN_REQ_EVT) {
157 return;
158 }
159
160 bta_hf_client_sco_conn_rsp(client_cb, &p_data->conn_evt);
161
162 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
163 }
164
165 /*******************************************************************************
166 *
167 * Function bta_hf_client_sco_conn_cback
168 *
169 * Description BTM SCO connection callback.
170 *
171 *
172 * Returns void
173 *
174 ******************************************************************************/
bta_hf_client_sco_conn_cback(uint16_t sco_idx)175 static void bta_hf_client_sco_conn_cback(uint16_t sco_idx) {
176 APPL_TRACE_DEBUG("%s: %d", __func__, sco_idx);
177
178 tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_sco_handle(sco_idx);
179 if (client_cb == NULL) {
180 APPL_TRACE_ERROR("%s: wrong SCO handle to control block %d", __func__,
181 sco_idx);
182 return;
183 }
184
185 BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
186 p_buf->event = BTA_HF_CLIENT_SCO_OPEN_EVT;
187 p_buf->layer_specific = client_cb->handle;
188 bta_sys_sendmsg(p_buf);
189 }
190
191 /*******************************************************************************
192 *
193 * Function bta_hf_client_sco_disc_cback
194 *
195 * Description BTM SCO disconnection callback.
196 *
197 *
198 * Returns void
199 *
200 ******************************************************************************/
bta_hf_client_sco_disc_cback(uint16_t sco_idx)201 static void bta_hf_client_sco_disc_cback(uint16_t sco_idx) {
202 APPL_TRACE_DEBUG("%s: sco_idx %d", __func__, sco_idx);
203
204 tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_sco_handle(sco_idx);
205 if (client_cb == NULL) {
206 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__, sco_idx);
207 return;
208 }
209
210 BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
211 p_buf->event = BTA_HF_CLIENT_SCO_CLOSE_EVT;
212 p_buf->layer_specific = client_cb->handle;
213 bta_sys_sendmsg(p_buf);
214 }
215
216 /*******************************************************************************
217 *
218 * Function bta_hf_client_create_sco
219 *
220 * Description
221 *
222 *
223 * Returns void
224 *
225 ******************************************************************************/
bta_hf_client_sco_create(tBTA_HF_CLIENT_CB * client_cb,bool is_orig)226 static void bta_hf_client_sco_create(tBTA_HF_CLIENT_CB* client_cb,
227 bool is_orig) {
228 tBTM_STATUS status;
229
230 APPL_TRACE_DEBUG("%s: %d", __func__, is_orig);
231
232 /* Make sure this SCO handle is not already in use */
233 if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
234 APPL_TRACE_WARNING("%s: Index 0x%04x already in use", __func__,
235 client_cb->sco_idx);
236 return;
237 }
238
239 // codec parameters
240 enh_esco_params_t params;
241 // Since HF device is not expected to receive AT+BAC send +BCS command,
242 // codec support of the connected AG device will be unknown,
243 // so HF device will always establish only CVSD connection.
244 if ((bta_hf_client_cb_arr.features & BTA_HF_CLIENT_FEAT_ESCO_S4) &&
245 (client_cb->peer_features & BTA_HF_CLIENT_PEER_ESCO_S4)) {
246 // eSCO CVSD, HFP 1.7 requires S4
247 params = esco_parameters_for_codec(ESCO_CODEC_CVSD_S4);
248 } else {
249 // eSCO CVSD, S3 is preferred by default(before HFP 1.7)
250 params = esco_parameters_for_codec(ESCO_CODEC_CVSD_S3);
251 }
252
253 /* if initiating set current scb and peer bd addr */
254 if (is_orig) {
255 BTM_SetEScoMode(¶ms);
256 /* tell sys to stop av if any */
257 bta_sys_sco_use(BTA_ID_HS, 1, client_cb->peer_addr);
258 }
259
260 status = BTM_CreateSco(&client_cb->peer_addr, is_orig, params.packet_types,
261 &client_cb->sco_idx, bta_hf_client_sco_conn_cback,
262 bta_hf_client_sco_disc_cback);
263 if (status == BTM_CMD_STARTED && !is_orig) {
264 if (!BTM_RegForEScoEvts(client_cb->sco_idx,
265 bta_hf_client_esco_connreq_cback))
266 APPL_TRACE_DEBUG("%s: SCO registration success", __func__);
267 }
268
269 APPL_TRACE_API("%s: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x",
270 __func__, is_orig, client_cb->sco_idx, status,
271 params.packet_types);
272 }
273
274 /*******************************************************************************
275 *
276 * Function bta_hf_client_sco_event
277 *
278 * Description Handle SCO events
279 *
280 *
281 * Returns void
282 *
283 ******************************************************************************/
bta_hf_client_sco_event(tBTA_HF_CLIENT_CB * client_cb,uint8_t event)284 static void bta_hf_client_sco_event(tBTA_HF_CLIENT_CB* client_cb,
285 uint8_t event) {
286 APPL_TRACE_DEBUG("%s: before state: %d event: %d", __func__,
287 client_cb->sco_state, event);
288
289 switch (client_cb->sco_state) {
290 case BTA_HF_CLIENT_SCO_SHUTDOWN_ST:
291 switch (event) {
292 // For WBS we only listen to SCO requests. Even for outgoing SCO
293 // requests we first do a AT+BCC and wait for remote to initiate SCO
294 case BTA_HF_CLIENT_SCO_LISTEN_E:
295 /* create SCO listen connection */
296 bta_hf_client_sco_create(client_cb, false);
297 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
298 break;
299
300 // For non WBS cases and enabling outgoing SCO requests we need to force
301 // open a SCO channel
302 case BTA_HF_CLIENT_SCO_OPEN_E:
303 /* remove listening connection */
304 bta_hf_client_sco_remove(client_cb);
305
306 /* create SCO connection to peer */
307 bta_hf_client_sco_create(client_cb, true);
308 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
309 break;
310
311 default:
312 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTDOWN_ST: Ignoring event %d",
313 event);
314 break;
315 }
316 break;
317
318 case BTA_HF_CLIENT_SCO_LISTEN_ST:
319 switch (event) {
320 case BTA_HF_CLIENT_SCO_LISTEN_E:
321 /* create SCO listen connection */
322 bta_hf_client_sco_create(client_cb, false);
323 break;
324
325 case BTA_HF_CLIENT_SCO_OPEN_E:
326 /* remove listening connection */
327 bta_hf_client_sco_remove(client_cb);
328
329 /* create SCO connection to peer */
330 bta_hf_client_sco_create(client_cb, true);
331 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
332 break;
333
334 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
335 case BTA_HF_CLIENT_SCO_CLOSE_E:
336 /* remove listening connection */
337 bta_hf_client_sco_remove(client_cb);
338
339 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
340 break;
341
342 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
343 /* SCO failed; create SCO listen connection */
344 bta_hf_client_sco_create(client_cb, false);
345 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
346 break;
347
348 default:
349 APPL_TRACE_WARNING(
350 "%s: BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d", __func__,
351 event);
352 break;
353 }
354 break;
355
356 case BTA_HF_CLIENT_SCO_OPENING_ST:
357 switch (event) {
358 case BTA_HF_CLIENT_SCO_CLOSE_E:
359 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPEN_CL_ST;
360 break;
361
362 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
363 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
364 break;
365
366 case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
367 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPEN_ST;
368 break;
369
370 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
371 /* SCO failed; create SCO listen connection */
372 bta_hf_client_sco_create(client_cb, false);
373 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
374 break;
375
376 default:
377 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPENING_ST: Ignoring event %d",
378 event);
379 break;
380 }
381 break;
382
383 case BTA_HF_CLIENT_SCO_OPEN_CL_ST:
384 switch (event) {
385 case BTA_HF_CLIENT_SCO_OPEN_E:
386 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
387 break;
388
389 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
390 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
391 break;
392
393 case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
394 /* close SCO connection */
395 bta_hf_client_sco_remove(client_cb);
396
397 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
398 break;
399
400 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
401 /* SCO failed; create SCO listen connection */
402
403 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
404 break;
405
406 default:
407 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_CL_ST: Ignoring event %d",
408 event);
409 break;
410 }
411 break;
412
413 case BTA_HF_CLIENT_SCO_OPEN_ST:
414 switch (event) {
415 case BTA_HF_CLIENT_SCO_CLOSE_E:
416 if (bta_hf_client_sco_remove(client_cb)) {
417 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
418 }
419 break;
420
421 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
422 /* remove listening connection */
423 bta_hf_client_sco_remove(client_cb);
424
425 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
426 break;
427
428 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
429 /* peer closed SCO */
430 bta_hf_client_sco_create(client_cb, false);
431 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
432 break;
433
434 default:
435 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_ST: Ignoring event %d",
436 event);
437 break;
438 }
439 break;
440
441 case BTA_HF_CLIENT_SCO_CLOSING_ST:
442 switch (event) {
443 case BTA_HF_CLIENT_SCO_OPEN_E:
444 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSE_OP_ST;
445 break;
446
447 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
448 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
449 break;
450
451 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
452 /* peer closed sco; create SCO listen connection */
453 bta_hf_client_sco_create(client_cb, false);
454 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
455 break;
456
457 default:
458 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSING_ST: Ignoring event %d",
459 event);
460 break;
461 }
462 break;
463
464 case BTA_HF_CLIENT_SCO_CLOSE_OP_ST:
465 switch (event) {
466 case BTA_HF_CLIENT_SCO_CLOSE_E:
467 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
468 break;
469
470 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
471 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
472 break;
473
474 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
475 /* open SCO connection */
476 bta_hf_client_sco_create(client_cb, true);
477 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
478 break;
479
480 default:
481 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSE_OP_ST: Ignoring event %d",
482 event);
483 break;
484 }
485 break;
486
487 case BTA_HF_CLIENT_SCO_SHUTTING_ST:
488 switch (event) {
489 case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
490 /* close SCO connection; wait for conn close event */
491 bta_hf_client_sco_remove(client_cb);
492 break;
493
494 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
495 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
496 break;
497
498 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
499 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
500 break;
501
502 default:
503 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTTING_ST: Ignoring event %d",
504 event);
505 break;
506 }
507 break;
508
509 default:
510 break;
511 }
512
513 APPL_TRACE_DEBUG("%s: after state: %d", __func__, client_cb->sco_state);
514 }
515
516 /*******************************************************************************
517 *
518 * Function bta_hf_client_sco_listen
519 *
520 * Description Initialize SCO listener
521 *
522 *
523 * Returns void
524 *
525 ******************************************************************************/
bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA * p_data)526 void bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA* p_data) {
527 APPL_TRACE_DEBUG("%s", __func__);
528
529 tBTA_HF_CLIENT_CB* client_cb =
530 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
531 if (client_cb == NULL) {
532 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
533 p_data->hdr.layer_specific);
534 return;
535 }
536
537 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_LISTEN_E);
538 }
539
540 /*******************************************************************************
541 *
542 * Function bta_hf_client_sco_shutdown
543 *
544 * Description
545 *
546 *
547 * Returns void
548 *
549 ******************************************************************************/
bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_CB * client_cb)550 void bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_CB* client_cb) {
551 APPL_TRACE_DEBUG("%s", __func__);
552
553 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_SHUTDOWN_E);
554 }
555
556 /*******************************************************************************
557 *
558 * Function bta_hf_client_sco_conn_open
559 *
560 * Description
561 *
562 *
563 * Returns void
564 *
565 ******************************************************************************/
bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA * p_data)566 void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA* p_data) {
567 APPL_TRACE_DEBUG("%s", __func__);
568
569 tBTA_HF_CLIENT_CB* client_cb =
570 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
571 if (client_cb == NULL) {
572 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
573 p_data->hdr.layer_specific);
574 return;
575 }
576
577 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CONN_OPEN_E);
578
579 bta_sys_sco_open(BTA_ID_HS, 1, client_cb->peer_addr);
580
581 if (client_cb->negotiated_codec == BTM_SCO_CODEC_MSBC) {
582 bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT);
583 } else {
584 bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_OPEN_EVT);
585 }
586 }
587
588 /*******************************************************************************
589 *
590 * Function bta_hf_client_sco_conn_close
591 *
592 * Description
593 *
594 *
595 * Returns void
596 *
597 ******************************************************************************/
bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA * p_data)598 void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA* p_data) {
599 APPL_TRACE_DEBUG("%s", __func__);
600
601 tBTA_HF_CLIENT_CB* client_cb =
602 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
603 if (client_cb == NULL) {
604 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
605 p_data->hdr.layer_specific);
606 return;
607 }
608
609 /* clear current scb */
610 client_cb->sco_idx = BTM_INVALID_SCO_INDEX;
611
612 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CONN_CLOSE_E);
613
614 bta_sys_sco_close(BTA_ID_HS, 1, client_cb->peer_addr);
615
616 bta_sys_sco_unuse(BTA_ID_HS, 1, client_cb->peer_addr);
617
618 /* call app callback */
619 bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
620
621 if (client_cb->sco_close_rfc) {
622 client_cb->sco_close_rfc = false;
623 bta_hf_client_rfc_do_close(p_data);
624 }
625 }
626
627 /*******************************************************************************
628 *
629 * Function bta_hf_client_sco_open
630 *
631 * Description
632 *
633 *
634 * Returns void
635 *
636 ******************************************************************************/
bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA * p_data)637 void bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA* p_data) {
638 APPL_TRACE_DEBUG("%s", __func__);
639
640 tBTA_HF_CLIENT_CB* client_cb =
641 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
642 if (client_cb == NULL) {
643 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
644 p_data->hdr.layer_specific);
645 return;
646 }
647
648 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_OPEN_E);
649 }
650
651 /*******************************************************************************
652 *
653 * Function bta_hf_client_sco_close
654 *
655 * Description
656 *
657 *
658 * Returns void
659 *
660 ******************************************************************************/
bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA * p_data)661 void bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA* p_data) {
662 tBTA_HF_CLIENT_CB* client_cb =
663 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
664 if (client_cb == NULL) {
665 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
666 p_data->hdr.layer_specific);
667 return;
668 }
669
670 APPL_TRACE_DEBUG("%s: sco_idx 0x%x", __func__, client_cb->sco_idx);
671
672 if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
673 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CLOSE_E);
674 }
675 }
676