Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1852829
  • 博文数量: 274
  • 博客积分: 2366
  • 博客等级: 大尉
  • 技术积分: 1880
  • 用 户 组: 普通用户
  • 注册时间: 2007-04-22 09:37
文章分类

全部博文(274)

文章存档

2022年(1)

2020年(10)

2019年(7)

2018年(18)

2017年(26)

2016年(32)

2015年(43)

2014年(30)

2013年(44)

2012年(36)

2011年(17)

2010年(10)

分类: LINUX

2016-09-28 15:10:32


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


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




    [cpp] view plain copy
    if (isSSM()) {  
          fRTCPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, rtcpPortNum);  
        } else {  
          fRTCPSocket = new Groupsock(env(), tempAddr, rtcpPortNum, 255);  
        }  


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


    [cpp] view plain copy
    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会自动开始运行,如何运行的呢,我们再来看看。


    [cpp] view plain copy
    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);  
    }  


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


    [cpp] view plain copy
    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。


    [cpp] view plain copy
    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),来看看




    [cpp] view plain copy
    void RTCPInstance::onExpire(RTCPInstance* instance) {  
      instance->onExpire1();  
    }  


    [cpp] view plain copy
    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


    [cpp] view plain copy
    void OnExpire(event e,  
                     int    members,  
                     int    senders,  
                     double rtcp_bw,  
                     int    we_sent,  
                     double *avg_rtcp_size,  
                     int    *initial,  
                     time_tp   tc,  
                     time_tp   *tp,  
                     int    *pmembers)  
       {  
           /* This function is responsible for deciding whether to send 
            * an RTCP report or BYE packet now, or to reschedule transmission. 
            * It is also responsible for updating the pmembers, initial, tp, 
            * and avg_rtcp_size state variables. This function should be called 
            * upon expiration of the event timer used by Schedule(). */  
      
           double t;     /* Interval */  
           double tn;    /* Next transmit time */  
      
           /* In the case of a BYE, we use "unconditional reconsideration" to 
            * reschedule the transmission of the BYE if necessary */  
      
           if (TypeOfEvent(e) == EVENT_BYE) {  
               t = rtcp_interval(members,  
                                 senders,  
                                 rtcp_bw,  
                                 we_sent,  
                                 *avg_rtcp_size,  
                                 *initial);  
               tn = *tp + t;  
               if (tn <= tc) {  
                   SendBYEPacket(e);  
                   exit(1);  
               } else {  
                   Schedule(tn, e);  
               }  
      
           } else if (TypeOfEvent(e) == EVENT_REPORT) {  
               t = rtcp_interval(members,  
                                 senders,  
                                 rtcp_bw,  
                                 we_sent,  
                                 *avg_rtcp_size,  
                                 *initial);  
               tn = *tp + t;  
      
               if (tn <= tc) {  
                   SendRTCPReport(e);  
                   *avg_rtcp_size = (1./16.)*SentPacketSize(e) +  
                       (15./16.)*(*avg_rtcp_size);  
                   *tp = tc;  
      
                   /* We must redraw the interval. Don't reuse the 
                      one computed above, since its not actually 
                      distributed the same, as we are conditioned 
                      on it being small enough to cause a packet to 
                      be sent */  
      
                   t = rtcp_interval(members,  
                                     senders,  
                                     rtcp_bw,  
                                     we_sent,  
                                     *avg_rtcp_size,  
                                     *initial);  
      
                   Schedule(t+tc,e);  
                   *initial = 0;  
               } else {  
                   Schedule(tn, e);  
               }  
               *pmembers = members;  
           }  
       }  






     

  • 阅读(2142) | 评论(0) | 转发(0) |
    给主人留下些什么吧!~~