Example #1
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 ;
}       
Example #2
0
/****************************************************************************
DESCRIPTION
    sends the current microphone volume to the AG on connection
    
*/
void VolumeSendMicrophoneVolume( uint16 pVolume ) 
{
uint8 i;

    /*if there is a hfp attached - then send the vol change*/
    if ( stateManagerIsConnected() )
    {
        /* scan all available profiles and send mic volume if connected */
        for(i=0;i<MAX_PROFILES;i++)
        {
            /* send mic volume to AG */
            HfpVolumeSyncMicrophoneGainRequest ( (i + hfp_primary_link) , (uint8*)&pVolume ) ;
        }
    }
}
Example #3
0
/****************************************************************************
NAME    
    sinkInitiateLNR
    
DESCRIPTION
    If HFP and connected - issues command
    If HFP and not connected - connects and issues if not in call
    If HSP sends button press

RETURNS
    void
*/
void sinkInitiateLNR ( hfp_link_priority priority )
{

    CM_DEBUG(("CM: LNR\n")) ;

    /* if device not connected to any AG initiate a connection */
    if (!stateManagerIsConnected() )
    {
#ifdef ENABLE_AVRCP       
        sinkAvrcpCheckManualConnectReset(NULL);
#endif        
        MessageSend ( &theSink.task , EventUsrEstablishSLC , 0 ) ;
        sinkQueueEvent(EventUsrLastNumberRedial) ;
    }
    /* have at least one connection */    
    else
    {
        uint8 Option = hfp_primary_link;
        
        CM_DEBUG(("CM: LNR Connected\n")) ;
   
        /* for multipoint use there are two options */
        if(theSink.MultipointEnable) 
        {
            /* these being to use separate LNR buttons, one for AG1 and one for AG2
               or use one LNR event and dial using the AG that last made an outgoing
               call */
            if(theSink.features.SeparateLNRButtons)
            {
                CM_DEBUG(("CM: LNR use separate LNR buttons\n")) ;
                Option = priority;
            }
            /* dial using AG that made last outgoing call */
            else
            {
                CM_DEBUG(("CM: LNR use last outgoing AG = %d\n",theSink.last_outgoing_ag)) ;
                Option = theSink.last_outgoing_ag;
            }
        }
        CM_DEBUG(("CM: LNR on AG %d\n",Option)) ;
        /* perform last number redial */        
        HfpDialLastNumberRequest(Option);
    }
}
Example #4
0
/****************************************************************************
NAME    
    sinkInitiateVoiceDial
    
DESCRIPTION
    If HFP and connected - issues command
    If HFP and not connected - connects and issues if not in call
    If HSP sends button press

RETURNS
    void
*/
void sinkInitiateVoiceDial ( hfp_link_priority priority )
{
    CM_DEBUG(("CM: VD\n")) ;
	
    if (!stateManagerIsConnected() )
    {	
#ifdef ENABLE_AVRCP
        sinkAvrcpCheckManualConnectReset(NULL);
#endif        
        MessageSend ( &theSink.task , EventUsrEstablishSLC , 0 ) ;
        sinkQueueEvent( EventUsrInitateVoiceDial ) ;
        
        theSink.VoiceRecognitionIsActive = hfp_invalid_link ;
    }
    else
    {
        uint8 Option = hfp_primary_link;
    
        CM_DEBUG(("CM: VD Connected\n")) ;
        
        /* for multipoint use there are two options */
        if(theSink.MultipointEnable) 
        {
            /* these being to use separate VD buttons, one for AG1 and one for AG2
               or use one VD event and dial using the AG that last made an outgoing
               call */
            if(theSink.features.SeparateVDButtons)
            {
                Option = priority;
            }
            /* voice dial using AG that made last outgoing call */
            else
            {
                Option = theSink.last_outgoing_ag;
            }
        }             
        CM_DEBUG(("CM: VoiceDial on %d\n",Option)) ;
        HfpVoiceRecognitionEnableRequest(Option, TRUE);    
        theSink.VoiceRecognitionIsActive = Option;
    }    
}
Example #5
0
void VolumeSendAndSetHeadsetVolume( uint16 pNewVolume , bool pPlayTone, hfp_link_priority priority ) 
{
    bool lOverideMute = theHeadset.features.OverideMute ;
    
    /* ensure profile is connected before changing volume */
    if(priority)
    {
        /*if there is a hfp attached - then send the vol change, but only if not
          muted and mute overide is not in effect*/
        if ( (stateManagerIsConnected() && (!theHeadset.gMuted ))||
             ( lOverideMute ))
        {     
            HfpVolumeSyncSpeakerGainRequest ( priority , (uint8*)&pNewVolume ) ;
        }
        VOL_DEBUG(("VOL: SEND and %x",(unsigned int) priority)) ;

		#if 1
		VolumeSetHeadsetVolume( pNewVolume , pPlayTone, priority, TRUE, dir );
		#else
        VolumeSetHeadsetVolume( pNewVolume , pPlayTone, priority, TRUE );
		#endif
    }
}
Example #6
0
/*
	Dial the first entry in the phonebook
*/
void pbapDialPhoneBook( uint8 phonebook )
{
    if(theHeadset.pbap_dial_state != pbapc_dialling)
    {
        if (!stateManagerIsConnected() )
        {	
#ifdef ENABLE_AVRCP
            headsetAvrcpCheckManualConnectReset(NULL);
#endif            
            PBAP_DEBUG(("Pbap dial, Connect the HFP profile first\n"));
            MessageSend ( &theHeadset.task , EventEstablishSLC , 0 ) ;
            
            switch(phonebook)
            {
                case pbap_ich:
                    headsetQueueEvent( EventPbapDialIch ) ;
                break;
                case pbap_mch:
                    headsetQueueEvent( EventPbapDialMch ) ;
                break;
                default:
                break;
            }
        }
        else
        {   
        	#ifdef ActiveRubiASR
				#if 0
				if(strcmp(TTS_text , ""))
				{
					PBAP_DEBUG(("Pbap : Rubi > UnloadRubiEngine***\n"));	

					TTSTerminate();

					AudioDisconnect();
					/* clear sco_sink value to indicate no routed audio */
					theHeadset.sco_sink = 0;

					UnloadRubidiumEngine();
					memset(TTS_text, 0, sizeof(TTS_text));  
				}
				#endif
				if(theHeadset.TTS_ASR_Playing)
				{
					PBAP_DEBUG(("Pbap : Rubi > UnloadRubiEngine***\n"));	

					TTSTerminate();

					AudioDisconnect();
					/* clear sco_sink value to indicate no routed audio */
					theHeadset.sco_sink = 0;

					UnloadRubidiumEngine();
					
					theHeadset.TTS_ASR_Playing = false;
				}
			#endif
			
            pbapDial(phonebook);
        }    
        
        theHeadset.pbap_dial_state = pbapc_dialling;
    }
}
Example #7
0
void slcContinueEstablishSLCRequest( void )
{
    SLC_DEBUG(("SLC: ContSLCReq, listId = %d\n",gSlcData.gListID)) ;

    /* is multipoint enabled ?, if so see if necessary to connect further devices, also check for 
       non multipoint and no devices, otherwise exit */
    if((!gSlcData.gSlcConnectRemote) && (deviceManagerCanConnect()) && 
#ifdef ENABLE_PARTYMODE
       (!((theSink.PartyModeEnabled)&&(theSink.features.PartyMode)))&&
#endif
       (stateManagerGetState() != deviceLimbo))
    {
        if(slcDetermineConnectAction() & AR_Rssi)
        {
            /* Connect next result*/
            inquiryConnectNext();
        }
        else
        {
            /* if there are more devices to connect to then continue */
            if(slcGetNextListID())
            {
                SLC_DEBUG(("SLC: PDL entry available for connection , listId = %d\n",gSlcData.gListID)) ;
                /* attempt to connect to next item in list */ 
                slcAttemptConnection();
            }
            /* otherwise check whether any connection attempt was successful, if not check feature
               to automatically enter pairing mode */
            else if(theSink.features.EnterPairingModeOnFailureToConnect && !stateManagerIsConnected())
            {
                SLC_DEBUG(("SLC: Failed to Connect to anything, enter pairing mode\n")) ;
                /* enter pairing mode */
                MessageSend(&theSink.task, EventUsrEnterPairing, 0);
                /* now allow role switches */
                theSink.rundata->connection_in_progress = FALSE;
            }
            /* all connection attempts now complete, allow role switching */
            else
            {
                /* now allow role switches */
                theSink.rundata->connection_in_progress = FALSE;
            }
        }
    }
    /* Need to handle this case to stop RSSI when all devs connected */
    else if(slcDetermineConnectAction() & AR_Rssi)
    {
        /* All done, stop inquiring */
        if(theSink.inquiry.action != rssi_subwoofer)
            inquiryStop();
        /* set flag to block role switch requests until all connections are complete to avoid unneccesary switching */
        theSink.rundata->connection_in_progress = FALSE;
    }
    /* connections complete, allow role switches to commence if necessary */
    else
    {
        /* set flag to block role switch requests until all connections are complete to avoid unneccesary switching */
        theSink.rundata->connection_in_progress = FALSE;
    }

    /* reset connection via remote ag instead of device flag */
    gSlcData.gSlcConnectRemote = FALSE;

    SLC_DEBUG(("SLC: StopReq\n")) ;
}       
Example #8
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 ;
}
Example #9
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 ) ;
	    }
    }
    
}