Esempio n. 1
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;
}
/****************************************************************************
NAME
    handleClRole

DESCRIPTION
    Checks the current role.

*/
static void handleClRole(devInstanceTaskData *inst, hci_role role, hci_status status, bool role_switch)
{
    Sink sink = 0;
    
    if (inst->a2dp)
        sink = inst->a2dp_sig_sink;
    else if (inst->aghfp_sink)
        sink = inst->aghfp_sink;
        
    /* store the current role */
    if ((status == hci_success) && (inst->role != role))
    {
        inst->role = role;
        DEBUG_CL(("    Current role: inst[0x%x] role:[%d]\n", (uint16)inst, inst->role));
        if (sink)
        {
            if (inst->role == hci_role_master)
            {
                /* Set link supervision timeout 5 seconds */
                ConnectionSetLinkSupervisionTimeout(sink, 0x1F80);
            }
        }
    }        
}
Esempio n. 3
0
/****************************************************************************
NAME    
    linkPolicyHandleRoleCfm
    
DESCRIPTION
    this is a function checks the returned role of the device and makes the decision of
    whether to change it or not, if it  needs changing it sends a role change reuest

RETURNS
    void
*/
void linkPolicyHandleRoleCfm(CL_DM_ROLE_CFM_T *cfm)
{
    hci_role requiredRole = hci_role_dont_care;
    
    LP_DEBUG(("RoleConfirm, status=%u  sink=0x%X  role=%s\n", cfm->status, (unsigned int)cfm->sink, (cfm->role == hci_role_master) ? "master" : "slave"));
   
    /* ensure role read successfully */
    if ((cfm->status == hci_success)&&(!theSink.features.DisableRoleSwitching))
    {
        /* when multipoint enabled connect as master, this can be switched to slave
        later on if required when only 1 ag is connected */
        if((theSink.MultipointEnable) && (linkPolicyNumberPhysicalConnections() > 1))
        {
#if defined ENABLE_PEER
            uint16 priority;
            
            if (getA2dpIndexFromSink(cfm->sink, &priority) && (theSink.a2dp_link_data->peer_device[priority] == remote_device_peer))
            {
                if (A2dpMediaGetRole(theSink.a2dp_link_data->device_id[priority], theSink.a2dp_link_data->stream_id[priority]) == a2dp_source)
                {
                    LP_DEBUG(("LP: Multipoint: Peer (relaying), require Master role\n")) ;
                    requiredRole = hci_role_master;
                    /* Set the link supervision timeout as the role switch will have reset it back
                       to firmware defaults */
                    ConnectionSetLinkSupervisionTimeout(cfm->sink, SINK_LINK_SUPERVISION_TIMEOUT);
                }
                else
                {
                    LP_DEBUG(("LP: Multipoint: Peer, don't change role\n")) ;
                    requiredRole = hci_role_dont_care;
                }
            }
            else
#endif
            {
#if defined ENABLE_PEER && defined PEER_SCATTERNET_DEBUG   /* Scatternet debugging only */
                if (getA2dpIndexFromSink(cfm->sink, &priority) && theSink.a2dp_link_data->invert_ag_role[priority])
                {
                    LP_DEBUG(("LP: Multipoint: Non-peer, require Slave role (inverted)\n")) ;
                    requiredRole = hci_role_slave;
                }
                else
#endif
                {
                    LP_DEBUG(("LP: Multipoint: Non-peer, require Master role\n")) ;
                    requiredRole = hci_role_master;
                    /* Set the link supervision timeout as the role switch will have reset it back
                       to firmware defaults */
                    ConnectionSetLinkSupervisionTimeout(cfm->sink, SINK_LINK_SUPERVISION_TIMEOUT);
                }
            }
        }
#ifdef ENABLE_SUBWOOFER
        /* when a sub woofer is in use the sink app needs to be master of all links
           to maintain stable connections */
        else if((cfm->status == hci_success)&&(SwatGetSignallingSink(theSink.rundata->subwoofer.dev_id)))
        {
            LP_DEBUG(("LP: Subwoofer, require Master role\n")) ;
            requiredRole = hci_role_master;

            /* Restore the Set link supervision timeout to 1 second as this is reset after a role change */
            ConnectionSetLinkSupervisionTimeout(SwatGetSignallingSink(theSink.rundata->subwoofer.dev_id), SUBWOOFER_LINK_SUPERVISION_TIMEOUT);
        }        
#endif        
        /* non multipoint case, device needs to be slave */
        else
        {
            /* Set required role to slave as only one AG connected */
            if((theSink.user_power_table)&&(theSink.user_power_table->normalEntries))
            {   /* if user supplied role request then use that */
                LP_DEBUG(("LP: Singlepoint, require Master role\n")) ;
                requiredRole = theSink.user_power_table->normalRole;
            }
            else 
            {
#if defined ENABLE_PEER
                uint16 priority;
            
                if (getA2dpIndexFromSink(cfm->sink, &priority) && (theSink.a2dp_link_data->peer_device[priority] == remote_device_peer))
                {
                    if (A2dpMediaGetRole(theSink.a2dp_link_data->device_id[priority], theSink.a2dp_link_data->stream_id[priority]) == a2dp_source)
                    {
                        LP_DEBUG(("LP: Singlepoint: Peer (relaying), require Master role\n")) ;
                        requiredRole = hci_role_master;
                        /* Set the link supervision timeout as the role switch will have reset it back
                           to firmware defaults */
                        ConnectionSetLinkSupervisionTimeout(cfm->sink, SINK_LINK_SUPERVISION_TIMEOUT);
                    }
                    else
                    {
                        LP_DEBUG(("LP: Singlepoint: Peer, don't change role\n")) ;
                        requiredRole = hci_role_dont_care;
                    }
                }
                else
#endif
                {   /* otherwise default to slave */
                    LP_DEBUG(("LP: Singlepoint, require Slave role\n")) ;
                    requiredRole = hci_role_slave;
                }
            }
        }
    }
    /* check for failure of role switch due to AG having a sco open, if this is the case then
    reschedule the role switch until it is successfull or fails completely */
    else if((cfm->status == hci_error_role_change_not_allowed)&&(!theSink.features.DisableRoleSwitching))
    {
        LP_DEBUG(("LP: hci_error_role_change_not_allowed on sink = %x\n",(uint16)cfm->sink));    
    }
    /* automatic role switching is disabled, use the hfp_power_table pskey role requirements
       instead */
    else if(cfm->status == hci_success)
    {
        LP_DEBUG(("LP: Bypass Automatic role sw, use hfp_power_table role requirements\n")) ;

        /* check for the prescence of a user configured role requirement */
        if(theSink.user_power_table)
        {
            /* determine device state, if stream a2dp check for power table entry and use that role
               if available */
            if((stateManagerGetState() == deviceA2DPStreaming)&&(theSink.user_power_table->A2DPStreamEntries))
            {
                LP_DEBUG(("LP: Bypass: use A2dp role\n")) ;
                requiredRole = theSink.user_power_table->A2DPStreamRole;
            }
            /* or if in call and sco is present check for sco power table entry and use role from that */
            else if((stateManagerGetState() > deviceConnected)&&(theSink.routed_audio)&&(theSink.user_power_table->SCOEntries))
            {
                LP_DEBUG(("LP: Bypass: use SCO role\n")) ;
                requiredRole = theSink.user_power_table->SCORole;
            }
            /* or default to normal role power table entry and use role from that */
            else if(theSink.user_power_table->normalEntries)
            {                    
                LP_DEBUG(("LP: Bypass: use Normal role\n")) ;
                requiredRole = theSink.user_power_table->normalRole;
            }
            /* if no suitable power table entries available then default to slave role */
            else
            {
                LP_DEBUG(("LP: Bypass: use default slave role\n")) ;
                requiredRole = hci_role_slave;
            }
        }
    }        
    
    /* Request a role change if required */
    if (requiredRole != hci_role_dont_care) 
    {
        if (cfm->role != requiredRole)
        {
            LP_DEBUG(("LP: Set dev as %s %x\n",(requiredRole == hci_role_master) ? "master" : "slave", (unsigned int)cfm->sink)) ;

            /* Set role for this connection */
            ConnectionSetRole(&theSink.task, cfm->sink, requiredRole);             
        }
        else
        {
            LP_DEBUG(("LP: role not set, already %s\n",(requiredRole == hci_role_master) ? "master" : "slave")) ;
            
            sinkA2dpSetLinkRole(cfm->sink, cfm->role);
        }
    }
    else
    {
        sinkA2dpSetLinkRole(cfm->sink, cfm->role);
        
        LP_DEBUG(("LP: role change not required\n")) ;
    }
}