RTP协议--RR,SR,实例程序 并附有RTCP控制协议解释

  RTCP默认5秒发送一次大概。

RTCP SR格式:https://blog.csdn.net/linux_vae/article/details/90257419

RTCP RR的格式:

https://blog.csdn.net/linux_vae/article/details/90257386

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 <netinet/in.h>
 #include <arpa/inet.h>
#else
 #include <winsock2.h>
#endif // WIN32
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>

 

//添加库

#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_THREAD

void 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<<total++<<endl;
    cout << "        GetSSRC: "<<srcdat->GetSSRC()<<endl;
    cout << "        Fraction lost:    " << srcdat->RR_GetFractionLost() <<endl;
    cout << "        Packets lost:     " << srcdat->RR_GetPacketsLost() <<endl;
    cout << "        Ext.High.Seq:     " << srcdat->RR_GetExtendedHighestSequenceNumber() <<endl;
    cout << "        Jitter:           " << srcdat->RR_GetJitter() << endl;
    cout << "        LSR:              " << srcdat->RR_GetLastSRTimestamp() <<endl;
    cout << "        DLSR:             " << srcdat->RR_GetDelaySinceLastSR() <<endl;
    cout << "        Receive time:     " << srcdat->RR_GetReceiveTime().GetSeconds() <<endl;
   }
   srcdat->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<<ssrc<<endl;
 while(1)
 {
    RTPTime::Wait(RTPTime(1,0));
    status = sess.SendPacket((void *)"1234567890",10,0,false,10);
    checkerror(status); 
  }
 
 sess.BYEDestroy(RTPTime(10,0),0,0);

#ifdef WIN32
 WSACleanup();
#endif // WIN32
 return 0;
}

#endif // RTP_SUPPORT_THREAD

//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 <netinet/in.h>
 #include <arpa/inet.h>
#else
 #include <winsock2.h>
#endif // WIN32
#include "rtpsourcedata.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>

#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()<<endl;
  cout<<"Recv PacketCount:"<<srcdat.SR_GetPacketCount()<<endl;
  cout<< "from SSRC: " << srcdat.GetSSRC() << std::endl;
  cout<<"GetFractionLost:"<<srcdat.SR_Prev_GetPacketCount();
  cout<<endl;
 }
}

// The main routine

int main(void)
{
#ifdef WIN32
 WSADATA dat;
 WSAStartup(MAKEWORD(2,2),&dat);
#endif // WIN32
 
 MyRTPSession sess;//这里用的重载类
 int status,num;
    
 RTPUDPv4TransmissionParams transparams;
 RTPSessionParams sessparams;

 sessparams.SetOwnTimestampUnit(1.0/8000.0);  
 
 transparams.SetPortbase(6006);
 sessparams.SetUsePollThread(true);//默认是开启的
 status = sess.Create(sessparams,&transparams); 
 checkerror(status);

 uint8_t ip[]= {127,0,0,1};//要加入发送端的IP,用于返回信息
 RTPIPv4Address addr(ip,7000);
 
 status = sess.AddDestination(addr);
 checkerror(status);
 cout<<"Waiting recv data!/n";

 while(1)
 {

 }  
 sess.BYEDestroy(RTPTime(10,0),0,0);
#ifdef WIN32
 WSACleanup();
#endif // WIN32
 return 0;
}

#else

int main(void)
{
 std::cerr << "Thread support is required for this example" << std::endl;
 return 0;
}
#endif // RTP_SUPPORT_THREAD
发布了747 篇原创文章 · 获赞 108 · 访问量 83万+

猜你喜欢

转载自blog.csdn.net/sunxiaopengsun/article/details/103026035