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