DTMF从2833到inband的方案

news2025/4/2 15:38:41

概述

freeswitch是一款简单好用的VOIP开源软交换平台。

之前的文章中介绍过通过dialplan拨号计划配置的方法,实现2833到inband的转换,但是实际生产环境中的场景会更复杂,无法预先在dialplan中设置好相关参数和函数。

环境

CentOS 7.9

freeswitch 1.10.7

问题描述

在与运营商的对接过程中,因为对传统PSTN线路的兼容,被叫侧并不是所有的号码都支持2833,B路响应的SDP中会没有rfc2833的媒体描述,也可能183SDP中支持2833,但是200SDP中不支持2833。

fs对于该场景并没有简单的配置方案,默认的处理逻辑会使用INFO消息来转发DTMF,但是运营商并不支持该方式。

所以,我们需要一种简单的配置即可实现的rfc2833到inband的DTMF转发模式。

默认流程

从SDP媒体协商的日志中看到,协商过程都是在“switch_core_media_negotiate_sdp”函数实现的。

fs默认的dtmf匹配流程如下,略过了正常的rfc2833过程。

1,检查B路响应SDP中的“telephone-event”并根据rate匹配一个最佳te。switch_core_media.c:5964。

2,如果没有匹配到最佳te,检查vars.xml中的“rtp_liberal_dtmf”配置为true,则直接使用本地te作为最佳te。switch_core_media.c:6003。

3,如果仍然没有最佳te,检查通道变量“rtp_info_when_no_2833”不是false,则使用INFO模式转发DTMF,否则设置B路的“dtmf_type”为none。

修改方案

修改后的dtmf匹配流程。

1,检查B路响应SDP中的“telephone-event”并根据rate匹配一个最佳te。switch_core_media.c:5964。

2,如果没有匹配到最佳te,检查vars.xml中的“rtp_liberal_dtmf”配置为true,则直接使用本地te作为最佳te。switch_core_media.c:6003。

3,如果有最佳te,走第4步,没有最佳te,走第5步。

4,在设置协商好的te payload之后,增加逻辑,如果在183的协商中已经设置了inband模式,后续的update协商中需要取消inband模式的函数设置。

5,检查通道变量“rtp_info_when_no_2833”不是false,则使用INFO模式转发DTMF。通道变量“rtp_info_when_no_2833”不是false,设置B路的“dtmf_type”为inband,设置B路通道变量“spandsp_dtmf_rx_filter_dialtone”为true,设置B路在answer后调用app函数“deduplicate_dtmf”和“spandsp_start_dtmf”,设置A路在answer后调用app函数“start_dtmf_generate”。

代码如下,switch_core_media.c:6009行开始,红色部分为修改代码。

if (best_te) {
    smh->mparams->te_rate = best_te_rate;

    if (smh->mparams->dtmf_type == DTMF_AUTO || smh->mparams->dtmf_type == DTMF_2833 ||
        switch_channel_test_flag(session->channel, CF_LIBERAL_DTMF)) {
        if (sdp_type == SDP_TYPE_REQUEST) {
            smh->mparams->te = smh->mparams->recv_te = (switch_payload_t) best_te;
            switch_channel_set_variable(session->channel, "dtmf_type", "rfc2833");
            smh->mparams->dtmf_type = DTMF_2833;
        } else {
            smh->mparams->te = (switch_payload_t) best_te;
            switch_channel_set_variable(session->channel, "dtmf_type", "rfc2833");
            smh->mparams->dtmf_type = DTMF_2833;
        }
    }

    if (a_engine->rtp_session) {
        switch_rtp_set_telephony_event(a_engine->rtp_session, smh->mparams->te);
        switch_channel_set_variable_printf(session->channel, "rtp_2833_send_payload", "%d", smh->mparams->te);
        switch_rtp_set_telephony_recv_event(a_engine->rtp_session, smh->mparams->recv_te);
        switch_channel_set_variable_printf(session->channel, "rtp_2833_recv_payload", "%d", smh->mparams->recv_te);
    }

    switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Set 2833 dtmf send payload to %u recv payload to %u\n",
        switch_channel_get_name(session->channel), smh->mparams->te, smh->mparams->recv_te);

    //add by zr 20241018, for 2833 to inband, update method
    //如果在183的协商中已经设置了inband模式,后续的update协商中需要取消inband模式的函数设置
    if (switch_true(switch_channel_get_variable(session->channel, "inband_flag"))) 
    {
        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "reset inband_flag and channel variables.\n");
        //B路
        switch_channel_set_variable(session->channel, "inband_flag", NULL);
        switch_channel_set_variable(session->channel, "spandsp_dtmf_rx_filter_dialtone", NULL);
        switch_channel_set_variable(session->channel, "execute_on_answer_101", NULL);
        switch_channel_set_variable(session->channel, "execute_on_answer_102", NULL);

        //A路,2833 to inband
        if( switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS )
        {
            switch_channel_set_variable(other_session->channel, "execute_on_answer_101", NULL);
            switch_core_session_rwunlock(other_session);
        }
    }
} else {
    /* by default, use SIP INFO if 2833 is not in the SDP */
    if (!switch_false(switch_channel_get_variable(channel, "rtp_info_when_no_2833"))) {
        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "No 2833 in SDP.  Disable 2833 dtmf and switch to INFO\n");
        switch_channel_set_variable(session->channel, "dtmf_type", "info");
        smh->mparams->dtmf_type = DTMF_INFO;
        smh->mparams->recv_te = smh->mparams->te = 0;
    } else {
        // switch_channel_set_variable(session->channel, "dtmf_type", "none");
        // smh->mparams->dtmf_type = DTMF_NONE;
        // smh->mparams->recv_te = smh->mparams->te = 0;
        //add by zr 20241018, for 2833 to inband, update method
        switch_channel_set_variable(session->channel, "dtmf_type", "inband");
        smh->mparams->dtmf_type = DTMF_AUTO;
        smh->mparams->recv_te = smh->mparams->te = 0;
        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "set inband_flag, No 2833 in SDP. Disable 2833 dtmf and switch to INBAND.\n");
        
        //TODO: add inband dtmf
        //A路,2833 to inband
        if( switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS )
        {
            switch_channel_set_variable(other_session->channel, "execute_on_answer_101", "start_dtmf_generate");
            switch_core_session_rwunlock(other_session);
        }

        //B路,inband to 2833
        switch_channel_set_variable(session->channel, "inband_flag", "true");
        switch_channel_set_variable(session->channel, "spandsp_dtmf_rx_filter_dialtone", "true");
        switch_channel_set_variable(session->channel, "execute_on_answer_101", "deduplicate_dtmf");
        switch_channel_set_variable(session->channel, "execute_on_answer_102", "spandsp_start_dtmf");
    }
}

代码编译安装后,修改fs配置,B路使用inband模式。

vars.xml

<X-PRE-PROCESS cmd="set" data="rtp_liberal_dtmf=false"/>

dialplan

<action application="export" data="rtp_info_when_no_2833=false" />

上面的配置可以适配各种情况,当A路支持rfc2833,B路不支持2833的时候。

B路如果仍然希望使用2833则设置“rtp_liberal_dtmf”为true。

B路如果希望使用INFO模式则设置“rtp_liberal_dtmf”为fase,“rtp_info_when_no_2833”为true。

B路如果希望使用inband模式则设置“rtp_liberal_dtmf”为fase,“rtp_info_when_no_2833”为false。

测试

sip媒体的协商过程比较复杂,场景较多,下面列出了各种协商过程和预期结果。

1,200sdp带2833。2833双向正常

2,200sdp不带2833。2833 to inband双向正常

3,183sdp带2833,200不带sdp。2833双向正常

4,183sdp不带2833,200不带sdp。2833 to inband双向正常

5,183sdp不带2833,200sdp不带2833。2833 to inband双向正常

6,183sdp带2833,200sdp不带2833。2833双向正常

7,183sdp不带2833,200sdp带2833。2833 to inband双向正常

8,183sdp带2833,200sdp带2833。2833双向正常

9,183sdp带2833,update sdp带2833,200sdp带2833。2833双向正常

10,183sdp不带2833,update sdp带2833,200sdp带2833。2833双向正常

11,183sdp带2833,update sdp不带2833,200sdp带2833。2833 to inband双向正常

12,183sdp带2833,update sdp带2833,200sdp不带2833。2833双向正常

13,183sdp不带2833,update sdp不带2833,200sdp带2833。2833 to inband双向正常

14,183sdp不带2833,update sdp带2833,200sdp不带2833。2833双向正常

15,183sdp带2833,update sdp不带2833,200sdp不带2833。2833 to inband双向正常

16,183sdp不带2833,update sdp不带2833,200sdp不带2833。2833 to inband双向正常

17,183sdp带2833,update sdp带2833,200不带sdp。2833双向正常

18,183sdp不带2833,update sdp带2833,200不带sdp。2833双向正常

19,183sdp带2833,update sdp不带2833,200不带sdp。2833 to inband双向正常

20,183sdp不带2833,update sdp不带2833,200不带sdp。2833 to inband双向正常

21,A路不带2833的以上20种场景。

经过测试,上诉各场景的预期结果基本满足。从媒体抓包中,可以分别对A路的rtpevent和B路的inband媒体流一一对应起来。

总结

根据sip协议的规范,在媒体协商的过程中,如果已经有183SDP或update的SDP了,则200SDP会被忽略。

上述流程中,对于AB路的其中一路固定为rfc2833的媒体协商是满足的,但是对于AB两路的DTMF模式都不固定的场景仍然有遗留问题,因为场景限制关系,暂不讨论。

上述流程中,对于B路的inband使用了“spandsp_start_dtmf”转换为rfc2833,但是该函数有一定缺陷,转换后的A路媒体流中既有rfc2833,又有少量遗留的inband(擦除不完全,遗留40ms,仍然可以被检测出DTMF),该缺陷会在后续的文章中解决。

空空如常

求真得真

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2323938.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在Vue 3 + TypeScript + Vite 项目中安装和使用 SCSS

在Vue 3 TypeScript Vite 项目中安装和使用 SCSS 1、安装 SCSS 的相关依赖 npm install sass --save-dev2、配置 Vite 对于 Vue 3&#xff0c;Vite 已经内置了对 SCSS 的支持&#xff0c;通常不需要额外的配置。但是&#xff0c;如果需要自定义配置&#xff0c;可以在路径…

Uni-app入门到精通:tabBar节点实现多页面的切换

tabBar节点用于实现多页面的切换。对于一个多tabBar应用&#xff0c;可以通过tabBar节点配置项指定一级导航栏&#xff0c;以及tabBar切换时显示的对应页面。在pages.json中提供tabBar节点配置&#xff0c;不仅是为了方便快速开发导航&#xff0c;更重要的是提示App平台和小程序…

运筹说 第134期 | 矩阵对策的解法

上一期我们了解了矩阵对策的基本理论&#xff0c;包含矩阵对策的纯策略、矩阵对策的混合策略和矩阵对策的基本定理。 接下来小编将为大家介绍矩阵对策的解法&#xff0c;包括图解法、方程组法和线性规划法三种经典方法。 01 图解法 本节首先介绍矩阵对策的图解法&#xff0c;…

3. 轴指令(omron 机器自动化控制器)——>MC_CamOut

机器自动化控制器——第三章 轴指令 15 MC_CamOut变量▶输入变量▶输出变量▶输入输出变量 功能说明▶时序图▶指令的中止▶重启运动指令▶多重启动运动指令▶异常 MC_CamOut 结束通过输入参数指定的轴的凸轮动作 指令名称FB/FUN图形表现ST表现MC_CamOut解除凸轮动作FBMC_Cam…

TF32 与 FP32 的区别

TF32&#xff08;Tensor Float 32&#xff09;与FP32&#xff08;单精度浮点数&#xff09;是两种用于深度学习和高性能计算的浮点格式&#xff0c;其核心区别体现在精度、性能优化和应用场景上。以下是两者的详细对比分析&#xff1a; 一、位宽与结构差异 FP32的位宽结构 FP32…

【大模型】视觉语言模型:Qwen2.5-VL的使用

官方github地址&#xff1a;https://github.com/QwenLM/Qwen2.5-VL 目录 Qwen家族的最新成员&#xff1a;Qwen2.5-VL 主要增强功能 模型架构更新 快速开始 使用Transformers聊天 Docker Qwen家族的最新成员&#xff1a;Qwen2.5-VL 主要增强功能 强大的文档解析功能&am…

测试用例与需求脱节的修复方案

测试用例与需求脱节的问题可通过明确需求定义、加强需求追踪、建立有效沟通机制进行修复。其中&#xff0c;加强需求追踪尤为关键&#xff0c;能确保测试用例与实际需求的精确匹配&#xff0c;避免资源浪费和测试效果不佳。据行业研究&#xff0c;约70%的软件缺陷源于需求管理不…

【Unity】 鼠标拖动物体移动速度跟不上鼠标,会掉落

错误示范&#xff1a; 一开始把移动的代码写到update里去了&#xff0c;发现物体老是掉(总之移动非常不流畅&#xff0c;体验感很差&#xff09; void Update(){Ray ray Camera.main.ScreenPointToRay(Input.mousePosition);if (Physics.Raycast(ray, out RaycastHit hit, M…

VLAN 高级特性

VLAN Access 类型端口&#xff1a;只能属于 1 个 VLAN&#xff0c;发出数据时只能根据 PVID 剥离一个 VLAN Tag 入方向&#xff1a;针对没有 tag 的数据包打上 PVID 的 tag出方向&#xff1a;将 tag 为本接口 PVID 的数据包去掉 tag&#xff0c;发出数据。&#xff08;只有在与…

学习中学习的小tips(主要是学习苍穹外卖的一些学习)

目录 架构的细分 使用实体类来接收配置文件中的值 webMvcConfig类&#xff1a; jwt令牌 管理端的拦截器&#xff1a; JwtProperties&#xff1a; JwtTokenAdminInterceptor &#xff1a; 对密码加密操作 Redis&#xff1a; 分页查询 整体思想 为什么动态 SQL 推荐传实体…

【极速版 -- 大模型入门到进阶】LORA:大模型轻量级微调

文章目录 &#x1f30a; 有没有低成本的方法微调大模型&#xff1f;&#x1f30a; LoRA 的核心思想&#x1f30a; LoRA 的初始化和 r r r 的值设定&#x1f30a; LoRA 实战&#xff1a;LoraConfig参数详解 论文指路&#xff1a;LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE M…

线程同步——读写锁

Linux——线程同步 读写锁 目录 一、基本概念 1.1 读写锁的基本概念 1.2 读写锁的优点 1.3 读写锁的实现 1.4 代码实现 一、基本概念 线程同步中的读写锁&#xff08;Read-Write Lock&#xff09;&#xff0c;也常被称为共享-独占锁&#xff08;Shared-Exclusive Lock&a…

邪性!Anaconda安装避坑细节Windows11

#工作记录 最近不断重置系统和重装Anaconda&#xff0c;配置的要累死&#xff0c;经几十次意料之外的配置状况打击之后&#xff0c;最后发现是要在在Anaconda安装时&#xff0c;一定要选“仅为我安装”这个选项&#xff0c;而不要选“为所有用户安装”这个选项。 选“仅为我安…

【大模型】激活函数之SwiGLU详解

文章目录 1. Swish基本定义主要特点代码实现 2. GLU (Gated Linear Unit)基本定义主要特点代码实现 3. SwiGLU基本定义主要特点代码实现 参考资料 SWiGLU是大模型常用的激活函数&#xff0c;是2020年谷歌提出的激活函数&#xff0c;它结合了Swish和GLU两者的特点。SwiGLU激活函…

AOA与TOA混合定位,MATLAB例程,三维空间下的运动轨迹,滤波使用EKF,附下载链接

本文介绍一个MATLAB代码&#xff0c;实现基于 到达角&#xff08;AOA&#xff09; 和 到达时间&#xff08;TOA&#xff09; 的混合定位算法&#xff0c;结合 扩展卡尔曼滤波&#xff08;EKF&#xff09; 对三维运动目标的轨迹进行滤波优化。代码通过模拟动态目标与基站网络&am…

【211】线上教学系统

--基于SSM线上教学平添 主要实现的功能有&#xff1a; 管理员 : 首页、个人中心、学员管理、资料类型管理、学习资料管理、交流论坛、我的收藏管理、试卷管理、留言板管理、试题管理、系统管理、考试管理。 学员 : 首页、个人中心、我的收藏管理、留言板管理、考试管理。 前台…

从混乱思绪到清晰表达:记录想法如何改变你的学习人生

关键要点 • 记录想法似乎是发现自己想法并将其组织成可传播形式的最佳理由&#xff0c;研究表明写作和教学能增强学习和理解。 • 证据倾向于支持写作有助于澄清思想&#xff0c;而教学通过“教授效应”深化知识。 • 教学和分享被认为是最有效的学习方法&#xff0c;这与记录…

电机控制常见面试问题(二十)

文章目录 一.整流电路绕组接法二.电机为什么需要转速器三.电机转矩产生原理四.电机控制中载波频率大小的确定五.开关周期 Tpwm 一.整流电路绕组接法 为了引出直流的输出&#xff0c;一定要在整流变压器的二次侧引出零线&#xff0c;所以二次侧绕组必须接成星形 一次绕组必须要…

小爱控制via电视浏览器搜索图片-Homeassistant重制上一个自动化

制作自动化详情 为了完成图片搜&#xff0c;暂定指令找找{描述} 在执行脚本的adb地方输入以下指令&#xff0c;百度 因安全不让在图片地址直接搜转用bing >- >am start -n mark.via.gp/mark.via.Shell -a android.intent.action.VIEW -d https://cn.bing.com/images/…

unity一个图片的物体,会有透明的效果

如图 想要去掉这个透明效果 选择一个高层级的layer即可。