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