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就是一个profilevoid 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);看注释是什么同步连接必须要注册这个函数,所以不用管了之后
接下来我还在看英文的文档。。。
相关文章推荐
- HDU 3974 Assign the task
- 通过ValueAnimator实现点击展开和关闭的效果
- break,continue,return
- 没有猜中开头,更加没有预料结尾的我,正努力走在向程序媛发展的道路上……
- uva11462
- K-means算法原理与R语言实例
- JSON C# Class Generator ---由json字符串生成C#实体类的工具
- 简单理解python下的字符串
- Linux 盐计划:免费申请电脑试用 Linux,让你无忧折腾够
- 68. Pascal's Triangle II
- Mac下的VI bundle配置
- oKit6.0震撼发布,全面开启自定义模式
- 如果不小心把mysql的权限表删除了恢复方法
- 跨平台、高性能的媒体转发服务器实现
- 60个开发者不容错过的免费资源库
- hdu 3364(异或方程的高斯消元)
- 服务器之间建立信任关系
- 多线程实例
- I am back-电商网站开发&jQuery
- 字符编码