本文共 3598 字,大约阅读时间需要 11 分钟。
Qos.NACK
一、前言
RTP/RTCP协议是流媒体通信最基本协议。RTP协议定义流媒体数据在互联网上传输的数据包格式,而RTCP协议则负责可靠传输、流量控制和拥塞控制等服务质量保证。在很多项目中,如WebRTC中,RTP/RTCP模块作为传输模块的一部分,负责对发送端采集到的媒体数据进行进行封包,然后交给上层网络模块发送;在接收端RTP/RTCP模块收到上层模块的数据包后,进行解包操作,最后把负载发送到解码模块。RTP协议是Internet上针对流媒体传输的基础协议,该协议详细说明在互联网上传输音视频的标准数据包格式。
RTP协议本身只保证实时数据的传输,RTCP协议则负责流媒体的传输质量保证,提供流量控制和拥塞控制等服务。在RTP会话期间,各参与者周期性彼此发送RTCP报文。报文中包含各参与者数据发送和接收等统计信息,参与者可以据此动态控制流媒体传输质量。RFC3550 [1]定义RTP/RTCP协议的基本内容,包括报文格式、传输规则等。
二、NACK(Non-Acknowledge)
说NACK前,先说说ACK。ACK实际上就是到达通知技术。大家都知道TCP是可靠的连接,他之所以可靠,那是因为接收方在收到数据后会给发送方返回一个“已收到数据”的消息(ACK),告诉发送方“我已经收到了”,确保消息的可靠。
NACK也是一种通知技术,只是触发通知的条件刚好的ACK相反,在未收到消息时,通知发送方“我未收到消息”,即通知未达。那么问题来了,接受者怎么知道自己未收到消息?音视频数据包都是按时间顺序发送的,一般都带序号(升序排列的时间戳)。例如发送方按顺序发送了时间戳为60,120,180,240,320共五个包,接收者已经收到了60包,本来预期下一个接收的包的序号应该是序号120的包,但序号是120的包一直没收到,后面的包却收到了。那么接收者就可以判断,120这个包丢了,这时候接收方需要向发送方发出NACK消息(消息中带有丢包的序号,这里是120),让发送方重新发送丢失的包。
在WebRTC中,前向纠错(FEC)和丢包重传(NACK)是抵抗网络错误的重要手段。FEC在发送端将数据包添加冗余纠错码,纠错码连同数据包一起发送到接收端;接收端根据纠错码对数据进行检查和纠正。RFC5109[1]定义FEC数据包的格式。NACK则在接收端检测到数据丢包后,发送NACK报文到发送端;发送端根据NACK报文中的序列号,在发送缓冲区找到对应的数据包,重新发送到接收端。NACK需要发送端发送缓冲区的支持,RFC5104[2]定义NACK数据包的格式。
三、NACK协议
NACK报文是类型为205的RTCP 扩展反馈报文,在RFC4585中定义[4]。
/* *| 0 1 2 3 | *| 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 *+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *|V=2|P| RC | PT=205 | length | * *+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *| SSRC of packet sender | *+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+==+=+ *| SSRC of media source | *+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *| PID | BLP | *+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */其中PT = 205,FMT = 1,Packet identifier(PID)即为丢失RTP数据包的序列号,Bitmao of Lost Packets(BLP)指示从PID开始接下来16个RTP数据包的丢失情况。一个NACK报文可以携带多个RTP序列号,NACK接收端对这些序列号逐个处理。NACK报文构造完成以后,发送到网络层。NACK报文是RTCP报文的一种,因此其发送、接收和分析遵循RTCP报文处理的一般流程。
注意version, padding, blockcount, packettype, length , ssrc为公共头部分,即所有消息都具有,此头信息,而ssrcsource, pid, blp为NACK消息特有部分。
class NackStructor {
public:
uint32_tversion :2; //协议版本号(2bit)
uint32_t padding :1;
uint32_t fmt :5; //(5bit)在不同消息中叫法不同,也叫blockcount或RC,此处指格式
//format,在NACK消息中此值为1,之所以同时具有fmt和packettype
//是因为某些消息存在多级类型,比如当前的NACK消息属于Feedback
//类型。因此fmt=1(Feedback).
uint32_t packettype :8; //包类型(8bit),NACK消息类型值为205,Feedback子类型
uint32_t length :16; //(16bit)消息长度
uint32_t ssrc; //构造发送当前消息包的端的SSRC,若本端是此NACK包的发送者,此
//SSRC值就是本端的SSRC值(源标识符)
uint32_t ssrcsource; //NACK消息部分,也是SSRC值,在此可称为媒体源标识符,用来指明
//此消息要反鐀谁的情况。比如我是接收端,我知道发送端的音频流
//(SSRC:1234)给我发来的数据包有丢包,我要反鐀对方音频流的
//情况,那这个地方就应该填写1234(对方音频流SSRC)。
uint32_t pid:16; //packet id(sequence number)详见下面PID-BLP图
uint32_t blp:16;
};
//在一个消息的一个公用头后面的NACK块部分可以有多个,每个NACK块可以反鐀1个流(SSRC)的情况。当然
1个NACK块中的blp部分也可以有多个。
四、WebRTC中实现NACK
(1)接收端的NACK报文构造和发送工作在ModuleProcessThread线程中周期性完成。
ModuleProcessThread线程周期性调用VideoReceiver::process函数,该函数通过VCMReceiver调用VCMJitterBuffer::GetNackList,从missing_seq_nums集合中得到过去一段时间内丢失RTP数据包的序列号。然后调用RtpStreamReceiver::ResendPackets函数。调用流程最终会到达RTCPSender::SendRTCP,发送类型为NACK的RTCP报文。
(2)接收端在接收和解析NACK报文后,通过回调机制处理各种类型的RTCP报文,对于NACK报文,会调用RTPSender重新发送RTP数据包,如图所示:
RTCPReceiver在解析RTCP之后,得到RTCP报文的描述结构,然后通过回调进行报文语义处理。NACK报文会被发送到RTPSender进行处理。RTPSender根据NACK报文中包含的序列号,到RTPPacketHistory缓存中查找对应的RTP数据包。如果找到,则把数据包发送到网络。至此,一个完整的NACK报文回路完成,丢失的RTP数据包会重新发送到接收端。
参考文献 [1] RFC5109 - RTP Payload Format for Generic Forward Error Correction. [2] RFC5104 - RFC 5104 - Codec Control Messages in the RTP Audio-Visual Profile with Feedback (AVPF) [3] WebRTC中RTP/RTCP协议实现分析 - http://www.jianshu.com/p/c84be6f3ddf3 [4] RFC4585 - Extended RTP Profile for Real-time Transport Control Protocol (RTCP)-Based Feedback (RTP/AVPF)
转载地址:http://mdqxi.baihongyu.com/