在前两篇我们介绍了mrcp接收后的处理,最后会调用apr_queue_push扔到消息队列里面。 
对应的,在apt_consumer_task.apt_consumer_task_run()中会循环调用pr_queue.apr_queue_pop()从队列里面取出数据:

apt_consumer_task.apt_consumer_task_run –> 
apr_queue.apr_queue_pop –> 
apt_task.apt_task_msg_process –> 
mrcp_client.mrcp_client_msg_process –> 
mrcp_client_session.mrcp_client_on_message_receive–> 
mrcp_client_session.mrcp_app_control_message_raise–> 
mod_unimrcp.recog_message_handler –> mrcp_application.mrcp_application_message_dispatch–> 
mod_unimrcp.recog_on_message_receive–> 
mod_unimrcp.recog_channel_set_result_headers–> 
mod_unimrcp.recog_channel_set_results–> 
mod_unimrcp.speech_channel_set_state

在apt_consumer_task_run中是一个while循环,调用apr_queue_pop不断去读取队列数据。然后调用apt_task_msg_process处理取出来的数据。

APT_DECLARE(apt_bool_t) apt_task_msg_process(apt_task_t *task, apt_task_msg_t *msg)
{
    apt_bool_t status = FALSE;
    apt_log(APT_LOG_MARK,APT_PRIO_DEBUG,"Process Message [%s] ["APT_PTR_FMT";%d;%d]",
        task->name, msg, msg->type, msg->sub_type);
    if(msg->type == TASK_MSG_CORE) {
        status = apt_core_task_msg_process(task,msg);
    }
    else {
        if(task->vtable.process_msg) {
            status = task->vtable.process_msg(task,msg);
        }
    }

apt_task_msg_release(msg);
    return status;
}

这里主要调用task->vtable.process_msg来处理。在mrcp_client_create函数中,process_msg 被赋值为mrcp_client_msg_process:

vtable = apt_task_vtable_get(task);
    if(vtable) {
        vtable->process_msg = mrcp_client_msg_process;
        vtable->on_start_complete = mrcp_client_on_start_complete;
        vtable->on_terminate_complete = mrcp_client_on_terminate_complete;
    }

所以实际上调用的是mrcp_client_msg_process()。消息的type为:MRCP_CLIENT_CONNECTION_TASK_MSG,subtype为:CONNECTION_AGENT_TASK_MSG_RECEIVE_MESSAGE,所以会调用mrcp_client_on_message_receive,进而调用mrcp_app_control_message_raise()。

static apt_bool_t mrcp_app_control_message_raise(mrcp_client_session_t *session, mrcp_channel_t *channel, mrcp_message_t *mrcp_message)
{
    if(mrcp_message->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE) {
        mrcp_app_message_t *response;
        mrcp_message_t *mrcp_request;
        if(!session->active_request || !session->active_request->control_message) {
            return FALSE;
        }
        response = mrcp_client_app_response_create(session->active_request,0,session->base.pool);
        mrcp_request = session->active_request->control_message;
        mrcp_message->start_line.method_id = mrcp_request->start_line.method_id;
        mrcp_message->start_line.method_name = mrcp_request->start_line.method_name;
        response->control_message = mrcp_message;
        apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Raise App MRCP Response "APT_NAMESID_FMT, 
            MRCP_SESSION_NAMESID(session));
        session->application->handler(response);

session->active_request = apt_list_pop_front(session->request_queue);
        if(session->active_request) {
            mrcp_app_request_dispatch(session,session->active_request);
        }
    }
    else if(mrcp_message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
        mrcp_app_message_t *app_message;
        app_message = mrcp_client_app_control_message_create(session->base.pool);
        app_message->control_message = mrcp_message;
        app_message->application = session->application;
        app_message->session = &session->base;
        app_message->channel = channel;
        apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->base.log_obj,"Raise App MRCP Event "APT_NAMESID_FMT, 
            MRCP_SESSION_NAMESID(session));
        session->application->handler(app_message);
    }
    return TRUE;
}

最终调用的是session->application->handler(app_message),application是一个mrcp_application_t对象。在recog_load()的时候创建

/* Create the recognizer application and link its callbacks */
    if ((globals.recog.app = mrcp_application_create(recog_message_handler, (void *) 0, pool)) == NULL) {
        return SWITCH_STATUS_FALSE;
    }

mrcp_application_create的实现如下:

/** Create application instance */
MRCP_DECLARE(mrcp_application_t*) mrcp_application_create(const mrcp_app_message_handler_f handler, void *obj, apr_pool_t *pool)
{
    mrcp_application_t *application;
    if(!handler) {
        return FALSE;
    }
    apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Create Application");
    application = apr_palloc(pool,sizeof(mrcp_application_t));
    application->obj = obj;
    application->handler = handler;
    application->client = NULL;
    return application;
}

所以最后调用的是recog_message_handler(),进而调用mrcp_application_message_dispatch()。message_type为:MRCP_APP_MESSAGE_TYPE_CONTROL。

case MRCP_APP_MESSAGE_TYPE_CONTROL:
        {
            if(dispatcher->on_message_receive) {
                status = dispatcher->on_message_receive(
                                        app_message->application,
                                        app_message->session,
                                        app_message->channel,
                                        app_message->control_message);
            }
            break;
        }

在recog_load()函数中

globals.recog.dispatcher.on_session_update = NULL;
    globals.recog.dispatcher.on_session_terminate = speech_on_session_terminate;
    globals.recog.dispatcher.on_channel_add = speech_on_channel_add;
    globals.recog.dispatcher.on_channel_remove = speech_on_channel_remove;
    globals.recog.dispatcher.on_message_receive = recog_on_message_receive;

所以实际上调用的是:recog_on_message_receive()。

/**
 * Handle the MRCP responses/events
 */
static apt_bool_t recog_on_message_receive(mrcp_application_t *application, mrcp_session_t *session, mrcp_channel_t *channel, mrcp_message_t *message)
{
    speech_channel_t *schannel = (speech_channel_t *) mrcp_application_channel_object_get(channel);
    mrcp_recog_header_t *recog_hdr = (mrcp_recog_header_t *) mrcp_resource_header_get(message);
    if (message->start_line.message_type == MRCP_MESSAGE_TYPE_RESPONSE) {
        /* received MRCP response */
        if (message->start_line.method_id == RECOGNIZER_RECOGNIZE) {
            /* received the response to RECOGNIZE request */
            if (message->start_line.request_state == MRCP_REQUEST_STATE_INPROGRESS) {
                /* RECOGNIZE in progress */
                switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) RECOGNIZE IN PROGRESS\n", schannel->name);
                speech_channel_set_state(schannel, SPEECH_CHANNEL_PROCESSING);
            } else if (message->start_line.request_state == MRCP_REQUEST_STATE_COMPLETE) {
                /* RECOGNIZE failed to start */
                if (!recog_hdr || recog_hdr->completion_cause == RECOGNIZER_COMPLETION_CAUSE_UNKNOWN) {
                    switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) RECOGNIZE failed: status = %d\n", schannel->name,
                                      message->start_line.status_code);
                } else {
                    switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) RECOGNIZE failed: status = %d, completion-cause = %03d\n",
                                      schannel->name, message->start_line.status_code, recog_hdr->completion_cause);
                }
                speech_channel_set_state(schannel, SPEECH_CHANNEL_ERROR);
            } else if (message->start_line.request_state == MRCP_REQUEST_STATE_PENDING) {
                /* RECOGNIZE is queued */
                switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) RECOGNIZE PENDING\n", schannel->name);
            } else {
                /* received unexpected request_state */
                switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) unexpected RECOGNIZE request state: %d\n", schannel->name,
                                  message->start_line.request_state);
                speech_channel_set_state(schannel, SPEECH_CHANNEL_ERROR);
            }
        } else if (message->start_line.method_id == RECOGNIZER_STOP) {
            /* received response to the STOP request */
            if (message->start_line.request_state == MRCP_REQUEST_STATE_COMPLETE) {
                /* got COMPLETE */
                switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) RECOGNIZE STOPPED\n", schannel->name);
                speech_channel_set_state(schannel, SPEECH_CHANNEL_READY);
            } else {
                /* received unexpected request state */
                switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) unexpected STOP request state: %d\n", schannel->name,
                                  message->start_line.request_state);
                speech_channel_set_state(schannel, SPEECH_CHANNEL_ERROR);
            }
        } else if (message->start_line.method_id == RECOGNIZER_START_INPUT_TIMERS) {
            /* received response to START-INPUT-TIMERS request */
            if (message->start_line.request_state == MRCP_REQUEST_STATE_COMPLETE) {
                if (message->start_line.status_code >= 200 && message->start_line.status_code <= 299) {
                    switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) timers started\n", schannel->name);
                    recog_channel_set_timers_started(schannel);
                } else {
                    switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) timers failed to start, status code = %d\n", schannel->name,
                                      message->start_line.status_code);
                }
            }
        } else if (message->start_line.method_id == RECOGNIZER_DEFINE_GRAMMAR) {
            /* received response to DEFINE-GRAMMAR request */
            if (message->start_line.request_state == MRCP_REQUEST_STATE_COMPLETE) {
                if (message->start_line.status_code >= 200 && message->start_line.status_code <= 299) {
                    switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) grammar loaded\n", schannel->name);
                    speech_channel_set_state(schannel, SPEECH_CHANNEL_READY);
                } else {
                    switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) grammar failed to load, status code = %d\n", schannel->name,
                                      message->start_line.status_code);
                    speech_channel_set_state(schannel, SPEECH_CHANNEL_ERROR);
                }
            }
        } else {
            /* received unexpected response */
            switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) unexpected response, method_id = %d\n", schannel->name,
                              (int) message->start_line.method_id);
            speech_channel_set_state(schannel, SPEECH_CHANNEL_ERROR);
        }
    } else if (message->start_line.message_type == MRCP_MESSAGE_TYPE_EVENT) {
        /* received MRCP event */
        if (message->start_line.method_id == RECOGNIZER_RECOGNITION_COMPLETE) {
            switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) RECOGNITION COMPLETE, Completion-Cause: %03d\n", schannel->name,
                              recog_hdr->completion_cause);
            if (message->body.length > 0) {
                if (message->body.buf[message->body.length - 1] == '\0') {
                    recog_channel_set_result_headers(schannel, recog_hdr);
                    recog_channel_set_results(schannel, message->body.buf);
                } else {
                    /* string is not null terminated */
                    char *result = (char *) switch_core_alloc(schannel->memory_pool, message->body.length + 1);
                    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
                                      "(%s) Recognition result is not null-terminated.  Appending null terminator.\n", schannel->name);
                    strncpy(result, message->body.buf, message->body.length);
                    result[message->body.length] = '\0';
                    recog_channel_set_result_headers(schannel, recog_hdr);
                    recog_channel_set_results(schannel, result);
                }
            } else {
                char *completion_cause = switch_mprintf("Completion-Cause: %03d", recog_hdr->completion_cause);
                switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) No result\n", schannel->name);
                recog_channel_set_result_headers(schannel, recog_hdr);
                recog_channel_set_results(schannel, completion_cause);
                switch_safe_free(completion_cause);
            }
            speech_channel_set_state(schannel, SPEECH_CHANNEL_READY);
        } else if (message->start_line.method_id == RECOGNIZER_START_OF_INPUT) {
            switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) START OF INPUT\n", schannel->name);
            recog_channel_set_start_of_input(schannel);
        } else {
            switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) unexpected event, method_id = %d\n", schannel->name,
                              (int) message->start_line.method_id);
            speech_channel_set_state(schannel, SPEECH_CHANNEL_ERROR);
        }
    } else {
        switch_log_printf(SWITCH_CHANNEL_UUID_LOG(schannel->session_uuid), SWITCH_LOG_DEBUG, "(%s) unexpected message type, message_type = %d\n", schannel->name,
                          message->start_line.message_type);
        speech_channel_set_state(schannel, SPEECH_CHANNEL_ERROR);
    }

return TRUE;
}

在这里干了几件实事!在介绍之前先介绍一个对象 
speech_channel_t,每个通道都有一个speech_channel_t对象,speech_channel_t里面有个属性叫data,类型为recognizer_data_t。 
这个就是用来保存识别结果的,非常重要,后面会看到每一个数据传输周期后都会校验一下是否有识别结果并上传给上层应用。 
这里做的事情主要有: 
1.recog_channel_set_result_headers 
将识别结果的头部信息放到recognizer_data_t的result_headers中。 
2.recog_channel_set_results 
将识别结果的具体内容放到recognizer_data_t的result中。 
3.speech_channel_set_state 
更新通道的状态
————————————————
版权声明:本文为CSDN博主「罗自荣」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/luozirong/article/details/78876787

freeswitch mrcp 源码分析--数据接收(下)相关推荐

  1. 【VUE】源码分析 - 数据劫持的基本原理

    tips:本系列博客的代码部分(示例等除外),均出自vue源码内容,版本为2.6.14.但是为了增加易读性,会对不相关内容做选择性省略.如果大家想了解完整的源码,建议自行从官方下载.https://g ...

  2. 基于TCP网络通信的自动升级程序源码分析-客户端接收文件

    升级程序客户端接收文件 /// <summary>/// 文件数据缓存 索引是 ConnectionInfo对象 数据包的顺序号 值是数据/// </summary>Dicti ...

  3. 阿里开源一站式分布式事务框架seata源码分析(AT模式下TM与RM分析)

    序言: 对于阿里开源分布式事务框架seata的详细了解可以参考官网,这里不会详细介绍.本章只会介绍seata中AT模式的源码分析(对阿seata有一定了解或者成功完成过demo). seata中一个事 ...

  4. Nginx源码分析--数据对齐posix_memalign和memalign函数

    posix_memalign函数() /*  * 背景:  *      1)POSIX 1003.1d  *      2)POSIX 标明了通过malloc( ), calloc( ), 和 re ...

  5. JDK源码分析(三)——HashMap 下(基于JDK8)

    目录 概述 内部字段及构造方法 哈希值与索引计算 存储元素 扩容 删除元素 查找元素 总结 概述   在上文我们基于JDK7分析了HashMap的实现源码,介绍了HashMap的加载因子loadFac ...

  6. freeSWITCH detect_speech源码分析

    前段时间用detect_speech配合阿里的引擎做了些ASR的测试.涉及到一点源码的改动.这里记录detect_speech的源码.有助于理解FS的ASR实现. 这里的源码基于V1.8.7描述. d ...

  7. openstack nova 源码分析3-nova目录下的service.py

    nova下的service.py的源码,今天阅读之后 直接就把我理解的以注释的形式添加到了源码中,有些地方不好或者是错了,希望大家帮我指出! import inspect import os impo ...

  8. 风讯dotNETCMS源码分析—数据存取篇

    前几天突然对CMS感兴趣,就去下载了风讯dotNETCMS源码.当前版本是dotnetcms1.0 sp5免费版,风讯的官方主页上可以下载. 用Visual Studio 2008打开后,初步分析了它 ...

  9. android+小米文件管理器源码,[MediaStore]小米文件管理器android版源码分析——数据来源...

    打开小米的文件管理器,我们很快会看到如下图所示的界面: 其中,会把各种文件分类显示.并且显示出每种文件的个数. 这是怎么做到的呢?当然不是每次启动都查询sdcard和应用程序data目录文件啦,那样实 ...

  10. gre tunnel源码分析之接收流程

    GRE(Generic Routing Encapsulation,通用路由封装)协议是对某些网络层协议(如IP 和IPX)的数据报文进行封装,使这些被封装的数据报文能够在另一个网络层协议(如IP)中 ...

最新文章

  1. GPS及惯性传感器在无人驾驶中的应用
  2. 接口自动化实战设计思路,想法及疑问(一)
  3. java大数据组件HBase
  4. mysql单实例多数据库_MySQL单台服务器跑多个实例子详解
  5. 洛谷 P3387 【模板】缩点
  6. React-Native组件之Text内文字垂直居中方案
  7. JDK8 有关集合部分常用的语法
  8. 英语四六级听力有线传输无线发射系统方案
  9. SIM800A模块发短信调试中出现的问题并解决
  10. Emacs-224-彩虹猫的实现
  11. 用python画小兔子_用Python画一只兔子——turtle库circle画圆函数的详细用法介绍
  12. 软件开发自学靠谱吗?
  13. 如何打破双亲委派机制
  14. 社会工程管理——股权分配
  15. 瑞吉外卖项目 基于spring Boot+mybatis-plus开发 超详细笔记,有源码链接
  16. 常用软件安装及破解——IntelliJ IDEA 2019.1
  17. Centos7 Python3.6+Qt5.12.9+ PyQt5.12+Sip v5+QScintilla-2.10+Eric6
  18. Keep It for Mac(专业笔记工具)
  19. 电 脑 小 知 识 荟萃
  20. 前端随机生成验证码vuejsvant~element

热门文章

  1. 技术变化太快,程序员咋办? 从Adobe Flash想到那些年我幸运躲过的MFC和塞班
  2. 没想到你们是这样的女生……
  3. PHP+Wampserver(其中的MariaDB数据库)制作留言板
  4. 正点原子IIC例程讲解笔记(三)——24cxx.c中函数理解
  5. 群晖邮箱服务器需要什么证书,群晖NAS邮件通知及两步验证登录详解
  6. Zabbix 4.2 支持 Prometheus 数据收集
  7. 高性能服务器开发基础系列 (七)——开源一款即时通讯软件的源码
  8. Ubuntu安装有道词典出现缺少依赖关系问题
  9. Linux I2C 核心、总线、与设备驱动
  10. 山东理工ACM[2444]正方形