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