/******************************************************************************* ** ** Function bta_ag_sm_execute ** ** Description State machine event handling function for AG ** ** ** Returns void ** *******************************************************************************/ void bta_ag_sm_execute(tBTA_AG_SCB *p_scb, UINT16 event, tBTA_AG_DATA *p_data) { tBTA_AG_ST_TBL state_table; UINT8 action; int i; UINT16 in_event = event; UINT8 in_state = p_scb->state; if (in_event != BTA_AG_API_RESULT_EVT || p_scb->state == BTA_AG_OPEN_ST) { #if BTA_AG_DEBUG == TRUE APPL_TRACE_IMP("AG evt (hdl 0x%04x): State %d (%s), Event 0x%04x (%s)", bta_ag_scb_to_idx(p_scb), p_scb->state, bta_ag_state_str(p_scb->state), event, bta_ag_evt_str(event, p_data->api_result.result)); #else APPL_TRACE_IMP("AG evt (hdl 0x%04x): State %d, Event 0x%04x", bta_ag_scb_to_idx(p_scb), p_scb->state, event); #endif } event &= 0x00FF; if (event >= (BTA_AG_MAX_EVT & 0x00FF)) { APPL_TRACE_ERROR("AG evt out of range, ignoring..."); return; } /* look up the state table for the current state */ state_table = bta_ag_st_tbl[p_scb->state]; /* set next state */ p_scb->state = state_table[event][BTA_AG_NEXT_STATE]; /* execute action functions */ for (i = 0; i < BTA_AG_ACTIONS; i++) { if ((action = state_table[event][i]) != BTA_AG_IGNORE) { (*bta_ag_action[action])(p_scb, p_data); } else { break; } } if (p_scb->state != in_state) { #if BTA_AG_DEBUG == TRUE APPL_TRACE_IMP("BTA AG State Change: [%s] -> [%s] after Event [%s]", bta_ag_state_str(in_state), bta_ag_state_str(p_scb->state), bta_ag_evt_str(in_event, p_data->api_result.result)); #else APPL_TRACE_IMP("BTA AG State Change: [%d] -> [%d]", in_state, p_scb->state); #endif } }
/******************************************************************************* ** ** Function bta_ag_rfc_open ** ** Description Handle RFCOMM channel open. ** ** ** Returns void ** *******************************************************************************/ void bta_ag_rfc_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) { /* initialize AT feature variables */ p_scb->clip_enabled = FALSE; p_scb->ccwa_enabled = FALSE; p_scb->cmer_enabled = FALSE; p_scb->cmee_enabled = FALSE; p_scb->inband_enabled = ((p_scb->features & BTA_AG_FEAT_INBAND) == BTA_AG_FEAT_INBAND); /* set up AT command interpreter */ p_scb->at_cb.p_at_tbl = (tBTA_AG_AT_CMD *) bta_ag_at_tbl[p_scb->conn_service]; p_scb->at_cb.p_cmd_cback = (tBTA_AG_AT_CMD_CBACK *) bta_ag_at_cback_tbl[p_scb->conn_service]; p_scb->at_cb.p_err_cback = (tBTA_AG_AT_ERR_CBACK *) bta_ag_at_err_cback; p_scb->at_cb.p_user = p_scb; p_scb->at_cb.cmd_max_len = BTA_AG_CMD_MAX; bta_ag_at_init(&p_scb->at_cb); /* call app open call-out */ bta_ag_co_data_open(bta_ag_scb_to_idx(p_scb), bta_ag_svc_id[p_scb->conn_service]); bta_sys_conn_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); bta_ag_cback_open(p_scb, NULL, BTA_AG_SUCCESS); if (p_scb->conn_service == BTA_AG_HFP) { /* if hfp start timer for service level conn */ bta_sys_start_timer(&p_scb->act_timer, BTA_AG_SVC_TOUT_EVT, p_bta_ag_cfg->conn_tout); } else { /* else service level conn is open */ bta_ag_svc_conn_open(p_scb, p_data); } }
/******************************************************************************* ** ** Function bta_ag_scb_alloc ** ** Description Allocate an AG service control block. ** ** ** Returns pointer to the scb, or NULL if none could be allocated. ** *******************************************************************************/ static tBTA_AG_SCB *bta_ag_scb_alloc(void) { tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0]; int i; for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) { if (!p_scb->in_use) { /* initialize variables */ p_scb->in_use = TRUE; p_scb->sco_idx = BTM_INVALID_SCO_INDEX; /* set up timers */ p_scb->act_timer.param = (UINT32) p_scb; p_scb->act_timer.p_cback = bta_ag_timer_cback; APPL_TRACE_DEBUG1("bta_ag_scb_alloc %d", bta_ag_scb_to_idx(p_scb)); break; } } if (i == BTA_AG_NUM_SCB) { /* out of scbs */ p_scb = NULL; APPL_TRACE_WARNING0("Out of ag scbs"); } return p_scb; }
/******************************************************************************* ** ** Function bta_ag_rfc_do_close ** ** Description Close RFCOMM connection. ** ** ** Returns void ** *******************************************************************************/ void bta_ag_rfc_do_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) { tBTA_AG_RFC *p_buf; UNUSED(p_data); if (p_scb->conn_handle) { RFCOMM_RemoveConnection(p_scb->conn_handle); } else { /* Close API was called while AG is in Opening state. */ /* Need to trigger the state machine to send callback to the app */ /* and move back to INIT state. */ if ((p_buf = (tBTA_AG_RFC *) GKI_getbuf(sizeof(tBTA_AG_RFC))) != NULL) { p_buf->hdr.event = BTA_AG_RFC_CLOSE_EVT; p_buf->hdr.layer_specific = bta_ag_scb_to_idx(p_scb); bta_sys_sendmsg(p_buf); } /* Cancel SDP if it had been started. */ /* if(p_scb->p_disc_db) { (void)SDP_CancelServiceSearch (p_scb->p_disc_db); } */ } }
/******************************************************************************* ** ** Function bta_ag_start_servers ** ** Description Setup RFCOMM servers for use by AG. ** ** ** Returns void ** *******************************************************************************/ void bta_ag_start_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services) { int i; int bta_ag_port_status; services >>= BTA_HSP_SERVICE_ID; for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) { /* if service is set in mask */ if (services & 1) { BTM_SetSecurityLevel(FALSE, "", bta_ag_sec_id[i], p_scb->serv_sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, bta_ag_cb.profile[i].scn); bta_ag_port_status = RFCOMM_CreateConnection(bta_ag_uuid[i], bta_ag_cb.profile[i].scn, TRUE, BTA_AG_MTU, (UINT8 *) bd_addr_any, &(p_scb->serv_handle[i]), bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]); if( bta_ag_port_status == PORT_SUCCESS ) { bta_ag_setup_port(p_scb, p_scb->serv_handle[i]); } else { /* TODO: CR#137125 to handle to error properly */ APPL_TRACE_DEBUG("bta_ag_start_servers: RFCOMM_CreateConnection returned error:%d", bta_ag_port_status); } } } }
/******************************************************************************* ** ** Function bta_ag_scb_alloc ** ** Description Allocate an AG service control block. ** ** ** Returns pointer to the scb, or NULL if none could be allocated. ** *******************************************************************************/ static tBTA_AG_SCB *bta_ag_scb_alloc(void) { tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0]; int i; for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) { if (!p_scb->in_use) { /* initialize variables */ p_scb->in_use = TRUE; p_scb->sco_idx = BTM_INVALID_SCO_INDEX; #if (BTM_WBS_INCLUDED == TRUE ) p_scb->codec_updated = FALSE; #endif /* set up timers */ p_scb->act_timer.param = (UINT32) p_scb; p_scb->act_timer.p_cback = bta_ag_timer_cback; #if (BTM_WBS_INCLUDED == TRUE) /* set eSCO mSBC setting to T2 as the preferred */ p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2; #endif APPL_TRACE_DEBUG("bta_ag_scb_alloc %d", bta_ag_scb_to_idx(p_scb)); break; } } if (i == BTA_AG_NUM_SCB) { /* out of scbs */ p_scb = NULL; APPL_TRACE_WARNING("Out of ag scbs"); } return p_scb; }
/******************************************************************************* ** ** Function bta_ag_svc_conn_open ** ** Description Service level connection opened ** ** ** Returns void ** *******************************************************************************/ void bta_ag_svc_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) { tBTA_AG_CONN evt; UNUSED(p_data); if (!p_scb->svc_conn) { /* set state variable */ p_scb->svc_conn = TRUE; /* Clear AT+BIA mask from previous SLC if any. */ p_scb->bia_masked_out = 0; /* stop timer */ bta_sys_stop_timer(&p_scb->act_timer); /* call callback */ evt.hdr.handle = bta_ag_scb_to_idx(p_scb); evt.hdr.app_id = p_scb->app_id; evt.peer_feat = p_scb->peer_features; bdcpy(evt.bd_addr, p_scb->peer_addr); #if (BTM_WBS_INCLUDED == TRUE ) evt.peer_codec = p_scb->peer_codecs; #endif if ((p_scb->call_ind != BTA_AG_CALL_INACTIVE) || (p_scb->callsetup_ind != BTA_AG_CALLSETUP_NONE)) { bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); } (*bta_ag_cb.p_cback)(BTA_AG_CONN_EVT, (tBTA_AG *) &evt); } }
/******************************************************************************* ** ** Function bta_ag_rfc_do_close ** ** Description Close RFCOMM connection. ** ** ** Returns void ** *******************************************************************************/ void bta_ag_rfc_do_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) { tBTA_AG_RFC *p_buf; UNUSED(p_data); if (p_scb->conn_handle) { RFCOMM_RemoveConnection(p_scb->conn_handle); } else { /* Close API was called while AG is in Opening state. */ /* Need to trigger the state machine to send callback to the app */ /* and move back to INIT state. */ if ((p_buf = (tBTA_AG_RFC *) GKI_getbuf(sizeof(tBTA_AG_RFC))) != NULL) { p_buf->hdr.event = BTA_AG_RFC_CLOSE_EVT; p_buf->hdr.layer_specific = bta_ag_scb_to_idx(p_scb); bta_sys_sendmsg(p_buf); } /* Cancel SDP if it had been started. */ /* if(p_scb->p_disc_db) { (void)SDP_CancelServiceSearch (p_scb->p_disc_db); } */ } #ifdef _WIN32_WCE { /* Windows versions of RFCOMM does NOT generate a closed callback when we close */ tPORT_CALLBACK *rfc_mgmt_cback = bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]; if (rfc_mgmt_cback) { (rfc_mgmt_cback)(PORT_CLOSED, p_scb->conn_handle); } } #endif }
/******************************************************************************* ** ** Function bta_ag_rcvd_slc_ready ** ** Description Handles SLC ready call-in in case of pass-through mode. ** ** Returns void ** *******************************************************************************/ void bta_ag_rcvd_slc_ready(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) { UNUSED(p_data); APPL_TRACE_DEBUG("bta_ag_rcvd_slc_ready: handle = %d", bta_ag_scb_to_idx(p_scb)); if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH) { /* In pass-through mode, BTA knows that SLC is ready only through call-in. */ bta_ag_svc_conn_open(p_scb, NULL); } }
/******************************************************************************* ** ** Function bta_ag_timer_cback ** ** Description AG timer callback. ** ** ** Returns void ** *******************************************************************************/ static void bta_ag_timer_cback(void *p) { BT_HDR *p_buf; TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *) p; if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) { p_buf->event = p_tle->event; p_buf->layer_specific = bta_ag_scb_to_idx((tBTA_AG_SCB *) p_tle->param); bta_sys_sendmsg(p_buf); } }
/******************************************************************************* ** ** Function bta_ag_setup_port ** ** Description Setup RFCOMM port for use by AG. ** ** ** Returns void ** *******************************************************************************/ void bta_ag_setup_port(tBTA_AG_SCB *p_scb, UINT16 handle) { UINT16 i = bta_ag_scb_to_idx(p_scb) - 1; /* set up data callback if using pass through mode */ if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH) { PORT_SetDataCallback(handle, bta_ag_data_cback_tbl[i]); } PORT_SetEventMask(handle, BTA_AG_PORT_EV_MASK); PORT_SetEventCallback(handle, bta_ag_port_cback_tbl[i]); }
/******************************************************************************* ** ** Function bta_ag_rfc_do_open ** ** Description Open an RFCOMM connection to the peer device. ** ** ** Returns void ** *******************************************************************************/ void bta_ag_rfc_do_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) { BTM_SetSecurityLevel(TRUE, "", bta_ag_sec_id[p_scb->conn_service], p_scb->cli_sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, p_scb->peer_scn); if (RFCOMM_CreateConnection(bta_ag_uuid[p_scb->conn_service], p_scb->peer_scn, FALSE, BTA_AG_MTU, p_scb->peer_addr, &(p_scb->conn_handle), bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]) == PORT_SUCCESS) { bta_ag_setup_port(p_scb, p_scb->conn_handle); APPL_TRACE_DEBUG("bta_ag_rfc_do_open : conn_handle = %d", p_scb->conn_handle); } /* RFCOMM create connection failed; send ourselves RFCOMM close event */ else { bta_ag_sm_execute(p_scb, BTA_AG_RFC_CLOSE_EVT, p_data); } }
/******************************************************************************* ** ** Function bta_ag_resume_open ** ** Description Resume opening process. ** ** ** Returns void ** *******************************************************************************/ void bta_ag_resume_open (tBTA_AG_SCB *p_scb) { if (p_scb) { APPL_TRACE_DEBUG ("bta_ag_resume_open, Handle(%d)", bta_ag_scb_to_idx(p_scb)); /* resume opening process. */ if (p_scb->state == BTA_AG_INIT_ST) { p_scb->state = BTA_AG_OPENING_ST; bta_ag_start_open (p_scb, NULL); } } else { APPL_TRACE_ERROR ("bta_ag_resume_open, Null p_scb"); } }
/******************************************************************************* ** ** Function bta_ag_cback_open ** ** Description Send open callback event to application. ** ** ** Returns void ** *******************************************************************************/ static void bta_ag_cback_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data, tBTA_AG_STATUS status) { tBTA_AG_OPEN open; /* call app callback with open event */ open.hdr.handle = bta_ag_scb_to_idx(p_scb); open.hdr.app_id = p_scb->app_id; open.status = status; open.service_id = bta_ag_svc_id[p_scb->conn_service]; if(p_data) { /* if p_data is provided then we need to pick the bd address from the open api structure */ bdcpy(open.bd_addr, p_data->api_open.bd_addr); } else { bdcpy(open.bd_addr, p_scb->peer_addr); } (*bta_ag_cb.p_cback)(BTA_AG_OPEN_EVT, (tBTA_AG *) &open); }
/******************************************************************************* ** ** Function bta_ag_setcodec ** ** Description Handle API SetCodec ** ** ** Returns void ** *******************************************************************************/ void bta_ag_setcodec(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) { #if (BTM_WBS_INCLUDED == TRUE ) tBTA_AG_PEER_CODEC codec_type = p_data->api_setcodec.codec; tBTA_AG_VAL val; val.hdr.handle = bta_ag_scb_to_idx(p_scb); val.hdr.app_id = p_scb->app_id; bdcpy(val.bd_addr, p_scb->peer_addr); /* Check if the requested codec type is valid */ if((codec_type != BTA_AG_CODEC_NONE) && (codec_type != BTA_AG_CODEC_CVSD) && (codec_type != BTA_AG_CODEC_MSBC)) { val.num = codec_type; val.hdr.status = BTA_AG_FAIL_RESOURCES; APPL_TRACE_ERROR("bta_ag_setcodec error: unsupported codec type %d", codec_type); (*bta_ag_cb.p_cback)(BTA_AG_WBS_EVT, (tBTA_AG *) &val); return; } if((p_scb->peer_codecs & codec_type) || (codec_type == BTA_AG_CODEC_NONE) || (codec_type == BTA_AG_CODEC_CVSD)) { p_scb->sco_codec = codec_type; p_scb->codec_updated = TRUE; val.num = codec_type; val.hdr.status = BTA_AG_SUCCESS; APPL_TRACE_DEBUG("bta_ag_setcodec: Updated codec type %d", codec_type); } else { val.num = codec_type; val.hdr.status = BTA_AG_FAIL_RESOURCES; APPL_TRACE_ERROR("bta_ag_setcodec error: unsupported codec type %d", codec_type); } (*bta_ag_cb.p_cback)(BTA_AG_WBS_EVT, (tBTA_AG *) &val); #endif }
/******************************************************************************* ** ** Function bta_ag_register ** ** Description This function initializes values of the AG cb and sets up ** the SDP record for the services. ** ** ** Returns void ** *******************************************************************************/ void bta_ag_register(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) { tBTA_AG_REGISTER reg; /* initialize control block */ p_scb->reg_services = p_data->api_register.services; p_scb->serv_sec_mask = p_data->api_register.sec_mask; p_scb->features = p_data->api_register.features; p_scb->app_id = p_data->api_register.app_id; /* create SDP records */ bta_ag_create_records(p_scb, p_data); /* start RFCOMM servers */ bta_ag_start_servers(p_scb, p_scb->reg_services); /* call app callback with register event */ reg.hdr.handle = bta_ag_scb_to_idx(p_scb); reg.hdr.app_id = p_scb->app_id; reg.status = BTA_AG_SUCCESS; (*bta_ag_cb.p_cback)(BTA_AG_REGISTER_EVT, (tBTA_AG *) ®); }
/******************************************************************************* ** ** Function bta_ag_scb_dealloc ** ** Description Deallocate a service control block. ** ** ** Returns void ** *******************************************************************************/ void bta_ag_scb_dealloc(tBTA_AG_SCB *p_scb) { UINT8 idx; BOOLEAN allocated = FALSE; APPL_TRACE_DEBUG("bta_ag_scb_dealloc %d", bta_ag_scb_to_idx(p_scb)); /* stop timers */ bta_sys_stop_timer(&p_scb->act_timer); #if (BTM_WBS_INCLUDED == TRUE) bta_sys_stop_timer(&p_scb->cn_timer); #endif bta_sys_stop_timer(&p_scb->colli_timer); /* initialize control block */ memset(p_scb, 0, sizeof(tBTA_AG_SCB)); p_scb->sco_idx = BTM_INVALID_SCO_INDEX; /* If all scbs are deallocated, callback with disable event */ if (!bta_sys_is_register (BTA_ID_AG)) { for (idx = 0; idx < BTA_AG_NUM_SCB; idx++) { if (bta_ag_cb.scb[idx].in_use) { allocated = TRUE; break; } } if (!allocated) { (*bta_ag_cb.p_cback)(BTA_AG_DISABLE_EVT, NULL); } } }
/******************************************************************************* ** ** Function bta_ag_do_disc ** ** Description Do service discovery. ** ** ** Returns void ** *******************************************************************************/ void bta_ag_do_disc(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service) { tSDP_UUID uuid_list[2]; UINT16 num_uuid = 1; UINT16 attr_list[4]; UINT8 num_attr; BOOLEAN db_inited = FALSE; /* HFP initiator; get proto list and features */ if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_INT) { attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST; attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST; attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST; attr_list[3] = ATTR_ID_SUPPORTED_FEATURES; num_attr = 4; uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE; } /* HFP acceptor; get features */ else if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_ACP) { attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST; attr_list[1] = ATTR_ID_BT_PROFILE_DESC_LIST; attr_list[2] = ATTR_ID_SUPPORTED_FEATURES; num_attr = 3; uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE; } /* HSP initiator; get proto list */ else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT) { attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST; attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST; attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST; attr_list[3] = ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL; num_attr = 4; uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HEADSET; /* Legacy from HSP v1.0 */ if (p_scb->hsp_version >= HSP_VERSION_1_2) { uuid_list[1].uu.uuid16 = UUID_SERVCLASS_HEADSET_HS; num_uuid = 2; } } /* HSP acceptor; no discovery */ else { return; } /* allocate buffer for sdp database */ p_scb->p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_AG_DISC_BUF_SIZE); if(p_scb->p_disc_db) { /* set up service discovery database; attr happens to be attr_list len */ uuid_list[0].len = LEN_UUID_16; uuid_list[1].len = LEN_UUID_16; db_inited = SDP_InitDiscoveryDb(p_scb->p_disc_db, BTA_AG_DISC_BUF_SIZE, num_uuid, uuid_list, num_attr, attr_list); } if(db_inited) { /*Service discovery not initiated */ db_inited = SDP_ServiceSearchAttributeRequest(p_scb->peer_addr, p_scb->p_disc_db, bta_ag_sdp_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]); } if(!db_inited) { /*free discover db */ bta_ag_free_db(p_scb, NULL); /* sent failed event */ bta_ag_sm_execute(p_scb, BTA_AG_DISC_FAIL_EVT, NULL); } }
/******************************************************************************* ** ** Function bta_ag_rfc_close ** ** Description RFCOMM connection closed. ** ** ** Returns void ** *******************************************************************************/ void bta_ag_rfc_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data) { tBTA_AG_CLOSE close; tBTA_SERVICE_MASK services; int i, num_active_conn = 0; UNUSED(p_data); #ifdef _WIN32_WCE /* The BTE RFCOMM automatically removes the connection when closed, but BTW does not */ if (p_scb->conn_handle != 0) RFCOMM_RemoveConnection (p_scb->conn_handle); #endif /* reinitialize stuff */ p_scb->conn_service = 0; p_scb->peer_features = 0; #if (BTM_WBS_INCLUDED == TRUE ) p_scb->peer_codecs = BTA_AG_CODEC_NONE; p_scb->sco_codec = BTA_AG_CODEC_NONE; /* Clear these flags upon SLC teardown */ p_scb->codec_updated = FALSE; p_scb->codec_fallback = FALSE; p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2; #endif p_scb->role = 0; p_scb->post_sco = BTA_AG_POST_SCO_NONE; p_scb->svc_conn = FALSE; p_scb->hsp_version = HSP_VERSION_1_2; bta_ag_at_reinit(&p_scb->at_cb); /* stop timers */ bta_sys_stop_timer(&p_scb->act_timer); #if (BTM_WBS_INCLUDED == TRUE) bta_sys_stop_timer(&p_scb->cn_timer); #endif close.hdr.handle = bta_ag_scb_to_idx(p_scb); close.hdr.app_id = p_scb->app_id; bdcpy(close.bd_addr, p_scb->peer_addr); bta_sys_conn_close(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); /* call close call-out */ bta_ag_co_data_close(close.hdr.handle); /* call close cback */ (*bta_ag_cb.p_cback)(BTA_AG_CLOSE_EVT, (tBTA_AG *) &close); /* if not deregistering (deallocating) reopen registered servers */ if (p_scb->dealloc == FALSE) { /* Clear peer bd_addr so instance can be reused */ bdcpy(p_scb->peer_addr, bd_addr_null); /* start only unopened server */ services = p_scb->reg_services; for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++) { if(p_scb->serv_handle[i]) services &= ~((tBTA_SERVICE_MASK)1 << (BTA_HSP_SERVICE_ID + i)); } bta_ag_start_servers(p_scb, services); p_scb->conn_handle = 0; /* Make sure SCO state is BTA_AG_SCO_SHUTDOWN_ST */ bta_ag_sco_shutdown(p_scb, NULL); /* Check if all the SLCs are down */ for (i = 0; i < BTA_AG_NUM_SCB; i++) { if (bta_ag_cb.scb[i].in_use && bta_ag_cb.scb[i].svc_conn) num_active_conn++; } if(!num_active_conn) { bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); } } /* else close port and deallocate scb */ else { RFCOMM_RemoveServer(p_scb->conn_handle); bta_ag_scb_dealloc(p_scb); } }