/**************************************************************************** NAME sinkHangUpCall DESCRIPTION Hang up the call from the device. RETURNS void */ void sinkHangUpCall( void ) { /* Determine which is the current active call */ hfp_link_priority priority = hfp_invalid_link; hfp_call_state call_state; /* Get profile if AG with audio, also ensure AG is actually in a call, otherwise try other methods */ if((theSink.routed_audio)&&(HfpLinkGetCallState(HfpLinkPriorityFromAudioSink(theSink.routed_audio), &call_state)&& (call_state))) priority = HfpLinkPriorityFromAudioSink(theSink.routed_audio); /* No audio so use AG state */ if(!priority) priority = HfpLinkPriorityFromCallState(hfp_call_state_active); /* No active call, check for an outgoing call to terminate */ if(!priority) priority = HfpLinkPriorityFromCallState(hfp_call_state_outgoing); /* No active/outgoing calls, check for TWC state */ if(!priority) priority = HfpLinkPriorityWithActiveCall(FALSE); /* no active calls but still a held call on the phone */ if(!priority) priority = HfpLinkPriorityFromCallState(hfp_call_state_held_remaining); /* If match found */ if(priority && HfpLinkGetCallState(priority, &call_state)) { switch(call_state) { case hfp_call_state_twc_incoming: case hfp_call_state_twc_outgoing: case hfp_call_state_held_active: case hfp_call_state_multiparty: CM_DEBUG(("CM: HangUp TWC active Call on AG%x\n",priority)) ; HfpCallHoldActionRequest(priority, hfp_chld_release_active_accept_other, 0); break; case hfp_call_state_held_remaining: CM_DEBUG(("CM: HangUp TWC held Call on AG%x\n",priority)) ; HfpCallHoldActionRequest(priority, hfp_chld_release_held_reject_waiting, 0); break; default: /* Terminate call using AT+CHUP */ CM_DEBUG(("CM: HangUp Call on AG%x\n",priority)) ; HfpCallTerminateRequest(priority); break; } } }
/**************************************************************************** NAME sinkCheckForAudioTransfer DESCRIPTION checks on connection for an audio connction and performs a transfer if not present RETURNS void */ void sinkCheckForAudioTransfer ( void ) { sinkState lState = stateManagerGetState() ; AUD_DEBUG(("AUD: Tx[%d] [%x]\n", lState , (int)theSink.routed_audio)) ; switch (lState) { case deviceIncomingCallEstablish : case deviceThreeWayCallWaiting : case deviceThreeWayCallOnHold : case deviceThreeWayMulticall : case deviceIncomingCallOnHold : case deviceActiveCallNoSCO : { Sink sink; hfp_call_state state; hfp_link_priority priority = hfp_invalid_link; /* check call state and sink of AG1 */ if((HfpLinkGetCallState(hfp_primary_link, &state))&&(state == hfp_call_state_active)&& (HfpLinkGetAudioSink(hfp_primary_link, &sink))&&(!sink)) { priority = hfp_primary_link; } /* or check call state and sink of AG2 */ else if((HfpLinkGetCallState(hfp_secondary_link, &state))&&(state == hfp_call_state_active)&& (HfpLinkGetAudioSink(hfp_secondary_link, &sink))&&(!sink)) { priority = hfp_secondary_link; } /* if call found with no audio */ if (priority) { hfp_audio_params * audio_params = NULL; HfpAudioTransferRequest(priority, hfp_audio_to_hfp , theSink.HFP_supp_features.packet_types, audio_params ); } } break ; default: break; } }
/**************************************************************************** NAME sinkRejectHeldIncomingCall DESCRIPTION looks for a held incoming call and performs the twc reject held incoming call function RETURNS void */ void sinkRejectHeldIncomingCall(void) { hfp_call_state CallState; /* find incoming held call */ if((HfpLinkGetCallState(hfp_primary_link, &CallState))&& (CallState == hfp_call_state_incoming_held)) { CM_DEBUG(("MAIN: Hold incoming Call on AG1\n")) ; HfpResponseHoldActionRequest(hfp_primary_link, hfp_reject_held_incoming_call); } else if((HfpLinkGetCallState(hfp_secondary_link, &CallState))&& (CallState == hfp_call_state_incoming_held)) { CM_DEBUG(("MAIN: Hold incoming Call on AG2\n")) ; HfpResponseHoldActionRequest(hfp_secondary_link, hfp_reject_held_incoming_call); } }
/**************************************************************************** NAME sinkPlaceIncomingCallOnHold DESCRIPTION looks for an incoming call and performs the twc hold incoming call function RETURNS void */ void sinkPlaceIncomingCallOnHold(void) { hfp_call_state CallState; /* find incoming call to hold */ if((HfpLinkGetCallState(hfp_primary_link, &CallState))&& (CallState == hfp_call_state_incoming)) { CM_DEBUG(("MAIN: Hold incoming Call on AG1\n")) ; HfpResponseHoldActionRequest(hfp_primary_link, hfp_hold_incoming_call); } else if((HfpLinkGetCallState(hfp_secondary_link, &CallState))&& (CallState == hfp_call_state_incoming)) { CM_DEBUG(("MAIN: Hold incoming Call on AG2\n")) ; HfpResponseHoldActionRequest(hfp_secondary_link, hfp_hold_incoming_call); } }
/**************************************************************************** NAME audioHandleSyncConnectCfm DESCRIPTION Handle HFP_AUDIO_CONNECT_CFM. This indicates that an incoming sychronous connection has been established RETURNS */ void audioHandleSyncConnectCfm ( const HFP_AUDIO_CONNECT_CFM_T * pCfm ) { uint8 index = PROFILE_INDEX(pCfm->priority); hfp_call_state CallState; /* Get the priority of the other link */ hfp_link_priority other = (pCfm->priority == hfp_primary_link) ? hfp_secondary_link : hfp_primary_link; AUD_DEBUG(("Synchronous Connect Cfm from [%x]:\n", (uint16)pCfm->priority)) ; /* if successful */ if ( pCfm->status == hfp_success) { Sink sink; /* obtain sink for this audio connection */ if(HfpLinkGetSlcSink(pCfm->priority, &sink)) { /* Send our link policy settings for active SCO role */ linkPolicyUseHfpSettings(pCfm->priority, sink); } /* store in individual hfp struct as it may be necessary to disconnect and reconnect audio on a per hfp basis for multipoint multiparty calling */ theSink.profile_data[index].audio.tx_bandwidth= pCfm->tx_bandwidth; theSink.profile_data[index].audio.link_type= pCfm->link_type; theSink.profile_data[index].audio.codec_selected = pCfm->codec; /* Send an event to indicate that a SCO has been opened */ /* this indicates that an audio connection has been successfully created to the AG*/ MessageSend ( &theSink.task , EventSCOLinkOpen , 0 ) ; /* update the audio priority state is this sco a streaming audio sco?, check call state for this ag */ if(HfpLinkGetCallState(pCfm->priority, &CallState)) { /* determine sco priority based on call status */ switch(CallState) { /* no call so this is a steaming audio connection */ case hfp_call_state_idle: setScoPriorityFromHfpPriority(pCfm->priority, sco_streaming_audio); break; /* incoming call so this is an inband ring sco */ case hfp_call_state_incoming: case hfp_call_state_incoming_held: case hfp_call_state_twc_incoming: setScoPriorityFromHfpPriority(pCfm->priority, sco_inband_ring); break; /* active call states so this sco has highest priority */ case hfp_call_state_active: case hfp_call_state_twc_outgoing: /* this audio connection may have been the result of the an audio transfer from the AG and there is already an active call on the other AG, check for this and make this new audio connection held leaving the other routed audio connection intact */ if(getScoPriorityFromHfpPriority(other)==sco_active_call) setScoPriorityFromHfpPriority(pCfm->priority, sco_held_call); else setScoPriorityFromHfpPriority(pCfm->priority, sco_active_call); break; /* an outgoing call sco has highest priority, if there is a call on other AG it needs to be put on hold whilst this outgoing call is made */ case hfp_call_state_outgoing: /* does other AG have active call on it?, if so hold the audio */ if(getScoPriorityFromHfpPriority(other)==sco_active_call) setScoPriorityFromHfpPriority(other, sco_held_call); /* make the outgoing call audio the one that gets routed */ setScoPriorityFromHfpPriority(pCfm->priority, sco_active_call); break; /* this call is held so the sco is put to on hold priority which is lower than active call but higher than streaming */ case hfp_call_state_held_active: case hfp_call_state_held_remaining: if(theSink.routed_audio) setScoPriorityFromHfpPriority(pCfm->priority, sco_held_call); break; /* non covered states treat as highest priority sco connection */ default: setScoPriorityFromHfpPriority(pCfm->priority, sco_active_call); break; } } /* route the appropriate audio connection */ audioHandleRouting(audio_source_none); /*change the active call state if necessary*/ if ((stateManagerGetState() == deviceActiveCallNoSCO) ) { stateManagerEnterActiveCallState(); } #ifdef DEBUG_AUDIO switch (pCfm->link_type) { case (sync_link_unknown): AUD_DEBUG(("AUD: Link = ?\n")) ; break ; case (sync_link_sco) : AUD_DEBUG(("AUD: Link = SCO\n")) ; break; case sync_link_esco: AUD_DEBUG(("AUD: Link = eSCO\n")) ; break ; } #endif } else { AUD_DEBUG(("Synchronous Connect Cfm: FAILED\n")) ; } AUD_DEBUG(("AUD : Sco->\n")) ; }