📄 hfp_slc.c
字号:
/****************************************************************************
Copyright (C) Cambridge Silicon Radio Ltd. 2004-2006
Part of BlueLab 3.4.2-release
FILE NAME
hfp_slc.c
DESCRIPTION
Handles the HFP Connection.
*/
/****************************************************************************
Header files
*/
#include "headset_private.h"
#include "av_stream_control.h"
#include "hfp_audio.h"
#include "headset_common.h"
#include "headset_power.h"
#include "hfp_ring.h"
#include "hfp_slc.h"
#include "headset_tones.h"
#include <connection.h>
#include <hfp.h>
#include <panic.h>
#include <ps.h>
static void playConnectTone(headsetTaskData* app)
{
headsetPlayTone(app, tone_type_connect);
}
static void playErrorTone(headsetTaskData* app)
{
headsetPlayTone(app, tone_type_error);
}
static void slcConnectFail(headsetTaskData *app, bool play_tone)
{
/* Update the app state */
setHfpState(app, headsetReady);
/* No connection */
app->profile_connected = hfp_no_profile;
/* Cancel the queued button presses */
(void) MessageCancelAll(&app->task, BUTTON_MFB_SHORT);
(void) MessageCancelAll(&app->task, BUTTON_MFB_LONG_RELEASE);
if (app->headset_connecting_hfp > 1)
{
MessageSend(getAppTask(), APP_HFP_SLC_REQ, 0);
}
else
{
(void) MessageCancelAll(getAppTask(), APP_HFP_SLC_TIMEOUT_IND);
app->headset_connecting_hfp = 0;
/* Play an error tone to indicate the connect attempt failed. */
if (play_tone)
playErrorTone(app);
/* Restart music if streaming */
if (app->av_stream_stopped)
MessageSend(getAppTask(), APP_MUSIC_RESTART_IND, 0);
}
}
/****************************************************************************
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 */
if (app->profile_connected == hfp_no_profile)
{
HfpSlcConnectResponse(ind->hfp, 1, &ind->addr, 0);
/* Update the app state */
setHfpState(app, 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)
{
/* 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)
setHfpState(app, headsetConnected);
/* Play connect tone */
playConnectTone(app);
/*End pairing mode*/
MessageSend(getAppTask(), APP_PAIR_MODE_END_IND, 0);
(void) MessageCancelAll(getAppTask(), APP_HFP_SLC_TIMEOUT_IND);
app->headset_connecting_hfp = 0;
/* 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);
/* Inform AG of the current gain settings */
if (app->profile_connected == hfp_handsfree_profile)
{
HfpSendSpeakerVolume(app->hfp, (uint16)app->speaker_volume.hfp_volume);
HfpSendMicrophoneVolume(app->hfp , app->mic_volume);
}
}
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, 1);
}
else
/* Unknown profile instance */
Panic();
}
else if (cfm->status == hfp_connect_failed)
{
/* Something failed during SLC establishment, check we're not trying to disconnect */
if (app->headset_power_state == power_state_powering_down)
{
slcConnectFail(app, 0);
headsetCheckPowerDownStatus(app);
}
else
slcConnectFail(app, 1);
}
else
{
/* Update local state to reflect this */
slcConnectFail(app, 1);
}
}
/*******************Ps*********************************************************
NAME
hfpHeadsetHandleSlcConnectRequest
DESCRIPTION
Request to create a connection to a remote AG.
RETURNS
void
*/
void hfpHeadsetHandleSlcConnectRequest(headsetTaskData *app, hfp_profile profile)
{
bdaddr addr;
/* Retrieve the address of the last used AG from PS */
if (!PsRetrieve(LAST_USED_AG, &addr, sizeof(bdaddr)))
{
if (!PsRetrieve(LAST_PAIRED_DEVICE, &addr, sizeof(bdaddr)))
{
slcConnectFail(app, 1);
return;
}
/* Play an error tone to indicate we don't have a valid address */
playErrorTone(app);
}
/* Update the app state */
setHfpState(app, 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)
{
headsetRestartAV(app);
}
/* Update the app state */
setHfpState(app, headsetReady);
/* Connection disconnected */
app->profile_connected = hfp_no_profile;
app->voice.voice_recognition_enabled = 0;
app->voice.old_voice_recognition_enabled = 0;
/* Cancel a voice request that could be in progress after connection */
(void) MessageCancelAll(getAppTask(), BUTTON_MFB_SHORT);
/* 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.
*/
(void) MessageCancelAll(getAppTask(), APP_MUSIC_RESTART_IND);
MessageSendLater(getAppTask(), APP_MUSIC_RESTART_IND, 0, SLC_CONNECT_TIMEOUT + 1000);
if (app->a2dp_state == avHeadsetA2dpStreaming)
{
avHeadsetAvStreamStop(app, TRUE);
}
/* Send a reconnect attempt */
app->headset_connecting_hfp = 2;
MessageSend(getAppTask(), APP_HFP_SLC_REQ, 0);
/* Set the connect attempt timeout. */
MessageSendLater(getAppTask(), APP_HFP_SLC_TIMEOUT_IND, 0, (uint32) SLC_CONNECT_TIMEOUT);
}
/* If we're ready to power down don't wait any longer */
headsetCheckPowerDownStatus(app);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -