static void connection_request_cb(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *data) { assert(data != NULL); // Don't care about change of link parameters, only connection requests. if (event != BTM_ESCO_CONN_REQ_EVT) return; pthread_mutex_lock(&lock); const tBTM_ESCO_CONN_REQ_EVT_DATA *conn_data = &data->conn_evt; sco_socket_t *sco_socket = sco_socket_find_locked(conn_data->sco_inx); int client_fd = INVALID_FD; if (!sco_socket) { LOG_ERROR(LOG_TAG, "%s unable to find sco_socket for handle: %hu", __func__, conn_data->sco_inx); goto error; } if (sco_socket != listen_sco_socket) { LOG_ERROR(LOG_TAG, "%s received connection request on non-listening socket handle: %hu", __func__, conn_data->sco_inx); goto error; } sco_socket_t *new_sco_socket = sco_socket_establish_locked(true, NULL, &client_fd); if (!new_sco_socket) { LOG_ERROR(LOG_TAG, "%s unable to allocate new sco_socket.", __func__); goto error; } // Swap socket->sco_handle and new_socket->sco_handle uint16_t temp = sco_socket->sco_handle; sco_socket->sco_handle = new_sco_socket->sco_handle; new_sco_socket->sco_handle = temp; sock_connect_signal_t connect_signal; connect_signal.size = sizeof(connect_signal); memcpy(&connect_signal.bd_addr, conn_data->bd_addr, sizeof(bt_bdaddr_t)); connect_signal.channel = 0; connect_signal.status = 0; if (socket_write_and_transfer_fd(sco_socket->socket, &connect_signal, sizeof(connect_signal), client_fd) != sizeof(connect_signal)) { LOG_ERROR(LOG_TAG, "%s unable to send new file descriptor to listening socket.", __func__); goto error; } BTM_RegForEScoEvts(listen_sco_socket->sco_handle, connection_request_cb); BTM_EScoConnRsp(conn_data->sco_inx, HCI_SUCCESS, NULL); pthread_mutex_unlock(&lock); return; error:; pthread_mutex_unlock(&lock); if (client_fd != INVALID_FD) close(client_fd); BTM_EScoConnRsp(conn_data->sco_inx, HCI_ERR_HOST_REJECT_RESOURCES, NULL); }
bt_status_t btsock_sco_listen(int *sock_fd, UNUSED_ATTR int flags) { assert(sock_fd != NULL); pthread_mutex_lock(&lock); sco_socket_t *sco_socket = sco_socket_establish_locked(true, NULL, sock_fd); if (sco_socket) { BTM_RegForEScoEvts(sco_socket->sco_handle, connection_request_cb); listen_sco_socket = sco_socket; } pthread_mutex_unlock(&lock); return sco_socket ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; }
/******************************************************************************* ** ** Function bta_hf_client_create_sco ** ** Description ** ** ** Returns void ** *******************************************************************************/ static void bta_hf_client_sco_create(BOOLEAN is_orig) { tBTM_STATUS status; UINT8 *p_bd_addr = NULL; tBTM_ESCO_PARAMS params; APPL_TRACE_DEBUG2("%s %d", __FUNCTION__, is_orig); /* Make sure this sco handle is not already in use */ if (bta_hf_client_cb.scb.sco_idx != BTM_INVALID_SCO_INDEX) { APPL_TRACE_WARNING2("%s: Index 0x%04x already in use", __FUNCTION__, bta_hf_client_cb.scb.sco_idx); return; } params = bta_hf_client_esco_params[1]; /* if initiating set current scb and peer bd addr */ if (is_orig) { /* Attempt to use eSCO if remote host supports HFP >= 1.5 */ if (bta_hf_client_cb.scb.peer_version >= HFP_VERSION_1_5 && !bta_hf_client_cb.scb.retry_with_sco_only) { BTM_SetEScoMode(BTM_LINK_TYPE_ESCO, ¶ms); /* If ESCO or EDR ESCO, retry with SCO only in case of failure */ if((params.packet_types & BTM_ESCO_LINK_ONLY_MASK) ||!((params.packet_types & ~(BTM_ESCO_LINK_ONLY_MASK | BTM_SCO_LINK_ONLY_MASK)) ^ BTA_HF_CLIENT_NO_EDR_ESCO)) { bta_hf_client_cb.scb.retry_with_sco_only = TRUE; APPL_TRACE_API0("Setting retry_with_sco_only to TRUE"); } } else { if(bta_hf_client_cb.scb.retry_with_sco_only) APPL_TRACE_API0("retrying with SCO only"); bta_hf_client_cb.scb.retry_with_sco_only = FALSE; BTM_SetEScoMode(BTM_LINK_TYPE_SCO, ¶ms); } /* tell sys to stop av if any */ bta_sys_sco_use(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr); } else { bta_hf_client_cb.scb.retry_with_sco_only = FALSE; } p_bd_addr = bta_hf_client_cb.scb.peer_addr; status = BTM_CreateSco(p_bd_addr, is_orig, params.packet_types, &bta_hf_client_cb.scb.sco_idx, bta_hf_client_sco_conn_cback, bta_hf_client_sco_disc_cback); if (status == BTM_CMD_STARTED && !is_orig) { if(!BTM_RegForEScoEvts(bta_hf_client_cb.scb.sco_idx, bta_hf_client_esco_connreq_cback)) APPL_TRACE_DEBUG1("%s SCO registration success", __FUNCTION__); } APPL_TRACE_API5("%s: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x", __FUNCTION__, is_orig, bta_hf_client_cb.scb.sco_idx, status, params.packet_types); }