时间点 | A | B | C | D |
发送 | 30 | 60 | 90 | 120 |
接收 | 40 | 90 | 100 | 130 |
延时 | null | 50 | 10 | 30 |
不像视频一帧数据那么大,音频一帧数据包都比较小,UDP的1500个字节完全可以装满一帧。所以音频在发送端的发送时间间隔是按照固定的打包时长节奏发送的。
以上图30ms打包时长为例,ABCD四个报文的发送时间间隔都是30ms。若没有网络影响,接收端的包间间隔也是30ms,音频播放清晰流畅。
但网络传输各种不可控因素会导致音频报文到达接收端存在丢包、乱序、抖动等异常。接收端若不特殊处理,用户体验会很差。
对于丢包异常传输层可以使用FEC/NACK/交织编码修复。编解码层可以使用PLC(Packet Loss Compensation)等算法修复。
对于乱序、抖动异常,需要使用JitterBuffer做平滑。JitterBuffer实现机制有静态JB和动态JB两种。
DelayManager、BufferLevelFilter两个模块配合实现动态JB功能。以设置合理的缓冲空间,保证音频平稳播放。
这里首先介绍DelayManager模块实现原理。
DelayManager模块的核心思想是计算target_level_这个参数,通过这个参数在DelayManager::BufferLimits函数中,计算最大最小缓存BUF。
target_level_参数由两个因素决定:IATVector直方图、DelayPeakDetector检测kMaxPeakPeriodMs秒周期内抖动的峰值。
IATVector直方图(Histogram of inter-arrival times)由65成成员变量组成,每个IATVector的成员变量是该延时出现的概率。
IAT(inter arrival times) | 出现概率 |
0 | 72887611 |
1 | 999495224 |
2 | 529939 |
3 | 0 |
4 | 0 |
5 | 0 |
6 | 0 |
7 | 75384 |
。。。。。。 | 0 |
63 | 0 |
64 | 0 |
IATVector直方图里面保存的概率是以1<<30为分母的分子部分。
iat_packet=实际包间间隔 / 打包时长
函数:DelayManager::Update
packet_iat_stopwatch_->ElapsedMs():每收到一包,启动一次定时器,用来计算两次收包实际时间间隔。
packet_len_ms:该报文的打包时长,单位ms。
其中打包时长是根据RTP报文时间戳计算的。我们以G.711A编码10ms打包格式为例,一秒钟的采样率是8000HZ。一包报文的时间戳间隔计算公式为:(8000HZ*10ms打包时长)/1000ms=80个点。
同理,报文的打包时长也可以通过时间戳换算出来。计算公式为packet_len_ms=(1000ms*两包时间戳差值)/采样率。
DelayManager::UpdateHistogram函数会根据计算的iat_packet,将该iat_packet插入IATVector直方图对应数组下标内。并更新该直方图的数据下标下概率参数。一共有四步操作:
调整方式为假设当前概率分布之和为tempSum,则:
这四步操作,都在函数DelayManager::UpdateHistogram中实现。
DelayManager::CalculateTargetLevel函数在每收到一包音频数据的时候,都会更新一次target_level_的值。
IATVector直方图的更新原理是,从IAT为0开始,累加出现的概率,当概率达到设定的kLimitProbability门限值时,配置target_level_为该直方图的数组下标。
IATVector直方图的做法的思想是参考从通话启动,到目前为止的平均延时值,但是实时音视频通话中,还要考虑短时延时波动的影响。所以webrtc里面也引入了DelayPeakDetector算法,检测短期内的延时最大值。作为target_level_的参考值。
实现的原理是,采用一个长度为kMaxNumPeaks的二维数组Peak,统计IAT的峰值。二维数组Peak,保存两个参数:峰值幅度(peak_height_packets)、峰值间隔时间(period_ms)。其中峰值间隔时间(period_ms)是统计当前探测到的峰值距离上一次峰值被发现的时间间隔。当Peak成员变量大于kMinPeaksToTrigger,且当前检测周期小于2*max(period_ms)则target_level_参考该峰值配置。若没有,使用 IATVector直方图计算的值。
至此,完成target_level_的计算。
《WebRTC语音引擎中NetEQ技术的研究_吴江锐》