Ejemplo n.º 1
0
/****************************************************************************
NAME    
    deviceManagerGetProfileAddr
    
DESCRIPTION
    Get bluetooth address from connection mask

RETURNS
    TRUE if connection is valid, otherwise FALSE
*/
static bool deviceManagerGetProfileAddr(conn_mask mask, bdaddr* dev_addr)
{
    if(mask & conn_hfp)
    {
        /* Get bluetooth address for this profile if connected */
        hfp_link_priority hfp = ((mask & conn_hfp_pri) ? hfp_primary_link : hfp_secondary_link);
        /* Only valid if we have processed HFP connect */
        if(theSink.profile_data[PROFILE_INDEX(hfp)].status.connected)        
            return HfpLinkGetBdaddr(hfp, dev_addr);
    }
    else if(mask & conn_a2dp)
    {
        /* Get bluetooth address for this profile if connected */
        a2dp_link_priority a2dp = ((mask & conn_a2dp_pri) ? a2dp_primary : a2dp_secondary);
        /* Only valid if we have processed A2DP connect */
        if(theSink.a2dp_link_data->device_id[a2dp] != INVALID_DEVICE_ID)
        {
            *dev_addr = theSink.a2dp_link_data->bd_addr[a2dp];
            return TRUE;
        }
    }
    
    /* Couldn't find connection for this profile */
    return FALSE;
}
Ejemplo n.º 2
0
/****************************************************************************
NAME 
 VolumeDown

DESCRIPTION
 Decrements volume - sends a response to the AG

RETURNS
 void
    
*/
void VolumeDown ( void )
{
    uint16 lOldVol = 0;
    uint16 lNewVol = 0;
  
    /* check for a2dp streaming before checking for hpf profiles */
    if(!CheckVolumeA2dp(decrease_volume) && theHeadset.conf->no_of_profiles_connected)
    {
        /* Get the link to change volume on */
        hfp_link_priority priority = audioGetLinkPriority(TRUE);

        /* get current volume for this profile */
        lOldVol = theHeadset.profile_data[PROFILE_INDEX(priority)].audio.gSMVolumeLevel;
        /* obtain new volume level */
        lNewVol = theHeadset.audioData.gVolMaps[lOldVol].DecVol ;
        /* send, set and store new volume level */

		#if 1
		VolumeSendAndSetHeadsetVolume ( lNewVol ,TRUE ,priority,decrease_volume) ;
		#else
        VolumeSendAndSetHeadsetVolume ( lNewVol ,TRUE ,priority) ;
        #endif
		
       	VOL_DEBUG(("VOL: VolDwn[%d][%d]to AG%d\n",lOldVol, lNewVol, priority))  ;
    }      
}
Ejemplo n.º 3
0
/****************************************************************************
NAME
    deviceManagerUpdateAttributes
    
DESCRIPTION
    Stores the current attribute values for a given HFP/A2DP connection in
    PS.

RETURNS
    void
*/
void deviceManagerUpdateAttributes(const bdaddr* bd_addr, sink_link_type link_type, hfp_link_priority hfp_priority, a2dp_link_priority a2dp_priority)
{
    EVENT_UPDATE_ATTRIBUTES_T* update = PanicUnlessNew(EVENT_UPDATE_ATTRIBUTES_T);
    
    memset(update,0,sizeof(EVENT_UPDATE_ATTRIBUTES_T)); 
    
    update->bd_addr = *bd_addr;
    
    if(link_type == sink_hfp)
    {
        update->attributes.profiles = sink_hfp;
        update->attributes.hfp.volume = theSink.profile_data[PROFILE_INDEX(hfp_priority)].audio.gSMVolumeLevel;
    }
    else if(link_type == sink_a2dp)
    {
        update->attributes.profiles = sink_a2dp;
        update->attributes.a2dp.volume = theSink.a2dp_link_data->gAvVolumeLevel[a2dp_priority];
        update->attributes.a2dp.clock_mismatch = theSink.a2dp_link_data->clockMismatchRate[a2dp_priority];
    }
#ifdef ENABLE_SUBWOOFER
    else if(link_type == sink_swat)
    {
        update->attributes.profiles = sink_swat;
        update->attributes.sub.sub_trim = theSink.rundata->subwoofer.sub_trim_idx;
    }
#endif        

    DEV_DEBUG(("DEV: DelayUpdateAttributes - type %d profiles %d, hfp_vol %d, a2dp_vol %d\n",link_type, update->attributes.profiles, update->attributes.hfp.volume, update->attributes.a2dp.volume));
    MessageSendConditionally(&theSink.task, EventUpdateAttributes, update, (const uint16 *)AudioBusyPtr());
}
Ejemplo n.º 4
0
/****************************************************************************
NAME    
    TonesPlayTone
    
DESCRIPTION
  	Works out the correct volume to play tones or Audio Prompts at
    
RETURNS
    void
*/
uint16 TonesGetToneVolume(bool PlayToneAtDefaultLevel)
{           
    uint16 lToneVolume;
    
    /* if play at fixed volume selected */
    if (theSink.features.PlayTonesAtFixedVolume)
    {      
        /* volume level is already in raw gain units, no need to use volume mapping table */
        lToneVolume = theSink.features.FixedToneVolumeLevel ;
    }
    /* check for play tone at default level */
    else 
    {    
        /* default volume level unless changed by other options */
        uint8 index = theSink.features.DefaultVolume ;            
        
        /* is tone not being played at default volume? */
        if(!PlayToneAtDefaultLevel)
        {
            /* use primary hfp volume */            
            index = theSink.profile_data[PROFILE_INDEX(hfp_primary_link)].audio.gSMVolumeLevel;  			
        }
        /* get volume gain from volume mapped table */     
        lToneVolume = theSink.conf1->volume_config.gVolMaps[index].VolGain;
    }
    
    TONE_DEBUG(("TONE Volume [%d]\n", lToneVolume));
    
    return lToneVolume;
}
Ejemplo n.º 5
0
/****************************************************************************
NAME    
    slcConnectionComplete
    
DESCRIPTION
    SLC connection has completed

RETURNS
    void
*/
static void slcConnectionComplete(hfp_link_priority priority, Sink sink, bdaddr* bd_addr)
{
    	
    /* mark as connected */
    theSink.profile_data[PROFILE_INDEX(priority)].status.connected = TRUE;

    /* Another connection made, update number of current connections */
 	SLC_DEBUG(("SLC: Pro Connected[%x], NoOfDev=%x\n", (int)sink,deviceManagerNumConnectedDevs())) ;

	/* Enter connected state if applicable */
    if(!stateManagerIsConnected())
        stateManagerEnterConnectedState();
    
    /* Ensure the underlying ACL is encrypted */
    if(theSink.features.EncryptOnSLCEstablishment)
        ConnectionSmEncrypt( &theSink.task , sink , TRUE );
            
    /* send message to do indicate a stop of the paging process when in connectable state */
    if(theSink.paging_in_progress)
        MessageSend(&theSink.task, EventSysStopPagingInConnState ,0);

    /* if device initiated connection */
    if(!gSlcData.gSlcConnectRemote)
    {
        /* If no event is queued send button press */
        if(!theSink.gEventQueuedOnConnection)
            HfpHsButtonPressRequest(priority);
            
        /* Continue trying to connect to next device in 0.1 seconds time to allow current device to finish connecting */
        MessageSendLater(&theSink.task,EventSysContinueSlcConnectRequest,0,theSink.conf1->timeouts.SecondAGConnectDelayTime_s);
    }

    /* Initialise call transfer flag */
    gSlcData.gCallTransferInProgress = FALSE ;
}       
Ejemplo n.º 6
0
void VolumeSetHeadsetVolume( uint16 pNewVolume , bool pPlayTone, hfp_link_priority priority, bool set_gain, volume_direction dir ) 
{      
    bool lPlayTone = FALSE ;
    bool lOverideMute = theHeadset.features.OverideMute ;
    bool lMuteLocalVolAction = theHeadset.features.MuteLocalVolAction ;

    VOL_DEBUG(("SetVol [%x] [%d][%d][%d]\n " ,pNewVolume, theHeadset.gMuted , lOverideMute , lMuteLocalVolAction)) ;
    
	/* this should only occur if we are not muted or if we are muted but wish to overide */
    if ( (!theHeadset.gMuted ) || ( lOverideMute ) || (lMuteLocalVolAction))
    {
        /*set the local volume only*/
        if ((theHeadset.gMuted) && (!lMuteLocalVolAction))
			MessageSend( &theHeadset.task , EventMuteOff , 0 ) ;
       
        /* the tone needs to be played so set flag */
        lPlayTone = TRUE ;     
        
        /* set new volume */
        theHeadset.profile_data[PROFILE_INDEX(priority)].audio.gSMVolumeLevel = pNewVolume ; 
        
        if(set_gain)
            AudioSetVolume ( theHeadset.audioData.gVolMaps[ pNewVolume ].VolGain , theHeadset.codec_task ) ;
    }
    
    /* ensure there is a valid tone (non zero) to be played */
    if( pPlayTone && lPlayTone && theHeadset.audioData.gVolMaps[pNewVolume].Tone )
    {   /*only attempt to play the tone if it has not yet been played*/

		/*VOL_DEBUG(("VOL: VolTone[%x]\n" , (int)theHeadset.audioData.gVolMaps[pNewVolume].Tone)) ;*/

#if 1
		if(theHeadset.TTS_ASR_Playing == false)
		{
			VOL_DEBUG(("VOL: VolTone[%x]\n" , (int)theHeadset.audioData.gVolMaps[pNewVolume].Tone)) ;
			#ifdef DifferentToneForVolumeButton
			if((stateManagerGetState() == headsetActiveCallSCO || stateManagerGetState() == headsetActiveCallNoSCO) && (theHeadset.sco_sink != 0))
			{
				if(dir)
				{
					TonesPlayTone(0x42 ,theHeadset.features.QueueVolumeTones, FALSE);
				}
				else
				{
	        		TonesPlayTone(theHeadset.audioData.gVolMaps[pNewVolume].Tone ,theHeadset.features.QueueVolumeTones, FALSE);
				}
			}
			#else
			/*TonesPlayTone(theHeadset.audioData.gVolMaps[pNewVolume].Tone ,theHeadset.features.QueueVolumeTones, FALSE);*/
			#endif
		}
#endif
    }    
}
Ejemplo n.º 7
0
/****************************************************************************
NAME 
 VolumeMuteOff

DESCRIPTION
 Disables Mute

RETURNS
 void
    
*/
void VolumeMuteOff ( void )
{
	/*update the mutestate*/    
    VOL_DEBUG(("VOL: UnMute\n")) ;        
    theHeadset.gMuted = FALSE ;
    
	/* If headset wants to mute off, detect which AG has active sco and sent mute off */
		/* If headset wants to mute on or receive +VGM = 0 command from one AG, 
	   Send command to both AG mute itself 
	*/
	if(theHeadset.features.EnableSyncMuteMicophones)
	{
		VOL_DEBUG(("VOL: Send AT+VGM = 1 to AG1 if AG1 does not require to unmute Mic\n")) ; 
		if( !theHeadset.profile_data[PROFILE_INDEX(hfp_primary_link)].audio.gAgSyncMuteFlag )
            HfpVolumeSyncMicrophoneGainRequest(hfp_primary_link, 0);
		else
			theHeadset.profile_data[PROFILE_INDEX(hfp_primary_link)].audio.gAgSyncMuteFlag = 0;
			
		/* if AG2 is connected, send a message to AG2 */
 		if((theHeadset.conf->no_of_profiles_connected > 1) )
   		{
    		VOL_DEBUG(("VOL: Send AT+VGM = 1 to AG2 if AG2 does not require to unmute Mic\n")) ; 
			if( !theHeadset.profile_data[PROFILE_INDEX(hfp_secondary_link)].audio.gAgSyncMuteFlag )
				HfpVolumeSyncMicrophoneGainRequest(hfp_secondary_link, 0);
			else
				theHeadset.profile_data[PROFILE_INDEX(hfp_secondary_link)].audio.gAgSyncMuteFlag = 0;
		}     
	}

	/*cancel any mute reminders*/
    MessageCancelAll( &theHeadset.task , EventMuteReminder ) ;
    
    AudioSetMode ( AUDIO_MODE_CONNECTED , NULL ) ;  
    
	if (theHeadset.sco_sink)
	{
    	    /*set the mic bias*/
	    PioSetMicrophoneBias ( TRUE ) ;
	}
}
Ejemplo n.º 8
0
/****************************************************************************
NAME 
 VolumeMuteOn

DESCRIPTION
 Enables Mute

RETURNS
 void
    
*/
void VolumeMuteOn ( void )
{
    VOL_DEBUG(("VOL: Mute\n")) ;        
    
	/* If headset wants to mute on or receive +VGM = 0 command from one AG, 
	   Send command to both AGs and mute itself 
	*/
	if(theHeadset.features.EnableSyncMuteMicophones)
	{
		VOL_DEBUG(("VOL: Send AT+VGM = 0 to AG1 if AG1 does not require to mute Mic\n")) ;
		if( !theHeadset.profile_data[PROFILE_INDEX(hfp_primary_link)].audio.gAgSyncMuteFlag )
			HfpVolumeSyncMicrophoneGainRequest(hfp_primary_link, 0);
		else
			theHeadset.profile_data[PROFILE_INDEX(hfp_primary_link)].audio.gAgSyncMuteFlag = 0;
			
		/* if AG2 is connected, send a message to AG2 */
   		if((theHeadset.conf->no_of_profiles_connected > 1))
   		{
			VOL_DEBUG(("VOL: Send AT+VGM = 0 to AG2 if AG2 does not require to mute Mic\n")) ;
			if( !theHeadset.profile_data[PROFILE_INDEX(hfp_secondary_link)].audio.gAgSyncMuteFlag )
				HfpVolumeSyncMicrophoneGainRequest(hfp_secondary_link, 0);
			else
				theHeadset.profile_data[PROFILE_INDEX(hfp_secondary_link)].audio.gAgSyncMuteFlag = 0;
		}     
	}

    if (theHeadset.features.MuteSpeakerAndMic)
        AudioSetMode ( AUDIO_MODE_MUTE_BOTH , NULL ) ;
    else
        AudioSetMode ( AUDIO_MODE_MUTE_MIC , NULL) ;

    PioSetMicrophoneBias ( FALSE ) ; 
 
    /*update the mutestate*/    
    theHeadset.gMuted = TRUE ;
	
	if(theHeadset.conf->timeouts.MuteRemindTime_s !=0)
    	MessageSendLater( &theHeadset.task , EventMuteReminder , 0 ,D_SEC(theHeadset.conf->timeouts.MuteRemindTime_s ) ) ;
}
Ejemplo n.º 9
0
/****************************************************************************
NAME    
    audioHfpConnectAudio
    
DESCRIPTION
    attempt to reconnect an audio connection from the sink value associcated 
    with the passed hfp instance

RETURNS
    
*/
void audioHfpConnectAudio (hfp_link_priority priority, Sink sink)
{    
    uint8 index = PROFILE_INDEX(priority);
    
    /* ensure sink is valid before trying to route audio */
    TaskData *plugin = NULL;
    
    /* ensure a valid codec is negotiated, should be at least cvsd */
    if(theSink.profile_data[index].audio.codec_selected)       
    {                
        AudioPluginFeatures features;

        /* determine additional features applicable for this audio plugin */
        features.stereo = (AUDIO_PLUGIN_FORCE_STEREO || theSink.features.stereo);
        features.use_i2s_output = theSink.features.UseI2SOutputCapability;
                
        theSink.routed_audio = sink;    
        
        plugin = audioHfpGetPlugin(theSink.profile_data[index].audio.codec_selected, theSink.features.audio_plugin);

        AUD_DEBUG(("AUD: plugin [%d] [%d], sink [%x]\n" , theSink.features.audio_plugin 
                                                        , theSink.profile_data[index].audio.codec_selected
                                                        , (uint16)theSink.routed_audio)) ;
        /* connect audio using the audio plugin selected above */            
        AudioConnect ( plugin,
                       theSink.routed_audio  ,
                       theSink.profile_data[index].audio.link_type ,
                       theSink.codec_task ,
                       theSink.conf1->gVolMaps[ theSink.profile_data[index].audio.gSMVolumeLevel ].VolGain ,
                       theSink.profile_data[index].audio.tx_bandwidth ,
                       features ,
                       AUDIO_MODE_CONNECTED,
                       AUDIO_ROUTE_INTERNAL,
                       powerManagerGetLBIPM(),
                       AUDIO_CONNECT_PARAMS,
                       NULL ) ;       

        audioControlLowPowerCodecs (TRUE) ;

        AUD_DEBUG(("AUD: Route SCO\n"));
    
        AUD_DEBUG(("Audio Connect[%d][%x]\n", theSink.features.audio_plugin , theSink.profile_data[index].audio.gSMVolumeLevel )) ;
       
        AudioSetVolume ( theSink.conf1->gVolMaps[ theSink.profile_data[index].audio.gSMVolumeLevel ].VolGain , TonesGetToneVolume(FALSE), theSink.codec_task ) ;
            
        /* mute control */
        VolumeSetMicrophoneGain(priority, (theSink.profile_data[index].audio.gMuted ? VOLUME_MUTE_ON : VOLUME_MUTE_OFF));            
    }
}
Ejemplo n.º 10
0
/****************************************************************************
NAME    
    audioHfpConnectAudio
    
DESCRIPTION
    attempt to reconnect an audio connection from the sink value associcated 
    with the passed hfp instance

RETURNS
    
*/
void audioHfpConnectAudio (hfp_link_priority priority, Sink sink)
{    
    uint8 index = PROFILE_INDEX(priority);
    
    /* ensure sink is valid before trying to route audio */
    TaskData *plugin = NULL;
    
    /* ensure a valid codec is negotiated, should be at least cvsd */
    if(theSink.profile_data[index].audio.codec_selected)       
    {                

        /* determine additional features applicable for this audio plugin */
                
        theSink.routed_audio = sink;    
        
        plugin = audioHfpGetPlugin(theSink.profile_data[index].audio.codec_selected, theSink.features.audio_plugin);

        AUD_DEBUG(("AUD: plugin [%d] [%d], sink [%x]\n" , theSink.features.audio_plugin 
                                                        , theSink.profile_data[index].audio.codec_selected
                                                        , (uint16)theSink.routed_audio)) ;
        /* connect audio using the audio plugin selected above */            
        AudioConnect ( plugin,
                       theSink.routed_audio  ,
                       theSink.profile_data[index].audio.link_type ,
                       theSink.codec_task ,
                       theSink.conf1->volume_config.gVolMaps[ theSink.profile_data[index].audio.gSMVolumeLevel ].VolGain ,
                       theSink.profile_data[index].audio.tx_bandwidth ,
                       theSink.conf2->audio_routing_data.PluginFeatures  ,
                       AUDIO_MODE_CONNECTED,
                       AUDIO_ROUTE_INTERNAL,
                       powerManagerGetLBIPM(),
                       AUDIO_CONNECT_PARAMS,
                       koovox.presentEnable,
                       &theSink.task) ;    

		DEBUG(("===presentEnable=%d\n", koovox.presentEnable));

        audioControlLowPowerCodecs (TRUE) ;

        AUD_DEBUG(("AUD: Route SCO\n"));
    
        AUD_DEBUG(("Audio Connect[%d][%x]\n", theSink.features.audio_plugin , theSink.profile_data[index].audio.gSMVolumeLevel )) ;
       
        AudioSetVolume ( theSink.conf1->volume_config.gVolMaps[ theSink.profile_data[index].audio.gSMVolumeLevel ].VolGain , TonesGetToneVolume(FALSE), theSink.codec_task ) ;
            
        /* mute control */
        VolumeSetMicrophoneGain(priority, (theSink.profile_data[index].audio.gMuted ? VOLUME_MUTE_ON : VOLUME_MUTE_OFF));            
    }
}
Ejemplo n.º 11
0
/****************************************************************************
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;
}
Ejemplo n.º 12
0
/****************************************************************************
NAME    
    audioHandleSyncConnectInd
    
DESCRIPTION
    Handle HFP_AUDIO_CONNECT_IND.  This indicates that an incoming sychronous 
    connection is being requested

RETURNS
    
*/
void audioHandleSyncConnectInd ( const HFP_AUDIO_CONNECT_IND_T *pInd )
{
    sync_pkt_type     packet_types;
    hfp_audio_params* audio_params;
    bool              disable_wbs_override = FALSE;
    
    AUD_DEBUG(("AUD: Synchronous Connect Ind [%d] from [%x]:\n" , pInd->codec, PROFILE_INDEX(pInd->priority))) ;
    
    audio_params = audioGetSettings(pInd->priority, &packet_types);
    
    AUD_DEBUG(("AUD : [%lx][%x][%x][%x]\n" , audio_params->bandwidth ,audio_params->max_latency   ,
                                            audio_params->voice_settings ,audio_params->retx_effort)) ;
    
    /* WBS test case - use bad WBS params */
    if(theSink.FailAudioNegotiation)
    {
        packet_types = sync_all_sco;
        disable_wbs_override = TRUE;
    }
    
    HfpAudioConnectResponse(pInd->priority, TRUE, packet_types, audio_params, disable_wbs_override);
}
Ejemplo n.º 13
0
/****************************************************************************
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();
}
Ejemplo n.º 14
0
/****************************************************************************
NAME    
    sinkHandleSlcDisconnectInd
    
DESCRIPTION
    Indication that the SLC has been released.

RETURNS
    void
*/
void sinkHandleSlcDisconnectInd( const HFP_SLC_DISCONNECT_IND_T *ind )
{	    
    conn_mask mask = deviceManagerProfilesConnected(&ind->bd_addr);

    SLC_DEBUG(("SLC: slc DiscInd for index %d, status = %d\n",ind->priority, ind->status)) ;     
        
    if(ind->status == hfp_disconnect_success || ind->status == hfp_disconnect_link_loss || ind->status == hfp_disconnect_abnormally)
    {
        /* store volume info */
        deviceManagerUpdateAttributes(&ind->bd_addr, sink_hfp, ind->priority, 0); 

        /* Sends the indication to the device manager to send an event out if a device has disconnected*/
        deviceManagerDeviceDisconnectedInd(&ind->bd_addr);
	
        /*if the device is off then this is disconnect as part of the power off cycle - dont re-enable connectable*/	
    	if ( stateManagerGetState() != deviceLimbo)
        {
            /* Enable A2dp link loss management if connected on remote device */
            if( theSink.a2dp_link_data && (theSink.a2dp_link_data->connected[a2dp_primary]) && BdaddrIsSame(&ind->bd_addr, &theSink.a2dp_link_data->bd_addr[a2dp_primary]) )
            {
                A2dpDeviceManageLinkloss(theSink.a2dp_link_data->device_id[a2dp_primary], TRUE);
            }
            else if( theSink.a2dp_link_data && (theSink.a2dp_link_data->connected[a2dp_secondary]) && BdaddrIsSame(&ind->bd_addr, &theSink.a2dp_link_data->bd_addr[a2dp_secondary]) )
            {
                A2dpDeviceManageLinkloss(theSink.a2dp_link_data->device_id[a2dp_secondary], TRUE);
            }

            /* Kick role checking now a device has disconnected */
            linkPolicyCheckRoles();

            /* at least one device disconnected, re-enable connectable for another 60 seconds */
            sinkEnableMultipointConnectable();
        }
    
        /*a disconnect in active call state is a call transfer*/
        if ( (stateManagerGetState() == deviceActiveCallSCO) || 
             (stateManagerGetState() == deviceActiveCallNoSCO) )
        {
		    gSlcData.gCallTransferInProgress = TRUE ;           
        }
        else
        {
		    gSlcData.gCallTransferInProgress = FALSE ;	
        }
    
        /* if not a link loss reset the last outgoing AG as AG1 will no longer exist now */        
        theSink.last_outgoing_ag = hfp_primary_link;

        /* reset the list id of the device just dropped */              
        theSink.profile_data[PROFILE_INDEX(ind->priority)].status.list_id = INVALID_LIST_ID;

        /* if device has now disconnected all profiles, mark as disconnected */
        if((ind->status != hfp_disconnect_link_loss)&&(!(mask & conn_hfp)))
            theSink.profile_data[PROFILE_INDEX(ind->priority)].status.connected = FALSE;
        
        /* If primary disconnected */
        if(ind->priority == hfp_primary_link)
        {
            /* ...and we have a secondary link it will be promoted to primary */
            if(theSink.profile_data[PROFILE_INDEX(hfp_secondary_link)].status.list_id != INVALID_LIST_ID)
            {
                /* Block copy secondary data to primary location */
                theSink.profile_data[PROFILE_INDEX(hfp_primary_link)] = theSink.profile_data[PROFILE_INDEX(hfp_secondary_link)];
                /* Secondary link no longer exists, set it to invalid */
                theSink.profile_data[PROFILE_INDEX(hfp_secondary_link)].status.list_id = INVALID_LIST_ID;
            }
        }
        /* send event slc disconnected only if the status of the indication is success or link loss indication */
        MessageSend(&theSink.task , ((ind->status == hfp_disconnect_link_loss) ? EventSysReconnectFailed : EventSysSLCDisconnected) , 0) ;
    }
    

    /*if the device is off then this is disconnect as part of the power off cycle, otherwise check
      whether device needs to be made connectable */	
	if ( stateManagerGetState() != deviceLimbo)
    {
	    /* if the device state still shows connected and there are no profiles currently
           connected then update the device state to reflect the change of connections */
	    if ((stateManagerIsConnected()) && (!deviceManagerNumConnectedDevs()))
	    {
	        stateManagerEnterConnectableState( FALSE ) ;
	    }
    }
    
}
Ejemplo n.º 15
0
/****************************************************************************
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")) ;
}
Ejemplo n.º 16
0
/****************************************************************************
NAME    
    setScoPriorityFromHfpPriority
    
DESCRIPTION
    sets the current sco priority level of the AG priority passed in

RETURNS
    nothing
*/   
void setScoPriorityFromHfpPriority(hfp_link_priority priority, audio_priority level)
{
    AUD_DEBUG(("AUD: SetScoPriority - %d=%d\n",priority,level)) ;
    if(priority != hfp_invalid_link)    
        theSink.profile_data[PROFILE_INDEX(OTHER_PROFILE(priority))].audio.sco_priority = level;
}
Ejemplo n.º 17
0
/****************************************************************************
NAME    
    getScoPriorityFromHfpPriority
    
DESCRIPTION
    obtain the current sco priority level of the AG priority passed in

RETURNS
    current sco priority level, if any, may not have a sco
*/   
audio_priority getScoPriorityFromHfpPriority(hfp_link_priority priority)
{
    AUD_DEBUG(("AUD: GetScoPriority - %d=%d\n",priority,theSink.profile_data[PROFILE_INDEX(OTHER_PROFILE(priority))].audio.sco_priority)) ;
    return theSink.profile_data[PROFILE_INDEX(OTHER_PROFILE(priority))].audio.sco_priority;
}
Ejemplo n.º 18
0
/****************************************************************************
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 ;
}