?? cvc_headset.c
字號:
/****************************************************************************
Copyright (C) Cambridge Silicon Radio Ltd. 2004-2006
Part of BlueLab 3.5.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_codec.h"
#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
/* 5 Minute Demonstration Mode */
/* If ENABLE_DEMO_MODE is defined the audio will mute in 5 minutes */
/* if the CVC security signature is invalid. */
/* If ENABLE_DEMO_MODE is not defined the audio will mute */
/* immediately if the CVC security signature is invalid. This */
/* can be used for immediate notification of an invalid security */
/* signature during production testing. */
#define ENABLE_DEMO_MODE
/* CVC Message IDs From Kalimba */
#define CVC_READY 0x1000
#define CVC_SETMODE 0x1001
#define CVC_VOLUME 0x1002
#define CVC_CODEC 0x1006
#define CVC_STATUS 0x1007
#define CVC_SECPASSED 0x100c
/* CVC Message IDs Not From Kalimba */
/* Security Failure Message ID */
#define CVC_SECFAILED 0x1000
/* System Modes */
#define SYSMODE_HFK 1
#define SYSMODE_ASR 2
#define SYSMODE_PSTHRGH 3
#define SYSMODE_STANDBY 6
/* Call State */
#define CALLST_CONNECTED 1
#define CALLST_MUTE 3
/* 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);
/* This is the table of codec gain values used with CVC */
/* Table entries are configurable, but the maximum value cannot exceed 15 */
static const uint8 vgsToCodecGainCvc[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
/* The Sidetone level can be controlled 3 different ways: */
/* 1) The VM application can send the level as a parameter to the CVC_VOLUME message. */
/* 2) The level can be specified in the cvc "parameters.psr" file. */
/* 3) The value specified in the cvc "parameter.psr" file can be auto leveled by the */
/* dsp such that the level is always constant or it can be made to change with volume. */
/* */
/* The cvc ParamMgr.exe is used to write a psr file that specifies which method is being */
/* used. Regardless of the method, the maximum level that the sidetone gain can be is */
/* -11 dBFS. */
/* If the sidetone level is being controlled by the VM application the following table */
/* will be used. Otherwise, the values sent from this table will be ignored by the dsp. */
/* Note if a value larger than 0x23D7 is used, it will be limited to 0x23D7 by the dsp. */
/* This corresponds to a limit -11 dBFS. */
static const uint8 SideToneGain[16] = {0x23D7, 0x23D7, 0x23D7, 0x23D7, 0x23D7, 0x23D7, 0x23D7, 0x23D7,
0x23D7, 0x23D7, 0x23D7, 0x1CA7, 0x1449, 0x0E5C, 0x0A2A, 0x0732};
static bool cvc_init(headsetTaskData* app)
{
bool ret = FALSE;
if (!app->cvc.hfkdspready)
{
start_kalimba(app);
codec_configure_mono_8000(app);
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;
/* Mute audio before connecting the stream */
CodecSetOutputGainNow(app->codec_task, 0, left_and_right_ch);
/* 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));
/* Tell cvc to set the DAC gain */
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)
{
headsetTaskData *app = getApp();
switch(id)
{
case MESSAGE_FROM_KALIMBA:
{
const DSP_REGISTER_T *m = (const DSP_REGISTER_T *) message;
uint16 a = m->a;
uint16 b = m->b;
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 sent to us to indicate that the DSP is */
/* initialized and ready. At this point we need to send the */
/* configuration parameters to the DSP and allocate memory to */
/* hold a configuration record. This is done within the */
/* CvcConfigureDsp() function which is defined in the */
/* libcvcdsp.a file. */
/* */
/* If multiple sets of parameters are required, Persistent */
/* Store Keys can be defined for each and CvcConfigureDsp can */
/* be called to load the various parameter sets. Note that */
/* the first call to CvcConfigureDsp must be done here as a */
/* response to the CVC_READY message, but that successive */
/* calls do not need to be here. */
a = CvcConfigureDsp(PS_PARAM_BASE,NULL,0,PS_PARAM_BASE2,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);
}
/* Set timer for security fail condition */
/* If the security check on the kalimba passes this mesage */
/* will be cancelled - see CVC_SECPASSED below. */
app->cvc.sec_mute = 0;
MessageSendLater(task, CVC_SECFAILED, 0, 500);
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). The mic level is meant to be */
/* fixed throughout CVC operation. The DAC level changes */
/* in correspondace with volume changes. When using the */
/* CVC algorithm, the DAC gain should always be set using */
/* the CvcHeadsetVolume message so that CVC is aware of the */
/* DAC gain. */
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);
}
/* Clear the upper bytes of the input gain argument */
b &= 0xff;
CodecSetInputGainNow(app->codec_task, b, left_and_right_ch);
break;
case CVC_SECPASSED:
CVC_DEBUG(("CVC: Security passed.\n"));
MessageCancelAll(task, CVC_SECFAILED);
break;
}
}
break;
case CVC_SECFAILED: /* message not from kalimba */
#ifdef ENABLE_DEMO_MODE
CVC_DEBUG(("CVC: Running in Demo Mode.\n"));
#else
CVC_DEBUG(("CVC: Security failed.\n"));
app->cvc.sec_mute = 1;
CvcSetMode(app);
#endif
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;
}
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(StreamPcmSource(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 volume_index = app->speaker_volume.hfp_volume;
if(app->cvc.hfkdspready)
{
CVC_DEBUG(("CVC: Cvc volume = %x\n",volume_index));
CVC_DEBUG(("CVC: Cvc DAC gain = %x\n",app->cvc.cvc_output_codec_gain));
if(!KalimbaSendMessage(CVC_VOLUME, volume_index, 0, vgsToCodecGainCvc[volume_index], SideToneGain[volume_index]))
{
CVC_DEBUG(("CVC: SetVolume FAILURE\n"));
}
}
}
void CvcSetMode(headsetTaskData *app)
{
if (!app->cvc.hfkdspready)
return;
if(app->cvc.sec_mute)
{
if(!KalimbaSendMessage(CVC_SETMODE, SYSMODE_STANDBY, 0, 0, 0))
{
CVC_DEBUG(("CVC: SetMode SYSMODE_STANDBY\n"));
}
}
else 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 + -