• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&params);
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 
309         case BTA_HF_CLIENT_SCO_OPEN_E:
310           /* remove listening connection */
311           bta_hf_client_sco_remove(client_cb);
312 
313           /* create SCO connection to peer */
314           bta_hf_client_sco_create(client_cb, true);
315           client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
316           break;
317 
318         case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
319         case BTA_HF_CLIENT_SCO_CLOSE_E:
320           /* remove listening connection */
321           bta_hf_client_sco_remove(client_cb);
322 
323           client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
324           break;
325 
326         case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
327           /* SCO failed; create SCO listen connection */
328           bta_hf_client_sco_create(client_cb, false);
329           client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
330           break;
331 
332         default:
333           APPL_TRACE_WARNING(
334               "%s: BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d", __func__,
335               event);
336           break;
337       }
338       break;
339 
340     case BTA_HF_CLIENT_SCO_OPENING_ST:
341       switch (event) {
342         case BTA_HF_CLIENT_SCO_CLOSE_E:
343           client_cb->sco_state = BTA_HF_CLIENT_SCO_OPEN_CL_ST;
344           break;
345 
346         case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
347           client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
348           break;
349 
350         case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
351           client_cb->sco_state = BTA_HF_CLIENT_SCO_OPEN_ST;
352           break;
353 
354         case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
355           /* SCO failed; create SCO listen connection */
356           bta_hf_client_sco_create(client_cb, false);
357           client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
358           break;
359 
360         default:
361           APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPENING_ST: Ignoring event %d",
362                              event);
363           break;
364       }
365       break;
366 
367     case BTA_HF_CLIENT_SCO_OPEN_CL_ST:
368       switch (event) {
369         case BTA_HF_CLIENT_SCO_OPEN_E:
370           client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
371           break;
372 
373         case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
374           client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
375           break;
376 
377         case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
378           /* close SCO connection */
379           bta_hf_client_sco_remove(client_cb);
380 
381           client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
382           break;
383 
384         case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
385           /* SCO failed; create SCO listen connection */
386 
387           client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
388           break;
389 
390         default:
391           APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_CL_ST: Ignoring event %d",
392                              event);
393           break;
394       }
395       break;
396 
397     case BTA_HF_CLIENT_SCO_OPEN_ST:
398       switch (event) {
399         case BTA_HF_CLIENT_SCO_CLOSE_E:
400           if (bta_hf_client_sco_remove(client_cb)) {
401             client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
402           }
403           break;
404 
405         case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
406           /* remove listening connection */
407           bta_hf_client_sco_remove(client_cb);
408 
409           client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
410           break;
411 
412         case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
413           /* peer closed SCO */
414           bta_hf_client_sco_create(client_cb, false);
415           client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
416           break;
417 
418         default:
419           APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_ST: Ignoring event %d",
420                              event);
421           break;
422       }
423       break;
424 
425     case BTA_HF_CLIENT_SCO_CLOSING_ST:
426       switch (event) {
427         case BTA_HF_CLIENT_SCO_OPEN_E:
428           client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSE_OP_ST;
429           break;
430 
431         case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
432           client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
433           break;
434 
435         case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
436           /* peer closed sco; create SCO listen connection */
437           bta_hf_client_sco_create(client_cb, false);
438           client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
439           break;
440 
441         default:
442           APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSING_ST: Ignoring event %d",
443                              event);
444           break;
445       }
446       break;
447 
448     case BTA_HF_CLIENT_SCO_CLOSE_OP_ST:
449       switch (event) {
450         case BTA_HF_CLIENT_SCO_CLOSE_E:
451           client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
452           break;
453 
454         case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
455           client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
456           break;
457 
458         case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
459           /* open SCO connection */
460           bta_hf_client_sco_create(client_cb, true);
461           client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
462           break;
463 
464         default:
465           APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSE_OP_ST: Ignoring event %d",
466                              event);
467           break;
468       }
469       break;
470 
471     case BTA_HF_CLIENT_SCO_SHUTTING_ST:
472       switch (event) {
473         case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
474           /* close SCO connection; wait for conn close event */
475           bta_hf_client_sco_remove(client_cb);
476           break;
477 
478         case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
479           client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
480           break;
481 
482         case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
483           client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
484           break;
485 
486         default:
487           APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTTING_ST: Ignoring event %d",
488                              event);
489           break;
490       }
491       break;
492 
493     default:
494       break;
495   }
496 
497   APPL_TRACE_DEBUG("%s: after state: %d", __func__, client_cb->sco_state);
498 }
499 
500 /*******************************************************************************
501  *
502  * Function         bta_hf_client_sco_listen
503  *
504  * Description      Initialize SCO listener
505  *
506  *
507  * Returns          void
508  *
509  ******************************************************************************/
bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA * p_data)510 void bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA* p_data) {
511   APPL_TRACE_DEBUG("%s", __func__);
512 
513   tBTA_HF_CLIENT_CB* client_cb =
514       bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
515   if (client_cb == NULL) {
516     APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
517                      p_data->hdr.layer_specific);
518     return;
519   }
520 
521   bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_LISTEN_E);
522 }
523 
524 /*******************************************************************************
525  *
526  * Function         bta_hf_client_sco_shutdown
527  *
528  * Description
529  *
530  *
531  * Returns          void
532  *
533  ******************************************************************************/
bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_CB * client_cb)534 void bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_CB* client_cb) {
535   APPL_TRACE_DEBUG("%s", __func__);
536 
537   bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_SHUTDOWN_E);
538 }
539 
540 /*******************************************************************************
541  *
542  * Function         bta_hf_client_sco_conn_open
543  *
544  * Description
545  *
546  *
547  * Returns          void
548  *
549  ******************************************************************************/
bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA * p_data)550 void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA* p_data) {
551   APPL_TRACE_DEBUG("%s", __func__);
552 
553   tBTA_HF_CLIENT_CB* client_cb =
554       bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
555   if (client_cb == NULL) {
556     APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
557                      p_data->hdr.layer_specific);
558     return;
559   }
560 
561   bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CONN_OPEN_E);
562 
563   bta_sys_sco_open(BTA_ID_HS, 1, client_cb->peer_addr);
564 
565   if (client_cb->negotiated_codec == BTM_SCO_CODEC_MSBC) {
566     bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT);
567   } else {
568     bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_OPEN_EVT);
569   }
570 }
571 
572 /*******************************************************************************
573  *
574  * Function         bta_hf_client_sco_conn_close
575  *
576  * Description
577  *
578  *
579  * Returns          void
580  *
581  ******************************************************************************/
bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA * p_data)582 void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA* p_data) {
583   APPL_TRACE_DEBUG("%s", __func__);
584 
585   tBTA_HF_CLIENT_CB* client_cb =
586       bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
587   if (client_cb == NULL) {
588     APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
589                      p_data->hdr.layer_specific);
590     return;
591   }
592 
593   /* clear current scb */
594   client_cb->sco_idx = BTM_INVALID_SCO_INDEX;
595 
596   bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CONN_CLOSE_E);
597 
598   bta_sys_sco_close(BTA_ID_HS, 1, client_cb->peer_addr);
599 
600   bta_sys_sco_unuse(BTA_ID_HS, 1, client_cb->peer_addr);
601 
602   /* call app callback */
603   bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
604 
605   if (client_cb->sco_close_rfc) {
606     client_cb->sco_close_rfc = false;
607     bta_hf_client_rfc_do_close(p_data);
608   }
609 }
610 
611 /*******************************************************************************
612  *
613  * Function         bta_hf_client_sco_open
614  *
615  * Description
616  *
617  *
618  * Returns          void
619  *
620  ******************************************************************************/
bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA * p_data)621 void bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA* p_data) {
622   APPL_TRACE_DEBUG("%s", __func__);
623 
624   tBTA_HF_CLIENT_CB* client_cb =
625       bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
626   if (client_cb == NULL) {
627     APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
628                      p_data->hdr.layer_specific);
629     return;
630   }
631 
632   bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_OPEN_E);
633 }
634 
635 /*******************************************************************************
636  *
637  * Function         bta_hf_client_sco_close
638  *
639  * Description
640  *
641  *
642  * Returns          void
643  *
644  ******************************************************************************/
bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA * p_data)645 void bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA* p_data) {
646   tBTA_HF_CLIENT_CB* client_cb =
647       bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
648   if (client_cb == NULL) {
649     APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
650                      p_data->hdr.layer_specific);
651     return;
652   }
653 
654   APPL_TRACE_DEBUG("%s: sco_idx 0x%x", __func__, client_cb->sco_idx);
655 
656   if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
657     bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CLOSE_E);
658   }
659 }
660