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

📄 a2dp_handler.c

📁 实现蓝牙立体声耳机功能。。可以接收并播放来自有蓝牙功能的手机
💻 C
字号:
/****************************************************************************
Copyright (C) Cambridge Silicon Radio Ltd. 2004-2006
Part of BlueLab 3.6.2-release

FILE NAME
    a2dp_handler.c        

DESCRIPTION
    Deals with A2dp functionality.

*/


/****************************************************************************
    Header files
*/
#include "headset_private.h"
#include "a2dp_handler.h"
#include "av_stream_control.h"
#include "avrcp_handler.h"
#include "headset_common.h"
#include "headset_power.h"
#include "headset_tones.h"

#include <codec.h>
#include <kalimba.h>
#include <panic.h>
#include <ps.h>
#include <stdlib.h>


#ifdef DEBUG_A2DP
#define A2DP_DEBUG(x) DEBUG(x)
#else
#define A2DP_DEBUG(x) 
#endif


static void playConnectTone(headsetTaskData* app)
{
    headsetPlayTone(app, tone_type_connect);
}

static void playErrorTone(headsetTaskData* app)
{
    headsetPlayTone(app, tone_type_error);
}


/**************************************************************************/
void avHeadsetRegisterSep(const headsetTaskData *app, a2dp_sep_type sep)
{
	a2dp_sep_config config;    
	config.sep_type = sep;
	config.params = 0;
	
    A2dpAddSep(app->a2dp, &config);
}


/**************************************************************************/
void avHeadsetHandleA2dpAddSepCfm(headsetTaskData* app, const A2DP_ADD_SEP_CFM_T* cfm)
{
    if(cfm->status == a2dp_success)
    {
		/* SBC is registered last, so wait for it.*/
        if (cfm->sep_type == a2dp_sbc)
        {
            avrcp_init_params config;
            config.device_type = avrcp_controller;
            config.priority = 50;

			/* Go ahead and Initialise the AVRCP library */
			AvrcpInit(&app->task, &config);
                    
			/* Change to Ready state */
			setA2dpState(app, avHeadsetA2dpReady);
		}
    }
    else
    {
        A2DP_DEBUG(("A2DP: Unable to register SEPs\n"));
	Panic();
    }
}


/**************************************************************************/
void avHeadsetHandleA2dpOpenInd(headsetTaskData* app, const A2DP_OPEN_IND_T* ind)
{   
    bdaddr bdaddr_ind;

	APP_AVRCP_CONNECT_REQ_T *message = PanicNull(malloc(sizeof(APP_AVRCP_CONNECT_REQ_T)));
    
    (void) SinkGetBdAddr(ind->media_sink, &bdaddr_ind);

	message->addr = bdaddr_ind;
    MessageSendLater(getAppTask(), APP_AVRCP_CONNECT_REQ, message, 0);

    setA2dpState(app, avHeadsetA2dpConnected);

    /* Store the address of the device that just connecetd to us */
    (void)PsStore(LAST_USED_AV_SOURCE, &bdaddr_ind, sizeof(bdaddr)); 
    (void)PsStore(LAST_USED_AV_SOURCE_SEP, &(ind->sep_type), sizeof(a2dp_sep_type));
    
    /* Store the media sink */
    app->media_sink = ind->media_sink;
}


/**************************************************************************/
void avHeadsetHandleA2dpSignallingOpenInd(headsetTaskData* app, const A2DP_SIGNALLING_OPEN_IND_T* ind)
{   
	bdaddr bdaddr_ind;

    app->sig_sink = ind->sink;
    
    /* We are now connected */
    if ((app->a2dp_state == avHeadsetA2dpReady) || (app->a2dp_state == avHeadsetA2dpInitiating))
        setA2dpState(app, avHeadsetA2dpSignallingActive);
    

    /* Establish an AVRCP connection if required */
	if (app->avrcp_state == avHeadsetAvrcpReady)
	{	
        APP_AVRCP_CONNECT_REQ_T *message = PanicNull(malloc(sizeof(APP_AVRCP_CONNECT_REQ_T)));
		(void) SinkGetBdAddr(ind->sink, &bdaddr_ind);
        message->addr = bdaddr_ind;
        MessageSendLater(getAppTask(), APP_AVRCP_CONNECT_REQ, message, 3000);
	}

    playConnectTone(app);  
}


/**************************************************************************/
void avHeadsetHandleA2dpOpenCfm(headsetTaskData* app, const A2DP_OPEN_CFM_T* cfm)
{
    bdaddr bdaddr_cfm;
    
    if (cfm->result == a2dp_success)
    {
		APP_AVRCP_CONNECT_REQ_T *message = PanicNull(malloc(sizeof(APP_AVRCP_CONNECT_REQ_T)));

		(void)PsStore(LAST_USED_AV_SOURCE_SEP, &(cfm->sep_type), sizeof(a2dp_sep_type));  
        A2dpStart(app->a2dp, cfm->media_sink); 
        
        setA2dpState(app, avHeadsetA2dpConnected);
        
        /* Store the media sink and source id*/
        app->media_sink = cfm->media_sink;
        
        SinkGetBdAddr(cfm->media_sink, &bdaddr_cfm);
		message->addr = bdaddr_cfm;
        MessageSendLater(getAppTask(), APP_AVRCP_CONNECT_REQ, message, 0);
    }
    else
    {
        if (app->sig_sink)
            setA2dpState(app, avHeadsetA2dpSignallingActive);
        else
		{
			/* Try SBC if MP3 failed */
			if ((cfm->sep_type == a2dp_mpeg_audio)  && (cfm->result == a2dp_fail))
			{
				bdaddr addr;
				bool found = FALSE;
				found = PsRetrieve(LAST_USED_AV_SOURCE, &addr, sizeof(bdaddr));
				if (!found)
					found = PsRetrieve(LAST_PAIRED_DEVICE, &addr, sizeof(bdaddr));
				if (found)
				{
					A2dpOpen(app->a2dp, a2dp_sbc, &addr);
					return;
				}
			}
			setA2dpState(app, avHeadsetA2dpReady);
			playErrorTone(app);
		}
    }
    app->headset_connecting_av = FALSE;
}


/**************************************************************************/
void avHeadsetHandleA2dpStartInd(headsetTaskData* app, const A2DP_START_IND_T* ind)
{
    if (!app->media_sink || (app->a2dp_state == avHeadsetA2dpStreaming))
        return;
    
    if (app->sco_sink)
    {
        /* SCO is active so don't start AV */
        A2dpSuspend(app->a2dp, ind->media_sink);
        avHeadsetSendPause(app);
    }
    else
	{
		avHeadsetUpdateAvrcpPlayState(app, 1);
        avHeadsetAvStreamStart(app);
	}
    /* Change to streaming state */
    setA2dpState(app, avHeadsetA2dpStreaming);
    
    /* Cancel pairing mode */
    (void) MessageCancelAll(getAppTask(), APP_PAIR_MODE_END_IND);
    MessageSend(getAppTask(), APP_PAIR_MODE_END_IND, 0);
}


/**************************************************************************/
void avHeadsetHandleA2dpStartCfm(headsetTaskData* app, const A2DP_START_CFM_T* cfm)
{
    if (cfm->result == a2dp_success)
    {   
        /* Cancel pairing mode */
        (void) MessageCancelAll(getAppTask(), APP_PAIR_MODE_END_IND);
        MessageSend(getAppTask(), APP_PAIR_MODE_END_IND, 0);

        /* start Kalimba decoding if it isn't already */
        if (app->av_stream_stopped)
        {			
            if (app->sco_sink)
            {
                /* 
                    SCO has become active while we were waiting for a START_CFM.
				    AV doesn't want to be streaming now, so we must try to 
				    suspend the source again.
				*/
                A2dpSuspend(app->a2dp, cfm->media_sink);
                avHeadsetSendPause(app);
                return;
            }
            else
            {
				avHeadsetUpdateAvrcpPlayState(app, 1);
                avHeadsetAvStreamStart(app);
            }
        } 
        
        setA2dpState(app, avHeadsetA2dpStreaming);
    }
    else
    {
        /* failed to start, close the connection */
        A2dpClose(app->a2dp, cfm->media_sink);

        if (app->avrcp_state == avHeadsetAvrcpConnected)
            AvrcpDisconnect(app->avrcp);
    }
}


/**************************************************************************/
void avHeadsetHandleA2dpSuspendInd(headsetTaskData *app)
{
    /* Change to connected state */
    setA2dpState(app, avHeadsetA2dpConnected);
	avHeadsetUpdateAvrcpPlayState(app, 0);
    avHeadsetAvStreamStop(app, FALSE);
}


/**************************************************************************/
void avHeadsetHandleA2dpSuspendCfm(headsetTaskData* app, const A2DP_SUSPEND_CFM_T* ind)
{
    if (ind->result == a2dp_success)
    {
        setA2dpState(app, avHeadsetA2dpConnected);
        
        if (!app->av_stream_stopped)
        {
            /* We must have had a stream restart at this end occuring so restart AV source */
            A2dpStart(app->a2dp, app->media_sink);
            avHeadsetSendPlay(app);
        }
        else
        {
            /* We have suspended the AV source. */
            app->sent_suspend = TRUE;
        }
    }
}


/**************************************************************************/
void avHeadsetHandleA2dpCloseInd(headsetTaskData *app, const A2DP_CLOSE_IND_T *ind)
{
    /* Stop the media stream */
    avHeadsetAvStreamStop(app,FALSE);

    /* Power down the codec */
    CodecPowerDown(app->codec_task);

    /* Change state */
    if ((app->a2dp_state == avHeadsetA2dpStreaming) || (app->a2dp_state == avHeadsetA2dpConnected))
        setA2dpState(app, avHeadsetA2dpSignallingActive);
    else
        setA2dpState(app, avHeadsetA2dpReady);
   
    /* Switch to hfp mode */
    
    app->media_sink = 0;
	avHeadsetUpdateAvrcpPlayState(app, 0);
    app->sent_suspend = FALSE;

}


/**************************************************************************/
void avHeadsetHandleA2dpSignallingCloseInd(headsetTaskData* app, const A2DP_SIGNALLING_CLOSE_IND_T* ind)
{
    /* Change to ready state */
    setA2dpState(app, avHeadsetA2dpReady);
    
    app->sig_sink = 0;
	
	if (app->avrcp_state == avHeadsetAvrcpConnected)
        AvrcpDisconnect(app->avrcp);
	
	/* Switch to hfp mode */
    app->active_profile = hfp_active;
    
    /* Reconnect on link loss */
    if (ind->result == a2dp_disconnect_link_loss)
        avHeadsetHandleAvConnectRequest(app);

}


/**************************************************************************/
void avHeadsetHandleA2dpCloseCfm(headsetTaskData* app)
{
    /* Stop the media stream */
    avHeadsetAvStreamStop(app,FALSE);
    /* Switch to hfp mode */
    app->active_profile = hfp_active;

    /* Change state */
    if ((app->a2dp_state == avHeadsetA2dpStreaming) || (app->a2dp_state == avHeadsetA2dpConnected))
        setA2dpState(app, avHeadsetA2dpSignallingActive);
    else
        setA2dpState(app, avHeadsetA2dpReady);
    
    app->media_sink = 0;
	avHeadsetUpdateAvrcpPlayState(app, 0);
    app->sent_suspend = FALSE;
}


/**************************************************************************/
void avHeadsetHandleA2dpCodecSettingsInd(headsetTaskData *theAvApp, const A2DP_CODEC_SETTINGS_IND_T *ind)
{
	/* Store the codec config settings */
	theAvApp->channel_mode = ind->channel_mode;
	theAvApp->rate = ind->rate;
}

/****************************************************************************/
void avHeadsetHandleAvConnectRequest(headsetTaskData *app)
{
    bdaddr addr;
	uint8 mp3_enabled = 0;
	a2dp_sep_type sep_type = a2dp_sbc;
    
    /* Retrieve the address of the last used AG from PS */
    if (!PsRetrieve(LAST_USED_AV_SOURCE, &addr, sizeof(bdaddr)))
    {
		if (!PsRetrieve(LAST_PAIRED_DEVICE, &addr, sizeof(bdaddr)))
		{
            /* Play an error tone to indicate we don't have a valid address */
		    playErrorTone(app);		    
		    return;
	    }
	}
			
    if ((app->a2dp_state == avHeadsetA2dpReady) || (app->a2dp_state == avHeadsetA2dpSignallingActive))
    {
        app->headset_connecting_av = TRUE;
        setA2dpState(app, avHeadsetA2dpInitiating);

		/*If last connected using MP3 and if MP3 is enabled, reconnect using MP3, otherwise 
		  using SBC*/

		if (PsRetrieve(MP3_ENABLED, &mp3_enabled, sizeof(uint8)))
			if (mp3_enabled)
			{
				if (!PsRetrieve(LAST_USED_AV_SOURCE_SEP, &sep_type, sizeof(a2dp_sep_type)))
					sep_type = a2dp_sbc;
			}

        A2dpOpen(app->a2dp, sep_type, &addr);
    }
}

⌨️ 快捷键说明

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