spandsp_start_dtmf的bug及修复

ops/2025/3/2 8:30:50/

概述

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

之前的文章中介绍过DTMF从2833到inband的转换,其中inband到2833的转换使用了“spandsp_start_dtmf”,这个函数在转换的过程中有缺陷。

环境

CentOS 7.9

freeswitch 1.10.7

问题描述

在fs桥接的呼叫,经过“spandsp_start_dtmf”处理inband中的dtmf按键,转换到otherleg的时候,2833的dtmf可以正常产生,但是inband中的波形删除的不够干净,如果后续的语音节点会检测inband的话,就会产生重码的问题。

解决方案

修改思路,在spandsp对dtmf波形的处理过程中,缓存2个媒体包,当检测到DTMF时,将缓存的媒体包清空。

修改mod_dtptools.c

case SWITCH_DTMF_RTP:switch_channel_set_variable(switch_core_session_get_channel(session), "deduplicate_dtmf_seen_rtp", "true");/* change state to only allow RTP events */filter->only_rtp = 1;//modify by zr, 20241021, for DTMF inband to 2833/* stop inband detector */// switch_ivr_broadcast(switch_core_session_get_uuid(session), "spandsp_stop_dtmf::", SMF_ECHO_ALEG);break;

修改mod_spandsp_dsp.c

//modify by zr, 20241021, for DTMF inband to 2833
#define INBAND_DTMF_BUF_SIZE (2)
#define INBAND_DTMF_BUF_LEN (512)typedef struct {switch_core_session_t *session;dtmf_rx_state_t *dtmf_detect;int verbose;char last_digit;uint32_t samples;uint32_t last_digit_end;uint32_t digit_begin;uint32_t min_dup_digit_spacing;int twist;int reverse_twist;int filter_dialtone;int threshold;switch_audio_resampler_t *resampler;
//modify by zr, 20241021, for DTMF inband to 2833char data_buf[INBAND_DTMF_BUF_SIZE][INBAND_DTMF_BUF_LEN];int buf_index;
} switch_inband_dtmf_t;...dtmf_rx(pvt->dtmf_detect, dp, samples);//modify by zr, 20241021, for DTMF inband to 2833// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "dtmf_rx return, last_hit=%d, in_digit=%d, current_sample=%d,"// 														"duration=%d, lost_digits=%d, current_digits=%d\n", // 														pvt->dtmf_detect->last_hit, pvt->dtmf_detect->in_digit, pvt->dtmf_detect->current_sample, // 														pvt->dtmf_detect->duration, pvt->dtmf_detect->lost_digits, pvt->dtmf_detect->current_digits);if(pvt->dtmf_detect->filter_dialtone){	// double buffer modeif(pvt->dtmf_detect->last_hit > 0 || pvt->dtmf_detect->in_digit > 0) {switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "inband_dtmf_callback, memset frame to 0x00, pvt->dtmf_detect->last_hit=%d, pvt->dtmf_detect->in_digit=%d\n", pvt->dtmf_detect->last_hit, pvt->dtmf_detect->in_digit);memset(pvt->data_buf, 0x00, INBAND_DTMF_BUF_LEN*INBAND_DTMF_BUF_SIZE);memset(frame->data, 0x00, frame->datalen);}else{char data_tmp[INBAND_DTMF_BUF_LEN] = {0};memcpy(data_tmp, frame->data, INBAND_DTMF_BUF_LEN);memcpy(frame->data, pvt->data_buf[pvt->buf_index], frame->datalen);memcpy(pvt->data_buf[pvt->buf_index], data_tmp, datalen);}pvt->buf_index = (1 - pvt->buf_index);}switch_core_media_bug_set_read_replace_frame(bug, frame);...pvt->session = session;//modify by zr, 20241021, for DTMF inband to 2833pvt->buf_index = 0;

修改switch_core_media.c

				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 inbandif( 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 methodswitch_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 inbandif( 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 2833switch_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桥接的呼叫,经过“spandsp_start_dtmf”处理inband中的dtmf按键,在A路的波形中没有遗留。

总结

因为需要对inband的媒体流做缓存,所以该处理会产生40ms左右的语音时延。

空空如常

求真得真

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

相关文章

商密测评题库详解:商用密码应用安全性评估从业人员考核题库详细解析(9)

1. 申请商用密码测评机构需提交材料考点 根据《商用密码应用安全性测评机构管理办法(试行)》,申请成为商用密码应用安全性测评机构的单位应当提交的材料不包括( )。 A. 从事与普通密码相关工作情况的说明 B. 开展测评工作所需的软硬件及其他服务保障设施配备情况 C. 管…

能源行业区块链相关的书籍

《能源区块链技术与场景应用》 由李申章等人撰写,主要介绍了能源数字化发展、区块链在能源行业的发展需求、区块链原理及应用等方面的内容。这本书提供了对区块链技术如何应用于能源行业的深刻理解,并探讨了其潜在的应用场景。 《物联网区块链技术及其…

第27章 苏睿所长的关键沟通

这几天,苏睿所长心里像揣了只活蹦乱跳的小兔子,七上八下不得安宁。航天智控项目已推进到关键阶段,可配套的战略欺骗计划却依旧悬而未决,这事儿就像一块沉重的巨石,沉甸甸地压在他的心头,压得他几乎喘不过气…

Sentinel 控制台集成 Nacos 实现规则配置双向同步和持久化存储(提供改造后源码)

目录 一、前言二、Sentinel 控制台规则推送实现原理三、Sentinel控制台源码改造前置准备工作3.1、本文使用各组件版本3.2、下载Sentinel控制台源码3.3、启动Sentinel控制台3.4、应用服务实现 Sentinel 客户端动态获取 Nacos 规则配置3.4.1、添加sentinel集成nacos包 3.4.2、Nac…

Attention Free Transformer (AFT)-2020论文笔记

名称: Attention Free Transformer (AFT) 来源: [2105.14103] An Attention Free Transformer 相关工作: #Approximatingthedotproduct #Sparselocalattention #Contextcompression #Eliminatingdotproductattention #MLPsforvision 创…

C++封装红黑树实现mymap和myset和模拟实现详解

文章目录 map和set的封装map和set的底层 map和set的模拟实现insertiterator实现的思路operatoroperator- -operator[ ] map和set的封装 介绍map和set的底层实现 map和set的底层 一份模版实例化出key的rb_tree和pair<k,v>的rb_tree rb_tree的Key和Value不是我们之前传统意…

JavaScript系列(43)--依赖注入系统实现详解

JavaScript依赖注入系统实现详解 &#x1f489; 今天&#xff0c;让我们深入探讨JavaScript的依赖注入系统实现。依赖注入是一种设计模式&#xff0c;它通过将依赖关系的创建和管理从代码中分离出来&#xff0c;提高了代码的可维护性和可测试性。 依赖注入基础概念 &#x1f…

【Elasticsearch 】自定义分词器

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…