概述

近期在和同事调试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. pycharm创建脚本头文件模板

    代码头文件信息可以包括:python 解析器的位置.字符集.作者信息.创建脚本时间等,pycharm工具创建头部信息模板操作步骤如下: 设置头文件:文件-->设置-->编辑器-->文 ...

  2. 论文翻译:2019_TCNN: Temporal convolutional neural network for real-time speech enhancement in the time domain

    论文地址:TCNN:时域卷积神经网络用于实时语音增强 论文代码:https://github.com/LXP-Never/TCNN(非官方复现) 引用格式:Pandey A, Wang D L. TC ...

  3. .Net Core依赖注入

    一.配置文件的读取 利用Startup类中的configuration读取appsettings.json中的配置 { "Logging": { "LogLevel&qu ...

  4. 全网最全的Java SpringBoot点赞功能实现

    前言 最近公司在做一个NFT商城的项目,大致就是一个只买卖数字产品的平台,项目中有个需求是用户可以给商品点赞,还需要获取商品的点赞总数,类似下图 起初感觉这功能很好实现,无非就是加个点赞表嘛,后来发现 ...

  5. 集合框架-HashSet集合(无序唯一)

    1 package cn.itcast.p4.hashset.demo; 2 3 import java.util.HashSet; 4 import java.util.Iterator; 5 /* ...

  6. 集合框架-Map集合特点及常用方法

    1 package cn.itcast.p6.map.demo; 2 3 import java.util.HashMap; 4 import java.util.Iterator; 5 import ...

  7. 001 研发同学必学哪些 Linux 命令?

    01 研发同学为啥要掌握 Linux 命令? 身为研发同学,Linux 是绕不过去的一个小山包,不是说要掌握的十分精通,在程序员界里做个极客,也不是说要抢了 Devops 同学的饭碗,但至少要做到摆脱 ...

  8. 学习JAVAWEB第八天

    1. C/S:客户端/服务器端 2. B/S:浏览器/服务器端 2. 资源分类 1. 静态资源:所有用户访问后,得到的结果都是一样的,称为静态资源.静态资源可以直接被浏览器解析 * 如: html,c ...

  9. django之js模板插件artTemplate的使用

    安装: 方式1:artTemplate模板源码下载地址:https://aui.github.io/art-template/zh-cn/index.html 方式2:使用node.js进行安装:np ...

  10. java 变量的定义 类型转换 基本的数据类型

    package com.aaa.zxf.ajax.test; import org.junit.Test; /** * 六. * 如何在ideal的maven项目中导入 Test 测试类? * * * ...