• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&params);
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