当网络质量突然变的很差并开始丢包时,声音听起来音质会变差,画面帧速会下降,甚至会完全卡住。我们可能需要某种机制来应对这种情况。在WebRTC中,主要有两种机制来应该网络变差的情况:
-
前向纠错:在每个数据包中,您将添加一些关于前一个信息的信息,以防丢失,您需要重新构建它们(flexfec是WebRTC [1]中的新格式)。
-
重传:当接收方检测到有丢包时,它会发送NACK类型的RTCP包给发送方,发送方会重发这些数据。
这些机制可以根据网络条件进行组合,也可以针对特定情况进行调整,如[2]中所述的可扩展视频。在Chrome中,理论上音频,视频丢包都可以重传,但默认情况下只会启用视频丢包重传。下面会详细介绍丢包重传的具体实现。
RTP接收方
丢包重传的请求是由RTP接收方发起的。当RTP接收方检测RTP包头中的seq属性发现有丢包时,丢包重传机制就会启用。但是,是否检测到下一个RTP包不是自己预期想要的哪个就会要求重传呢?比如当前RTP序号是99,下一个来的包序号是101,哪就是否意味着序号为100的包就丢了呢?由于RTP协议是基于UDP的,而UDP又是无序传输的。再下一个包又可能就是序号为100的包。WebRTC会以500毫秒周期性的检测有没有丢包,然后不断请求重传特定数据包,除非序列号为“超过10000 old”,列表中丢失的数据包数量大于1000,您已经询问了相同的数据包10次,或者您有一个新的可解码的完整数据帧(任何依赖于其他帧的数据包都不丢失)。
# code from nack_module.cc
on_packet(rtp):
#检测丢包
if rtp.seq_num < newest_seq_num: # out of order or retransmnission
return
add_missing(newest_seq_num + 1, rtp.seq_num)
if rtp.is_first_packet_of_keyframe:
keyframes.insert(rtp.seq_num)
newest_seq_num = packet.seq_num
if nack = generate_nack(SEQ):
send_nack(nack)
#删除过时的包
add_missing(from_seq_num, to_seq_num):
packets_lost.remove_older_than(10000) # MAX_PACKET_AGE (sequence numbers)
if packets_lost.size() > 1000: # MAX_SIZE
packets_lost.remove_until_keyframe()
if packets_lost.size() > 1000: # Still too big
packets_lost.clear()
sender.request_keyframe()
return
for seq_num in range(from_seq_num, to_seq_num):
packets_lost.insert(seq_num)
# 有一个最新的可解码完整帧,清空重传队列
cleanup_to(to_seq_num):
packets_lost.remove(seq_num < to_seq_num);
generate_nack(mode):
seq_nums = []
for packet in packets_lost:
if packet.retries > 10: # MAX_RETRIES
packets_lost.remove(packet)
if (mode == SEQ and packet.seq_num < newest_seq_num) or (mode == TIME and packet.sent_at + rtt > now()):
seq_nums.insert(packet.seq_num)
packet.sent_at = now()
return seq_nums
every_20_msec():
if nack = generate_nack(TIME):
send_nack(nack)
#rtp_rtcp_impl.cc 发送nack重传rtcp包
send_nack(seq_nums):
if now - time_last_full_nack_sent < 1.5 * RTT:
seq_nums.filter(seq_num > seq_num_last_nack_sent)
else:
time_last_full_nack_sent = now
if seq_nums.length > 253:
seq_nums = seq_nums[:-253]
send(new RtcpNack(seq_nums))
RTP发送方实现
RTP发送方接收到NACK重传请求后会重传所有的数据包吗?WebRTC是这样实现的:
-
保留在最近1000毫秒(“历史”)中发送的数据包的副本。
-
当接收到NACK时,如果历史记录中仍然有这个数据包,尝试发送数据包。
-
但...(rtp_sender.cc)
-
如果这个数据包刚在前面一个RTT时间范围内传输过了,就忽略。
-
如果要求重传数据太多,请忽略该请求。
-
如果启用了WebRTC的pacing模块,则将该重传数据包插入到队列中,并且具有正常的优先级,由pacing模块发送。
(tanningzhong) |