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