/**************************************************************************** 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)); } } }
/* Disconnect an existing audio (Synchronous) connection */ static void audioDisconnectRequest(AGHFP *aghfp) { if ( !aghfpCallManagerActiveNotComplete(aghfp) ) { /* Send a disconnect request to the connection lib */ aghfp->audio_connection_state = aghfp_audio_disconnecting; ConnectionSyncDisconnect(aghfp->audio_sink, hci_error_oetc_user); } else { /* Inform app that call manager is active, setting up or shutting down a call */ sendAudioConnectCfmToApp(aghfp, aghfp_audio_disconnect_call_manager_active, hci_success); } }
/* Handle Codec Connection request from the HF (AT+BCC). This function performs the the actual actions of handling the AT+BCC (once the audio params have been obtained from the app, i.e. after aghfpHandleWbsCodecConReq() and ). */ static void aghfpHandleWbsCodecConReqProcessing(AGHFP *aghfp) { /* Are we supporting WBS */ if (aghfp->use_wbs) { /* OK to initiate WBS Codec Negotiation. */ /* Send OK */ aghfpSendOk(aghfp); /* If we haven't negotiatied a codec we need to do so. If we have, we're gonna go ahead and use it here. */ if (aghfp->use_codec == 0) { /* Start codec negotiation with HF. */ if (aghfpWbsStartCodecNegotiation(aghfp, aghfp_negotiate_audio_at_hf)) { aghfp->audio_connection_state = aghfp_audio_codec_connect; } } else { if (!aghfpCallManagerActiveNotComplete(aghfp)) { MAKE_AGHFP_MESSAGE(AGHFP_INTERNAL_AUDIO_CONNECT_REQ); AGHFP_DEBUG((" Normal Audio Connection\n")); message->audio_params = aghfp->audio_params; message->packet_type = aghfp->audio_packet_type; MessageSend(&aghfp->task, AGHFP_INTERNAL_AUDIO_CONNECT_REQ, message); } else { /* Save the audio packet type for Call Manager */ aghfpStoreAudioParams(aghfp, aghfp->audio_packet_type, &aghfp->audio_params); /* Answer the call again now that the WBS negotiation is complete. */ aghfpManageCall(aghfp, CallEventAnswer, CallFlagOpenAudio); } } } else { /* WBS not supported, send ERROR. */ aghfpSendError(aghfp); } }
void AghfpStartAudioAfterAppCodecNegotiation(AGHFP * aghfp) { if (!aghfpCallManagerActiveNotComplete(aghfp)) { MAKE_AGHFP_MESSAGE(AGHFP_INTERNAL_AUDIO_CONNECT_REQ); AGHFP_DEBUG((" Normal Audio Connection\n")); /* Assume that the audio parameters have been previously stored using aghfpStoreAudioParams() */ message->audio_params = aghfp->audio_params; message->packet_type = aghfp->audio_packet_type; MessageSend(&aghfp->task, AGHFP_INTERNAL_AUDIO_CONNECT_REQ, message); } else { /* Answer the call again now that the WBS negotiation is complete. */ aghfpManageCall(aghfp, CallEventAnswer, CallFlagOpenAudio); } }
/* Attempt to create a new audio (Synchronous) connection */ static void audioConnectRequest(AGHFP *aghfp, sync_pkt_type packet_type, const aghfp_audio_params *audio_params) { if ( !aghfpCallManagerActiveNotComplete(aghfp) ) { if ( aghfpStoreAudioParams(aghfp, packet_type, audio_params) ) { startAudioConnectRequest(aghfp); } else { /* Inform app that one or more parameters were invalid */ sendAudioConnectCfmToApp(aghfp, aghfp_audio_connect_invalid_params, hci_success); } } else { /* Inform app that call manager is active, setting up or shutting down a call */ sendAudioConnectCfmToApp(aghfp, aghfp_audio_connect_call_manager_active, hci_success); } }
/**************************************************************************** NAME aghfpHandleSyncConnectCfm DESCRIPTION Confirmation in response to an audio (SCO/eSCO) open request indicating the outcome of the Synchronous connect attempt. RETURNS void */ void aghfpHandleSyncConnectCfm(AGHFP *aghfp, const CL_DM_SYNC_CONNECT_CFM_T *cfm) { if ( aghfp->audio_connection_state==aghfp_audio_connecting_esco || aghfp->audio_connection_state==aghfp_audio_connecting_sco || aghfp->audio_connection_state==aghfp_audio_accepting ) { /* Informs us of the outcome of the Synchronous connect attempt */ if (cfm->status == hci_success) { /* store the audio parameters */ aghfp->audio_sink = cfm->audio_sink; aghfp->rx_bandwidth = cfm->rx_bandwidth; aghfp->tx_bandwidth = cfm->tx_bandwidth; aghfp->link_type = cfm->link_type; aghfp->audio_connection_state = aghfp_audio_connected; /* Tell the app about this */ if ( aghfpCallManagerActiveNotComplete(aghfp) ) { /* Audio connection request will have come from call manager */ aghfpManageCall(aghfp, CallEventAudioConnected, CallFlagSuccess); } else { /* Audio connection request will have come fom app */ sendAudioConnectCfmToApp(aghfp, aghfp_audio_connect_success, cfm->status); } } else { /* Give up if we are either attempting to accept in incoming connection or error code indicates it is pointless to continue. */ if ( cfm->status<=hci_error_host_timeout || (cfm->status>=hci_error_oetc_user && cfm->status<=hci_error_unknown_lmp_pdu) || aghfp->audio_connection_state==aghfp_audio_accepting ) { aghfp->audio_connection_state = aghfp_audio_disconnected; resetAudioParams(aghfp); /* SCO/eSCO connect failed */ if ( aghfpCallManagerActiveNotComplete(aghfp) ) { /* Audio connection request will have come from call manager */ aghfpManageCall(aghfp, CallEventAudioConnected, CallFlagFail); } else { /* Audio connection request will have come fom app */ sendAudioConnectCfmToApp(aghfp, aghfp_audio_connect_failure, cfm->status); } } else { /* This step failed, move onto next stage of connection attempt */ continueAudioConnectRequest(aghfp); } } } else { /* Should never get here */ AGHFP_DEBUG(("aghfpHandleSyncConnectCfm invalid state %d",aghfp->audio_connection_state)); } }
/* Handle Codec Negotiation resopnse from the HF (AT+BCS) */ void aghfpHandleWbsCodecNegReq(AGHFP *aghfp, uint16 codecUUID16) { sync_pkt_type audio_packet_type = aghfp->audio_packet_type; aghfp_audio_params audio_params = aghfp->audio_params; uint16 codec; /* Codec bitmap used internally */ AGHFP_DEBUG(("aghfpHandleWbsCodecNegReq : ")); /* Translate from codec UUID16 format to internal bitmap. */ codec = WbsUuid16ToCodec((codecs_info*)&(aghfp->codecs_info), codecUUID16); /* Note that one bit should be set in the bitmaps and it must be the same bit for success. */ if(aghfp->use_wbs && (aghfp->use_codec == codec)) { AGHFP_DEBUG(("Starting WB-Speech eSCO\n")); /* Send OK */ aghfpSendOk(aghfp); /* audio_packet_type and audio_params already set to WBS values. */ /* Force connection create. WBS SCO connection are always initiated by the AG. */ if(aghfp->wbs_negotiate_action != aghfp_negotiate_no_audio) { aghfp->wbs_negotiate_action = aghfp_negotiate_audio_at_ag; } } else { AGHFP_DEBUG(("Falling back to request eSCO type\n")); /* send Error */ aghfpSendError(aghfp); /* Reset any saved codecs; Codec Negotiation aborted. */ aghfp->use_codec = 0; /* For normal SCO we only set up the SCO here if the AG initiated the connection. */ if (aghfp->wbs_negotiate_action == aghfp_negotiate_audio_at_ag) { /* Start eSCO Connection */ audio_packet_type = aghfp->audio_packet_type; audio_params = aghfp->audio_params; audio_params.override_wbs = TRUE; } } if (aghfp->wbs_negotiate_action == aghfp_negotiate_audio_at_ag) { /* Start eSCO Connection. We get here if we are setting up a WBS link or an AG initiated normal SCO. */ if (!aghfpCallManagerActiveNotComplete(aghfp)) { MAKE_AGHFP_MESSAGE(AGHFP_INTERNAL_AUDIO_CONNECT_REQ); AGHFP_DEBUG((" Normal Audio Connection\n")); message->audio_params = audio_params; message->packet_type = audio_packet_type; MessageSend(&aghfp->task, AGHFP_INTERNAL_AUDIO_CONNECT_REQ, message); } else { /* Save the audio packet type for Call Manager */ aghfpStoreAudioParams(aghfp, audio_packet_type, &audio_params); /* Answer the call again now that the WBS negotiation is complete. */ aghfpManageCall(aghfp, CallEventAnswer, CallFlagOpenAudio); } } aghfp->wbs_negotiate_action = aghfp_negotiate_undefined; /* Reset flag to ensure it is correct next time */ }