live555的RTCP .

 

live555中默认支持RTCP,如果要监视网络状态就要了解RTCP。我们这里以openRTSP为例看看RTCP的过程。

在前面的openRTSP分析中分析了openRTSP的流程,其中在在continueAfterDESCRIBE中有subsession->initiate(simpleRTPoffsetArg),在这里进行了RTP socket和RTCP socket的建立。

  1. if (isSSM()) {  
  2.       fRTCPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, rtcpPortNum);  
  3.     } else {  
  4.       fRTCPSocket = new Groupsock(env(), tempAddr, rtcpPortNum, 255);  
  5.     }  
if (isSSM()) {
	  fRTCPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, rtcpPortNum);
	} else {
	  fRTCPSocket = new Groupsock(env(), tempAddr, rtcpPortNum, 255);
	}

这里建立了RTCP 的socket,下面初始化fRTCPInstance

  1. if (fRTPSource != NULL && fRTCPSocket != NULL) {// Finally, create our RTCP instance. (It starts running automatically)   
  2.       // If bandwidth is specified, use it and add 5% for RTCP overhead.   
  3.       // Otherwise make a guess at 500 kbps.   
  4.       unsigned totSessionBandwidth  
  5.     = fBandwidth ? fBandwidth + fBandwidth / 20 : 500;  
  6.       fRTCPInstance = RTCPInstance::createNew(env(), fRTCPSocket,  
  7.                           totSessionBandwidth,  
  8.                           (unsigned char const*)  
  9.                           fParent.CNAME(),  
  10.                           NULL /* we're a client */,  
  11.                           fRTPSource);  
  12.       if (fRTCPInstance == NULL) {  
  13.     env().setResultMsg("Failed to create RTCP instance");  
  14.     break;  
  15.       }  
  16.     }  
if (fRTPSource != NULL && fRTCPSocket != NULL) {// Finally, create our RTCP instance. (It starts running automatically)
      // If bandwidth is specified, use it and add 5% for RTCP overhead.
      // Otherwise make a guess at 500 kbps.
      unsigned totSessionBandwidth
	= fBandwidth ? fBandwidth + fBandwidth / 20 : 500;
      fRTCPInstance = RTCPInstance::createNew(env(), fRTCPSocket,
					      totSessionBandwidth,
					      (unsigned char const*)
					      fParent.CNAME(),
					      NULL /* we're a client */,
					      fRTPSource);
      if (fRTCPInstance == NULL) {
	env().setResultMsg("Failed to create RTCP instance");
	break;
      }
    }

根据注释提示,fRTCPInstance会自动开始运行,如何运行的呢,我们再来看看。

  1. RTCPInstance* RTCPInstance::createNew(UsageEnvironment& env, Groupsock* RTCPgs,  
  2.                       unsigned totSessionBW,  
  3.                       unsigned char const* cname,  
  4.                       RTPSink* sink, RTPSource const* source,  
  5.                       Boolean isSSMSource) {  
  6.   return new RTCPInstance(env, RTCPgs, totSessionBW, cname, sink, source,  
  7.               isSSMSource);  
  8. }  
RTCPInstance* RTCPInstance::createNew(UsageEnvironment& env, Groupsock* RTCPgs,
				      unsigned totSessionBW,
				      unsigned char const* cname,
				      RTPSink* sink, RTPSource const* source,
				      Boolean isSSMSource) {
  return new RTCPInstance(env, RTCPgs, totSessionBW, cname, sink, source,
			  isSSMSource);
}

为了过程的清晰,这里还是贴出所有代码

  1. RTCPInstance::RTCPInstance(UsageEnvironment& env, Groupsock* RTCPgs,  
  2.                unsigned totSessionBW,  
  3.                unsigned char const* cname,  
  4.                RTPSink* sink, RTPSource const* source,  
  5.                Boolean isSSMSource)  
  6.   : Medium(env), fRTCPInterface(this, RTCPgs), fTotSessionBW(totSessionBW),  
  7.     fSink(sink), fSource(source), fIsSSMSource(isSSMSource),  
  8.     fCNAME(RTCP_SDES_CNAME, cname), fOutgoingReportCount(1),  
  9.     fAveRTCPSize(0), fIsInitial(1), fPrevNumMembers(0),  
  10.     fLastSentSize(0), fLastReceivedSize(0), fLastReceivedSSRC(0),  
  11.     fTypeOfEvent(EVENT_UNKNOWN), fTypeOfPacket(PACKET_UNKNOWN_TYPE),  
  12.     fHaveJustSentPacket(False), fLastPacketSentSize(0),  
  13.     fByeHandlerTask(NULL), fByeHandlerClientData(NULL),  
  14.     fSRHandlerTask(NULL), fSRHandlerClientData(NULL),  
  15.     fRRHandlerTask(NULL), fRRHandlerClientData(NULL),  
  16.     fSpecificRRHandlerTable(NULL) {  
  17. #ifdef DEBUG   
  18.   fprintf(stderr, "RTCPInstance[%p]::RTCPInstance()\n"this);  
  19. #endif   
  20.   if (fTotSessionBW == 0) { // not allowed!   
  21.     env << "RTCPInstance::RTCPInstance error: totSessionBW parameter should not be zero!\n";  
  22.     fTotSessionBW = 1;  
  23.   }  
  24.   
  25.   if (isSSMSource) RTCPgs->multicastSendOnly(); // don't receive multicast   
  26.   
  27.   double timeNow = dTimeNow();  
  28.   fPrevReportTime = fNextReportTime = timeNow;  
  29.   
  30.   fKnownMembers = new RTCPMemberDatabase(*this);  
  31.   fInBuf = new unsigned char[maxPacketSize];  
  32.   if (fKnownMembers == NULL || fInBuf == NULL) return;  
  33.   fNumBytesAlreadyRead = 0;  
  34.   
  35.   // A hack to save buffer space, because RTCP packets are always small:   
  36.   unsigned savedMaxSize = OutPacketBuffer::maxSize;  
  37.   OutPacketBuffer::maxSize = maxPacketSize;  
  38.   fOutBuf = new OutPacketBuffer(preferredPacketSize, maxPacketSize);  
  39.   OutPacketBuffer::maxSize = savedMaxSize;  
  40.   if (fOutBuf == NULL) return;  
  41.   
  42.   // Arrange to handle incoming reports from others:   
  43.   TaskScheduler::BackgroundHandlerProc* handler  
  44.     = (TaskScheduler::BackgroundHandlerProc*)&incomingReportHandler;  
  45.   fRTCPInterface.startNetworkReading(handler);  
  46.   
  47.   // Send our first report.   
  48.   fTypeOfEvent = EVENT_REPORT;  
  49.   onExpire(this);  
  50. }  
RTCPInstance::RTCPInstance(UsageEnvironment& env, Groupsock* RTCPgs,
			   unsigned totSessionBW,
			   unsigned char const* cname,
			   RTPSink* sink, RTPSource const* source,
			   Boolean isSSMSource)
  : Medium(env), fRTCPInterface(this, RTCPgs), fTotSessionBW(totSessionBW),
    fSink(sink), fSource(source), fIsSSMSource(isSSMSource),
    fCNAME(RTCP_SDES_CNAME, cname), fOutgoingReportCount(1),
    fAveRTCPSize(0), fIsInitial(1), fPrevNumMembers(0),
    fLastSentSize(0), fLastReceivedSize(0), fLastReceivedSSRC(0),
    fTypeOfEvent(EVENT_UNKNOWN), fTypeOfPacket(PACKET_UNKNOWN_TYPE),
    fHaveJustSentPacket(False), fLastPacketSentSize(0),
    fByeHandlerTask(NULL), fByeHandlerClientData(NULL),
    fSRHandlerTask(NULL), fSRHandlerClientData(NULL),
    fRRHandlerTask(NULL), fRRHandlerClientData(NULL),
    fSpecificRRHandlerTable(NULL) {
#ifdef DEBUG
  fprintf(stderr, "RTCPInstance[%p]::RTCPInstance()\n", this);
#endif
  if (fTotSessionBW == 0) { // not allowed!
    env << "RTCPInstance::RTCPInstance error: totSessionBW parameter should not be zero!\n";
    fTotSessionBW = 1;
  }

  if (isSSMSource) RTCPgs->multicastSendOnly(); // don't receive multicast

  double timeNow = dTimeNow();
  fPrevReportTime = fNextReportTime = timeNow;

  fKnownMembers = new RTCPMemberDatabase(*this);
  fInBuf = new unsigned char[maxPacketSize];
  if (fKnownMembers == NULL || fInBuf == NULL) return;
  fNumBytesAlreadyRead = 0;

  // A hack to save buffer space, because RTCP packets are always small:
  unsigned savedMaxSize = OutPacketBuffer::maxSize;
  OutPacketBuffer::maxSize = maxPacketSize;
  fOutBuf = new OutPacketBuffer(preferredPacketSize, maxPacketSize);
  OutPacketBuffer::maxSize = savedMaxSize;
  if (fOutBuf == NULL) return;

  // Arrange to handle incoming reports from others:
  TaskScheduler::BackgroundHandlerProc* handler
    = (TaskScheduler::BackgroundHandlerProc*)&incomingReportHandler;
  fRTCPInterface.startNetworkReading(handler);

  // Send our first report.
  fTypeOfEvent = EVENT_REPORT;
  onExpire(this);
}

可以看到这里加入了handler,handler为incomingReportHandler。看看这个startNetworkReading。

  1. void RTPInterface  
  2. ::startNetworkReading(TaskScheduler::BackgroundHandlerProc* handlerProc) {  
  3.   // Normal case: Arrange to read UDP packets:   
  4.   envir().taskScheduler().  
  5.     turnOnBackgroundReadHandling(fGS->socketNum(), handlerProc, fOwner);  
  6.   
  7.   // Also, receive RTP over TCP, on each of our TCP connections:   
  8.   fReadHandlerProc = handlerProc;  
  9.   for (tcpStreamRecord* streams = fTCPStreams; streams != NULL;  
  10.        streams = streams->fNext) {  
  11.     // Get a socket descriptor for "streams->fStreamSocketNum":   
  12.     SocketDescriptor* socketDescriptor = lookupSocketDescriptor(envir(), streams->fStreamSocketNum);  
  13.   
  14.     // Tell it about our subChannel:   
  15.     socketDescriptor->registerRTPInterface(streams->fStreamChannelId, this);  
  16.   }  
  17. }  
void RTPInterface
::startNetworkReading(TaskScheduler::BackgroundHandlerProc* handlerProc) {
  // Normal case: Arrange to read UDP packets:
  envir().taskScheduler().
    turnOnBackgroundReadHandling(fGS->socketNum(), handlerProc, fOwner);

  // Also, receive RTP over TCP, on each of our TCP connections:
  fReadHandlerProc = handlerProc;
  for (tcpStreamRecord* streams = fTCPStreams; streams != NULL;
       streams = streams->fNext) {
    // Get a socket descriptor for "streams->fStreamSocketNum":
    SocketDescriptor* socketDescriptor = lookupSocketDescriptor(envir(), streams->fStreamSocketNum);

    // Tell it about our subChannel:
    socketDescriptor->registerRTPInterface(streams->fStreamChannelId, this);
  }
}

第一句代码表示默认是通过udp来发送rtcp的包,如果rtp是tcp的就通过下面的代码处理。

这里的turnOnBackgroundReadHanding就是调用setBackgroundHandling(socketNum, SOCKET_READABLE, handlerProc, clientData);在前面分析过就是将socket加入到select set集中进行监视并传入handlerProc。这里不做重复讨论,接着看下面的注释是send our first report,接着调用了onExpire(this),来看看

  1. void RTCPInstance::onExpire(RTCPInstance* instance) {  
  2.   instance->onExpire1();  
  3. }  
void RTCPInstance::onExpire(RTCPInstance* instance) {
  instance->onExpire1();
}

  1. void RTCPInstance::onExpire1() {  
  2.   // Note: fTotSessionBW is kbits per second   
  3.   double rtcpBW = 0.05*fTotSessionBW*1024/8; // -> bytes per second   
  4.   
  5.   OnExpire(this// event   
  6.        numMembers(), // members   
  7.        (fSink != NULL) ? 1 : 0, // senders   
  8.        rtcpBW, // rtcp_bw   
  9.        (fSink != NULL) ? 1 : 0, // we_sent   
  10.        &fAveRTCPSize, // ave_rtcp_size   
  11.        &fIsInitial, // initial   
  12.        dTimeNow(), // tc   
  13.        &fPrevReportTime, // tp   
  14.        &fPrevNumMembers // pmembers   
  15.        );  
  16. }  
void RTCPInstance::onExpire1() {
  // Note: fTotSessionBW is kbits per second
  double rtcpBW = 0.05*fTotSessionBW*1024/8; // -> bytes per second

  OnExpire(this, // event
	   numMembers(), // members
	   (fSink != NULL) ? 1 : 0, // senders
	   rtcpBW, // rtcp_bw
	   (fSink != NULL) ? 1 : 0, // we_sent
	   &fAveRTCPSize, // ave_rtcp_size
	   &fIsInitial, // initial
	   dTimeNow(), // tc
	   &fPrevReportTime, // tp
	   &fPrevNumMembers // pmembers
	   );
}

再来看看这个OnExpire

  1. void OnExpire(event e,  
  2.                  int    members,  
  3.                  int    senders,  
  4.                  double rtcp_bw,  
  5.                  int    we_sent,  
  6.                  double *avg_rtcp_size,  
  7.                  int    *initial,  
  8.                  time_tp   tc,  
  9.                  time_tp   *tp,  
  10.                  int    *pmembers)  
  11.    {  
  12.        /* This function is responsible for deciding whether to send 
  13.         * an RTCP report or BYE packet now, or to reschedule transmission. 
  14.         * It is also responsible for updating the pmembers, initial, tp, 
  15.         * and avg_rtcp_size state variables. This function should be called 
  16.         * upon expiration of the event timer used by Schedule(). */  
  17.   
  18.        double t;     /* Interval */  
  19.        double tn;    /* Next transmit time */  
  20.   
  21.        /* In the case of a BYE, we use "unconditional reconsideration" to 
  22.         * reschedule the transmission of the BYE if necessary */  
  23.   
  24.        if (TypeOfEvent(e) == EVENT_BYE) {  
  25.            t = rtcp_interval(members,  
  26.                              senders,  
  27.                              rtcp_bw,  
  28.                              we_sent,  
  29.                              *avg_rtcp_size,  
  30.                              *initial);  
  31.            tn = *tp + t;  
  32.            if (tn <= tc) {  
  33.                SendBYEPacket(e);  
  34.                exit(1);  
  35.            } else {  
  36.                Schedule(tn, e);  
  37.            }  
  38.   
  39.        } else if (TypeOfEvent(e) == EVENT_REPORT) {  
  40.            t = rtcp_interval(members,  
  41.                              senders,  
  42.                              rtcp_bw,  
  43.                              we_sent,  
  44.                              *avg_rtcp_size,  
  45.                              *initial);  
  46.            tn = *tp + t;  
  47.   
  48.            if (tn <= tc) {  
  49.                SendRTCPReport(e);  
  50.                *avg_rtcp_size = (1./16.)*SentPacketSize(e) +  
  51.                    (15./16.)*(*avg_rtcp_size);  
  52.                *tp = tc;  
  53.   
  54.                /* We must redraw the interval. Don't reuse the 
  55.                   one computed above, since its not actually 
  56.                   distributed the same, as we are conditioned 
  57.                   on it being small enough to cause a packet to 
  58.                   be sent */  
  59.   
  60.                t = rtcp_interval(members,  
  61.                                  senders,  
  62.                                  rtcp_bw,  
  63.                                  we_sent,  
  64.                                  *avg_rtcp_size,  
  65.                                  *initial);  
  66.   
  67.                Schedule(t+tc,e);  
  68.                *initial = 0;  
  69.            } else {  
  70.                Schedule(tn, e);  
  71.            }  
  72.            *pmembers = members;  
  73.        }  
  74.    }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值