freeswitch mrcp 源码分析--数据接收(下)

本文深入分析了Freeswitch中MRCP数据接收的流程,从apr_queue_pop取出数据,经过apt_task_msg_process、mrcp_client_msg_process,直至调用recog_message_handler和mrcp_application_message_dispatch。重点讲解了消息处理路径及在recog_on_message_receive中执行的三个关键步骤:设置识别结果头部信息、设置识别结果内容和更新通道状态。

这里写图片描述
在前两篇我们介绍了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
<think> 在用户的问题中,用户明确询问FreeSWITCH中Channel-State-Number的含义及使用说明。根据之前的引用和对话历史,用户提供了三个引用,但这些引用主要涉及显示变量与通道变量的区别、网关配置事件以及分机配置存储到Redis的方法,并没有直接提到Channel-State-Number的具体信息。 不过,根据我对FreeSWITCH的了解,Channel-State-Number是一个重要的通道变量,它表示通道当前的状态编号。FreeSWITCH的通道状态机有多个状态,每个状态对应一个数字编号。这些状态反映了呼叫的生命周期,例如初始化、振铃、应答、挂机等。 由于引用中没有直接提供Channel-State-Number的详细信息,我需要根据知识库中的信息进行回答。以下是常见状态编号及其含义: 1. **CS_NEW (0)**: 通道刚被创建,处于初始状态。 2. **CS_INIT (1)**: 通道正在初始化。 3. **CS_ROUTING (2)**: 正在路由呼叫(查找目标)。 4. **CS_SOFT_EXECUTE (3)**: 正在软执行(准备执行应用)。 5. **CS_EXECUTE (4)**: 正在执行拨号计划应用(如bridge)。 6. **CS_EXCHANGE_MEDIA (5)**: 媒体交换中(通话建立)。 7. **CS_PARK (6)**: 通道被暂停(park)。 8. **CS_CONSUME_MEDIA (7)**: 正在消费媒体(如等待输入)。 9. **CS_HIBERNATE (8)**: 通道休眠(节省资源)。 10. **CS_RESET (9)**: 重置通道。 11. **CS_HANGUP (10)**: 挂机(清理中)。 12. **CS_REPORTING (11)**: 报告状态(生成CDR等)。 13. **CS_DESTROY (12)**: 通道即将销毁。 在使用上: - 可通过`uuid_getvar`获取指定通道的状态编号。 - 在拨号计划中,可通过`${channel_state_number}`访问。 - 日志中常见状态转换事件(如`CHANNEL_STATE`事件)。 注意:实际编号可能因版本略有差异,建议查阅官方文档或源码确认。 用户可能还需要知道如何监控这些状态变化,例如通过事件套接字(Event Socket)监听`CHANNEL_STATE`事件。 基于以上分析,我将组织一个清晰的回答,涵盖含义、状态列表及使用方法,并生成相关问题。 </think> ### FreeSWITCH Channel-State-Number 详解 #### 1. **基本含义** `Channel-State-Number` 是 FreeSWITCH 中表示通道当前生命周期的**数字状态码**,用于精确描述呼叫流程的实时阶段(如振铃、通话中、挂机等)。它本质上是通道状态机(State Machine)的数字化表示,每个数字对应一个特定状态[^1][^2]。 #### 2. **状态编号对照表** 以下是常见的状态编号及其含义(基于 FreeSWITCH 1.10+ 版本): | 状态编号 | 常量名 | 含义 | |----------|---------------------|------------------------------| | `0` | `CS_NEW` | 通道刚创建(初始状态) | | `1` | `CS_INIT` | 初始化参数 | | `2` | `CS_ROUTING` | 呼叫路由中(查找目标) | | `3` | `CS_SOFT_EXECUTE` | 准备执行应用(如拨号计划) | | `4` | `CS_EXECUTE` | 正在执行应用(如`bridge`) | | `5` | `CS_EXCHANGE_MEDIA`| **媒体已建立(通话中)** | | `6` | `CS_PARK` | 通道暂停(如呼叫保持) | | `10` | `CS_HANGUP` | **挂机请求已发出** | | `11` | `CS_REPORTING` | 生成话单(CDR) | | `12` | `CS_DESTROY` | 通道销毁(资源释放) | > 注:完整列表见 FreeSWITCH 源码 `switch_channel.h` 中的 `switch_channel_state_t` 枚举。 #### 3. **核心使用场景** - **拨号计划控制** 在 XML 拨号计划中通过条件判断状态: ```xml <condition field="${channel_state_number}" expression="^5$"> <!-- 当通话建立时执行操作 --> </condition> ``` - **API/事件监控** 通过 `event socket` 监听 `CHANNEL_STATE` 事件获取实时状态: ```bash event plain CHANNEL_STATE Channel-State-Number ``` 输出示例: ```json { "Channel-State-Number": "5", "Channel-Call-State": "ACTIVE" } ``` - **日志调试** 在日志中筛选特定状态(如排查未接听问题): ```bash grep "Channel-State-Number: 2" /var/log/freeswitch/freeswitch.log ``` #### 4. **与显示变量的关系** 在日志或事件中,`Channel-State-Number` 作为**显示变量(Info Variable)** 存在,需通过特定命令获取: - 日志中显示为:`Channel-State-Number: [编号]` - API 获取方式: ```bash uuid_getvar <UUID> channel_state_number # 返回数字状态码 ``` #### 5. **注意事项** 1. **与 `Channel-Call-State` 的区别**: `Channel-State-Number` 是精确数字状态,而 `Channel-Call-State` 是文本描述(如 `RINGING`, `ACTIVE`)[^1][^2]。 2. **自定义状态**: 开发者可通过 `switch_channel_set_state()` 扩展状态机,但需避免与系统编号冲突。 3. **版本差异**: 部分早期版本使用 `switch_channel_get_state()` 返回文本,新版本统一推荐用数字状态码[^3]。 --- ### 相关问题 1. 如何通过 `Channel-State-Number` 在拨号计划中实现呼叫超时自动挂断? 2. `CS_EXCHANGE_MEDIA (5)` 与 `CS_CONSUME_MEDIA (7)` 状态有何区别? 3. `Channel-State-Number` 在生成 CDR 话单时起什么作用?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值