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