您的位置:首页 > 其它

csr8670--sink工程的大致工作流程分析(以speaker为例)二

2016-01-23 17:58 411 查看

1.编解码任务的初始化

继续接着流程一分析:

1.1 当连接初始化完成之后,如下所示会调用编解码的初始化任务:这个编解码的任务作用是什么?

case CL_INIT_CFM:
MAIN_DEBUG(("CL_INIT_CFM [%d]\n" , ((CL_INIT_CFM_T*)message)->status ));
if(((CL_INIT_CFM_T*)message)->status == success)
{
/* Initialise the codec task */
sinkInitCodecTask();/*编解码的任务*/


1.2 sinkInitCodecTask函数

DESCRIPTION
Initialises the codec task/*初始化编解码相关的任务*/

RETURNS

*/
static void sinkInitCodecTask ( void )
{
/* The Connection Library has been successfully initialised,
initialise the HFP library to instantiate an instance of both
the HFP and the HSP */

/*init the codec task*/
/*注意传递的两个参数,第二个为最重要任务,注意这个rundata的结构体在main函数configManagerInitMemory();中开辟*/
CodecInitCsrInternal (&theSink.rundata->codec, &theSink.task) ;
}


1.3 接下来进入CodecInitCsrInternal 函数

void CodecInitCsrInternal(CsrInternalCodecTaskData* codec, Task appTask)
{
codec->task.handler = csrInternalMessageHandler;
codec->clientTask = appTask;/*这里很重要,编码器的任务就有了上层任务的入口,可以看一下很多任务的第二个结构体类型都是这样使用的*/
/*向codec的任务发送了一个消息,编码内部初始化请求*/
MessageSend(&codec->task, CODEC_INTERNAL_INIT_REQ, 0);
}


1.4 接下来转向csrInternalMessageHandler函数

void csrInternalMessageHandler(Task task, MessageId id, Message message)
{
CsrInternalCodecTaskData *codec = (CsrInternalCodecTaskData *) task;

/* Check the message id */
switch (id)
{
case CODEC_INTERNAL_INIT_REQ:/*第一次这里将被执行*/
handleCsrInternalCodecInitReq(codec);/*具体的初始化请求*/
break;
case CODEC_INTERNAL_CONFIG_REQ:
handleCsrInternalCodecConfigureReq(codec, (CODEC_INTERNAL_CONFIG_REQ_T *) message);
break;
case CODEC_INTERNAL_INPUT_GAIN_REQ:
handleCsrInternalInputGainReq((CODEC_INTERNAL_INPUT_GAIN_REQ_T *) message);
break;
case CODEC_INTERNAL_OUTPUT_GAIN_REQ:
handleCsrInternalOutputGainReq((CODEC_INTERNAL_OUTPUT_GAIN_REQ_T *) message);
break;

/* Not used */
case CODEC_INTERNAL_CODEC_ENABLE_REQ:
break;
case CODEC_INTERNAL_CODEC_DISABLE_REQ:
break;
case CODEC_INTERNAL_POWER_DOWN_REQ:
break;
default:
break;
}
}


1.5 接下来执行handleCsrInternalCodecInitReq这个函数

void handleCsrInternalCodecInitReq(CsrInternalCodecTaskData *codec)
{
/*发送确认向上层,传递过程中注意参数,codec_success*/
sendInitCfmToApp(&codec->task, codec->clientTask, codec_success, CODEC_INPUT_GAIN_RANGE, CODEC_OUTPUT_GAIN_RANGE);
}


1.6 执行确认发送函数

void sendInitCfmToApp(Task codecTask,
Task clientTask,
codec_status_code status,
uint16 inputGainRange,
uint16 outputGainRange)
{
MAKE_CODEC_MESSAGE(CODEC_INIT_CFM);/*这个信息也会在xIDE中被打印出来,原理是什么?*/
message->status = status;/*这里是codec_success*/
message->inputGainRange = inputGainRange;
message->outputGainRange = outputGainRange;
message->codecTask = codecTask;
MessageSend(clientTask, CODEC_INIT_CFM, message);/*此时clientTask就是上层那个任务,这个是向上层发送CODEC_INIT_CFM确认消息,这样的话上层就能收到这个消息,即这个初始化也完成了*/
}


1.7 接下来转向上层,处理这个消息,至此编解码的任务就算初始化完成,但是目前不知道这个编解码初始化函数有什么作用,好像整个过程什么也没有做啊???

static void handleCodecMessage  ( Task task, MessageId id, Message message )
{
MAIN_DEBUG(("CODEC MSG received [%x]\n", id)) ;

if (id == CODEC_INIT_CFM )
{       /* The codec is now initialised */

if ( ((CODEC_INIT_CFM_T*)message)->status == codec_success)
{
MAIN_DEBUG(("CODEC_INIT_CFM\n"));/*初始化完成*/
sinkHfpInit();/*进行hfp的初始化*/
theSink.codec_task = ((CODEC_INIT_CFM_T*)message)->codecTask ;/*在程序中有几个不懂的结构体,这个message是一个,有待分析*/
}
else
{
Panic();
}
}
}


接下来就会进行sinkHfpInit的初始化工作

2.Hfp任务的初始化过程

下图表示Hfp初始化过程,这里只对Hfp的初始化过程进行简单分析。



2.1 初始化函数

这个是Hfp的初始化函数,从上图可知当连接库和编解码任务初始化完成之后,下面需要做的就是初始化需要的profile,这个Hfp就是一个profile

void sinkHfpInit( void )
{
hfp_init_params hfp_params;/*定义了一个hfp初始化时用到的参数的结构体,这里为什么使用栈空间,不使用堆空间呢?难道是因为这个数据类型不大,所以用栈空间完全可以?*/

memset(&hfp_params, 0, sizeof(hfp_init_params));/*清空这个结构体*/

/* Get features config so HFP can be initialised correctly depending on mSBC support */
/*配置系统的features,这个信息是保存到theSink的成员中去的,这个features是什么?需要看结构体的定义,关系到系统支持的特性,这个函数很重要,2.1.1*/
configManagerInitFeatures();

sinkClearQueueudEvent(); /*清空消息队列的事件,什么意思呢?*/

/* get the extra hfp supported features such as supported sco packet types
from pskey user 5 */
configManagerHFP_SupportedFeatures();/*同理获取配置信息的,这个信息是保存到theSink的成员中去的*/

/* initialise the hfp library with parameters read from config*/
configManagerHFP_Init(&hfp_params);  /*这里是将刚定义的结构体进行赋值,也是通过获取配置信息,只不过这次只是HFP的配置*/

/* If the current audio plugin has no mSBC support but HFP1.6 is configured,
disable it and enable HFP1.5 */
/*字面翻译:如果当前的音频插件不支持mSBC,但是定义了HFP1.6的话,禁止1.6使能1.5,可以理解为1.5的HFP默认支持SBC,而1.6的需要mSBC的支持?是这样吗*/
if(!audioHfpGetPlugin(hfp_wbs_codec_mask_msbc, theSink.features.audio_plugin) &&
hfp_params.supported_profile & hfp_handsfree_106_profile)
{
/* remove HFP1.6 support */
hfp_params.supported_profile &= ~hfp_handsfree_106_profile;
/* add HFP1.5 support */
hfp_params.supported_profile |= hfp_handsfree_profile;
/* ensure mSBC is removed from the supported codecs */
hfp_params.supported_wbs_codecs &= hfp_wbs_codec_mask_cvsd;
}
/*将信息赋值给上层app*/
theSink.hfp_profiles = hfp_params.supported_profile;

/* store the link loss time in the app */
theSink.linkLossReminderTime = hfp_params.link_loss_interval;

/* initialise hfp library with pskey read configuration */
/*这个应该是具体的初始化hfp库的函数,注意传递的参数2.1.2*/
HfpInit(&theSink.task, &hfp_params, NULL);

/* initialise the audio library, uses one malloc slot */
AudioLibraryInit();
}


2.1.1 configManagerInitFeatures这个函数分析

/****************************************************************************
NAME
configManagerInitFeatures

DESCRIPTION
Read and configure the system features from PS/*看这个描述应该是从ps中读取信息*/

RETURNS
void

*/
void configManagerInitFeatures( void )
{
/* Read and configure the system features */
configManagerFeatureBlock( );
}


static void configManagerFeatureBlock( void )
{
uint8 i;

/* Read the feature block from persistent store */
/*这个就是很重要的那个函数,这个函数获取pstool设置的数据,其中第一个参数应该是pskey,第二个参数为这个数据需要保存在哪里,第三个参数为数据的大小,这里的feature代表的就是系统配置的特性*/
ConfigRetrieve(CONFIG_FEATURE_BLOCK, &theSink.features, sizeof(feature_config_type)) ;

#ifdef ENABLE_PEER
ValidatePeerUseDeviceIdFeature();
#endif

/*Set the default volume level*/
/*翻译设置音量等级*/
for(i=0;i<MAX_PROFILES;i++)
{
theSink.profile_data[i].audio.gSMVolumeLevel = theSink.features.DefaultVolume ;
}

/* if aptX Low Latency is enabled, automatically enable standard aptX */
/*aptX这个是高级应用,目前不考虑*/
if(theSink.features.A2dpOptionalCodecsEnabled & (1<<APTX_SPRINT_CODEC_BIT))
{
theSink.features.A2dpOptionalCodecsEnabled |= (1<<APTX_CODEC_BIT);
}

}


2.1.2 HfpInit函数的分析

MESSAGE RETURNED
HFP_INIT_CFM/*可以看出这个函数执行完之后,会有一个确认信息发出,我们往下看*/

RETURNS
void
*/
void HfpInit(Task theAppTask, const hfp_init_params *config, const char* extra_indicators)
{
if(theHfp)/*判断是否hfp任务已经有了,这里theHfp不为NULL,且config为传递过了的配置参数*/
{
hfpInitCfmToApp(hfp_init_reinit_fail);
return;
}

/* Check the app has passed in a valid pointer. */
if (!config)
{
HFP_DEBUG(("Config parameters not passed in\n"));/*不会执行*/
}
else
{
uint8             size_hfp_data;
hfp_task_data*    lHfp;
hfp_link_data*    link;
hfp_profile       profile  = config->supported_profile;

/* Calculate number of links and services */
uint8 num_links    = (config->multipoint ? 2 : 1);/*应该是判断是否支持多点连接,看英文注释:Whether multiple connections to one profile are supported */
uint8 num_services = 0;

if(supportedProfileIsHfp(profile))/*判断是否支持Hfp*/
num_services += num_links;/*如果支持的话,将支持的服务加1*/

if(supportedProfileIsHsp(profile))/*判断是否支持Hsp*/
num_services += num_links;/*经过这两个判断:num_services 可能出现的值有四个
1:不支持多点连接也不支持Hfp和Hsp
2:不支持多点连接支持Hfp或者Hsp
3:支持多点连接也支持Hfp或者Hsp
4:支持多点连接支持Hfp和Hsp      */

/* Calculate overall memory requirement */
/*计算需要的内存空间,需要为HFP任务做准备*/
size_hfp_data = sizeof(hfp_task_data)
+ num_links * sizeof(hfp_link_data)
+ num_services * sizeof(hfp_service_data);

/* Allocate and zero our hfp_task_data */
/*开辟空间,这样直接连续赋值可以吗?在c语言中?*/
lHfp = theHfp = PanicUnlessMalloc(size_hfp_data);/*这样的话lHfp和theHfp指向相同*/
memset(lHfp, 0, size_hfp_data);/*清空开辟的空间*/

/* Set pointers - NB. (lHfp + 1) compiles to (lHfp + (1 * sizeof(hfp_task_data))) */
/*这里看不懂??????????*/
lHfp->links    = (hfp_link_data*)(lHfp + 1);
lHfp->services = (hfp_service_data*)(lHfp->links + num_links);
lHfp->top      = (hfp_service_data*)(lHfp->services + num_services);

PRINT(("HFP Task Data taking up %d words\n", size_hfp_data));
PRINT(("%d Words for main task\n",           sizeof(hfp_task_data)));
PRINT(("%d Words for links\n",               sizeof(hfp_link_data) * num_links));
PRINT(("%d Words for services\n",            sizeof(hfp_service_data) * num_services));

/* Set the handler function */
lHfp->task.handler = hfpProfileHandler;/*设置回到函数*/

/* Mask out unsupported features. */
lHfp->hf_supported_features = (config->supported_features & ~HFP_ENHANCED_CALL_CONTROL);/*掩盖不支持的功能,这是百度翻译的结果T0T...*/

if(!supportedProfileIsHfp106(profile))/*Hfp也有版本,自行百度1.5与1.6*/
lHfp->hf_supported_features &= ~HFP_CODEC_NEGOTIATION;

/* Codec negotiation is supported */
if(hfFeatureEnabled(HFP_CODEC_NEGOTIATION))/*这个和支持的特性有关吧?*/
hfpWbsEnable(config->supported_wbs_codecs);

/* Set the number of link loss reconnect attempts */
/*参数断开连接式重连尝试的参数设置*/
lHfp->link_loss_time     = config->link_loss_time;
lHfp->link_loss_interval = config->link_loss_interval;

/* Set up other config options */
lHfp->extra_indicators = extra_indicators;
lHfp->optional_indicators = config->optional_indicators;
lHfp->disable_nrec = config->disable_nrec;
lHfp->extended_errors = config->extended_errors;
lHfp->csr_features = config->csr_features;

/* Store the app task so we know where to return responses */
lHfp->clientTask = theAppTask;/*又出现了,不用说了一样的作用*/

if(config->supported_profile == hfp_no_profile)/*什么意思,如果不支持hfp这个profile,发送初始化完成,正常情况下不会执行这个*/
{
hfpInitCfmToApp(hfp_init_success);/*发送的是hfp初始化完成信息,应用层怎样知道不支持hfp的呢?这里将标志设置为初始化成功??不明白*/
return;
}
/*抱歉这个地方看的不是很明白,稍后看完再分析..*/
/* Connection related state updated in separate function */
for_all_links(link)
{
/*hfpLinkReset(link, FALSE); - link already memset to 0 above */
link->ag_supported_features = (AG_THREE_WAY_CALLING | AG_IN_BAND_RING);
}

/* Ensure only one HFP version is specified (1.6 takes priority) */
if(supportedProfileIsHfp106(profile))
profile &= ~hfp_handsfree_profile;

/* Set up services and begin registration */
hfpServicesInit(profile, config->multipoint);/*服务初始化*/
hfpServiceChannelRegister(theHfp->services);/*服务注册,这两个意思不懂??*/

/* We want sync connect notifications */
ConnectionSyncRegister(&theHfp->task);/*代码看过去,往上层的连接库的回调函数发送的消息*/
}
}


2.1 HFP的流程文字版

这里需要对HFP的流程有一个明确的思路,这个hfp是两个设备之间进行通信的,所以只了解一端的数据是很难理解的,需要AG和HF端都能够了解,这样的话上面图片中的一些初始化消息到底是怎么来的才能看懂。在csr8670–不能不知道的基本知识,长期记录中,有对HFP的简单分析,但是这里,我们需要对HFP中的两个设备的过程进行详细的分析。

说明,以下来自HFP15_SPEC_V10r00.pdf的翻译,英文有限希望大家去看原文

不管是HF还是AG都会进行SCL(Service Level Connection )的连接建立,但是这个SCL的建立必须依赖于RFCOMM的建立,所以FHP的初始化首先会进行RFCOMM连接的建立。

也就是这两个函数

/* Set up theHfp->services structure with profiles from app configuration and corresponding default RFCOMM channels.*/
/*这里是初始化服务的,至于是哪个服务不了解,知道也初始化了RFC相关的通道*/
hfpServicesInit(profile, config->multipoint);

/*这里是RFC通道注册用的,执行这个函数,会上上面发送一个CL_INTERNAL_RFCOMM_REGISTER_REQ请求*/
hfpServiceChannelRegister(theHfp->services);


接下来处理发送的请求

case CL_INTERNAL_RFCOMM_REGISTER_REQ:
PRINT(("CL_INTERNAL_RFCOMM_REGISTER_REQ\n"));
/*注册rfc请求*/
connectionHandleRfcommRegisterReq((CL_INTERNAL_RFCOMM_REGISTER_REQ_T *)message);
break;

/*****************************************************************************
RFCOMM Register (Sequential)

Triggers:
ConnectionRfcommAllocateChannel
ConnectionRfcommAllocateChannelLazy

Message Sequence:
Connection -> BlueStack         RFC_REGISTER_REQ
Bluestack -> Connection         RFC_REGISTER_CFM

Response:
CL_RFCOMM_REGISTER_CFM  //执行这个函数之后会有一个注册确认响应

******************************************************************************/
void connectionHandleRfcommRegisterReq(const CL_INTERNAL_RFCOMM_REGISTER_REQ_T *req)
{
/*
Create an entry in the connection map to enable incoming primitives on this
server channel to be mapped to the correct task
*/
MAKE_PRIM_T(RFC_REGISTER_REQ);
prim->phandle           = 0;
prim->context           = (uint16) req->theAppTask;
prim->flags             = 0;
prim->loc_serv_chan_req = req->suggested_server_channel;
VmSendRfcommPrim(prim);
}
执行这个函数之后,会从Bluestack 发送回来MESSAGE_BLUESTACK_RFCOMM_PRIM接着执行--->connectionBluestackHandlerRfcomm(theCm, (RFCOMM_UPRIM_T *)message)--->由上面可知为RFC_REGISTER_CFM消息所以处理connectionHandleRfcommRegisterCfm((RFC_REGISTER_CFM_T*)message)函数,这个函数会发送一个CL_RFCOMM_REGISTER_CFM消息,也就是上面说的注册确认响应---> hfpInitRfcommRegisterCfm((CL_RFCOMM_REGISTER_CFM_T *) message)至此,RFCOMM的注册过程结束


接下来分析这个函数 ConnectionSyncRegister(&theHfp->task);

void ConnectionSyncRegister(Task theAppTask)
{
/* Send an internal register request message */
MAKE_CL_MESSAGE(CL_INTERNAL_SYNC_REGISTER_REQ);
message->theAppTask = theAppTask;
MessageSend(connectionGetCmTask(), CL_INTERNAL_SYNC_REGISTER_REQ, message);/*发送了一个同步注册请求,向连接库的回调函数*/
}
--->执行这个函数 connectionHandleSyncRegisterReq((CL_INTERNAL_SYNC_REGISTER_REQ_T *) message);看注释是什么同步连接必须要注册这个函数,所以不用管了之后


接下来我还在看英文的文档。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: