⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hfp_headset_slc.c

📁 CSR蓝牙芯片 无线蓝牙耳机的语音网关程序 蓝牙耳机程序已经上传
💻 C
字号:
/****************************************************************************
Copyright (C) Cambridge Silicon Radio Ltd. 2004

FILE NAME
    hfp_headset_slc.c

DESCRIPTION
    

NOTES

*/


/****************************************************************************
    Header files
*/
#include "headset_private.h"
#include "headset_scan.h"
#include "hfp_headset_sco.h"
#include "hfp_headset_slc.h"
#include "hfp_headset_ring.h"
#include "av_headset_controls.h"
#include "av_headset_kalimba.h"

#include <connection.h>
#include <hfp.h>
#include <panic.h>
#include <ps.h>


static void slcConnectFail(headsetTaskData *app)
{
    /* Update the app state */
    app->hfp_state = headsetReady;

    /* No connection */
    app->profile_connected = hfp_no_profile;

	/* Cancel button presses */
	(void) MessageCancelAll(&app->task, BUTTON_PLAY_PAUSE_LONG);
	(void) MessageCancelAll(&app->task, BUTTON_STOP_LONG);

    if (app->button_action_pending_lock > 1)
    {
        MessageSend(getAppTask(), APP_HFP_SLC_REQ, 0);
    }
    else
    {
        (void) MessageCancelAll(getAppTask(), APP_HFP_SLC_TIMEOUT_IND);
		app->button_action_pending_lock = 0;
    }

	if (app->av_stream_stopped && !app->sco_sink)
	{
		hfpHeadsetPlayRingTone(app, error_tone);
	}
}


/****************************************************************************
NAME    

    hfpHeadsetHandleSlcConnectInd
    
DESCRIPTION
    Handle a request to establish an SLC from the AG.

RETURNS
    void
*/
void hfpHeadsetHandleSlcConnectInd(headsetTaskData *app, const HFP_SLC_CONNECT_IND_T *ind)
{
    /* We support more than one HFP so check which one this request is for */   
    /* 
        TODO B-4373 we probably want to be a bit more fussy here but for now accept 
        the connection for whichever profile instance is specified in the message 
    */
    
    if (app->profile_connected == hfp_no_profile)
    {
        HfpSlcConnectResponse(ind->hfp, 1, &ind->addr, 0);
        
        /* Update the app state */
        app->hfp_state = headsetConnecting;

        /* See whether we are connecting as HSP or HFP */
        if (ind->hfp == app->hfp)
            app->profile_connected = hfp_handsfree_profile;
        else if (ind->hfp == app->hsp)
            app->profile_connected = hfp_headset_profile;
        else
            /* Something is wrong we should be either hfp or hsp */
            Panic();
    }
    else
    {
        /* Reject the connect attempt we're already connected */
        HfpSlcConnectResponse(ind->hfp, 0, &ind->addr, 0);
    }
}


/****************************************************************************
NAME    
    hfpHeadsetHandleSlcConnectCfm
    
DESCRIPTION
    Confirmation that the SLC has been established (or not).

RETURNS
    void
*/
void hfpHeadsetHandleSlcConnectCfm(headsetTaskData *app, const HFP_SLC_CONNECT_CFM_T *cfm)
{
    /* TODO: B-4373 how do we support multiple instances */

    /* Check the status of the SLC attempt */
    if (cfm->status == hfp_connect_success)
    {
		bdaddr ag_addr;

        /* Update the app state */
        if (app->hfp_state == headsetConnecting)
            app->hfp_state = headsetConnected;
        
        (void) MessageCancelAll(getAppTask(), APP_HFP_SLC_TIMEOUT_IND);
		app->button_action_pending_lock = 0;
        
        headsetTestForConnectablilty(app);

		/* Read the remote supported features of the AG */
		ConnectionReadRemoteSuppFeatures(getAppTask(), cfm->sink);

		/* Store the address as the last used AG which can be obtained from the sink */
		if (SinkGetBdAddr(cfm->sink, &ag_addr))
			(void) PsStore(LAST_USED_AG, &ag_addr, sizeof(bdaddr)); 
        
        /* If there is a pending APP_MUSIC_RESTART_IND message then it must have
           been sent because there was HFP link-loss and the AV stream was suspended 
           while the headset tried to reconnect back to the AG, to stop any AV stuttering.
           As the HFP connect has been a success, the AV can be restarted now.
        */
        if (MessageCancelAll(getAppTask(), APP_MUSIC_RESTART_IND))
            MessageSend(getAppTask(), APP_MUSIC_RESTART_IND, 0);
        
        /* 
            The sink is no longer valid, this could happen if the device connects 
            and disconnects very quickly. For now ignore, the disconnect message 
            should arrive shortly.
        */
    }
    else if (cfm->status == hfp_connect_sdp_fail)
    {
        /* We failed to find the requested profile */
        if (cfm->hfp == app->hfp)
        {
            /* Didn't find HFP so try HSP */
            hfpHeadsetHandleSlcConnectRequest(app, hfp_headset_profile);
        }
        else if (cfm->hfp == app->hsp)
        {
            /* We try the HSP after we've tried HFP so this AG supports neither, give up */
            slcConnectFail(app);
        }
        else
            /* Unknown profile instance */
            Panic();
    }
    else
    {
        /* Update local state to reflect this */
        slcConnectFail(app);
    }
}


/****************************************************************************
NAME    
    hfpHeadsetHandleSlcConnectRequest
    
DESCRIPTION
    Request to create a connection to a remote AG.

RETURNS
    void
*/
void hfpHeadsetHandleSlcConnectRequest(headsetTaskData *app, hfp_profile profile)
{
    bdaddr addr;    

    /* Set up the extra indicator config 
    const char *inds = "roam\rbattchg\rchargerconnected\rflobber\r"; */

    /* Retrieve the address of the last used AG from PS */
    if (!PsRetrieve(LAST_USED_AG, &addr, sizeof(bdaddr)))
    {
        /* Play an error tone to indicate we don't have a valid address */
		slcConnectFail(app);
		return;
    }
    
    /* Update the app state */
    app->hfp_state = headsetConnecting;

    if (profile == hfp_handsfree_profile)
    {
        app->profile_connected = hfp_handsfree_profile;

        /* Issue a connect request for HFP */
        HfpSlcConnect(app->hfp, &addr, 0);
    }
    else if (profile == hfp_headset_profile)
    {
        app->profile_connected = hfp_headset_profile;

        /* Issue a connect request for HFP */
        HfpSlcConnect(app->hsp, &addr, 0);
    }
    else
        /* The app should know what profile it wants to connect as */
        Panic();
}


/****************************************************************************
NAME    
    hfpHeadsetDisconnectSlc
    
DESCRIPTION
    Disconnect the SLC associated with this profile instance.

RETURNS
    void
*/
void hfpHeadsetDisconnectSlc(const headsetTaskData *app)
{
    /* Issue the disconnect request and let the HFP lib do the rest */
    HfpSlcDisconnect(app->hfp);
}


/****************************************************************************
NAME    
    hfpHeadsetHandleSlcDisconnectInd
    
DESCRIPTION
    Indication that the SLC has been released.

RETURNS
    void
*/
void hfpHeadsetHandleSlcDisconnectInd(headsetTaskData *app, const HFP_SLC_DISCONNECT_IND_T *ind)
{
	/*	Handle the case where an incoming call is rejected using the headset profile.
		As we get no indicator info, the AV must be restarted on a SLC disconnect.
	*/
	if ((app->profile_connected == hfp_headset_profile) && app->av_stream_stopped)
	{
		(void) MessageCancelAll(getAppTask(), APP_MUSIC_RESTART_IND);
        MessageSendLater(getAppTask(), APP_MUSIC_RESTART_IND, 0, (uint32) MUSIC_RESTART_DELAY);
	}

    /* Update the app state */
    app->hfp_state = headsetReady;
    
    /* Connection disconnected */
    app->profile_connected = hfp_no_profile;
    
    headsetTestForConnectablilty(app);
    
    /* Store the latest volume setting */
    (void) PsStore(VOLUME_LEVEL, &app->speaker_volume, sizeof(app->speaker_volume));
    
    /* Procedure for abnormal link-loss */
    if (ind->status == hfp_disconnect_link_loss)
    {
        /* If AV is streaming then Suspend it as the HFP reconnect will 
           cause interruptions in the audio.
        */
        if (app->a2dp_state == avHeadsetA2dpStreaming)
        {
            avHeadsetAvStreamStop(app, TRUE);
            (void) MessageCancelAll(getAppTask(), APP_MUSIC_RESTART_IND);
            MessageSendLater(getAppTask(), APP_MUSIC_RESTART_IND, 0, SLC_CONNECT_TIMEOUT + 2);
        }
		/* Send a reconnect attempt */
        app->button_action_pending_lock = 2;
        MessageSend(getAppTask(), APP_HFP_SLC_REQ, 0);
        /* Set the connect attempt timeout. */
        MessageSendLater(getAppTask(), APP_HFP_SLC_TIMEOUT_IND, 0, SLC_CONNECT_TIMEOUT);
    }

}


/****************************************************************************
NAME    
    headsetHandleRemoteSuppFeatures
    
DESCRIPTION
    Supported features of the remote device contained in the message if the 
    read succeeded. 

RETURNS
    void
*/
void headsetHandleRemoteSuppFeatures(headsetTaskData *app, const CL_DM_REMOTE_FEATURES_CFM_T *cfm)
{
    /* 
        If the read request succeeded then store the first work of the supported features 
        We should in theory store all four words but currently we only need the info in 
        the first word so for the sake of efficiency for the moment only store that.
    */
    if (cfm->status == hci_success)
	{
        app->supp_features_0 = cfm->features[0];

		/* 
			If we have a SCO open when we get this then we probably tried to 
			change the pkt type to HV1 so go and check the remote supported 
			features again to see if we can change to HV3. 
		*/
		if (app->sco_sink)
			ConnectionScoChangePktType(app->sco_sink, hfpGetBestScoPktType(app));
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -