/**************************************************************************** NAME linkPolicyPhonebookAccessComplete DESCRIPTION set the link policy requirements back after phonebook access, based on current device audio state RETURNS void */ void linkPolicyPhonebookAccessComplete(Sink sink) { typed_bdaddr taddr; uint16 DeviceId; uint16 StreamId; uint8 i; bool a2dpSetting = FALSE; /* If device is in the stream a2dp state, use a2dp link policy */ for_all_a2dp(i) { DeviceId = theSink.a2dp_link_data->device_id[i]; StreamId = theSink.a2dp_link_data->stream_id[i]; if( SinkGetBdAddr(sink, &taddr) && BdaddrIsSame(&theSink.a2dp_link_data->bd_addr[i], &taddr.addr) ) { a2dpSetting = TRUE; if(A2dpMediaGetState(DeviceId, StreamId)== a2dp_stream_streaming) linkPolicyUseA2dpSettings(DeviceId, StreamId, A2dpMediaGetSink(DeviceId, StreamId)); else linkPolicyUseHfpSettings(hfp_primary_link, sink); } } /* Otherwise, use hfp link policy */ if(!a2dpSetting) { linkPolicyUseHfpSettings(hfp_primary_link, sink); } }
/**************************************************************************** NAME audioHandleSyncDisconnectInd DESCRIPTION Handle HFP_AUDIO_DISCONNECT_IND. This indicates that an incoming sychronous connection has been disconnected RETURNS */ void audioHandleSyncDisconnectInd ( const HFP_AUDIO_DISCONNECT_IND_T * pInd ) { Sink sink; /* Get the priority of the other link */ hfp_link_priority other = (pInd->priority == hfp_primary_link) ? hfp_secondary_link : hfp_primary_link; AUD_DEBUG(("AUD: Synchronous Disconnect Ind [%x]:\n",pInd->priority)) ; /* ensure disconnection was succesfull */ if(pInd->status == hfp_audio_disconnect_success) { MessageSend ( &theSink.task , EventSCOLinkClose , 0 ) ; /* update sco priority */ setScoPriorityFromHfpPriority(pInd->priority, sco_none); /* SCO has been disconnected, check for the prescence of another sco in hold state, this occurs when the AG has performed an audio transfer, promote the held call to active */ if(getScoPriorityFromHfpPriority(other) == sco_held_call) setScoPriorityFromHfpPriority(other, sco_active_call); AUD_DEBUG(("AUD: Synchronous Disconnect Ind [%x]: sco_pri = %d\n",pInd->priority, HfpLinkPriorityFromAudioSink(theSink.routed_audio) )) ; /* deroute the audio */ audioHandleRouting(audio_source_none); /*change the active call state if necessary*/ if ((stateManagerGetState() == deviceActiveCallSCO)) stateManagerEnterActiveCallState(); /* Send our link policy settings for normal role now SCO is dropped */ if(HfpLinkGetSlcSink(pInd->priority, &sink)) linkPolicyUseHfpSettings(pInd->priority, sink); } }
/**************************************************************************** NAME slcConnectionSetup DESCRIPTION Perform link setup for a given SLC RETURNS void */ static void slcConnectionSetup(hfp_link_priority priority, Sink sink, bdaddr* bd_addr) { uint16 priorityIdx = PROFILE_INDEX(priority); /* Set timeout to 5 seconds */ ConnectionSetLinkSupervisionTimeout(sink, SINK_LINK_SUPERVISION_TIMEOUT); /* Send our link policy settings */ linkPolicyUseHfpSettings(priority, sink); /* Send a delayed message to request a role indication and make necessary changes as appropriate */ MessageCancelFirst(&theSink.task , EventSysCheckRole); MessageSendConditionally (&theSink.task , EventSysCheckRole , NULL , &theSink.rundata->connection_in_progress ); #ifdef ENABLE_PBAP /* Connect the PBAP link of this device */ pbapConnect(priority); #endif /* Sync volume level and mute settings with AG */ VolumeSendAndSetHeadsetVolume(theSink.profile_data[priorityIdx].audio.gSMVolumeLevel ,FALSE , priority) ; /* Enable +CLIP from AG if using Audio Prompt numbers/names or display, always request if using display */ #if !defined(ENABLE_DISPLAY) if(theSink.features.VoicePromptNumbers) #endif HfpCallerIdEnableRequest(priority, TRUE); /* HS uses call waiting indications when AG SCO is not routed */ HfpCallWaitingEnableRequest(priority, TRUE); /* Attempt to pull the audio across if not already present, delay by 5 seconds to prevent a race condition occuring with certain phones */ MessageSendLater ( &theSink.task , EventSysCheckForAudioTransfer , 0 , 5000 ) ; /* Send different event if first connection since power on - allows different LED pattern */ if((theSink.features.UseDiffConnectedEventAtPowerOn)&&(theSink.powerup_no_connection)) MessageSend (&theSink.task , EventSysSLCConnectedAfterPowerOn , NULL ); else MessageSend (&theSink.task , EventSysSLCConnected , NULL ); /* Reset the flag - first connection indicated */ theSink.powerup_no_connection = FALSE; }
/**************************************************************************** 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")) ; }