OSDN Git Service

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