1.NACK的含义
丢包重传(NACK)是抵抗网络错误的重要手段。NACK在接收端检测到数据丢包后,发送NACK报文到发送端;发送端根据NACK报文中的序列号,在发送缓冲区找到对应的数据包,重新发送到接收端。NACK需要发送端,发送缓冲区的支持。
WebRTC中支持音频和视频的NACK重传。我们这里只分析nack机制,不分析jitterbuffer或者neteq的更多实现。
2.WebRTC中NACK请求发送的条件
这里以视频为例。
下面是webrtc中接收端触发nack的条件,我们看下nack_module.cc文件中OnReceivedPacket的实现。
void NackModule::OnReceivedPacket(const VCMPacket& packet) {
rtc::CritScope lock(&crit_);
if (!running_)
return;
//获取包的seqnum
uint16_t seq_num = packet.seqNum;
// TODO(philipel): When the packet includes information whether it is
// retransmitted or not, use that value instead. For
// now set it to true, which will cause the reordering
// statistics to never be updated.
bool is_retransmitted = true;
//判断第一帧是不是关键帧
bool is_keyframe = packet.isFirstPacket && packet.frameType == kVideoFrameKey;
//拿到第一个包的时候判断,把第一个包的seqnum赋值给最新的last_seq_num,如果是关键帧的话,插入到关键帧列表中,同时把initialized_设置为true
if (!initialized_) {
last_seq_num_ = seq_num;
if (is_keyframe)
keyframe_list_.insert(seq_num);
initialized_ = true;
return;
}
if (seq_num == last_seq_num_)
return;
//判断有无乱序,乱序了,如来1,2,3,6包,然后来4包,就乱序了,就把4从nack_list中去掉,不再通知发送端重新发送4了
if (AheadOf(last_seq_num_, seq_num)) {
// An out of order packet has been received.
//把重新收到的包从nack_list中移除掉
nack_list_.erase(seq_num);
if (!is_retransmitted)
UpdateReorderingStatistics(seq_num);
return;
} else {
//没有乱序,如1,2,3,6包,就把(3+1,6)之间的包加入到nack_list中
AddPacketsToNack(last_seq_num_ + 1, seq_num);
last_seq_num_ = seq_num;
// Keep track of new keyframes.
if (is_keyframe)
keyframe_list_.insert(seq_num);
// And remove old ones so we don't accumulate keyframes.
auto it = keyframe_list_.lower_bound(seq_num - kMaxPacketAge);
if (it != keyframe_list_.begin())
keyframe_list_.erase(keyframe_list_.begin(), it);
// Are there any nacks that are waiting for this seq_num.
//从nack_list 中取出需要发送 NACK 的序号列表, 如果某个 seq 请求次数超过 kMaxNackRetries = 10次则会从nack_list 中删除.
std::vector<uin