// Must be called with |lock| held. static sco_socket_t *sco_socket_establish_locked(bool is_listening, const bt_bdaddr_t *bd_addr, int *sock_fd) { int pair[2] = { INVALID_FD, INVALID_FD }; sco_socket_t *sco_socket = NULL; if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pair) == -1) { LOG_ERROR(LOG_TAG, "%s unable to allocate socket pair: %s", __func__, strerror(errno)); goto error; } sco_socket = sco_socket_new(); if (!sco_socket) { LOG_ERROR(LOG_TAG, "%s unable to allocate new SCO socket.", __func__); goto error; } tBTM_STATUS status = BTM_CreateSco((uint8_t *)bd_addr, !is_listening, sco_parameters.packet_types, &sco_socket->sco_handle, connect_completed_cb, disconnect_completed_cb); if (status != BTM_CMD_STARTED) { LOG_ERROR(LOG_TAG, "%s unable to create SCO socket: %d", __func__, status); goto error; } socket_t *socket = socket_new_from_fd(pair[1]); if (!socket) { LOG_ERROR(LOG_TAG, "%s unable to allocate socket from file descriptor %d.", __func__, pair[1]); goto error; } *sock_fd = pair[0]; // Transfer ownership of one end to caller. sco_socket->socket = socket; // Hang on to the other end. list_append(sco_sockets, sco_socket); socket_register(socket, thread_get_reactor(thread), sco_socket, socket_read_ready_cb, NULL); return sco_socket; error:; if (pair[0] != INVALID_FD) close(pair[0]); if (pair[1] != INVALID_FD) close(pair[1]); sco_socket_free_locked(sco_socket); return NULL; }
/******************************************************************************* ** ** 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); }