本文共 4730 字,大约阅读时间需要 15 分钟。
RTCP默认5秒发送一次大概。
RTCP控制协议
RTCP控制协议需要与RTP数据协议一起配合使用,当应用程序启动一个RTP会话时将同时占用两个端口,分别供RTP和RTCP使用。RTP本身并不能为按序传输数据包提供可靠的保证,也不提供流量控制和拥塞控制,这些都由RTCP来负责完成。通常RTCP会采用与RTP相同的分发机制,向会话中的所有成员周期性地发送控制信息,应用程序通过接收这些数据,从中获取会话参与者的相关资料,以及网络状况、分组丢失概率等反馈信息,从而能够对服务质量进行控制或者对网络状况进行诊断。
RTCP协议的功能是通过不同的RTCP数据报来实现的,主要有如下几种类型:
SR 发送端报告,所谓发送端是指发出RTP数据报的应用程序或者终端,发送端同时也可以是接收端。 RR 接收端报告,所谓接收端是指仅接收但不发送RTP数据报的应用程序或者终端。 SDES 源描述,主要功能是作为会话成员有关标识信息的载体,如用户名、邮件地址、电话号码等,此外还具有向会话成员传达会话控制信息的功能。 BYE 通知离开,主要功能是指示某一个或者几个源不再有效,即通知会话中的其他成员自己将退出会话。 APP 由应用程序自己定义,解决了RTCP的扩展性问题,并且为协议的实现者提供了很大的灵活性。 RTCP数据报携带有服务质量监控的必要信息,能够对服务质量进行动态的调整,并能够对网络拥塞进行有效的控制。由于RTCP数据报采用的是多播方式,因此会话中的所有成员都可以通过RTCP数据报返回的控制信息,来了解其他参与者的当前情况。 在一个典型的应用场合下,发送媒体流的应用程序将周期性地产生发送端报告SR,该RTCP数据报含有不同媒体流间的同步信息,以及已经发送的数据报和字节的计数,接收端根据这些信息可以估计出实际的数据传输速率。另一方面,接收端会向所有已知的发送端发送接收端报告RR,该RTCP数据报含有已接收数据报的最大序列号、丢失的数据报数目、延时抖动和时间戳等重要信息,发送端应用根据这些信息可以估计出往返时延,并且可以根据数据报丢失概率和时延抖动情况动态调整发送速率,以改善网络拥塞状况,或者根据网络状况平滑地调整应用程序的服务质量。//RR例子:
#include "rtpsession.h"#include "rtppacket.h"#include "rtpudpv4transmitter.h"#include "rtpipv4address.h"#include "rtpsessionparams.h"#include "rtperrors.h"#include "rtpsourcedata.h"#include "rtcpsrpacket.h"#include "rtcprrpacket.h"#ifndef WIN32 #include#include #else #include #endif // WIN32#include #include #include #include //添加库#pragma comment(lib, "jrtplib.lib")#pragma comment(lib, "jthread.lib")#pragma comment(lib, "WS2_32.lib")using namespace std;int total= 0; #ifdef RTP_SUPPORT_THREADvoid checkerror(int rtperr){ if (rtperr < 0) { std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl; exit(-1); }}class MyRTPSession : public RTPSession{protected: void OnPollThreadStep();};void MyRTPSession::OnPollThreadStep() //重载虚函数,线程函数{ BeginDataAccess(); if (GotoFirstSource()) { do { RTPSourceData *srcdat; srcdat = GetCurrentSourceInfo(); if(srcdat->RR_HasInfo())//打印RR信息 { cout<<"RR Info:"; cout< < << " GetSSRC: "< GetSSRC()< << " Fraction lost: " << srcdat->RR_GetFractionLost() < << " Packets lost: " << srcdat->RR_GetPacketsLost() < << " Ext.High.Seq: " << srcdat->RR_GetExtendedHighestSequenceNumber() < << " Jitter: " << srcdat->RR_GetJitter() << endl; cout << " LSR: " << srcdat->RR_GetLastSRTimestamp() < << " DLSR: " << srcdat->RR_GetDelaySinceLastSR() < << " Receive time: " << srcdat->RR_GetReceiveTime().GetSeconds() < FlushPackets(); } while (GotoNextSource()); } EndDataAccess();} int main(void){#ifdef WIN32 WSADATA dat; WSAStartup(MAKEWORD(2,2),&dat);#endif // WIN32 int status,num; std::cout << std::endl; std::cout << "Number of packets you wish to be sent:" << std::endl; std::cin >> num; MyRTPSession sess; RTPUDPv4TransmissionParams transparams; RTPSessionParams sessparams; sessparams.SetOwnTimestampUnit(1.0/10.0); sessparams.SetAcceptOwnPackets(true); sessparams.SetUsePollThread(true);//默认是开启的,为确保开启再设置下 transparams.SetPortbase(7000); status = sess.Create(sessparams,&transparams); checkerror(status); uint8_t ip[]= {127,0,0,1}; RTPIPv4Address addr(ip,6006); status = sess.AddDestination(addr); checkerror(status); unsigned long ssrc= sess.GetLocalSSRC();//获取同步源标示 cout< <
//SR 接收端例子
#include "rtpsession.h"#include "rtppacket.h"#include "rtpudpv4transmitter.h"#include "rtpipv4address.h"#include "rtpsessionparams.h"#include "rtperrors.h"#include "rtcpsrpacket.h"#include "rtcprrpacket.h"#ifndef WIN32 #include#include #else #include #endif // WIN32#include "rtpsourcedata.h"#include #include #include #include #pragma comment(lib, "jrtplib.lib")#pragma comment(lib, "jthread.lib")#pragma comment(lib, "WS2_32.lib")using namespace std;#ifdef RTP_SUPPORT_THREAD //支持多线程void checkerror(int rtperr){ if (rtperr < 0) { std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl; exit(-1); }}//// The new class routine//class MyRTPSession : public RTPSession//重载类{protected: void OnPollThreadStep(); void ProcessRTPPacket(const RTPSourceData &srcdat,const RTPPacket &rtppack);};void MyRTPSession::OnPollThreadStep() //重载虚函数,线程函数{ BeginDataAccess(); // check incoming packets if (GotoFirstSourceWithData()) { do { RTPPacket *pack; RTPSourceData *srcdat; srcdat = GetCurrentSourceInfo(); while ((pack = GetNextPacket()) != NULL) { ProcessRTPPacket(*srcdat,*pack); DeletePacket(pack); } } while (GotoNextSourceWithData()); } EndDataAccess();}void MyRTPSession::ProcessRTPPacket(const RTPSourceData &srcdat,const RTPPacket &rtppack){ if(srcdat.SR_HasInfo())//打印SR信息 { cout<<"SR Info:/n"; cout << "Got packet GetExtendedSequenceNumber:" << rtppack.GetExtendedSequenceNumber()< <<"Recv PacketCount:"< < << "from SSRC: " << srcdat.GetSSRC() << std::endl; cout<<"GetFractionLost:"< <
转载地址:http://fpbxi.baihongyu.com/