/*******************************************************************************
**
** Function         bta_hf_client_remove_sco
**
** Description      Removes the specified SCO from the system.
**                  If only_active is TRUE, then SCO is only removed if connected
**
** Returns          BOOLEAN   - TRUE if Sco removal was started
**
*******************************************************************************/
static BOOLEAN bta_hf_client_sco_remove(BOOLEAN only_active)
{
    BOOLEAN     removed_started = FALSE;
    tBTM_STATUS status;

    APPL_TRACE_DEBUG2("%s %d", __FUNCTION__, only_active);

    if (bta_hf_client_cb.scb.sco_idx != BTM_INVALID_SCO_INDEX)
    {
        status = BTM_RemoveSco(bta_hf_client_cb.scb.sco_idx);

        APPL_TRACE_DEBUG3("%s idx 0x%04x, status:0x%x", __FUNCTION__, bta_hf_client_cb.scb.sco_idx, status);

        if (status == BTM_CMD_STARTED)
        {
            removed_started = TRUE;
        }
        /* If no connection reset the sco handle */
        else if ( (status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR) )
        {
            bta_hf_client_cb.scb.sco_idx = BTM_INVALID_SCO_INDEX;
        }
    }
    return removed_started;
}
/*******************************************************************************
**
** Function         bta_hf_client_sco_conn_cback
**
** Description      BTM SCO connection callback.
**
**
** Returns          void
**
*******************************************************************************/
static void bta_hf_client_sco_conn_cback(UINT16 sco_idx)
{
    BT_HDR  *p_buf;
    UINT8 *rem_bd;

    APPL_TRACE_DEBUG2("%s %d", __FUNCTION__, sco_idx);

    rem_bd = BTM_ReadScoBdAddr(sco_idx);

    if (rem_bd && bdcmp(bta_hf_client_cb.scb.peer_addr, rem_bd) == 0 &&
            bta_hf_client_cb.scb.svc_conn && bta_hf_client_cb.scb.sco_idx == sco_idx)
    {
        if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
        {
            p_buf->event = BTA_HF_CLIENT_SCO_OPEN_EVT;
            p_buf->layer_specific = bta_hf_client_cb.scb.conn_handle;
            bta_sys_sendmsg(p_buf);
        }
    }
    /* no match found; disconnect sco, init sco variables */
    else
    {
        bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
        BTM_RemoveSco(sco_idx);
    }
}
// Must be called with |lock| held except during teardown when we know the socket thread
// is no longer alive.
static void sco_socket_free_locked(sco_socket_t *sco_socket) {
  if (!sco_socket)
    return;

  if (sco_socket->sco_handle != BTM_INVALID_SCO_INDEX)
    BTM_RemoveSco(sco_socket->sco_handle);
  socket_free(sco_socket->socket);
  osi_free(sco_socket);
}
static void socket_read_ready_cb(UNUSED_ATTR socket_t *socket, void *context) {
  pthread_mutex_lock(&lock);

  sco_socket_t *sco_socket = (sco_socket_t *)context;
  socket_free(sco_socket->socket);
  sco_socket->socket = NULL;

  // Defer the underlying disconnect until the connection completes
  // since the BTM code doesn't behave correctly when a disconnect
  // request is issued while a connect is in progress. The fact that
  // sco_socket->socket == NULL indicates to the connect callback
  // routine that the socket is no longer desired and should be torn
  // down.
  if (sco_socket->connect_completed || sco_socket == listen_sco_socket) {
    if (BTM_RemoveSco(sco_socket->sco_handle) == BTM_SUCCESS)
      list_remove(sco_sockets, sco_socket);
    if (sco_socket == listen_sco_socket)
      listen_sco_socket = NULL;
  }

  pthread_mutex_unlock(&lock);
}
static void connect_completed_cb(uint16_t sco_handle) {
  pthread_mutex_lock(&lock);

  sco_socket_t *sco_socket = sco_socket_find_locked(sco_handle);
  if (!sco_socket) {
    LOG_ERROR(LOG_TAG, "%s SCO socket not found on connect for handle: %hu", __func__, sco_handle);
    goto out;
  }

  // If sco_socket->socket was closed, we should tear down because there is no app-level
  // interest in the SCO socket.
  if (!sco_socket->socket) {
    BTM_RemoveSco(sco_socket->sco_handle);
    list_remove(sco_sockets, sco_socket);
    goto out;
  }

  sco_socket->connect_completed = true;

out:;
  pthread_mutex_unlock(&lock);
}