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(&params);
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