RTP包中timestamp的间隔问题
概述
近期在和同事调试G729的编解码库时碰到一个语音质量的问题,问题产生的原因和RTP包中的时间戳设置有关,特此记录下来。
问题现象,1001和1002账号注册在fs,媒体设置为G729并通过fs中转,1001终端使用eyebean,1002终端使用自己开发的sip终端,从1001-1002的语音正常,从1002-1001的语音卡顿异常。
环境
centos:CentOS release 7.0 (Final)或以上版本
freeswitch:v1.8.7
GCC:4.8.5
问题分析
freeswitch在正常的语音转发中没有发现过类似问题。
从语音质量的现象看,只有单边的语音卡顿,即从1002-1001方向的语音有问题。
1002的终端属于自研产品,其中G729模块也是刚刚接入,发生问题的概率较大。
有了基本的分析之后,还是要找到明确的证据支撑,这时候就需要抓包分析。
使用wireshark对SIP终端侧进行抓包,查看抓包的RTP流。如下图
其中蓝色的第1、3行,是出现问题的RTP流。
再打开RTP流分析的页面。
从1002-fs的RTP流如下图。可以看到stream0的包分析结果。
从fs-1001的RTP流如下图。可以看到stream1的包分析结果。
这个页面我们发现了一个问题,就是RTP流的发包中,Delta(ms)列的数据有一些异常,每隔5个包,就会出现1个40ms间隔的包,非常的规律。
对应到RTP流中,根据timestamp字段就会发现,每隔6个包,就会有1个包丢掉了。
至此,我们可以得到一个初步的分析结果,就是1002发送的RTP包,经过fs的转发后,被部分丢弃了,造成1001收到的语音质量问题。
RTP包timestamp字段
由于1002SIP终端的G729库是新接入的,所以对于RTP打包格式是首先要怀疑的。
RTP头格式如下:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC |M| PT | sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| synchronization source (SSRC) identifier |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| contributing source (CSRC) identifiers |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
对于其他字段的介绍网上很多,直接略过,这里主要看一下timestamp字段。
timestamp,32比特。时间戳,反映了RTP数据包中第一个八位字节的采样时间。时间戳的初始值应当是随机的,类似序号。时钟频率依赖于负载数据格式,因此时间戳增量依赖于当前数据格式和策略。如果RTP数据包周期性产生,那么将使用采样时钟确定的标称采样时刻,而非读取系统时间。举例而言,对于固定采样率的音频,时间戳时钟可能会在每个采样周期增加1;如果音频应用程序从输入设备读取覆盖160个采样周期的块,则对于每个这样的块,时间戳将增加160,无论该块是在分组中传输还是作为静默丢弃。
上面这一段是官方的介绍,说实话我也看的稀里糊涂的,但是其中的关键是“时间戳将增加160”这一句,和我的认知有了冲突。
当我们看到timestamp字段的名字时,首先想到的是时间戳,既然是时间,按照正常的理解,应该是和打包时长ptime相对应,比如打包时长ptime是20ms,那么timestamp的间隔也应该是20。
但是事实上,RTP包中的timestamp字段并不是这样定义的。
在官方的RFC1889文档中,If an audio application reads blocks covering 160 sampling periods from the input device, the timestamp would be increased by 160 for each such block, regardless of whether the block is transmitted in a packet or dropped as silent.
下面翻译成我自己的理解。
timestamp字段和通常的时间没有关系。
timestamp字段是为了表示媒体流的采样长度和顺序。
timestamp字段的初始值是随机数。
timestamp字段的间隔的计算方法,根据媒体流协商的媒体类型来决定,具体由俩个指标,采样率和打包时长。
计算公式是(timestamp间隔=采样率*打包时长)。
举个栗子,媒体类型的协商结果是G729,其中采样率是8000,打包时长是20ms,那么timestamp的间隔 = 8000 * 0.02 = 160。
再举个栗子,媒体协商结果是iLBC,其中采样率是8000,打包时长是30ms,那么timestamp的间隔 = 8000 * 0.03 = 240。
再举最后一个栗子,媒体协商结果是opus,其中采样率是16000,打包时长是20ms,那么timestamp的间隔 = 16000 * 0.02 = 320。
总结
RTP流在VOIP和RTC通信中非常常见。
我们从一个问题出发,在分析解决的过程中,重新认识了RTP包格式,尤其是其中timestamp字段的定义,和平常的时间戳定义有区别。
碰到网络问题,wireshark抓包是非常好用的工具,可以解决90%的问题。
空空如常
求真得真
RTP包中timestamp的间隔问题的更多相关文章
- 得到RTP包中的timestamp
NTP------网络时间协议 PTP------精确时间协议 PTS,DTS的关系: http://www.cnblogs.com/qingquan/archive/2011/07/27/21189 ...
- Live555中RTP包的打包与发送过程分析
这里主要分析一下,live555中关于RTP打包发送的部分.在处理完PLAY命令之后,就开始发送RTP数据包了(其实在发送PLAY命令的response包之前,就会发送一个RTP包,这里传输就已经开始 ...
- RTP 包格式 详细解析
H.264 视频 RTP 负载格式 1. 网络抽象层单元类型 (NALU) NALU 头由一个字节组成, 它的语法如下: +---------------+ |0|1|2|3|4|5|6|7 ...
- H264 RTP包解析
1. 预备 视频: 由一副副连续的图像构成,由于数据量比较大,因此为了节省带宽以及存储,就需要进行必要的压缩与解压缩,也就是编解码. h264裸码流: 对一个图像或者一个视频序列进行压缩,即产生码流 ...
- NALU数据打RTP包流程详解
最近在看RTP发送H264数据的文章,感觉很乱,没有比较清晰易懂的教程,自己整理了一下各种资料,备忘! --------Part A ---- 先说说H264数据,H264在网络传输的是NALU(N ...
- RTP包的结构
live555中数据的发送最后是要使用RTP协议发送的,下面介绍一下RTP包格式. RTP packet RTP是基于UDP协议的,RTP服务器会通过UDP协议,通常每次会发送一个RTP packet ...
- FU-A分包方式,以及从RTP包里面得到H.264数据和AAC数据的方法。。
[原创] RFC3984是H.264的baseline码流在RTP方式下传输的规范,这里只讨论FU-A分包方式,以及从RTP包里面得到H.264数据和AAC数据的方法. 1.单个NAL包单元 12字节 ...
- (转)谈谈RTP传输中的负载类型和时间戳
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://ticktick.blog.51cto.com/823160/350142 最近被 ...
- rtp包格式
转载一篇帮助我了解h264 rtp的文档,地址http://www.cppblog.com/czanyou/archive/2009/12/25/67940.html 当packetization-m ...
随机推荐
- 《剑指offer》面试题53 - I. 在排序数组中查找数字 I
问题描述 统计一个数字在排序数组中出现的次数. 示例 1: 输入: nums = [5,7,7,8,8,10], target = 8 输出: 2 示例 2: 输入: nums = [5,7,7,8, ...
- 华为matebook x pro蓝屏和拆机更换固态硬盘
华为老版本的笔记本电脑现在总是蓝屏. 情况 原因 我个人认为是建兴的固态硬盘的缘故. 我的笔记本几乎没用过,因为考研.如果玩游戏使用的老ThinkPad S5.matebook我这个丐版因为没有独立显 ...
- 处理json中的空格
很多json中带有空格 而json解析类很多自带去空行 导致解析json如下 只能在解析之前用"111111"之类的替换 之后再替换回来 result = result.Repla ...
- golang中的pair
package main import "fmt" type Reader interface { ReadBook() } type Writer interface { Wri ...
- 负载均衡部署BBS
目录 一:部署后端服务(web服务器) 二:部署Python(web) 三:部署Django和uwsgi 四:配置并启动 五:部署负载均衡(lb01) 六:(web服务器 lb服务器) 1.测试 2. ...
- python利用正则表达式提取文本中特定内容
正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配. Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式. re 模块使 Python ...
- 在IDE中普通项目打成jar包
第一步: File---->Project Structe 第二步: 选择From modules.. 第三步:选择对应的Module和对应的JAR,然后点击ok 第四步:选择好对应的属性,然后 ...
- C# 获取网页验证码
转载请注明来源:https://www.cnblogs.com/hookjc/ 以下方法必需在WebBrowser控件加载网页完成后才可以调用,否则会提示无法将对象引用到实例,切记!!! public ...
- Android编译implement、api 和compile区别【转】
感谢大佬:https://blog.csdn.net/fengyeNom1/article/details/81903186 前言 2017 年google 后,Android studio 版本更新 ...
- 1、interface/implements 接口与引用
转载请注明来源:https://www.cnblogs.com/hookjc/ 1.类中全部为抽象方法 2.抽象方法前不用加abstract 3.接口抽象方法属性为public 4.成员属性必须为常量 ...