博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
生成Send Report的rtcp包接口
阅读量:4218 次
发布时间:2019-05-26

本文共 4755 字,大约阅读时间需要 15 分钟。

RTP需要RTCP为其服务质量提供保证,因此下面介绍一下RTCP的相关知识。


RTCP的主要功能是:服务质量的监视与反馈、媒体间的同步,以及多播组中成员的标识。在RTP会话期 间,各参与者周期性地传送RTCP包。RTCP包中含有已发送的数据包的数量、丢失的数据包的数量等统计资料,因此,各参与者可以利用这些信息动态地改变传输速率,甚至改变有效载荷类型。RTP和RTCP配合使用,它们能以有效的反馈和最小的开销使传输效率最佳化,因而特别适合传送网上的实时数据。


从图 1可以看到,RTCP也是用UDP来传送的,但RTCP封装的仅仅是一些控制信息,因而分组很短,所以可以将多个RTCP分组封装在一个UDP包中。RTCP有如下五种分组类型。

类型 

缩写表示 

用途


200 

SR(Sender Report) 

发送端报告


201 

RR(Receiver Report) 

接收端报告


202 

SDES(Source Description Items) 

源点描述


203 

BYE 

结束传输


204 

APP 

特定应用



表 1 RTCP的5种分组类型


上述五种分组的封装大同小异,下面只讲述SR类型,而其它类型请参考RFC3550。


发送端报告分组SR(Sender Report)用来使发送端以多播方式向所有接收端报告发送情况。SR分组的主要内容有:相应的RTP流的SSRC,RTP流中最新产生的RTP分组的时间戳和NTP,RTP流包含的分组数,RTP流包含的字节数。SR包的封装如图3所示。




图 3 RTCP头部的格式


版本(V):同RTP包头域。


填充(P):同RTP包头域。


接收报告计数器(RC):5比特,该SR包中的接收报告块的数目,可以为零。


包类型(PT):8比特,SR包是200。


长度域(Length):16比特,其中存放的是该SR包以32比特为单位的总长度减一。


同步源(SSRC):SR包发送者的同步源标识符。与对应RTP包中的SSRC一样。


NTP Timestamp(Network time protocol)SR包发送时的绝对时间值。NTP的作用是同步不同的RTP媒体流。


RTP Timestamp:与NTP时间戳对应,与RTP数据包中的RTP时间戳具有相同的单位和随机初始值。


Sender’s packet count:从开始发送包到产生这个SR包这段时间里,发送者发送的RTP数据包的总数. SSRC改变时,这个域清零。


Sender`s octet count:从开始发送包到产生这个SR包这段时间里,发送者发送的净荷数据的总字节数(不包括头部和填充)。发送者改变其SSRC时,这个域要清零。


同步源n的SSRC标识符:该报告块中包含的是从该源接收到的包的统计信息。


丢失率(Fraction Lost):表明从上一个SR或RR包发出以来从同步源n(SSRC_n)来的RTP数据包的丢失率。 


累计的包丢失数目:从开始接收到SSRC_n的包到发送SR,从SSRC_n传过来的RTP数据包的丢失总数。 


收到的扩展最大序列号:从SSRC_n收到的RTP数据包中最大的序列号, 


接收抖动(Interarrival jitter):RTP数据包接受时间的统计方差估计 


上次SR时间戳(Last SR,LSR):取最近从SSRC_n收到的SR包中的NTP时间戳的中间32比特。如果目前还没收到SR包,则该域清零。 


上次SR以来的延时(Delay since last SR,DLSR):上次从SSRC_n收到SR包到发送本报告的延时。 

2.4. RTP的会话过程


当应用程序建立一个RTP会话时,应用程序将确定一对目的传输地址。目的传输地址由一个网络地址和一对端口组成,有两个端口:一个给RTP包,一个给RTCP包,使得RTP/RTCP数据能够正确发送。RTP数据发向偶数的UDP端口,而对应的控制信号RTCP数据发向相邻的奇数UDP端口(偶数的UDP端口+1),这样就构成一个UDP端口对。 RTP的发送过程如下,接收过程则相反。


1) RTP协议从上层接收流媒体信息码流(如H.263),封装成RTP数据包;RTCP从上层接收控制信息,封装成RTCP控制包。


2) RTP将RTP 数据包发往UDP端口对中偶数端口;RTCP将RTCP控制包发往UDP端口对中的接收端口。

RTCP的bit图

//        0                   1                   2                   3 //        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //byte=0 |V=2|P|    RC   |   PT=SR=200   |             length            | //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //     4 |                         SSRC of sender                        | //       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ //     8 |              NTP timestamp, most significant word             | //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //    12 |             NTP timestamp, least significant word             | //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //    16 |                         RTP timestamp                         | //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //    20 |                     sender's packet count                     | //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //    24 |                      sender's octet count                     | //       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ //    28 |V=2|P|    SC   |  PT=SDES=202  |             length            | //       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ //    32 |                          SSRC/CSRC_1                          | //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //    36 |    CNAME=1    |     length    | user and domain name        ... //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
生成RTCP包的代码:

void CreateSendReportRtcp(std::string &buffer, uint32_t ssrc, uint32_t timestamp, int sendPacketsNum, int sendBytesNum)	{		buffer.resize(40);		*(uint8_t*)&buffer[0] = (uint8_t)(2 << 6);                              //  V=2,  P=RC=0		*(uint8_t*)&buffer[1] = (uint8_t)200;                                 // PT=SR=200		*(uint16_t*)&buffer[2] = (uint16_t)htons(6);                                         // length (7 32-bit words, minus one)		*(uint32_t*)&buffer[4] = (uint32_t)htonl(ssrc);		*(uint32_t*)&buffer[8] = (uint32_t)(timestamp >> 32);        // High 32-bits		*(uint32_t*)&buffer[12] = (uint32_t)(timestamp & 0xFFFFFFFF); // Low 32-bits		*(uint32_t*)&buffer[16] = (uint32_t)htonl(timestamp);		*(uint32_t*)&buffer[20] = (uint32_t)htonl(sendPacketsNum);		*(uint32_t*)&buffer[24] = (uint32_t)htonl(sendBytesNum);		*(uint8_t*)&buffer[28] = (uint8_t)(2 << 6 | 1);                          //  V=2, P=0, SC=1		*(uint8_t*)&buffer[29] = (uint8_t)202;		*(uint16_t*)&buffer[30] = (uint16_t)htons(2);		*(uint32_t*)&buffer[32] = (uint32_t)htonl(ssrc);		*(uint8_t*)&buffer[36] = (uint8_t)1;		*(uint8_t*)&buffer[37] = (uint8_t)0;		*(uint16_t*)&buffer[38] = (uint16_t)0;	}
注意:CNAME是用来音视频同步的,因为在写接口的过程中没有涉及音视频同步,所以CNAME均设为空。

转载地址:http://srpmi.baihongyu.com/

你可能感兴趣的文章
再谈StringBuilder和StringBuffer的区别
查看>>
Guava 常用工具类
查看>>
MySQL中乐观锁和悲观锁
查看>>
Java 中包装类型的比较注意事项
查看>>
Java查看字节码文件(基于JDK和IDEA)
查看>>
Java中如何存储金额的问题
查看>>
Spring 线程池定时监控
查看>>
Java 注解的原理及自定义注解
查看>>
Spring MyBatis generator自动生成配置
查看>>
java web中通过fork join来子任务拆分提高处理速度
查看>>
java面试题及答案
查看>>
常见的java查错题
查看>>
java面试题大全-代码与编程题
查看>>
java中equals和==的区别
查看>>
java中&与&&的区别
查看>>
JAVA数据类型间的相互转换
查看>>
js 操作select和option
查看>>
Java接口和Java抽象类
查看>>
java抽象类、接口和继承之间关系
查看>>
区分Tomcat与Web服务器、应用服务器的关系
查看>>