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

本文详细解析CSR8670 Sink工程的工作流程,包括编解码任务初始化、HFP任务初始化等关键步骤,并深入分析了HFP连接建立过程中的RFCOMM注册及同步注册机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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
  • 3
  • 4
  • 5
  • 6
  • 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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 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
  • 2
  • 3
  • 4
  • 5
  • 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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 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();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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

2.Hfp任务的初始化过程

下图表示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();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 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( );
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
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);              
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 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);/*代码看过去,往上层的连接库的回调函数发送的消息*/
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 接下来处理发送的请求
  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的注册过程结束
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 接下来分析这个函数 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);看注释是什么同步连接必须要注册这个函数,所以不用管了之后
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

接下来我还在看英文的文档。。。

原文地址 csr8670--sink工程的大致工作流程分析(以speaker为例)二 - 优快云博客 https://blog.youkuaiyun.com/code_warry/article/details/50524915


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值