今天谈的这个主题(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. ThinkPhp5.0_文件上传

    ===================================================================== 路径: F:\wamp\www\public\uploads ...

  2. Codeforces 448 E. Divisors (DFS,储存结构)

    题目链接:E. Divisors 题意: 给出一个X,f(X)是X所有约数的数列(例6:1 2 3 6),给出一个k,k是递归的次数(例:k=2 : f(f(X)) ; X=4,k=2: 1 1 2 ...

  3. linux如何安装java环境

    linux安装jdk7步骤: 1.首先使用命令查看linux系统版本号: lsb_release -a 11 2.下载对应的jdk版本,笔者使用的是jdk-7u79-linux-x64.tar.gz: ...

  4. Spring-depends on

    depends-on用来表示一个bean A的实例化依靠另一个bean B的实例化, 但是A并不需要持有一个B的对象,如果需要的话就不用depends-on. 示例: 步骤一: public clas ...

  5. 一个使用物理引擎的WebGL3D场景

    这是一个类似第三人称射击游戏(TPS)的3D场景,可以通过https://ljzc002.github.io/FPS2/index.html访问.场景运行效果如下图: 场景环境由一个天空盒和一个地面网 ...

  6. Python初识 - day5

    一.装饰器(decorator) 1.定义:本质是函数(装饰其它函数),就是为了其它函数添加附加功能. 2.原则:一是不能修改被装饰函数的源代码:二是不能修改被装饰函数的调用方式. 3.装饰器包含的知 ...

  7. CSS--开篇

    1,什么是CSS? 层叠样式表(Cascading Style Sheet ),定义了如何显示HTML元素,用来控制网页的样式和布局. 引入CSS后:HTML标记专门用于定义网页的内容,而使用CSS来 ...

  8. android 获取屏幕的宽和高

    屏幕高度:context.getResources().getDisplayMetrics().heightPixels 屏幕宽度:context.getResources().getDisplayM ...

  9. 【转】How to append current date and timestamp to filename in shell script

    $ date +"FORMAT" now=$(date +"%Y-%m-%d-%S") filename="my_program.$now.log&q ...

  10. 【PHP】学习中遇到的php方法

    [1]range()快速创建一个范围内数组 <?php range(0,20); 创建一个包含从 "0" 到 "20" 之间的元素范围的数组: range ...