使用RTP协议封装数据时,我们可以通过RTP报头的序列号连续性判断是否丢包。但由于RTP报头序列号只有两字节表示,值范围[0,65535],存在回绕问题(参考之前文章:WebRTC研究:RTP中的序列号以及时间戳比较,建议先阅读一遍此文章)。所以判断序列号连续性时得考虑回绕问题。下面我们就结合WebRTC这相关源码,讲下如何有效地根据序列号进行丢包判断。
首先看下这块代码,代码位于jitter_buffer.cc中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
bool VCMJitterBuffer::UpdateNackList(uint16_t sequence_number) { // Make sure we don't add packets which are already too old to be decoded. if (!last_decoded_state_.in_initial_state()) { latest_received_sequence_number_ = LatestSequenceNumber( latest_received_sequence_number_, last_decoded_state_.sequence_num()); } if (IsNewerSequenceNumber(sequence_number, latest_received_sequence_number_)) { // Push any missing sequence numbers to the NACK list. for (uint16_t i = latest_received_sequence_number_ + 1; IsNewerSequenceNumber(sequence_number, i); ++i) { missing_sequence_numbers_.insert(missing_sequence_numbers_.end(), i); } if (TooLargeNackList() && !HandleTooLargeNackList()) { RTC_LOG(LS_WARNING) << "Requesting key frame due to too large NACK list."; return false; } if (MissingTooOldPacket(sequence_number) && !HandleTooOldPackets(sequence_number)) { RTC_LOG(LS_WARNING) << "Requesting key frame due to missing too old packets"; return false; } } else { missing_sequence_numbers_.erase(sequence_number); } return true; } |
IsNewerSequenceNumber
函数以及latest_received_sequence_number_
介绍在之前文章说过,读者可参考前面给的文字链接。上述代码丢包判断用到的相关定义如下:
IsNewerSequenceNumber
:判断是否是最新的序列号sequence_number
:当前收到的包序列号latest_received_sequence_number_
:上一次收到的最新RTP包序列号missing_sequence_numbers_
:存储丢包序列号
丢包判断流程如下:
- 首先
IsNewerSequenceNumber
传入当前收到的包序列号sequence_number
以及之前收到的最新RTP包序列号latest_received_sequence_number_
,判断当前RTP包是否是新的数据包,而不是重传包或者乱序包 - 在for循环中,从
latest_received_sequence_number_ + 1
开始判断(因为如果丢包了,两个包序列号间隔大于1),满足IsNewerSequenceNumber(sequence_number, i)
则说明i
为丢失的RTP包序列号,插入missing_sequence_numbers_
中,接着++i
继续判断,否则退出
通过如上方法,我们就可以获取那些丢失的包序列号,是不是很简单。
文章评论
有问题请教大佬-qq1447382485