欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

RTCP报文之NACK包的处理机制(RTP接收端)

程序员文章站 2022-07-14 20:31:37
...

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的整体流程图:

RTCP报文之NACK包的处理机制(RTP接收端)

相关标签: 网络协议