/**************************************************************************** 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 sinkAnswerOrRejectCall DESCRIPTION Answer an incoming call from the device RETURNS void */ void sinkAnswerOrRejectCall( bool Action ) { hfp_link_priority priority; /* if the SR plugin is running, disconnect it */ MessageSend ( &theSink.task , EventSysSpeechRecognitionStop , 0 ) ; /* get profile if AG with incoming call */ priority = HfpLinkPriorityFromCallState(hfp_call_state_incoming); CM_DEBUG(("CM: Answer Call on AG%x\n",priority)) ; /* if match found */ if(priority) { /* answer call */ HfpCallAnswerRequest(priority, Action); theSink.profile_data[PROFILE_INDEX(priority)].status.local_call_action = TRUE; } /*terminate the ring tone*/ ToneTerminate(); }
/**************************************************************************** NAME sinkHandleSlcConnectCfm DESCRIPTION Confirmation that the SLC has been established (or not). RETURNS void */ bool sinkHandleSlcConnectCfm( const HFP_SLC_CONNECT_CFM_T *cfm ) { sink_attributes attributes; bool lResult = FALSE; #ifdef ENABLE_PEER inquiry_result_t* connecting_device = inquiryGetConnectingDevice(); #endif deviceManagerGetDefaultAttributes(&attributes, FALSE); (void)deviceManagerGetAttributes(&attributes, &cfm->bd_addr); /* cancel any link loss reminders */ MessageCancelAll(&theSink.task , EventSysLinkLoss ); /* Check the status of the SLC attempt */ if (cfm->status == hfp_connect_success) { SLC_DEBUG(("SLC: ConnCfm - Success\n")) ; lResult = TRUE ; /* update the profile volume level */ theSink.profile_data[PROFILE_INDEX(cfm->priority)].audio.gSMVolumeLevel = attributes.hfp.volume; /* Handle new connection setup */ slcConnectionComplete(cfm->priority, cfm->sink, (bdaddr *)&cfm->bd_addr); /* Handle common setup for new SLC/link loss */ slcConnectionSetup(cfm->priority, cfm->sink, (bdaddr *)&cfm->bd_addr); /* Record the position of the device in the PDL - prevents reconnection later */ theSink.profile_data[PROFILE_INDEX(cfm->priority)].status.list_id = deviceManagerSetPriority((bdaddr *)&cfm->bd_addr); #ifdef ENABLE_PEER /* If RSSI pairing, check inquiry results for A2DP support */ if (theSink.inquiry.action == rssi_pairing) { if ((connecting_device != NULL) && BdaddrIsSame(&connecting_device->bd_addr, &cfm->bd_addr) && (connecting_device->remote_profiles & profile_a2dp)) { attributes.profiles |= sink_a2dp; } } #endif /* Make sure we store this device */ attributes.profiles |= sink_hfp; deviceManagerStoreAttributes(&attributes, &cfm->bd_addr); /* if rssi pairing check to see if need to cancel rssi pairing or not */ if(theSink.inquiry.action == rssi_pairing) { /* if rssi pairing has completed and the device being connected currently doesn't support A2DP, then stop it progressing further */ if(!((theSink.features.PairIfPDLLessThan) && ( ConnectionTrustedDeviceListSize() < theSink.features.PairIfPDLLessThan ))) { #ifdef ENABLE_PEER if(!((connecting_device != NULL) && BdaddrIsSame(&connecting_device->bd_addr, &cfm->bd_addr) && (connecting_device->remote_profiles & profile_a2dp))) #endif { inquiryStop(); } } } /* Disable A2dp link loss management if connected on remote device */ if( theSink.a2dp_link_data && (theSink.a2dp_link_data->connected[a2dp_primary]) && BdaddrIsSame(&cfm->bd_addr, &theSink.a2dp_link_data->bd_addr[a2dp_primary]) ) { A2dpDeviceManageLinkloss(theSink.a2dp_link_data->device_id[a2dp_primary], FALSE); } else if( theSink.a2dp_link_data && (theSink.a2dp_link_data->connected[a2dp_secondary]) && BdaddrIsSame(&cfm->bd_addr, &theSink.a2dp_link_data->bd_addr[a2dp_secondary]) ) { A2dpDeviceManageLinkloss(theSink.a2dp_link_data->device_id[a2dp_secondary], FALSE); } /* Auto answer call if ringing - only answer the incoming call if its on the connecting AG */ if ( (theSink.features.AutoAnswerOnConnect) && (HfpLinkPriorityFromCallState(hfp_call_state_incoming) == cfm->priority) && (stateManagerGetState() < deviceActiveCallSCO) ) { MessageSend (&theSink.task , EventUsrAnswer , 0 ) ; SLC_DEBUG(("SLC: AutoAnswer triggered\n")) ; } } else { SLC_DEBUG(("SLC: ConnCfm - Fail\n")) ; /* a connection timeout will arrive here, need to report fail for multipoint connections also such that a link loss retry will be performed */ if(!stateManagerIsConnected() || theSink.MultipointEnable) { /* Update local state to reflect this */ slcConnectFail(); } } /* if using multipoint and both devices are connected disable connectable */ if((theSink.MultipointEnable) && (deviceManagerNumConnectedDevs() == MAX_MULTIPOINT_CONNECTIONS)) { SLC_DEBUG(("SLC: disable Conn \n" )); MessageCancelAll(&theSink.task, EventSysConnectableTimeout); #ifdef ENABLE_SUBWOOFER if(SwatGetSignallingSink(theSink.rundata->subwoofer.dev_id)) { sinkDisableConnectable(); } #else sinkDisableConnectable(); #endif } SLC_DEBUG(("SLC: Connect A2DP? En=%d att=%d\n",theSink.features.EnableA2dpStreaming,attributes.profiles)) ; /* if the AG supports A2DP profile attempt to connect to it if auto reconnect is enabled */ if ((theSink.features.EnableA2dpStreaming) && ((!cfm->priority)||(cfm->status == hfp_connect_success) || (cfm->status == hfp_connect_sdp_fail) || (cfm->status == hfp_connect_rejected)) && ((slcDetermineConnectAction() & AR_Rssi)||(attributes.profiles & sink_a2dp)) && ((slcDetermineConnectAction() & AR_Rssi)||(stateManagerGetState()!=deviceConnDiscoverable))) { SLC_DEBUG(("SLC: Connecting A2DP Remote %x\n",gSlcData.gSlcConnectRemote)) ; /* attempt connection to device supporting A2DP */ theSink.a2dp_link_data->remote_connection = gSlcData.gSlcConnectRemote; A2dpSignallingConnectRequest((bdaddr *)&cfm->bd_addr); MessageCancelFirst(&theSink.task, EventSysContinueSlcConnectRequest); /* if rssi pairing check to see if need to cancel rssi pairing or not */ if(theSink.inquiry.action == rssi_pairing) { /* if rssi pairing has completed then stop it progressing further */ if(!((theSink.features.PairIfPDLLessThan)&&( ConnectionTrustedDeviceListSize() < theSink.features.PairIfPDLLessThan ))) { #ifdef ENABLE_PEER if(!((connecting_device != NULL) && BdaddrIsSame(&connecting_device->bd_addr, &cfm->bd_addr) && (connecting_device->remote_profiles & profile_a2dp))) #endif { inquiryStop(); } } } } else { /* reset connection via remote ag instead of device flag */ gSlcData.gSlcConnectRemote = FALSE; } #ifdef ENABLE_MAPC mapcMasConnectRequest((bdaddr *)&cfm->bd_addr); #endif return lResult ; }