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

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值