今天谈的这个主题(tone)存在于我们的日常打电话过程中。先举两个场景:1,你拿起固话话筒准备打电话,按电话号码前先从话筒里听到“嗡”的连续音,这叫dial tone(拨号音,表示你可以拨电话号码了),你拨完号码对方振铃后你又听到有规律的“嘟-嘟-”的断续音,这叫ring back tone(回铃音,表示对方已振铃了)。2,你给企业服务号(比如中国移动的10086)打电话,对方叫你按键选择,当你按下键后会听到按键声,这叫DTMF tone(双音多频音)。感觉到它存在于我们日常的打电话过程中了吧。现在我们就从技术的角度谈谈这些tone。

在语音通信中tone主要分两大类:CPT(call progress tone,呼叫过程音)tone和DTMF(dual tone multi frequency,双音多频音)tone。CPT tone存在于通话过程中,主要用于告诉用户目前在什么状态,主要有dial tone(拨号音)/ringback tone(回铃音)/busy tone(忙音)等。CPT tone是单频音,即由一个频率的正弦波形成。CPT tone没有全球统一的标准,而是各个国家有自己的标准,比如中国的标准,欧洲的标准,美国的标准等。下表就是我们国家的标准:

还有其他类型的CPT tone,由于用的相对较少,这里就不一一列出了。相对于CPT tone是单频音,DTMF tone是双频音,即用两个频率(一个高频和一个低频)的正弦波叠加去表示某个按键值。与CPT tone各国有自己的标准不同的是DTMF tone全球有统一的标准,下表列出了常用的16个按键值是由哪些高频音和低频音组合而成的:

从软件实现的角度对tone主要有两类处理:tone generation,让用户听到tone;tone detection,主要是指DTMF tone的detection,让软件知道哪个按键按下了,好进行后续的处理。我们先看tone generation,也就是生成单个频率的正弦波(CPT tone)或者两个频率正弦波的叠加(DTMF tone),在信号处理上有相应的算法。对于单频正弦波,各个采样点上值的生成可通过如下的数学表达式求得:

其中a/y(0)/y(1)在各个频点上的值已事先根据数学公式做成表,从而减少数学运算。对于DTMF这样的双频率音来说,采样点上的值就是两个频率采样点上的值相加。Tone generation分两个方向,local 和remote。Local是tone让自己听到,把生成的正弦波放到RX stream上;remote是tone让对端听到,把生成的正弦波放到TX stream上。对于像ring back tone等断续音还需要timer控制放多长时间停多长时间。

再来看tone detection,这里主要是指对DTMF的tone detection。有专门的算法(Goertzel戈泽尔算法)来detect DTMF的键值,把DTMF的音频信号(多帧的PCM信号)作为算法的输入,经过一定帧数后得到的就是DTMF的键值。原理这里就不详细讲了,有兴趣的可以看相关文章。有时候我们需要告诉对端按下的是什么DTMF键,即要把键值传给对端,主要有三种方法,具体如下:

1,把DTMF音频信号直接编码得到码流放在RTP中发给对端。对端收到RTP包后解码复原出音频信号,然后再通过DTMF detection算法得到键值。这通常被叫做in-band方法。

2,在本端做DTMF detection得到键值,然后根据RFC2833(后来升级成RFC4733)组成RFC2833包发给对端。对端收到RFC2833包后去解析就知道是哪个键值了。这通常被叫做out-of-band方法。RFC2833包也是用RTP做承载,不过它的payload type是动态的(96~127之间一个值),payload共4个字节(32个比特),具体如下:

其中bit0-7(共8位)表示键值,bit8表示DTMF按键结束,bit9目前保留不用,bit10-15(共6位)表示按键信号的level(dBm表示),bit16-31(共16位)表示按键持续的时间(以采样值为单位)。一个DTMF键会生成多个RFC2833包,对同一个键值而言,这些包的sequence number会每次加1,但是timestamp不变,duration会持续增加,以8k采样率20ms为一包为例,第一个RFC2833包duration为160,第二个RFC2833包duration为320,依次向上加,直到END包(bit8置1)结束。END包会发3次(发3 次主要是为了防丢包),每个END包sequence number会加1,但是duration保持不变。

3,在本端做DTMF detection得到键值,然后通过SIP信令的INFO带给对端,让对端知道是哪个键值。

这三种方法中,具体用那种方法要看双方设备的支持程度,在SDP中有个协商的过程,最终选用双方都支持的一种方法(如果双方都支持多种方法,还有一个优先级来控制选择哪种方法)来传送DTMF值。

谈谈语音通信中的各种tone的更多相关文章

  1. 语音通信中终端上的时延(latency)及减小方法

    时延是语音通信中的一个重要指标,当端到端(end2end)的时延(即one-way-delay,单向时延)低于150Ms时人感觉不到,当端到端的时延超过150Ms且小于450Ms时人能感受到但能忍受不 ...

  2. 如何在嵌入式Linux上开发一个语音通信解决方案

    开发一个语音通信解决方案是一个软件项目.既然是软件项目,就要有相应的计划:有多少功能,安排多少软件工程师去做,这些工程师在这一领域的经验如何,是否需要培训,要多长时间做完,中间有几个主要的milest ...

  3. 浅谈传统语音通信和APP语音通信音频软件开发之不同点

    本人在传统的语音通信公司做过手机和IP电话上的语音软件开发,也在移动互联网公司做过APP上的语音软件开发.现在带实时语音通信功能的APP有好多,主流的有微信语音.QQ电话.钉钉等,当然也包括我开发过的 ...

  4. 腾讯云H5语音通信QoE优化

    本文首发在云+社区,未经许可,不得转载. 云+导语:4月21日,腾讯云+社区在京举办"'音'你而来,'视'而可见--音视频技术开发实战沙龙",腾讯音视频实验室高级工程师张轲围绕网络 ...

  5. Fixed-Length Frames 谈谈网络编程中应用层(基于TCP/UDP)的协议设计

    http://blog.sina.com.cn/s/blog_48d4cf2d0101859x.html 谈谈网络编程中应用层(基于TCP/UDP)的协议设计 (2013-04-27 19:11:00 ...

  6. 【原】谈谈对Objective-C中代理模式的误解

    [原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...

  7. 谈谈MVC项目中的缓存功能设计的相关问题

    本文收集一些关于项目中为什么需要使用缓存功能,以及怎么使用等,在实际开发中对缓存的设计的考虑 为什么需要讨论缓存呢? 缓存是一个中大型系统所必须考虑的问题.为了避免每次请求都去访问后台的资源(例如数据 ...

  8. Android IOS WebRTC 音视频开发总结(七五)-- WebRTC视频通信中的错误恢复机制

    本文主要介绍WebRTC视频通信中的错误恢复机制(我们翻译和整理的,译者:jiangpeng),最早发表在[这里] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:blac ...

  9. 使用SSL确保通信中的数据安全

    #region Server /// <summary> /// 用于保存非对称加密(数字证书)的公钥 /// </summary> private string public ...

随机推荐

  1. JavaScript之BST

    自己尝试用js实现了数据结构的二叉查找树. // node function Node(data) { this.data = data; this.lc = null; this.rc = null ...

  2. dedecms====phpcms 区别==[工作]

    {template "content","header"}{dede:include filename="head.htm"/} ----- ...

  3. Java泛型解析

    1. 概述    在引入范型之前,Java类型分为原始类型.复杂类型,其中复杂类型分为数组和类.引入范型后,一个复杂类型就可以在细分成更多的类型. 例如原先的类型List,现在在细分成List< ...

  4. winform程序压缩文件上传,服务器端asp.net mvc进行接收解压

    期间编程没什么难度,唯一可能忽略导致结果失败是asp.net  mvc配置 对于压缩文件大的话,需要配置mvc的最大接收量: <system.web> <httpRuntime ma ...

  5. Python判断文件是否存在的三种方法【转】

    转:http://www.cnblogs.com/jhao/p/7243043.html 通常在读写文件之前,需要判断文件或目录是否存在,不然某些处理方法可能会使程序出错.所以最好在做任何操作之前,先 ...

  6. mysql-innoDB-多版本并发控制(MVCC)

    InnoDB的MVCC,是通过在每行记录后面保存三个隐藏的列来实现的其中的两个列一个保存了行的创建时间,一个保存行的过期时间(或删除时间).当然存储的并不是实际的时间值,而是系统版本号(system ...

  7. JavaScript var的作用域和提升

    在ES6标准之前,var 作为唯一的声明变量关键字,本篇将着重介绍var的作用域和变量提升. 1. var Hoisting(变量提升) va rHoisting:使用var在函数或全局内任何地方声明 ...

  8. python_tornado_session用户验证

    什么是session? -- Django中带有session,tornado中自己写 -- 逻辑整理 用户请求过来,验证通过,随机生成一个字符串当作value返回给浏览器, 在服务器中用户信息与随机 ...

  9. 获取用户IP地址的三个属性的区别 (HTTP_X_FORWARDED_FOR,HTTP_VIA,REMOTE_ADDR)

    一.没有使用代理服务 器的情况: REMOTE_ADDR = 您的 IPHTTP_VIA = 没数值或不显示HTTP_X_FORWARDED_FOR = 没数值或不显示 二.使用透明代理服务器的情 况 ...

  10. jdk源码->多线程->Thread

    线程的创建 java提供了三种创建线程的方法: 通过继承 Thread 类本身: 通过实现 Runnable 接口: 通过 Callable 和 Future 创建线程. 继承Thread类 步骤: ...