📄 headset_a2dp_msg_handler.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 + -