原文链接:http://www.rtcbits.com/2017/03/retransmissions-in-webrtc.html
翻译:刘通
引言
当你的网络发生了拥塞,部分数据包丢失了,你需要一个机制来弥补这些。如果我们不考虑信号处理的技巧(比如拉长jitter buffer里前一个和后一个音频数据包的长度),有两个选项可供选择:
# 前向纠错:你需要在每个数据包中加入关于前一个包的额外的信息,为了万一它们在传输过程中遗失的话,你还可以重建它们([1]中给出了一种新的方式)。
# 重传:发送端通常在接收端发回指出哪些数据包丢失的NACK之后,会对这些数据包进行重新传输。
取决于网络情况的好坏,这些机制可以被捆绑使用,也可以调整成像[2]中描述的可调视频那样的特殊情况。在Chrome中,重传机制被应用于音频和视频之中,但是默认情况下,其只在视频中被使用。
本篇文章是关于重传机制的,尤其针对如何请求进行重传,以及何时不需要重传进行了介绍。
在RTP接收端的实现
RTP接收端是当它检测到有数据包丢失的情况发生时,通过发送一个NACK RTCP包来进行重传请求的一方。
但是,我应不应该在探测到接收到的序列编号中出现了一个空隙就立马进行重传呢?Google的实现是这么做的,并且还加了一个额外的重复计时器来进行持续请求。
而且,我应该持续进行多长时间的重传请求呢?Chrome对一个特定的数据包持续进行重传的请求,直到这个所需要的序列号已经有“10000岁的高龄”了,如果序列里丢失的数据包超过1000个,那么你对同一个数据包就要请求10次,或者你已经有了一个新的可以进行解码的完整帧(对于其依赖的其他帧来讲没有丢包)。
这是将Google的WebRTC实现翻译成的伪代码:
在RTP发送端的实现
RTP发送端是接收重传请求(NACK)以及在可能的情况下重新发送丢失的数据包的一方。
这里主要的问题是,我是否要按照每一个重传请求的要求做。目前Goole的WebRTC是这样做的:
#1 备份在过去1000ms内发送的数据包(“发送历史”)
#2 当收到NACK时,如果我们在发送历史中还有指定的数据包的话,就尝试发送数据包请求。
#3 但是……(rtp_sender.cc)
·如果数据包已经在上一个RTT ms中已经进行重传,那么忽视此次请求
·如果我们已经发送了太多次重传,那么忽视此次请求。这里有一个速率限制器 (retransmission_rate_limiter),是根据对整个信道带宽估计而配置的。
·如果pacing算法是启用的,那么以正常的优先级将这个数据包插到队列中。
参考文献
[1] https://tools.ietf.org/html/draft-ietf-payload-flexible-fec-scheme-03
[2] https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/41611.pdf
[3] https://chromium.googlesource.com/external/webrtc/+/master/webrtc/modules/video_coding/nack_module.cc
[4] https://chromium.googlesource.com/external/webrtc/+/master/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
[5] https://chromium.googlesource.com/external/webrtc/+/master/webrtc/modules/rtp_rtcp/source/rtp_sender.cc