RTCP报文之NACK包的处理机制(RTP接收端)
首先来看看整体的处理流程(上图)。
处理过程主要包括两个:
1、判断收到的RTP 的seq num与最近最大的seq num的差值。根据差值不同,做不同的处理。
2、判断每个seq num的重发次数是否超过指定次数,如果超过,则不再重发。
下面是主要逻辑的代码:
synchronized private boolean received(int seq)
{
if (lastReceivedSeq == -1)
{
lastReceivedSeq = seq;
return false;
}
int diff = RTPUtils.getSequenceNumberDelta(seq, lastReceivedSeq);
if (diff <= 0)
{
// An older packet, possibly already requested.
Request r = requests.remove(seq);
if (requests.isEmpty())
{
nextRequestAt = -1;
}
if (r != null && logger.isDebugEnabled())
{
long rtt
= stream.getMediaStreamStats().getSendStats().getRtt();
if (rtt > 0)
{
// firstRequestSentAt is if we created a Request, but
// haven't yet sent a NACK. Assume a delta of 0 in that
// case.
long firstRequestSentAt = r.firstRequestSentAt;
long delta
= firstRequestSentAt > 0
? timeProvider.currentTimeMillis() - r.firstRequestSentAt
: 0;
logger.debug(Logger.Category.STATISTICS,
"retr_received,stream=" + stream
.hashCode() +
" delay=" + delta +
",rtt=" + rtt);
}
}
}
else if (diff == 1)
{
// The very next packet, as expected.
lastReceivedSeq = seq;
}
else if (diff <= MAX_MISSING)
{
for (int missing = (lastReceivedSeq + 1) % (1<<16);
missing != seq;
missing = (missing + 1) % (1<<16))
{
Request request = new Request(missing);
requests.put(missing, request);
}
lastReceivedSeq = seq;
nextRequestAt = 0;
return true;
}
else // if (diff > MAX_MISSING)
{
// Too many packets missing. Reset.
lastReceivedSeq = seq;
if (logger.isDebugEnabled())
{
logger.debug("Resetting retransmission requester state. "
+ "SSRC: " + ssrc
+ ", last received: " + lastReceivedSeq
+ ", current: " + seq
+ ". Removing " + requests.size()
+ " unsatisfied requests.");
}
requests.clear();
nextRequestAt = -1;
}
return false;
}
第一步是判断seq num的差值,做不同处理。
int diff = RTPUtils.getSequenceNumberDelta(seq, lastReceivedSeq);
if (diff <= 0)
{}else if (diff == 1)
{}else if (diff <= MAX_MISSING)
{}else // if (diff > MAX_MISSING)
{}
这里分成了4中情况:
一、差值小于等于0。
二、差值等于1
三、差值小于等于100
四、差值大于100
一、差值小于等于0
比如之前收到了seq num为100的RTP报文, 然后才收到值为90的RTP,说明因为网络原因,本来应该提前收到的报文延时收到了。这里需要跳转到(三)部分中,有涉及到一个存储着已丢包的map,将该报文从map中删除掉。
// An older packet, possibly already requested.
Request r = requests.remove(seq);
二、差值等于1
这种情况是正常的情况,下一个RTP比上一个RTP的seq num大于1,按照正常流程处理,然后将最近RTP的seq num更新成当前的seq num。
// The very next packet, as expected.
lastReceivedSeq = seq;
三、差值小于等于100
当差值大于0而小于100时,可以简单的认为中间丢失了(当前seq num - 最近最大seq num)个报文。尽管可能并不是真的丢失,也许马上就能收到其中丢失的一部分,但这部分逻辑在(一、差值小于等于0)中已经有做处理了。
然后,将最近最大序号和当前收到序号之间的所有报文,都添加到存储丢包的map中。将最大序号重置成当前序号。
for (int missing = (lastReceivedSeq + 1) % (1<<16);
missing != seq;
missing = (missing + 1) % (1<<16))
{
Request request = new Request(missing);
requests.put(missing, request);
}lastReceivedSeq = seq;
nextRequestAt = 0;
四、差值大于100
此时说明丢包的间隔过大,已不再需要重传,将前面的map清空。将最大序号重置成当前序号。
lastReceivedSeq = seq;
requests.clear();
下面贴一张webrtc中nack的整体流程图:
上一篇: Rtp载荷H264解包过程分析,ffmpeg解码qt展示
下一篇: RTP协议分析