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 <bluetooth/log.h>
21 
22 #include <cstdint>
23 
24 #include "bta/hf_client/bta_hf_client_int.h"
25 #include "osi/include/allocator.h"
26 #include "stack/include/bt_hdr.h"
27 #include "stack/include/btm_api.h"
28 #include "stack/include/btm_client_interface.h"
29 
30 #define BTA_HF_CLIENT_NO_EDR_ESCO                                \
31   (ESCO_PKT_TYPES_MASK_NO_2_EV3 | ESCO_PKT_TYPES_MASK_NO_3_EV3 | \
32    ESCO_PKT_TYPES_MASK_NO_2_EV5 | ESCO_PKT_TYPES_MASK_NO_3_EV5)
33 
34 using namespace bluetooth;
35 
36 enum {
37   BTA_HF_CLIENT_SCO_LISTEN_E,
38   BTA_HF_CLIENT_SCO_OPEN_E,       /* open request */
39   BTA_HF_CLIENT_SCO_CLOSE_E,      /* close request */
40   BTA_HF_CLIENT_SCO_SHUTDOWN_E,   /* shutdown request */
41   BTA_HF_CLIENT_SCO_CONN_OPEN_E,  /* SCO opened */
42   BTA_HF_CLIENT_SCO_CONN_CLOSE_E, /* SCO closed */
43 };
44 
45 /*******************************************************************************
46  *
47  * Function         bta_hf_client_remove_sco
48  *
49  * Description      Removes the specified SCO from the system.
50  *
51  * Returns          bool   - true if SCO removal was started
52  *
53  ******************************************************************************/
bta_hf_client_sco_remove(tBTA_HF_CLIENT_CB * client_cb)54 static bool bta_hf_client_sco_remove(tBTA_HF_CLIENT_CB* client_cb) {
55   bool removed_started = false;
56   tBTM_STATUS status;
57 
58   log::verbose("");
59 
60   if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
61     status = BTM_RemoveSco(client_cb->sco_idx);
62 
63     log::verbose("idx 0x{:04x}, status:0x{:x}", client_cb->sco_idx, status);
64 
65     if (status == BTM_CMD_STARTED) {
66       removed_started = true;
67     }
68     /* If no connection reset the SCO handle */
69     else if ((status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR)) {
70       client_cb->sco_idx = BTM_INVALID_SCO_INDEX;
71     }
72   }
73   return removed_started;
74 }
75 
76 /*******************************************************************************
77  *
78  * Function         bta_hf_client_cback_sco
79  *
80  * Description      Call application callback function with SCO event.
81  *
82  *
83  * Returns          void
84  *
85  ******************************************************************************/
bta_hf_client_cback_sco(tBTA_HF_CLIENT_CB * client_cb,uint8_t event)86 void bta_hf_client_cback_sco(tBTA_HF_CLIENT_CB* client_cb, uint8_t event) {
87   tBTA_HF_CLIENT evt;
88 
89   memset(&evt, 0, sizeof(evt));
90   evt.bd_addr = client_cb->peer_addr;
91 
92   /* call app cback */
93   bta_hf_client_app_callback(event, &evt);
94 }
95 
96 /*******************************************************************************
97  *
98  * Function         bta_hf_client_sco_conn_rsp
99  *
100  * Description      Process the SCO connection request
101  *
102  *
103  * Returns          void
104  *
105  ******************************************************************************/
bta_hf_client_sco_conn_rsp(tBTA_HF_CLIENT_CB * client_cb,tBTM_ESCO_CONN_REQ_EVT_DATA * p_data)106 static void bta_hf_client_sco_conn_rsp(tBTA_HF_CLIENT_CB* client_cb,
107                                        tBTM_ESCO_CONN_REQ_EVT_DATA* p_data) {
108   enh_esco_params_t resp;
109   tHCI_STATUS hci_status = HCI_SUCCESS;
110 
111   log::verbose("");
112 
113   if (client_cb->sco_state == BTA_HF_CLIENT_SCO_LISTEN_ST) {
114     if (p_data->link_type == BTM_LINK_TYPE_SCO) {
115       // SCO
116       resp = esco_parameters_for_codec(SCO_CODEC_CVSD_D1, true);
117     } else if (client_cb->negotiated_codec == BTM_SCO_CODEC_LC3) {
118       // eSCO LC3, HFP 1.9
119       resp = esco_parameters_for_codec(ESCO_CODEC_LC3_T2, true);
120     } else if (client_cb->negotiated_codec == BTM_SCO_CODEC_MSBC) {
121       // eSCO mSBC
122       resp = esco_parameters_for_codec(ESCO_CODEC_MSBC_T2, true);
123     } else if (bta_hf_client_cb_arr.features & BTA_HF_CLIENT_FEAT_ESCO_S4) {
124       // eSCO CVSD, HFP 1.7 requires S4
125       resp = esco_parameters_for_codec(ESCO_CODEC_CVSD_S4, true);
126     } else {
127       // eSCO CVSD, S3 is preferred by default(before HFP 1.7)
128       resp = esco_parameters_for_codec(ESCO_CODEC_CVSD_S3, true);
129     }
130 
131     /* tell sys to stop av if any */
132     bta_sys_sco_use(BTA_ID_HS, 1, client_cb->peer_addr);
133   } else {
134     hci_status = HCI_ERR_HOST_REJECT_DEVICE;
135   }
136 
137   BTM_EScoConnRsp(p_data->sco_inx, hci_status, &resp);
138 }
139 
140 /*******************************************************************************
141  *
142  * Function         bta_hf_client_sco_connreq_cback
143  *
144  * Description      BTM eSCO connection requests and eSCO change requests
145  *                  Only the connection requests are processed by BTA.
146  *
147  * Returns          void
148  *
149  ******************************************************************************/
bta_hf_client_esco_connreq_cback(tBTM_ESCO_EVT event,tBTM_ESCO_EVT_DATA * p_data)150 static void bta_hf_client_esco_connreq_cback(tBTM_ESCO_EVT event,
151                                              tBTM_ESCO_EVT_DATA* p_data) {
152   log::verbose("{}", event);
153 
154   tBTA_HF_CLIENT_CB* client_cb =
155       bta_hf_client_find_cb_by_sco_handle(p_data->conn_evt.sco_inx);
156   if (client_cb == NULL) {
157     log::error("wrong SCO handle to control block {}",
158                p_data->conn_evt.sco_inx);
159     return;
160   }
161 
162   if (event != BTM_ESCO_CONN_REQ_EVT) {
163     return;
164   }
165 
166   bta_hf_client_sco_conn_rsp(client_cb, &p_data->conn_evt);
167 
168   client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
169 }
170 
171 /*******************************************************************************
172  *
173  * Function         bta_hf_client_sco_conn_cback
174  *
175  * Description      BTM SCO connection callback.
176  *
177  *
178  * Returns          void
179  *
180  ******************************************************************************/
bta_hf_client_sco_conn_cback(uint16_t sco_idx)181 static void bta_hf_client_sco_conn_cback(uint16_t sco_idx) {
182   log::verbose("{}", sco_idx);
183 
184   tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_sco_handle(sco_idx);
185   if (client_cb == NULL) {
186     log::error("wrong SCO handle to control block {}", sco_idx);
187     return;
188   }
189 
190   BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
191   p_buf->event = BTA_HF_CLIENT_SCO_OPEN_EVT;
192   p_buf->layer_specific = client_cb->handle;
193   bta_sys_sendmsg(p_buf);
194 }
195 
196 /*******************************************************************************
197  *
198  * Function         bta_hf_client_sco_disc_cback
199  *
200  * Description      BTM SCO disconnection callback.
201  *
202  *
203  * Returns          void
204  *
205  ******************************************************************************/
bta_hf_client_sco_disc_cback(uint16_t sco_idx)206 static void bta_hf_client_sco_disc_cback(uint16_t sco_idx) {
207   log::verbose("sco_idx {}", sco_idx);
208 
209   tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_sco_handle(sco_idx);
210   if (client_cb == NULL) {
211     log::error("wrong handle to control block {}", sco_idx);
212     return;
213   }
214 
215   BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
216   p_buf->event = BTA_HF_CLIENT_SCO_CLOSE_EVT;
217   p_buf->layer_specific = client_cb->handle;
218   bta_sys_sendmsg(p_buf);
219 }
220 
221 /*******************************************************************************
222  *
223  * Function         bta_hf_client_create_sco
224  *
225  * Description
226  *
227  *
228  * Returns          void
229  *
230  ******************************************************************************/
bta_hf_client_sco_create(tBTA_HF_CLIENT_CB * client_cb,bool is_orig)231 static void bta_hf_client_sco_create(tBTA_HF_CLIENT_CB* client_cb,
232                                      bool is_orig) {
233   tBTM_STATUS status;
234 
235   log::verbose("{}", is_orig);
236 
237   /* Make sure this SCO handle is not already in use */
238   if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
239     log::warn("Index 0x{:04x} already in use", client_cb->sco_idx);
240     return;
241   }
242 
243   // codec parameters
244   enh_esco_params_t params;
245   // Since HF device is not expected to receive AT+BAC send +BCS command,
246   // codec support of the connected AG device will be unknown,
247   // so HF device will always establish only CVSD connection.
248   if ((bta_hf_client_cb_arr.features & BTA_HF_CLIENT_FEAT_ESCO_S4) &&
249       (client_cb->peer_features & BTA_HF_CLIENT_PEER_ESCO_S4)) {
250     // eSCO CVSD, HFP 1.7 requires S4
251     params = esco_parameters_for_codec(ESCO_CODEC_CVSD_S4, true);
252   } else {
253     // eSCO CVSD, S3 is preferred by default(before HFP 1.7)
254     params = esco_parameters_for_codec(ESCO_CODEC_CVSD_S3, true);
255   }
256 
257   /* if initiating set current scb and peer bd addr */
258   if (is_orig) {
259     if (get_btm_client_interface().sco.BTM_SetEScoMode(&params) !=
260         BTM_SUCCESS) {
261       log::warn("Unable to set ESCO mode");
262     }
263     /* tell sys to stop av if any */
264     bta_sys_sco_use(BTA_ID_HS, 1, client_cb->peer_addr);
265   }
266 
267   status = BTM_CreateSco(&client_cb->peer_addr, is_orig, params.packet_types,
268                          &client_cb->sco_idx, bta_hf_client_sco_conn_cback,
269                          bta_hf_client_sco_disc_cback);
270   if (status == BTM_CMD_STARTED && !is_orig) {
271     if (!BTM_RegForEScoEvts(client_cb->sco_idx,
272                             bta_hf_client_esco_connreq_cback))
273       log::verbose("SCO registration success");
274   }
275 
276   log::verbose("orig {}, inx 0x{:04x}, status 0x{:x}, pkt types 0x{:04x}",
277                is_orig, client_cb->sco_idx, status, params.packet_types);
278 }
279 
280 /*******************************************************************************
281  *
282  * Function         bta_hf_client_sco_event
283  *
284  * Description      Handle SCO events
285  *
286  *
287  * Returns          void
288  *
289  ******************************************************************************/
bta_hf_client_sco_event(tBTA_HF_CLIENT_CB * client_cb,uint8_t event)290 static void bta_hf_client_sco_event(tBTA_HF_CLIENT_CB* client_cb,
291                                     uint8_t event) {
292   log::verbose("before state: {} event: {}", client_cb->sco_state, event);
293 
294   switch (client_cb->sco_state) {
295     case BTA_HF_CLIENT_SCO_SHUTDOWN_ST:
296       switch (event) {
297         // For WBS we only listen to SCO requests. Even for outgoing SCO
298         // requests we first do a AT+BCC and wait for remote to initiate SCO
299         case BTA_HF_CLIENT_SCO_LISTEN_E:
300           /* create SCO listen connection */
301           bta_hf_client_sco_create(client_cb, false);
302           client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
303           break;
304 
305         // For non WBS cases and enabling outgoing SCO requests we need to force
306         // open a SCO channel
307         case BTA_HF_CLIENT_SCO_OPEN_E:
308           /* remove listening connection */
309           bta_hf_client_sco_remove(client_cb);
310 
311           /* create SCO connection to peer */
312           bta_hf_client_sco_create(client_cb, true);
313           client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
314           break;
315 
316         default:
317           log::warn("BTA_HF_CLIENT_SCO_SHUTDOWN_ST: Ignoring event {}", event);
318           break;
319       }
320       break;
321 
322     case BTA_HF_CLIENT_SCO_LISTEN_ST:
323       switch (event) {
324         case BTA_HF_CLIENT_SCO_LISTEN_E:
325           /* create SCO listen connection */
326           bta_hf_client_sco_create(client_cb, false);
327           break;
328 
329         case BTA_HF_CLIENT_SCO_OPEN_E:
330           /* remove listening connection */
331           bta_hf_client_sco_remove(client_cb);
332 
333           /* create SCO connection to peer */
334           bta_hf_client_sco_create(client_cb, true);
335           client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
336           break;
337 
338         case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
339           /* remove listening connection */
340           bta_hf_client_sco_remove(client_cb);
341 
342           client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
343           break;
344 
345         case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
346           /* SCO failed; create SCO listen connection */
347           bta_hf_client_sco_create(client_cb, false);
348           client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
349           break;
350 
351         default:
352           log::warn("BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event {}", event);
353           break;
354       }
355       break;
356 
357     case BTA_HF_CLIENT_SCO_OPENING_ST:
358       switch (event) {
359         case BTA_HF_CLIENT_SCO_CLOSE_E:
360           client_cb->sco_state = BTA_HF_CLIENT_SCO_OPEN_CL_ST;
361           break;
362 
363         case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
364           client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
365           break;
366 
367         case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
368           client_cb->sco_state = BTA_HF_CLIENT_SCO_OPEN_ST;
369           break;
370 
371         case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
372           /* SCO failed; create SCO listen connection */
373           bta_hf_client_sco_create(client_cb, false);
374           client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
375           break;
376 
377         default:
378           log::warn("BTA_HF_CLIENT_SCO_OPENING_ST: Ignoring event {}", 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           log::warn("BTA_HF_CLIENT_SCO_OPEN_CL_ST: Ignoring event {}", event);
408           break;
409       }
410       break;
411 
412     case BTA_HF_CLIENT_SCO_OPEN_ST:
413       switch (event) {
414         case BTA_HF_CLIENT_SCO_CLOSE_E:
415           if (bta_hf_client_sco_remove(client_cb)) {
416             client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
417           }
418           break;
419 
420         case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
421           /* remove listening connection */
422           bta_hf_client_sco_remove(client_cb);
423 
424           client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
425           break;
426 
427         case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
428           /* peer closed SCO */
429           bta_hf_client_sco_create(client_cb, false);
430           client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
431           break;
432 
433         default:
434           log::warn("BTA_HF_CLIENT_SCO_OPEN_ST: Ignoring event {}", event);
435           break;
436       }
437       break;
438 
439     case BTA_HF_CLIENT_SCO_CLOSING_ST:
440       switch (event) {
441         case BTA_HF_CLIENT_SCO_OPEN_E:
442           client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSE_OP_ST;
443           break;
444 
445         case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
446           client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
447           break;
448 
449         case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
450           /* peer closed sco; create SCO listen connection */
451           bta_hf_client_sco_create(client_cb, false);
452           client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
453           break;
454 
455         default:
456           log::warn("BTA_HF_CLIENT_SCO_CLOSING_ST: Ignoring event {}", event);
457           break;
458       }
459       break;
460 
461     case BTA_HF_CLIENT_SCO_CLOSE_OP_ST:
462       switch (event) {
463         case BTA_HF_CLIENT_SCO_CLOSE_E:
464           client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
465           break;
466 
467         case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
468           client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
469           break;
470 
471         case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
472           /* open SCO connection */
473           bta_hf_client_sco_create(client_cb, true);
474           client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
475           break;
476 
477         default:
478           log::warn("BTA_HF_CLIENT_SCO_CLOSE_OP_ST: Ignoring event {}", event);
479           break;
480       }
481       break;
482 
483     case BTA_HF_CLIENT_SCO_SHUTTING_ST:
484       switch (event) {
485         case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
486           /* close SCO connection; wait for conn close event */
487           bta_hf_client_sco_remove(client_cb);
488           break;
489 
490         case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
491           client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
492           break;
493 
494         case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
495           client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
496           break;
497 
498         default:
499           log::warn("BTA_HF_CLIENT_SCO_SHUTTING_ST: Ignoring event {}", event);
500           break;
501       }
502       break;
503 
504     default:
505       break;
506   }
507 
508   log::verbose("after state: {}", client_cb->sco_state);
509 }
510 
511 /*******************************************************************************
512  *
513  * Function         bta_hf_client_sco_listen
514  *
515  * Description      Initialize SCO listener
516  *
517  *
518  * Returns          void
519  *
520  ******************************************************************************/
bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA * p_data)521 void bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA* p_data) {
522   log::verbose("");
523 
524   tBTA_HF_CLIENT_CB* client_cb =
525       bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
526   if (client_cb == NULL) {
527     log::error("wrong handle to control block {}", p_data->hdr.layer_specific);
528     return;
529   }
530 
531   bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_LISTEN_E);
532 }
533 
534 /*******************************************************************************
535  *
536  * Function         bta_hf_client_sco_shutdown
537  *
538  * Description
539  *
540  *
541  * Returns          void
542  *
543  ******************************************************************************/
bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_CB * client_cb)544 void bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_CB* client_cb) {
545   log::verbose("");
546 
547   bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_SHUTDOWN_E);
548 }
549 
550 /*******************************************************************************
551  *
552  * Function         bta_hf_client_sco_conn_open
553  *
554  * Description
555  *
556  *
557  * Returns          void
558  *
559  ******************************************************************************/
bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA * p_data)560 void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA* p_data) {
561   log::verbose("");
562 
563   tBTA_HF_CLIENT_CB* client_cb =
564       bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
565   if (client_cb == NULL) {
566     log::error("wrong handle to control block {}", p_data->hdr.layer_specific);
567     return;
568   }
569 
570   bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CONN_OPEN_E);
571 
572   bta_sys_sco_open(BTA_ID_HS, 1, client_cb->peer_addr);
573 
574   if (client_cb->negotiated_codec == BTM_SCO_CODEC_LC3) {
575     bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_LC3_OPEN_EVT);
576   } else if (client_cb->negotiated_codec == BTM_SCO_CODEC_MSBC) {
577     bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT);
578   } else {
579     bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_OPEN_EVT);
580   }
581 }
582 
583 /*******************************************************************************
584  *
585  * Function         bta_hf_client_sco_conn_close
586  *
587  * Description
588  *
589  *
590  * Returns          void
591  *
592  ******************************************************************************/
bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA * p_data)593 void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA* p_data) {
594   log::verbose("");
595 
596   tBTA_HF_CLIENT_CB* client_cb =
597       bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
598   if (client_cb == NULL) {
599     log::error("wrong handle to control block {}", p_data->hdr.layer_specific);
600     return;
601   }
602 
603   /* clear current scb */
604   client_cb->sco_idx = BTM_INVALID_SCO_INDEX;
605 
606   bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CONN_CLOSE_E);
607 
608   bta_sys_sco_close(BTA_ID_HS, 1, client_cb->peer_addr);
609 
610   bta_sys_sco_unuse(BTA_ID_HS, 1, client_cb->peer_addr);
611 
612   /* call app callback */
613   bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
614 
615   if (client_cb->sco_close_rfc) {
616     client_cb->sco_close_rfc = false;
617     bta_hf_client_rfc_do_close(p_data);
618   }
619 }
620 
621 /*******************************************************************************
622  *
623  * Function         bta_hf_client_sco_open
624  *
625  * Description
626  *
627  *
628  * Returns          void
629  *
630  ******************************************************************************/
bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA * p_data)631 void bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA* p_data) {
632   log::verbose("");
633 
634   tBTA_HF_CLIENT_CB* client_cb =
635       bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
636   if (client_cb == NULL) {
637     log::error("wrong handle to control block {}", p_data->hdr.layer_specific);
638     return;
639   }
640 
641   bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_OPEN_E);
642 }
643 
644 /*******************************************************************************
645  *
646  * Function         bta_hf_client_sco_close
647  *
648  * Description
649  *
650  *
651  * Returns          void
652  *
653  ******************************************************************************/
bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA * p_data)654 void bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA* p_data) {
655   tBTA_HF_CLIENT_CB* client_cb =
656       bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
657   if (client_cb == NULL) {
658     log::error("wrong handle to control block {}", p_data->hdr.layer_specific);
659     return;
660   }
661 
662   log::verbose("sco_idx 0x{:x}", client_cb->sco_idx);
663 
664   if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
665     bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CLOSE_E);
666   }
667 }
668