概述

近期在和同事调试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的间隔问题的更多相关文章

  1. 得到RTP包中的timestamp

    NTP------网络时间协议 PTP------精确时间协议 PTS,DTS的关系: http://www.cnblogs.com/qingquan/archive/2011/07/27/21189 ...

  2. Live555中RTP包的打包与发送过程分析

    这里主要分析一下,live555中关于RTP打包发送的部分.在处理完PLAY命令之后,就开始发送RTP数据包了(其实在发送PLAY命令的response包之前,就会发送一个RTP包,这里传输就已经开始 ...

  3. RTP 包格式 详细解析

    H.264 视频 RTP 负载格式 1. 网络抽象层单元类型 (NALU) NALU 头由一个字节组成, 它的语法如下: +---------------+      |0|1|2|3|4|5|6|7 ...

  4. H264 RTP包解析

    1.  预备 视频: 由一副副连续的图像构成,由于数据量比较大,因此为了节省带宽以及存储,就需要进行必要的压缩与解压缩,也就是编解码. h264裸码流: 对一个图像或者一个视频序列进行压缩,即产生码流 ...

  5. NALU数据打RTP包流程详解

    最近在看RTP发送H264数据的文章,感觉很乱,没有比较清晰易懂的教程,自己整理了一下各种资料,备忘! --------Part A  ---- 先说说H264数据,H264在网络传输的是NALU(N ...

  6. RTP包的结构

    live555中数据的发送最后是要使用RTP协议发送的,下面介绍一下RTP包格式. RTP packet RTP是基于UDP协议的,RTP服务器会通过UDP协议,通常每次会发送一个RTP packet ...

  7. FU-A分包方式,以及从RTP包里面得到H.264数据和AAC数据的方法。。

    [原创] RFC3984是H.264的baseline码流在RTP方式下传输的规范,这里只讨论FU-A分包方式,以及从RTP包里面得到H.264数据和AAC数据的方法. 1.单个NAL包单元 12字节 ...

  8. (转)谈谈RTP传输中的负载类型和时间戳

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://ticktick.blog.51cto.com/823160/350142 最近被 ...

  9. rtp包格式

    转载一篇帮助我了解h264 rtp的文档,地址http://www.cppblog.com/czanyou/archive/2009/12/25/67940.html 当packetization-m ...

随机推荐

  1. 1.linux中的常用命令

    本文积累工作中常用到的Linux命令 1. rz -be 文件上传到Linux服务器 此命令执行时,会弹出文件选择对话框,选择好需要上传的文件之后,点确定,就可以开始上传的过程了.上传的速度取决于当时 ...

  2. python分支结构与循环结构

    python分支结构 一.if 单条件形式 # 年轻人的世界都不容易 age > 18 age = int(input("请输入您的年龄:")) # input()函数 模拟 ...

  3. 带你玩转Flink流批一体分布式实时处理引擎

    摘要:Apache Flink是为分布式.高性能的流处理应用程序打造的开源流处理框架. 本文分享自华为云社区<[云驻共创]手把手教你玩转Flink流批一体分布式实时处理引擎>,作者: 萌兔 ...

  4. 【vps】Centos 7安装python3.8.5

    [vps]Centos 7安装python3.8.5 前言 由于服务器的搬迁,从香港搬到了大陆,原来的香港服务器即将到期,所以趁着大陆服务器在备案的时候,将新服务器的配置先配置一下.这篇文章就是分享C ...

  5. Go环境配置和GoModule

    Linux相关 Linux常用操作 mkdir directory --创建文件夹 vi file --创建文件,再关闭vim rm file --删除文件 rm -rf directory --递归 ...

  6. 【记录一个问题】redis中执行事务出现错误“EXECABORT Transaction discarded because of previous errors”

    执行事务的大致代码如下: redisClient := GetRedisClient() pipe := redisClient.TxPipeline() err := pipe.ZAdd(k, ar ...

  7. dubbo系列一、dubbo启动流程

    目录 dubbo启动流程分析记录 一.dubbo provider启动流程 1.自动装配 2.ServiceBean处理 3.服务暴露export() 3.1.检测dubbo.xxx.配置属性,配置到 ...

  8. golang中文件和路径用法

    package main import ( "fmt" "io/fs" "io/ioutil" "os" "p ...

  9. CTF web安全45天入门学习路线

    前言 因为最近在准备开发CTF学习平台,先做一个学习路线的整理,顺便也是对想学web的学弟学妹的一些建议. 学习路线 初期 刚刚走进大学,入了web安全的坑,面对诸多漏洞必然是迷茫的,这时的首要任务就 ...

  10. java-包与包之间的访问

    1 package face_package; 2 3 import face_packagedemoA.DemoA; 4 5 /* 包(package) 6 * 1,对类文件进行分类管理. 7 * ...