spandsp_start_dtmf的bug及修复

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

总结
因为需要对inband的媒体流做缓存,所以该处理会产生40ms左右的语音时延。
空空如常
求真得真
spandsp_start_dtmf的bug及修复的更多相关文章
- duilib List控件,横向滚动时列表项不移动或者显示错位的bug的修复
转载请说明出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/42264673 关于这个bug的修复我之前写过一篇博客,连接为:http:/ ...
- duilib combo控件,当鼠标滚动时下拉列表自动关闭的bug的修复
转载请说明出处,谢谢~~ 群里有朋友提到了使用Combo控件时,当下拉列表出现,此时鼠标滚轮滚动,下拉列表就自动消失了.我看了一下源码,这个bug的修复很简单. CComboUI控件被单击时创建CCo ...
- 逆向实战第一讲,寻找OllyDbg调试工具的Bug并修复
逆向实战第一讲,寻找OllyDbg调试工具的Bug并修复 首先我们要知道这个OD的Bug是什么. 我们调试一个UNICODE的窗口,看下其窗口过程. 一丶查看OllyDbg 的Bug 1.1spy++ ...
- WinForm IME输入法BUG完美修复
本文来自http://hi.baidu.com/wingingbob/item/a2cb3fc0fe3bd1bb0d0a7b5b <WinForm IME输入法BUG测试>里,我描述了在. ...
- Flutter实战视频-移动电商-34.列表页_小BUG的修复
34.列表页_小BUG的修复 当高粱酒的子类没有数据返回的时候就会报错. 解决接口空数据报错的问题 没有数据的时候,给用户一个友好的提示, 我们没有数据的时候还要告诉用户,提示一下他没有数据,在我们的 ...
- 常见IE浏览器bug及其修复方案(双外边距、3像素偏移、绝对定位)
1. 双外边距浮动bug IE6和更低版本中存在双外边距浮动bug,顾名思义,这个Windows bug使任何浮动元素上的外边距加倍 bug重现: <!DOCTYPE html> < ...
- duilib List控件,横向滚动时列表项不移动或者移动错位的bug的修复
转载请说明出处,谢谢~~ 这篇博客已经作废,只是留作记录,新的bug修复博客地址:http://blog.csdn.net/zhuhongshu/article/details/42264673 之前 ...
- IE6浏览器常见的bug及其修复方法
IE6不支持min-height,解决办法使用css hack: .target { min-height: 100px; height: auto !important; height: 100px ...
- IE常见bug及其修复方法
一.双边距浮动的bug 1.1一段无错的代码把一个居左浮动(float:left)的元素放置进一个容器盒(box) 2.1在浮动元素上使用了左边界(margin-left)来令它和容器的左边产 ...
- SpriteKit游戏Delve随机生成地牢地图一个Bug的修复
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) Delve是一个很有意思的地牢探险类型的游戏,其中每一关的地图 ...
随机推荐
- Redis究竟为什么这么快?
Redis为什么这么快? 完全基于内存,数据存在内存中,绝大部分请求是纯粹的内存操作,非常快速,跟传统的磁盘文件数据存储相比,避免了通过磁盘IO读取到内存这部分的开销. 数据结构简单,对数据操作也简单 ...
- Java的内存管理1:“并不只有C++程序员关心内存回收”——Java的内存管理2:"不中用的finalize( )方法"
通常Java的缓存管理会由垃圾回收器(Java Garbage Collection)定时处理,无须程序员操心.但Java Garbage Collection仅有权回收那些非"强引用&qu ...
- 软件逆向之IDA Pro
IDA Pro作为一款强大的逆向分析工具,对于软件开发和安全领域的专业人士来说是必不可少的. 1. 什么是逆向分析 逆向分析是指通过分析已有的软件或程序,推测出其内部运行机制.算法和逻辑等信息.通过逆 ...
- CudaSPONGE之Python接口
技术背景 在上一篇博客中我们介绍了CudaSPONGE的基本安装和使用方法.为了性能考虑,CudaSPONGE是基于纯CUDA C开发的,但是现在很多轮子都是Python开发的.为兼容更多的框架和平台 ...
- 新型大语言模型的预训练与后训练范式,Meta的Llama 3.1语言模型
前言:大型语言模型(LLMs)的发展历程可以说是非常长,从早期的GPT模型一路走到了今天这些复杂的.公开权重的大型语言模型.最初,LLM的训练过程只关注预训练,但后来逐步扩展到了包括预训练和后训练在内 ...
- Winform在主窗体里切换多个窗体
1.点击解决方案资源管理器的项目名称,右键添加用户控件(Windows窗体). 2.在主窗体代码中实例化添加的用户控件(Windows窗体). 点击查看代码 UserControl1 userCont ...
- 攻防世界:Web习题之 get_post
攻防世界:Web习题之 get_post 题目内容 https://adworld.xctf.org.cn/challenges/list 题目首先需要我们用GET方式提交一个名为a,值为1的变量: ...
- 云数据备份 | CDN 日志备份最佳实践
前言 内容分发网络(Content Delivery Network,CDN),是在现有 Internet 中增加的一层新的网络架构,可以有效降低用户访问延迟,提升可用性. CDN 按照小时粒度对 ...
- drf知识点
目录 drf知识点 1.web应用模式.API接口.接口测试工具postman.restful规范 2.序列化与反序列化的概念.基于django原生编写5个接口.drf介绍和快速使用.cbv源码分析 ...
- 解锁 Git Log 更多实用技巧
目前,在软件开发的协作中,Git 无疑是版本控制的王者. 而其中的 git log 命令,犹如一把强大的历史探寻之剑,能够帮助我们深入洞察项目的演进历程. 本篇将为大家整理解读几个实用的 git Lo ...