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

📄 headset_a2dp_msg_handler.c

📁 bc5_stereo:bluetooth stereo Headset CODE 支持A2DP HSP 和 HSP 。可作为车载免提。BlueLab 2007环境下编译
💻 C
字号:
/****************************************************************************
Copyright (C) Cambridge Silicon Radio Ltd. 2004-2007

FILE NAME
    headset_a2dp_msg_handler.c
    
DESCRIPTION
    Handle a2dp library messages arriving at the app.
    
*/

#include "headset_a2dp_connection.h"
#include "headset_a2dp_msg_handler.h"
#include "headset_a2dp_stream_control.h"
#include "headset_avrcp_event_handler.h"
#include "headset_avrcp_msg_handler.h"
#include "headset_debug.h"
#include "headset_hfp_slc.h"
#include "headset_init.h"
#include "headset_private.h"
#include "headset_statemanager.h"
#include "headset_tones.h"
#include "headset_configmanager.h"

#include <a2dp.h>
#include <bdaddr.h>
#include <panic.h>
#include <ps.h>


#ifdef DEBUG_A2DP_MSG
#define A2DP_MSG_DEBUG(x) DEBUG(x)
#else
#define A2DP_MSG_DEBUG(x) 
#endif


/****************************************************************************
  ENUM DEFINITIONS
*/


/****************************************************************************
  MESSAGE DEFINITIONS
*/


/****************************************************************************
  LOCAL FUNCTIONS
*/

/****************************************************************************/
static void sendPlayOnAvrcpConnection(hsTaskData *app)
{
	if ( stateManagerIsAvrcpConnected() )
	{
		if (app->autoSendAvrcp)
			avrcpSendPlay(app);
	}
	else
	{
		/* AVRCP is not connected yet, so send an avrcp_play once it is connected */
		if (stateManagerGetAvrcpState() == avrcpConnecting)
		{
			app->avrcp.send_play = 1;
			MessageSendConditionally( &app->task , APP_SEND_PLAY, 0, &app->avrcp.send_play );
		}
	}
}


/****************************************************************************
  LOCAL MESSAGE HANDLING FUNCTIONS
*/

static void handleA2DPInitCfm(hsTaskData *app, const A2DP_INIT_CFM_T *msg)
{
    uint8 mp3_enabled = 0;
    
    A2DP_MSG_DEBUG(("A2DP_INIT_CFM : "));
    
    if(msg->status == a2dp_success)
    {
        /* A2DP Library initialisation was a success */     
        /* Keep a record of the A2DP instance */
        if (!app->a2dp.a2dp)
        {
            a2dp_sep_config config;    
     
            A2DP_MSG_DEBUG(("Success\n"));
            
	        config.params = 0;
            
            app->a2dp.a2dp = msg->a2dp;
            
            /* Enable signalling channel indication for this application. */
            A2dpEnableSignallingIndications(app->a2dp.a2dp);

			if (PsRetrieve(PSKEY_MP3_ENABLED, &mp3_enabled, sizeof(uint8)))
			{
				app->a2dpMP3Enabled = (mp3_enabled == 0) ? FALSE:TRUE;
			}
			
			if (app->a2dpMP3Enabled)	
			{                
				/* Register Stream Endpoints - MP3 */
                config.sep_type = a2dp_mpeg_audio;
				A2dpAddSep(app->a2dp.a2dp, &config);
			}		

			/* ... and SBC */
			config.sep_type = a2dp_sbc;
			A2dpAddSep(app->a2dp.a2dp, &config);
        }
    }
    else
    {
	    A2DP_MSG_DEBUG(("Failed [Status %d]\n", msg->status));
        Panic();
    }
}

/**************************************************************************/
static void handleA2DPAddSepCfm(hsTaskData *app, const A2DP_ADD_SEP_CFM_T *msg)
{
	A2DP_MSG_DEBUG(("A2DP_ADD_SEP_CFM : "));
	
	if (!(app->a2dpReady))
	{
	    if(msg->status == a2dp_success)
	    {
		    A2DP_MSG_DEBUG(("Success\n"));
		    /* SBC is registered last, so when the CFM arrives, A2DP init is complete. */
			if (msg->sep_type == a2dp_sbc)
			{
				app->a2dpReady = TRUE;
		        InitAvrcp();
			}
		}
	    else if ((msg->sep_type) == a2dp_sbc)
	    {
	        A2DP_MSG_DEBUG(("Failure - SBC [Status %d]\n", msg->status));
	        Panic();
	    }
	    else
	    	A2DP_MSG_DEBUG(("Failure - Other [Status %d]\n", msg->status));
    }
    else
    {
	    A2DP_MSG_DEBUG(("Not in initialising state, ignoring\n"));
    }
}

static void handleA2DPOpenInd(hsTaskData *app, Sink sink, a2dp_sep_type sep)
{
    bdaddr bdaddr_ind;
    
    A2DP_MSG_DEBUG(("A2DP_OPEN_IND\n"));
    
	if (SinkGetBdAddr(sink, &bdaddr_ind))
	{
		avrcpConnectReq(app, bdaddr_ind, FALSE);
	
		/* Store the last used SEP on media connection */
		(void)PsStore(PSKEY_LAST_USED_AV_SOURCE_SEP, &sep, sizeof(a2dp_sep_type));
	    
		app->a2dp.sink = sink;
		app->a2dp.sep = sep;
		A2DP_MSG_DEBUG(("    Selected SEP = %d\n", sep));
		stateManagerEnterA2dpConnectedState(app);
		PROFILE_MEMORY(("A2DPOpen"))
	}
	else
	{
		A2DP_MSG_DEBUG(("    Can't find BDA associated with sink 0x%x\n", (uint16)sink));
/*		Panic();*/
	}
}

static void handleA2DPOpenCfm(hsTaskData *app, const A2DP_OPEN_CFM_T *msg)
{
	A2DP_MSG_DEBUG(("A2DP_OPEN_CFM : "));
	
	app->a2dpConnecting = FALSE;
	
	if (msg->result == a2dp_success)
	{
		A2DP_MSG_DEBUG(("Success\n"));
		handleA2DPOpenInd(app, msg->media_sink, msg->sep_type);
		
		/* Start the Streaming */
		A2dpStart(app->a2dp.a2dp, msg->media_sink);
	}
	else
	{
		A2DP_MSG_DEBUG(("Failure [result = %d]\n", msg->result));
		if ((msg->sep_type != a2dp_sbc)  && (msg->result == a2dp_fail))
		{
			bdaddr addr = {0,0,0};
			a2dp_sep_type sep_type;
			if (a2dpGetLastUsedSource(&addr, &sep_type))
			{
				A2dpOpen(app->a2dp.a2dp, a2dp_sbc, &addr, TRUE);
				app->a2dpConnecting = TRUE;
			}
		}
		else
		{
			/* reset flag as media connection failed */
			app->sendPlayOnConnection = FALSE;
			
			/* Only send event if no signalling connection */
			if (!app->a2dp.sig_sink)
				/* Send event to signify that all reconnection attempts failed */
				MessageSend(&app->task, EventA2dpReconnectFailed, 0);
		}
	}
}

static void handleA2DPStartInd(hsTaskData *app, A2DP_START_IND_T *msg)
{
	A2DP_MSG_DEBUG(("handleA2DPStartInd\n"));
	if (!stateManagerIsA2dpConnected())
	{
		A2DP_MSG_DEBUG(("    Not Connected - Ignoring\n"));
		return;
	}
	
    if (!app->a2dp.sink || (stateManagerIsA2dpStreaming()))
        return;
    
    if (app->sco_sink || hfpSlcIsConnecting(app))
    {
        /* SCO is active or currently connecting SLC so don't start AV */
        A2dpSuspend(app->a2dp.a2dp, msg->media_sink);
        /* I don't think we need to do this */
/*        avrcpSendPause(app);*/
		return;
    }

	streamControlConnectA2dpAudio(app);
	
	/* The A2DP state needs to be set based on what the headset thinks is the playing status of the media */ 
    if (app->PlayingState || IsA2dpSourceAnAg(app))       
		stateManagerEnterA2dpStreamingState(app);
	else
		stateManagerEnterA2dpPausedState(app);
}

static void handleA2DPStartCfm(hsTaskData *app, A2DP_START_CFM_T *msg)
{
	A2DP_MSG_DEBUG(("handleA2DPStartCfm\n"));
    if (msg->result == a2dp_success)
    {   
        /* start Kalimba decoding if it isn't already */
        if (!stateManagerIsA2dpStreaming())
        {			
            if (app->sco_sink || hfpSlcIsConnecting(app))
            {
                /* 
                    SCO has become active while we were waiting for a START_CFM (or SLC
					is connecting).
				    AV doesn't want to be streaming now, so we must try to 
				    suspend the source again.
				*/
                A2dpSuspend(app->a2dp.a2dp, msg->media_sink);
                /* I don't think we need to do this */
/*     			avrcpSendPause(app);*/
                return;
            }

			streamControlConnectA2dpAudio(app);
        } 
		
		/* The A2DP state needs to be set based on what the headset thinks is the playing status of the media */
		if (app->PlayingState || app->sendPlayOnConnection || IsA2dpSourceAnAg(app))       
		    stateManagerEnterA2dpStreamingState(app);
		else
			stateManagerEnterA2dpPausedState(app);
		
		if (app->sendPlayOnConnection)
		{
			sendPlayOnAvrcpConnection(app);
		}
    }
    else
    {
		A2DP_MSG_DEBUG(("handleA2DPStartCfm failed\n"));
		
		/* Workaraound for Samsung phones to start audio playing once media is connected.
 		   The phone sends an avdtp_start as soon as it receives the avdtp_open, so the
		   avdtp_start sent from the headset end will fail. But even though it is in the streaming
		   state we still need to send an avrcp_play here to start the music.
		*/
		if (stateManagerIsA2dpStreaming())
		{
			sendPlayOnAvrcpConnection(app);
		}
    }
	/* reset flag regardless of result code */
	app->sendPlayOnConnection = FALSE;
}

static void handleA2DPSuspendInd(hsTaskData *app, A2DP_SUSPEND_IND_T *msg)
{
	A2DP_MSG_DEBUG(("handleA2DPSuspendInd\n"));
	if (!stateManagerIsA2dpStreaming())
	{
		A2DP_MSG_DEBUG(("    Not Streaming - Ignoring\n"));
		return;
	}
    stateManagerEnterA2dpConnectedState(app);

    streamControlCeaseA2dpStreaming(app, FALSE);
}

static void handleA2DPSuspendCfm(hsTaskData *app, A2DP_SUSPEND_CFM_T *msg)
{
	A2DP_MSG_DEBUG(("handleA2DPSuspendCfm\n"));
	
	if (!stateManagerIsA2dpConnected())
	{
		A2DP_MSG_DEBUG(("    Not Connected - Ignoring\n"));
		return;
	}
    if (msg->result == a2dp_success)
    {        
	    if (app->dsp_process == dsp_process_a2dp)
        {
            /* We must have had a stream restart at this end occuring so restart AV source */
            A2dpStart(app->a2dp.a2dp, app->a2dp.sink);
			if (app->autoSendAvrcp)
            	avrcpSendPlay(app);
			return;
        }
		else
        {
            /* We have suspended the A2DP source. */
			app->a2dpSourceSuspended = TRUE;
        }
		
        stateManagerEnterA2dpConnectedState(app);
    }
}

static void handleA2DPClose(hsTaskData *app)
{
	A2DP_MSG_DEBUG(("handleA2DPClose\n"));
    PROFILE_MEMORY(("A2DPClose"))

	if (!stateManagerIsA2dpConnected())
	{
		A2DP_MSG_DEBUG(("    Not Connected - Ignoring\n"));
		return;
	}
	
    streamControlCeaseA2dpStreaming(app,FALSE);
	
	app->a2dpSourceSuspended = FALSE;
	
    /* Change state */	
	if (app->a2dp.sig_sink)
		stateManagerEnterA2dpConnectedState(app);
	else
		stateManagerEnterA2dpConnectableState(app, FALSE);
    
    app->a2dp.sink = 0;
}

static void handleA2DPCodecSettingsInd(hsTaskData *app, A2DP_CODEC_SETTINGS_IND_T *msg)
{
	A2DP_MSG_DEBUG(("handleA2DPCodecSettingsInd\n"));
	app->a2dp.channel_mode = msg->channel_mode;
	app->a2dp.rate = msg->rate;

}

static void handleA2DPSignallingOpenInd(hsTaskData *app, A2DP_SIGNALLING_OPEN_IND_T *msg)
{
	bdaddr bdaddr_ind;
	bool bdaddr_retrieved = FALSE;
	
	A2DP_MSG_DEBUG(("handleA2DPSignallingOpenInd\n"));

    app->a2dp.sig_sink = msg->sink;
	
	bdaddr_retrieved = SinkGetBdAddr(msg->sink, &bdaddr_ind);
	
	app->a2dpConnecting = FALSE;
    
    /* We are now connected */
    if (!stateManagerIsA2dpStreaming())
        stateManagerEnterA2dpConnectedState(app); 	
	
	if (bdaddr_retrieved)
		(void)PsStore(PSKEY_LAST_USED_AV_SOURCE, &bdaddr_ind, sizeof(bdaddr));
	
	/* Ensure the underlying ACL is encrypted */       
    ConnectionSmEncrypt( &app->task , msg->sink , TRUE );
	
	/* If we were in pairing mode then update HFP state also */
	if (stateManagerGetHfpState() == headsetConnDiscoverable)
		stateManagerEnterHfpConnectableState(app, FALSE);
	
	/* If the headset is off then disconnect */
	if (stateManagerGetHfpState() == headsetPoweringOn)
    {      
       a2dpDisconnectRequest( app );
    }
	else
	{
    	/* Establish an AVRCP connection if required */
		if (bdaddr_retrieved)
			avrcpConnectReq(app, bdaddr_ind, TRUE);

		MessageSend ( &app->task , EventA2dpConnected , 0 );
	}
}

static void handleA2DPSignallingCloseInd(hsTaskData *app, A2DP_SIGNALLING_CLOSE_IND_T *msg)
{
	A2DP_MSG_DEBUG(("handleA2DPSignallingCloseInd res=%d\n",msg->result));
    
    app->a2dp.sig_sink = 0;
	
    /* Change to ready state if no media channel open */
    if (app->a2dp.sink == 0)
	    stateManagerEnterA2dpConnectableState(app, FALSE);
		
	avrcpDisconnectReq(app);
		    
	if (msg->result == a2dp_disconnect_link_loss)
	{
		/* Reconnect on link loss */
		A2DP_MSG_DEBUG(("A2DP: Link Loss Detect\n")) ;
               
        MessageSend( &app->task , EventLinkLoss , 0 ) ;
					   
		a2dpReconnectProcedure(app);
	}
	
	MessageSend ( &app->task , EventA2dpDisconnected , 0 );
	PROFILE_MEMORY(("A2DPSigClose"))
}

/****************************************************************************
  INTERFACE FUNCTIONS
*/
void handleA2DPMessage( Task task, MessageId id, Message message )
{
    hsTaskData * app = (hsTaskData *) getAppTask() ;
    
    /*A2DP_MSG_DEBUG(("A2DP msg: 0x%x\n",id));*/
    
    switch (id)
    {
    case A2DP_INIT_CFM:
        handleA2DPInitCfm(app, (A2DP_INIT_CFM_T *) message);
        break;
    case A2DP_ADD_SEP_CFM:
    	handleA2DPAddSepCfm(app, (A2DP_ADD_SEP_CFM_T *) message);
        break;
        
    case A2DP_OPEN_IND:
    	handleA2DPOpenInd(app, ((A2DP_OPEN_IND_T*)message)->media_sink, ((A2DP_OPEN_IND_T*)message)->sep_type);
        break;
    case A2DP_OPEN_CFM:
    	handleA2DPOpenCfm(app, (A2DP_OPEN_CFM_T *)message);
        break;
                    
    case A2DP_START_IND:
    	handleA2DPStartInd(app, (A2DP_START_IND_T*)message);
        break;
    case A2DP_START_CFM:
    	handleA2DPStartCfm(app, (A2DP_START_CFM_T*)message);
        break;
        
    case A2DP_SUSPEND_IND:
    	handleA2DPSuspendInd(app, (A2DP_SUSPEND_IND_T*)message);
        break;
    case A2DP_SUSPEND_CFM:
    	handleA2DPSuspendCfm(app, (A2DP_SUSPEND_CFM_T*)message);
        break;
        
    case A2DP_CLOSE_IND:
    case A2DP_CLOSE_CFM: /* Deliberate Fall Through */
    	handleA2DPClose(app);
        break;
        
    case A2DP_CODEC_SETTINGS_IND:
    	handleA2DPCodecSettingsInd(app, (A2DP_CODEC_SETTINGS_IND_T*)message);
        break;
            
    case A2DP_SIGNALLING_OPEN_IND:
    	handleA2DPSignallingOpenInd(app, (A2DP_SIGNALLING_OPEN_IND_T*)message);
		break;
	case A2DP_SIGNALLING_CLOSE_IND:
    	handleA2DPSignallingCloseInd(app, (A2DP_SIGNALLING_CLOSE_IND_T*)message);
		break;
			
    default:       
		A2DP_MSG_DEBUG(("A2DP UNHANDLED MSG: 0x%x\n",id));
        break;
    }    
}

⌨️ 快捷键说明

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