RTP采样 p-Time Linux平台毫秒级别的延迟方法【原创】

    之前做voip的voice prompt功能时,两台话机建立通话后,其中一台话机给另一台话机播放语音提示, 类似呼叫中心的性质。但对方听到的语音给人的感觉断断续续,不如通过播放工具听起来圆润。 通过Wireshark 抓取数据然后直接播放,声音质量也是非常好,那问题到底出在哪里呢。

    通过Wireshark抓取的数据进行分析,每个rtp包之间的时间间隔大于20ms,这也就是我们所说的p-time。正常语音通话时p-time都是20ms,误差很小。

   说到这个p-time,就不的不说说RTP的数据采用,一般来说10ms 对应80bytes,20ms对应 160bytes,30ms对于240bytes,40ms对于320bytes,当然这是说的净荷,整个rtp包的话还要加上12bytes的header。

    以G711A编码的音频包如果以20ms打包,那么每个包有160个采样点(采样频率为8KHZ,那么每毫秒的采样个数为8个,因此20ms即为160个),这同样体现在时戳,如下图,两个包之间的时戳间隔为160。

    时间戳(timestamp):反映着个包第一个比特的采样时刻,且后面每个包时戳值呈线性增长,一个公式就是 timestamp = timestamp + (80 * (readDelay/10)); //readdelay为采样时间。

   

    言归正传:下面来说说如何解决这个p-time的问题。我们在应用层单独向far-end发送rtp的话,就需要精确这个延迟时间,对于之前使用的usleep(),通过实验是远远不行的,误差太大,20ms的延迟会多出来4ms这严重导致声音断续。下面就介绍一种更好的方法。

    select

    对就是这个万能的select。使用方法:

struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = readDelay*1000; //精确到的毫秒数
ret = select (0, NULL, NULL, NULL, &tv);
if (-1 == ret)
{
    printf("select error\n");

}

当ret返回0时,便表示超时时间到,那咱就可以将打包后的数据一股脑儿的发到far-end。

这时在使用Wireshark看看,p-time误差很小很小了,在听听声音质量,嗯,very good。

结束语:使用 select 来做延迟好处很多,不多说了。Linux下做毫秒级别的延迟用select非常好,其他平台还需测试。

附:参考网上一篇关于sleep,usleep,nanosleep,select的精度测试

猜你喜欢

转载自blog.csdn.net/zjf30366/article/details/84665853
RTP