/**************************************************************************** Outcome of the RFCOMM connect request or response. */ static void aghfpHandleRfcommConnectCfm(AGHFP *aghfp, rfcomm_connect_status status) { /* Check the status of the rfcomm connect cfm */ if (status == rfcomm_connect_success) { /* RFCOMM connection is up! Check which profile is supported by this task */ if (supportedProfileIsHsp(aghfp->supported_profile)) { /* HSP supported - SLC is up so tell the app */ aghfpSendSlcConnectCfmToApp(aghfp_connect_success, aghfp); } else if (supportedProfileIsHfp(aghfp->supported_profile)) { /* HFP supported - RFCOMM is up, so just wait for HF to send us some AT commends */ } else { /* This should never happen */ AGHFP_DEBUG_PANIC(("Unhandled profile type 0x%x\n", aghfp->supported_profile)); } /* Check for data in the buffer */ aghfpHandleReceivedData(aghfp, StreamSourceFromSink(aghfp->rfcomm_sink)); } else { /* RFCOMM connect failed - Tell the app. */ aghfpSendSlcConnectCfmToApp(convertRfcommConnectStatus(status), aghfp); } aghfp->rfcomm_lock = FALSE; }
/**************************************************************************** Register the service record corresponding to the specified profile */ void aghfpRegisterServiceRecord(AGHFP *aghfp, aghfp_profile profile, uint8 chan) { uint16 length; uint8 *service_record = 0; if (supportedProfileIsHsp(profile)) { /* Create a copy of the service record that we can modify */ length = sizeof(aghfp_hsp_service_record); service_record = (uint8 *)PanicUnlessMalloc(length); memcpy(service_record, aghfp_hsp_service_record, length); } else if (supportedProfileIsHfp(profile)) { /* Create a copy of the service record that we can modify */ length = sizeof(aghfp_hfp_service_record); service_record = (uint8 *)PanicUnlessMalloc(length); memcpy(service_record, aghfp_hfp_service_record, length); /* Insert the supported features into the service record */ if (!insertHfpSupportedFeatures(service_record, service_record + length, aghfp->supported_profile)) { /* Failed to insert the supported features into the service record */ MAKE_AGHFP_MESSAGE(AGHFP_INTERNAL_SDP_REGISTER_CFM); message->status = aghfp_fail; MessageSend(&aghfp->task, AGHFP_INTERNAL_SDP_REGISTER_CFM, message); /* Free the allocated memory */ free(service_record); return; } } else { /* Unknown profile, send an error */ MAKE_AGHFP_MESSAGE(AGHFP_INTERNAL_SDP_REGISTER_CFM); message->status = aghfp_fail; MessageSend(&aghfp->task, AGHFP_INTERNAL_SDP_REGISTER_CFM, message); return; } if (!insertRfcommServerChannel(service_record, service_record + length, chan)) { /* If we fail to insert the rfcomm channel return an error to the app */ MAKE_AGHFP_MESSAGE(AGHFP_INTERNAL_SDP_REGISTER_CFM); message->status = aghfp_fail; MessageSend(&aghfp->task, AGHFP_INTERNAL_SDP_REGISTER_CFM, message); /* Free the allocated memory */ free(service_record); } else { /* Send the service record to the connection lib to be registered with BlueStack */ ConnectionRegisterServiceRecord(&aghfp->task, length, service_record); } }
static bool usingHsp (AGHFP *aghfp) { if ( supportedProfileIsHsp(aghfp->supported_profile) ) { return TRUE; } return FALSE; }
/**************************************************************************** NAME aghfpHandleSyncDisconnectInd DESCRIPTION Audio (Synchronous) connection has been disconnected RETURNS void */ void aghfpHandleSyncDisconnectInd(AGHFP *aghfp, const CL_DM_SYNC_DISCONNECT_IND_T *ind) { /* If it's not our sink, silently ignore this indication */ if ( ind->audio_sink == aghfp->audio_sink ) { if ( aghfp->audio_connection_state==aghfp_audio_connected || aghfp->audio_connection_state==aghfp_audio_disconnecting ) { /* Inform the app */ if (ind->status == hci_success) { resetAudioParams(aghfp); aghfp->audio_connection_state = aghfp_audio_disconnected; if ( aghfpCallManagerActiveNotComplete(aghfp) ) { aghfpManageCall(aghfp, CallEventAudioDisconnected, CallFlagSuccess); } else { sendAudioDisconnectIndToApp(aghfp, aghfp_success); } } else { /* Disconnect has failed, we are still connected - inform the app */ if ( aghfpCallManagerActiveNotComplete(aghfp) ) { aghfpManageCall(aghfp, CallEventAudioDisconnected, CallFlagFail); } else { sendAudioDisconnectIndToApp(aghfp, aghfp_fail); } } /* Update the local state. Check current state in case SLC disconnect has beaten the SCO/eSCO disconnect */ if (!aghfpCallManagerActive(aghfp) && supportedProfileIsHsp(aghfp->supported_profile) && (aghfp->state != aghfp_ready)) { aghfpSetState(aghfp, aghfp_slc_connected); } } else { /* Should never get here */ AGHFP_DEBUG(("aghfpHandleSyncDisconnectInd invalid state %d\n",aghfp->audio_connection_state)); } } }
/**************************************************************************** NAME hfpHandleRfcommConnectCfm DESCRIPTION Outcome of the RFCOMM connect request or response. RETURNS void */ void hfpHandleRfcommConnectCfm(HFP *hfp, const CL_RFCOMM_CONNECT_CFM_T *cfm) { /* Check the status of the rfcomm connect cfm */ if (cfm->status == rfcomm_connect_success) { /* Store the sink */ hfp->sink = cfm->sink; /* RFCOMM connection is up! Check which profile is supported by this task */ if (supportedProfileIsHsp(hfp->hfpSupportedProfile)) { hfp->agSupportedProfile = hfp_headset_profile; /* HSP supported - SLC is up so tell the app */ hfpSendSlcConnectCfmToApp(hfp_connect_success, hfp); } else if (supportedProfileIsHfp(hfp->hfpSupportedProfile)) { /* Initiate SLC establishment */ MessageSend(&hfp->task, HFP_INTERNAL_AT_BRSF_REQ, 0); } else { /* This should never happen */ HFP_DEBUG(("Unhandled profile type 0x%x\n", hfp->hfpSupportedProfile)); } /* Check for data in the buffer */ hfpHandleReceivedData(hfp, StreamSourceFromSink(cfm->sink)); } else { /* RFCOMM connect failed - Tell the app. */ hfpSendSlcConnectCfmToApp(convertRfcommConnectStatus(cfm->status), hfp); } /* Free the rfcomm lock */ hfp->rfcomm_lock = FALSE; }
/**************************************************************************** Initiate a service search to get the rfcomm server channel of the required service on the remote device. We need this before we can initiate a service level connection. */ void aghfpGetProfileServerChannel(AGHFP *aghfp, const bdaddr *addr) { uint16 sp_len; uint8 *sp_ptr; sp_len = 0; sp_ptr = 0; /* Check which profile we support so we can device which search to use */ if (supportedProfileIsHsp(aghfp->supported_profile)) { /* This task supports the HSP */ sp_ptr = (uint8 *) HspServiceRequest; sp_len = sizeof(HspServiceRequest); } else if (supportedProfileIsHfp(aghfp->supported_profile)) { /* This task supports the HFP */ sp_ptr = (uint8 *)HfpServiceRequest; sp_len = sizeof(HfpServiceRequest); } else { /* This should never happen */ Panic(); } /* Issue the search request to the connection lib. The max number of attribute bytes is set to an arbitrary number, however the aim is to set it to a value so that if the remote end returns this many bytes we still have a block big enough to copy the data into. */ ConnectionSdpServiceSearchAttributeRequest( &aghfp->task, addr, 0x32, sp_len, sp_ptr, sizeof(protocolAttributeRequest), protocolAttributeRequest); }
/**************************************************************************** NAME hfpRegisterServiceRecord DESCRIPTION Register the service record corresponding to the specified service RETURNS void */ void hfpRegisterServiceRecord(hfp_service_data* service) { /* Ignore this silently if service is already registered */ if(service->sdp_record_handle == 0 && !hfpGetVisibleServiceFromProfile(service->profile)) { if(!theHfp->busy_channel) { const uint8* service_record = NULL; uint16 size_service_record = 0; theHfp->busy_channel = service->rfc_server_channel; /* Create a copy of the service record that we can modify */ if (supportedProfileIsHsp(service->profile)) { size_service_record = sizeof(hsp_service_record); /* If RFC channel matches use a constant record */ if(service->rfc_server_channel == HSP_DEFAULT_CHANNEL) service_record = hsp_service_record; else if(service->rfc_server_channel == HSP_DEFAULT_CHANNEL_2) service_record = hsp_service_record_2; else service_record = hfpSdpHspRecordCreate(service->rfc_server_channel); } else if (supportedProfileIsHfp(service->profile)) { uint16 features = BRSF_BITMAP_TO_SDP_BITMAP(theHfp->hf_supported_features); uint16 version = supportedProfileIsHfp106(service->profile) ? HFP_1_6_VERSION_NUMBER : HFP_1_5_VERSION_NUMBER; size_service_record = sizeof(hfp_service_record); /* If features, version and RFC channel match use a constant record */ if(features == HFP_DEFAULT_FEATURES && version == HFP_DEFAULT_VERSION) { if(service->rfc_server_channel == HFP_DEFAULT_CHANNEL) service_record = hfp_service_record; else if(service->rfc_server_channel == HFP_DEFAULT_CHANNEL_2) service_record = hfp_service_record_2; } /* Something didn't match, use a dynamic record */ if(!service_record) service_record = hfpSdpRecordCreate(service->rfc_server_channel, version, features); } else { /* If this is going to fail it will be during init, send init fail */ hfpInitSdpRegisterComplete(hfp_fail); return; } /* Send the service record to the connection lib to be registered with BlueStack */ ConnectionRegisterServiceRecord(&theHfp->task, size_service_record, service_record); } else { /* Queue registering this service */ MAKE_HFP_MESSAGE(HFP_INTERNAL_SDP_REGISTER_REQ); message->service = service; MessageSendConditionally(&theHfp->task, HFP_INTERNAL_SDP_REGISTER_REQ, message, (uint16*)&theHfp->busy_channel); } } else if(!theHfp->initialised && service == HFP_SERVICE_TOP) { /* Make sure we complete init if we're not registering the top service */ theHfp->busy_channel = service->rfc_server_channel; hfpInitSdpRegisterComplete(hfp_success); } }
/**************************************************************************** NAME hfpRegisterServiceRecord DESCRIPTION Register the service record corresponding to the specified profile RETURNS void */ void hfpRegisterServiceRecord(HFP *hfp) { uint8 *service_record = 0; hfp_profile profile = hfp->hfpSupportedProfile; uint8 chan = hfp->local_rfc_server_channel; if (!hfp->service_record) { if (supportedProfileIsHsp(profile)) { hfp->size_service_record = sizeof(hsp_service_record); hfp->service_record = (uint8 *) hsp_service_record; } else if (supportedProfileIsHfp(profile)) { hfp->size_service_record = sizeof(hfp_service_record); hfp->service_record = (uint8 *) hfp_service_record; } else { /* Unknown profile, send an error */ sendInternalSdpRegisterCfmMessage(hfp, hfp_fail); return; } } /* Create a copy of the service record that we can modify */ service_record = (uint8 *)PanicUnlessMalloc(hfp->size_service_record); memmove(service_record, hfp->service_record, hfp->size_service_record); if (supportedProfileIsHfp(profile)) { /* Insert the supported features into the service record. */ if (!insertHfpSupportedFeatures(service_record, service_record + hfp->size_service_record, hfp->hfpSupportedFeatures)) { /* Failed to insert the supported features into the service record */ sendInternalSdpRegisterCfmMessage(hfp, hfp_fail); /* Free the allocated memory */ free(service_record); return; } /* Insert the profile version number */ if (!insertHfpProfileVersion(service_record, service_record + hfp->size_service_record, profile)) { /* SDP register failed */ sendInternalSdpRegisterCfmMessage(hfp, hfp_fail); /* Free the allocated memory */ free(service_record); return; } } if (!insertRfcommServerChannel(service_record, service_record + hfp->size_service_record, chan)) { /* If we fail to insert the rfcomm channel return an error to the app */ sendInternalSdpRegisterCfmMessage(hfp, hfp_fail); /* Free the allocated memory */ free(service_record); } else { /* Send the service record to the connection lib to be registered with BlueStack */ ConnectionRegisterServiceRecord(&hfp->task, hfp->size_service_record, service_record); } }