📄 hfp_headset_sco.c
字号:
/****************************************************************************
Copyright (C) Cambridge Silicon Radio Ltd. 2004
FILE NAME
hfp_headset_sco.c
DESCRIPTION
NOTES
*/
/****************************************************************************
Header files
*/
#include "headset_private.h"
#include "hfp_headset_sco.h"
#include "av_headset_controls.h"
#include "av_headset_kalimba.h"
#include "cvc_headset.h"
#include <codec.h>
#include <connection.h>
#include <hfp.h>
#include <pcm.h>
#include <panic.h>
#include <sink.h>
#include <source.h>
/****************************************************************************
NAME
hfpGetBestScoPktType
DESCRIPTION
This function looks at the supported features of the remote device and
returns the most appropriate packet type depending on what packets the other
end can support. If the remote end supports HV3 then this is the type
returned. Failing that it checks if HV2 is supported and if so returns that.
Otherwise it returns the default packet type that all devices must support
HV1.
RETURNS
sco_pkt_type
*/
sco_pkt_type hfpGetBestScoPktType(const headsetTaskData *app)
{
if (((app->supp_features_0 >>8) & 0xff) & 0x20)
return sco_hv3;
else if (((app->supp_features_0 >>8) & 0xff) & 0x10)
return sco_hv2;
else
return sco_hv1;
}
/****************************************************************************
NAME
hfpSetupScoRouting
DESCRIPTION
Set up the SCO routing to the PCM.
RETURNS
bool
*/
bool hfpSetupScoRouting(headsetTaskData *app)
{
if (!SinkIsValid(app->sco_sink) || !SourceIsValid(StreamSourceFromSink(app->sco_sink)))
return FALSE;
#ifndef INCLUDE_CVC
StreamDisconnect(StreamPcmSource(0), StreamPcmSink(0));
StreamDisconnect(StreamPcmSource(1), StreamPcmSink(1));
(void) PanicFalse(PcmRoute(0,VM_PCM_NONE,PCM_NO_SYNC));
(void) PanicFalse(PcmRoute(1,VM_PCM_NONE,PCM_NO_SYNC));
#ifdef WOLFSON_CODEC
(void) PanicFalse(PcmRateAndRoute(0, PCM_NO_SYNC, 8000, 8000, VM_PCM_EXTERNAL_I2S));
(void) PanicFalse(PcmRateAndRoute(1, PCM_NO_SYNC, 8000, 8000, VM_PCM_EXTERNAL_I2S));
(void) PanicFalse(StreamConnect(StreamSourceFromSink(app->sco_sink), StreamPcmSink(0)));
(void) PanicFalse(StreamConnect(StreamPcmSource(0), app->sco_sink));
{
codec_config_params codec_settings;
codec_settings.inputs = mic_input;
codec_settings.outputs = 0x1;
codec_settings.adc_sample_rate = 8000;
codec_settings.dac_sample_rate = 8000;
CodecConfigure(app->codec_task,&codec_settings);
}
#else
(void) PanicFalse(PcmRateAndRoute(0, PCM_NO_SYNC, 8000, 8000, VM_PCM_INTERNAL_A_AND_B));
(void) PanicFalse(StreamConnect(StreamSourceFromSink(app->sco_sink), StreamPcmSink(0)));
(void) PanicFalse(StreamConnect(StreamPcmSource(0), app->sco_sink));
#endif
#endif
return TRUE;
}
/****************************************************************************
NAME
hfpHeadsetHandleScoConnectInd
DESCRIPTION
Indication of the AG opening a SCO to the headset.
RETURNS
void
*/
void hfpHeadsetHandleScoConnectInd(headsetTaskData *app, const HFP_SCO_CONNECT_IND_T *ind)
{
uint16 messages_cancelled = 0;
bool sco_routed = FALSE;
bool send_suspend = TRUE;
/* A SCO connection has been opened to this device */
/* TODO: B-4373 how do we support multiple instances */
if (ind->status == hfp_success)
{
/*
Cancel any audio transfer messages. This deals with the case where the AG
opens a SCO before the SLC is completed.
*/
(void) MessageCancelAll(&app->task, BUTTON_PLAY_PAUSE_REL);
(void) MessageCancelAll(&app->task, BUTTON_PLAY_PAUSE_LONG);
/* If AG only supports HV1 SCO packets then close all connected AV streams. */
if (hfpGetBestScoPktType(app) == sco_hv1)
{
A2dpCloseAll(app->a2dp);
send_suspend = FALSE;
}
/* Don't want to restart music as we now have a SCO connection */
messages_cancelled = MessageCancelAll(&app->task, APP_MUSIC_RESTART_IND);
if (!messages_cancelled && (app->a2dp_state == avHeadsetA2dpStreaming))
{
/* If the AV audio has not already been stopped then stop it now */
avHeadsetAvStreamStop(app, send_suspend);
}
/* Store the sink associated with the SCO */
app->sco_sink = ind->sco_sink;
/* Switch to hfp mode */
app->active_profile = hfp_active;
/* Route SCO to the PCM */
app->pcm_audio_state = pcm_sco;
sco_routed = hfpSetupScoRouting(app);
if (sco_routed)
{
/* Update the headset volume */
#ifdef INCLUDE_CVC
CvcHeadsetVolume(app->speaker_volume);
#else
avHeadsetUpdateHfVolume(app->codec_task, app->speaker_volume);
#endif
/* Request to change the SCO packet type to the best we can change it to */
ConnectionScoChangePktType(ind->sco_sink, hfpGetBestScoPktType(app));
}
/* If in HSP mode use sco set up as an indication of active call */
if (app->profile_connected == hfp_headset_profile)
{
app->hfp_state = headsetActiveCall;
/* The spec also requires us to send our current volume level so send it */
HfpSendSpeakerVolume(app->hsp, app->speaker_volume >> VOLUME_SHIFT);
}
#ifdef INCLUDE_CVC
CvcHeadsetConnect(app);
#endif
}
}
/****************************************************************************
NAME
hfpHeadsetHandleScoDisconnectInd
DESCRIPTION
Indication that the SCO connection has been released.
RETURNS
void
*/
void hfpHeadsetHandleScoDisconnectInd(headsetTaskData *app, const HFP_SCO_DISCONNECT_IND_T *ind)
{
ind = ind;
/* Power down the codec */
CodecPowerDown(app->codec_task);
/* Delay before re-starting music. Don't restart music if still an incoming call. */
if (app->hfp_state != headsetIncomingCallEstablish)
{
(void) MessageCancelAll(getAppTask(), APP_MUSIC_RESTART_IND);
MessageSendLater(getAppTask(), APP_MUSIC_RESTART_IND, 0, (uint32) MUSIC_RESTART_DELAY);
}
/* Reset the SCO sink as its no longer valid */
app->sco_sink = 0;
/* If in HSP mode use sco disconnect as an indication of a state change */
if ((app->profile_connected == hfp_headset_profile) && (app->hfp_state != headsetReady))
app->hfp_state = headsetConnected;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -