📄 cvc_headset.c
字号:
/****************************************************************************
Copyright (C) Cambridge Silicon Radio Ltd. 2004-2006
Part of BlueLab 3.4.2-release
FILE NAME
cvc_headset.c
DESCRIPTION
Support for CVC in av_headset_hfp
Only active if INCLUDE_CVC is defined in the project properties.
NOTES
The supporting DSP code is supplied as a preassembled .kap file and is
time limited until licenced.
*/
#ifdef INCLUDE_CVC
/****************************************************************************
Header files
*/
#include "headset_private.h"
#include "headset_tones.h"
#include "headset_volume.h"
#include "cvc_headset.h"
#include "cvcdsp.h"
#include <codec.h>
#include <file.h>
#include <kalimba.h>
#include <kalimba_standard_messages.h>
#include <pcm.h>
#include <stdlib.h>
#include <string.h>
#include <transform.h>
#include <panic.h>
#include <ps.h>
#include <pio.h>
#include <message.h>
#include <stream.h>
#ifdef DEBUG_CVC
#define CVC_DEBUG(x) DEBUG(x)
#else
#define CVC_DEBUG(x)
#endif
/* CVC Message IDs */
#define CVC_READY 0x1000
#define CVC_SETMODE 0x1001
#define CVC_VOLUME 0x1002
#define CVC_CODEC 0x1006
#define CVC_STATUS 0x1007
#define CVC_KEY_CMD 0x100A
#define CVC_KEY_RESP 0x100B
/* System Modes */
#define SYSMODE_HFK 1
#define SYSMODE_ASR 2
#define SYSMODE_PSTHRGH 3
/* Call State */
#define CALLST_CONNECTED 1
#define CALLST_MUTE 3
static unsigned short CvcKey[4];
/* Filename containing the CHF DSP code. */
static const char enc_codec[] = "cvc/cvc.kap";
static bool cvc_init(headsetTaskData* app);
static void start_kalimba(headsetTaskData* app);
static void connect_streams(headsetTaskData *app);
static void dsp_handler(Task, MessageId, Message);
static bool cvc_init(headsetTaskData* app)
{
bool ret = FALSE;
if (!app->cvc.hfkdspready)
{
start_kalimba(app);
/* Disconnect anything already connected to PCM slots 0 and 1 */
StreamDisconnect(StreamPcmSource(0), StreamPcmSink(0));
StreamDisconnect(StreamPcmSource(1), StreamPcmSink(1));
/*
Set both ports to none to allow reassigning of internal DACs below.
(A DAC can only be routed to one port at a time!)
*/
(void) PanicFalse(PcmClearRouting(0));
(void) PanicFalse(PcmClearRouting(1));
/* Configure port 0 to be routed to internal codec A and B, with a sample rate of 8k. */
(void) PanicFalse(PcmRateAndRoute(0, PCM_NO_SYNC, (uint32) 8000, (uint32) 8000, VM_PCM_INTERNAL_A_AND_B));
ret = TRUE;
}
return ret;
}
/* The following function is used to start the DSP code. The code */
/* for the DSP resides in the constant data area as a file in a file */
/* system. Once the file is located, the file is loaded into the DSP*/
/* and started. */
static void start_kalimba(headsetTaskData* app)
{
/* Find the codec file in the file system */
FILE_INDEX index = FileFind(FILE_ROOT,enc_codec,sizeof(enc_codec)-1/*don't pass terminator*/);
if(index == FILE_NONE)
{
/* Error - can't find file */
CVC_DEBUG(("CVC: CHF file index = %x \n",index));
Panic();
}
(void) MessageCancelAll(&app->cvc.task, MESSAGE_FROM_KALIMBA);
MessageKalimbaTask(&app->cvc.task);
/* Load the cvc algorithm into Kalimba */
if(!KalimbaLoad(index))
{
CVC_DEBUG(("CVC: Kalimba load fail\n"));
Panic();
}
/* Now the kap file has been loaded, wait for the CVC_READY message from the
dsp to be sent to the dsp_handler function. */
}
static void connect_streams(headsetTaskData *app)
{
bool r1, r2, r3, r4;
/* Connect the stream from the Mic to the DSP and the stream
from the DSP to the Speaker. */
r1 = StreamConnect(StreamPcmSource(0),StreamKalimbaSink(0));
r2 = StreamConnect(StreamKalimbaSource(0),StreamPcmSink(0));
/* Plug Incoming SCO link into DSP Channel 1 Input. */
r3 = StreamConnect(StreamSourceFromSink(app->sco_sink),StreamKalimbaSink(1));
/* Plug DSP Channel 1 Output into Outoing SCO Link */
r4 = StreamConnect(StreamKalimbaSource(1),app->sco_sink);
CVC_DEBUG(("CVC: connect_streams %d %d %d %d\n",r1,r2,r3,r4));
CodecSetOutputGainNow(app->codec_task, app->cvc.cvc_output_codec_gain, left_and_right_ch);
CvcHeadsetVolume(app);
/* Set the Dsp mode */
CvcSetMode(app);
}
/* The following function is used to handle messages that are */
/* dispatched from the DSP. */
typedef struct
{
uint16 id;
uint16 a;
uint16 b;
uint16 c;
uint16 d;
} DSP_REGISTER_T;
static void dsp_handler(Task task, MessageId id, Message message)
{
if (id== MESSAGE_FROM_KALIMBA)
{
const DSP_REGISTER_T *m = (const DSP_REGISTER_T *) message;
uint16 a = m->a;
uint16 b = m->b;
headsetTaskData *app = getApp();
CVC_DEBUG(("CVC: dsp_handler dsp_id = %x a= %x b= %x c= %x d= %x\n" ,m->id,a,b,m->c,m->d));
switch (m->id)
{
case CVC_READY:
/* This command is set to us to indicate that the DSP is */
/* initialized and ready. At this point we need to send the*/
/* configuration parameters to the DSP. Allocate memory to */
/* hold a configuration record. */
a = CvcConfigureDsp(PS_PARAM_BASE,NULL,0);
CVC_DEBUG(("CVC: CVC_READY: DSP is initialized and ready (%x)\n",a));
/* DSP is up and running */
app->cvc.hfkdspready = 1;
if (app->sco_sink && (app->pcm_audio_state == pcm_sco))
{
CVC_DEBUG(("CVC: Ok to connect streams\n"));
connect_streams(app);
}
break;
case CVC_CODEC:
/* We have received a message that defines the values that */
/* are to be loaded for gain levels. Parameter 1 (a) */
/* defines the DAC (speaker) gain. Parameter 2 (b) defines */
/* the ADC (microphone gain). These levels are meant to be */
/* fixed throughout CVC operation. Volume button pushes */
/* do not change codec gain values. Instead, the CVC */
/* algorithm handles these. */
app->cvc.cvc_output_codec_gain = a;
app->cvc.cvc_input_codec_gain = b;
CodecSetOutputGainNow(app->codec_task, a, left_and_right_ch);
CVC_DEBUG(("CVC: CVC_CODEC: Input gain = 0x%x Output gain = 0x%x\n",b,a));
if((b & 0x8000) == 0x8000)
{
CodecEnableMicInputGainA(1);
CodecEnableMicInputGainB(1);
}
else
{
CodecEnableMicInputGainA(0);
CodecEnableMicInputGainB(0);
}
CodecSetInputGainNow(app->codec_task, b, left_and_right_ch);
break;
case CVC_KEY_CMD:
b = CvcSecurityCheck(CvcKey,a);
CVC_DEBUG(("CVC: CVC_KEY_CMD: %x %x\n",a,b));
break;
}
}
}
void CvcInitialise(headsetTaskData *app)
{
app->cvc.task.handler = dsp_handler;
app->cvc.cvc_output_codec_gain = 0;
app->cvc.cvc_input_codec_gain = 0;
/* Check for Security */
PsRetrieve(PS_SEC_KEY,CvcKey, sizeof(uint16)*4);
}
void CvcHeadsetConnect(headsetTaskData *app)
{
CVC_DEBUG(("CVC: hfkdspready = %x\n",app->cvc.hfkdspready));
CVC_DEBUG(("CVC: hfp_state = %x\n",app->hfp_state));
if (!cvc_init(app))
{
/* Disconnect anything already connected to PCM slots 0 and 1 */
StreamDisconnect(0, StreamPcmSink(0));
/* Now connect up the new streams */
connect_streams(app);
CVC_DEBUG(("CVC: Cvc sco connected\n"));
}
}
void CvcHeadsetUnloaded(headsetTaskData *app)
{
/* The DSP has been reloaded by some other part of the application */
app->cvc.hfkdspready = 0;
CVC_DEBUG(("CVC: Cvc unloaded\n"));
}
void CvcHeadsetVolume(headsetTaskData *app)
{
uint16 gain = app->speaker_volume.hfp_volume;
if(app->cvc.hfkdspready)
{
CVC_DEBUG(("CVC: Cvc volume = %x\n",gain));
if(!KalimbaSendMessage(CVC_VOLUME, gain, 0 ,0, 0))
{
CVC_DEBUG(("CVC: SetVolume FAILURE\n"));
}
}
}
void CvcSetMode(headsetTaskData *app)
{
if (!app->cvc.hfkdspready)
return;
if (app->voice.voice_recognition_enabled)
{
CVC_DEBUG(("CVC: SetMode SYSMODE_ASR\n"));
/* Set the DSP mode to apply noise reduction only. */
if(!KalimbaSendMessage(CVC_SETMODE, SYSMODE_ASR, 0, 0, 0))
{
CVC_DEBUG(("CVC: SetMode SYSMODE_ASR FAILURE\n"));
}
}
else
{
CVC_DEBUG(("CVC: Set mode SYSMODE_HFK "));
if (app->mic_mute_on)
{
CVC_DEBUG(("(CALLST_MUTE)\n"));
if (!KalimbaSendMessage(CVC_SETMODE, SYSMODE_HFK, 0, CALLST_MUTE, 0))
{
CVC_DEBUG(("CVC: Set Mode SYSMODE_HFK (CALLST_MUTE) FAILURE\n"));
}
}
else
{
CVC_DEBUG(("(CALLST_CONNECTED)\n"));
/* Set the DSP mode to apply echo cancellation and noise reduction. */
if(!KalimbaSendMessage(CVC_SETMODE, SYSMODE_HFK, 0, CALLST_CONNECTED, 0))
{
CVC_DEBUG(("CVC: SetMode SYSMODE_HFK (CALLST_CONNECTED) FAILURE\n"));
}
}
}
}
#else /* ifndef INCLUDE_CVC */
extern int cvc_headset_dummy_int; /* Suppress empty-file error */
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -