⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtcp.cpp

📁 流媒体传输协议的实现代码,非常有用.可以支持rtsp mms等流媒体传输协议
💻 CPP
📖 第 1 页 / 共 2 页
字号:
      }    }          if (!packetOK) {#ifdef DEBUG      fprintf(stderr, "rejected bad RTCP subpacket: header 0x%08x\n", rtcpHdr);#endif      break;    } else {#ifdef DEBUG      fprintf(stderr, "validated entire RTCP packet\n");#endif    }          onReceive(typeOfPacket, totPacketSize, reportSenderSSRC);  } while (0);}void RTCPInstance::onReceive(int typeOfPacket, int totPacketSize,			     unsigned ssrc) {  fTypeOfPacket = typeOfPacket;  fLastReceivedSize = totPacketSize;  fLastReceivedSSRC = ssrc;  int members = (int)numMembers();  int senders = (fSink != NULL) ? 1 : 0;  OnReceive(this, // p	    this, // e	    &members, // members	    &fPrevNumMembers, // pmembers	    &senders, // senders	    &fAveRTCPSize, // avg_rtcp_size	    &fPrevReportTime, // tp	    dTimeNow(), // tc	    fNextReportTime);}void RTCPInstance::sendReport() {#ifdef DEBUG  fprintf(stderr, "sending REPORT\n");#endif  // Begin by including a SR and/or RR report:  addReport();  // Then, include a SDES:  addSDES();  // Send the report:  sendBuiltPacket();  // Periodically clean out old members from our SSRC membership database:  const unsigned membershipReapPeriod = 5;  if ((++fOutgoingReportCount) % membershipReapPeriod == 0) {    unsigned threshold = fOutgoingReportCount - membershipReapPeriod;    fKnownMembers->reapOldMembers(threshold);  }}void RTCPInstance::sendBYE() {#ifdef DEBUG  fprintf(stderr, "sending BYE\n");#endif  // The packet must begin with a SR and/or RR report:  addReport();  addBYE();  sendBuiltPacket();}void RTCPInstance::sendBuiltPacket() {#ifdef DEBUG  fprintf(stderr, "sending RTCP packet\n");  unsigned char* p = fOutBuf->packet();  for (unsigned i = 0; i < fOutBuf->curPacketSize(); ++i) {    if (i%4 == 0) fprintf(stderr," ");    fprintf(stderr, "%02x", p[i]);  }  fprintf(stderr, "\n");#endif  unsigned reportSize = fOutBuf->curPacketSize();  fRTCPInterface.sendPacket(fOutBuf->packet(), reportSize);  fOutBuf->resetOffset();  fLastSentSize = IP_UDP_HDR_SIZE + reportSize;  fHaveJustSentPacket = True;  fLastPacketSentSize = reportSize;}int RTCPInstance::checkNewSSRC() {  return fKnownMembers->noteMembership(fLastReceivedSSRC,				       fOutgoingReportCount);}void RTCPInstance::removeLastReceivedSSRC() {  removeSSRC(fLastReceivedSSRC);}void RTCPInstance::removeSSRC(u_int32_t ssrc) {  fKnownMembers->remove(ssrc);  // Also, remove records of this SSRC from any reception or transmission stats  if (fSource != NULL) fSource->receptionStatsDB().removeRecord(ssrc);  if (fSink != NULL) fSink->transmissionStatsDB().removeRecord(ssrc);}void RTCPInstance::onExpire(RTCPInstance* instance) {  instance->onExpire1();}// Member functions to build specific kinds of report:void RTCPInstance::addReport() {  // Include a SR or a RR, depending on whether we  // have an associated sink or source:  if (fSink != NULL) {    addSR();  } else if (fSource != NULL) {    addRR();  }}void RTCPInstance::addSR() {  // ASSERT: fSink != NULL  enqueueCommonReportPrefix(RTCP_PT_SR, fSink->SSRC(),			    5 /* extra words in a SR */);  // Now, add the 'sender info' for our sink  // Insert the NTP and RTP timestamps for the 'wallclock time':  struct timeval timeNow;  gettimeofday(&timeNow, NULL);  fOutBuf->enqueueWord(timeNow.tv_sec + 0x83AA7E80);      // NTP timestamp most-significant word (1970 epoch -> 1900 epoch)  double fractionalPart = (timeNow.tv_usec/15625.0)*0x04000000; // 2^32/10^6  fOutBuf->enqueueWord((unsigned)(fractionalPart+0.5));      // NTP timestamp least-significant word  unsigned rtpTimestamp = fSink->convertToRTPTimestamp(timeNow);  fOutBuf->enqueueWord(rtpTimestamp); // RTP ts  // Insert the packet and byte counts:  fOutBuf->enqueueWord(fSink->packetCount());  fOutBuf->enqueueWord(fSink->octetCount());  enqueueCommonReportSuffix();}void RTCPInstance::addRR() {  // ASSERT: fSource != NULL  enqueueCommonReportPrefix(RTCP_PT_RR, fSource->SSRC());  enqueueCommonReportSuffix();}void RTCPInstance::enqueueCommonReportPrefix(unsigned char packetType,					     unsigned SSRC,					     unsigned numExtraWords) {  unsigned numReportingSources;  if (fSource == NULL) {    numReportingSources = 0; // we don't receive anything  } else {    RTPReceptionStatsDB& allReceptionStats      = fSource->receptionStatsDB();    numReportingSources = allReceptionStats.numActiveSourcesSinceLastReset();    // This must be <32, to fit in 5 bits:    if (numReportingSources >= 32) { numReportingSources = 32; }    // Later: support adding more reports to handle >32 sources (unlikely)#####  }  unsigned rtcpHdr = 0x80000000; // version 2, no padding  rtcpHdr |= (numReportingSources<<24);  rtcpHdr |= (packetType<<16);  rtcpHdr |= (1 + numExtraWords + 6*numReportingSources);      // each report block is 6 32-bit words long  fOutBuf->enqueueWord(rtcpHdr);  fOutBuf->enqueueWord(SSRC);}void RTCPInstance::enqueueCommonReportSuffix() {  // Output the report blocks for each source:  if (fSource != NULL) {     RTPReceptionStatsDB& allReceptionStats      = fSource->receptionStatsDB();    RTPReceptionStatsDB::Iterator iterator(allReceptionStats);    while (1) {      RTPReceptionStats* receptionStats = iterator.next();      if (receptionStats == NULL) break;      enqueueReportBlock(receptionStats);    }    allReceptionStats.reset(); // because we have just generated a report  }}voidRTCPInstance::enqueueReportBlock(RTPReceptionStats* stats) {  fOutBuf->enqueueWord(stats->SSRC());  unsigned highestExtSeqNumReceived = stats->highestExtSeqNumReceived();  unsigned totNumExpected    = highestExtSeqNumReceived - stats->baseExtSeqNumReceived();  int totNumLost = totNumExpected - stats->totNumPacketsReceived();  // 'Clamp' this loss number to a 24-bit signed value:  if (totNumLost > 0x007FFFFF) {    totNumLost = 0x007FFFFF;  } else if (totNumLost < 0) {    if (totNumLost < -0x00800000) totNumLost = 0x00800000; // unlikely, but...    totNumLost &= 0x00FFFFFF;  }  unsigned numExpectedSinceLastReset    = highestExtSeqNumReceived - stats->lastResetExtSeqNumReceived();  int numLostSinceLastReset    = numExpectedSinceLastReset - stats->numPacketsReceivedSinceLastReset();   unsigned char lossFraction;  if (numExpectedSinceLastReset == 0 || numLostSinceLastReset < 0) {    lossFraction = 0;  } else {    lossFraction = (unsigned char)      ((numLostSinceLastReset << 8) / numExpectedSinceLastReset);  }    fOutBuf->enqueueWord((lossFraction<<24) | totNumLost);  fOutBuf->enqueueWord(highestExtSeqNumReceived);  fOutBuf->enqueueWord(stats->jitter());  unsigned NTPmsw = stats->lastReceivedSR_NTPmsw();  unsigned NTPlsw = stats->lastReceivedSR_NTPlsw();  unsigned LSR = ((NTPmsw&0xFFFF)<<16)|(NTPlsw>>16); // middle 32 bits  fOutBuf->enqueueWord(LSR);  // Figure out how long has elapsed since the last SR rcvd from this src:  struct timeval const& LSRtime = stats->lastReceivedSR_time(); // "last SR"  struct timeval timeNow, timeSinceLSR;  gettimeofday(&timeNow, NULL);  if (timeNow.tv_usec < LSRtime.tv_usec) {    timeNow.tv_usec += 1000000;    timeNow.tv_sec -= 1;  }  timeSinceLSR.tv_sec = timeNow.tv_sec - LSRtime.tv_sec;  timeSinceLSR.tv_usec = timeNow.tv_usec - LSRtime.tv_usec;  // The enqueued time is in units of 1/65536 seconds.  // (Note that 65536/1000000 == 1024/15625)   unsigned DLSR;  if (LSR == 0) {    DLSR = 0;  } else {    DLSR = (timeSinceLSR.tv_sec<<16)         | ( (((timeSinceLSR.tv_usec<<11)+15625)/31250) & 0xFFFF);  }  fOutBuf->enqueueWord(DLSR);}void RTCPInstance::addSDES() {  // For now we support only the CNAME item; later support more #####  // Begin by figuring out the size of the entire SDES report:  unsigned numBytes = 4;      // counts the SSRC, but not the header; it'll get subtracted out  numBytes += fCNAME.totalSize(); // includes id and length  numBytes += 1; // the special END item  unsigned num4ByteWords = (numBytes + 3)/4;  unsigned rtcpHdr = 0x81000000; // version 2, no padding, 1 SSRC chunk  rtcpHdr |= (RTCP_PT_SDES<<16);  rtcpHdr |= num4ByteWords;  fOutBuf->enqueueWord(rtcpHdr);  if (fSource != NULL) {    fOutBuf->enqueueWord(fSource->SSRC());  } else if (fSink != NULL) {    fOutBuf->enqueueWord(fSink->SSRC());  }  // Add the CNAME:  fOutBuf->enqueue(fCNAME.data(), fCNAME.totalSize());  // Add the 'END' item (i.e., a zero byte), plus any more needed to pad:  unsigned numPaddingBytesNeeded = 4 - (fOutBuf->curPacketSize() % 4);  unsigned char const zero = '\0';  while (numPaddingBytesNeeded-- > 0) fOutBuf->enqueue(&zero, 1);}void RTCPInstance::addBYE() {  unsigned rtcpHdr = 0x81000000; // version 2, no padding, 1 SSRC  rtcpHdr |= (RTCP_PT_BYE<<16);  rtcpHdr |= 1; // 2 32-bit words total (i.e., with 1 SSRC)  fOutBuf->enqueueWord(rtcpHdr);  if (fSource != NULL) {    fOutBuf->enqueueWord(fSource->SSRC());  } else if (fSink != NULL) {    fOutBuf->enqueueWord(fSink->SSRC());  }}void RTCPInstance::schedule(double nextTime) {  fNextReportTime = nextTime;  double secondsToDelay = nextTime - dTimeNow();#ifdef DEBUG  fprintf(stderr, "schedule(%f->%f)\n", secondsToDelay, nextTime);#endif  int usToGo = (int)(secondsToDelay * 1000000);  nextTask() = envir().taskScheduler().scheduleDelayedTask(usToGo,				(TaskFunc*)RTCPInstance::onExpire, this);}void RTCPInstance::reschedule(double nextTime) {  envir().taskScheduler().unscheduleDelayedTask(nextTask());  schedule(nextTime);}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	   );}////////// SDESItem //////////SDESItem::SDESItem(unsigned char tag, unsigned char const* value) {  unsigned length = strlen((char const*)value);  if (length > 511) length = 511;  fData[0] = tag;  fData[1] = (unsigned char)length;  memmove(&fData[2], value, length);  // Pad the trailing bytes to a 4-byte boundary:  while ((length)%4 > 0) fData[2 + length++] = '\0';}unsigned SDESItem::totalSize() const {  return 2 + (unsigned)fData[1];}////////// Implementation of routines imported by the "rtcp_from_spec" C codeextern "C" void Schedule(double nextTime, event e) {  RTCPInstance* instance = (RTCPInstance*)e;  if (instance == NULL) return;  instance->schedule(nextTime);}extern "C" void Reschedule(double nextTime, event e) {  RTCPInstance* instance = (RTCPInstance*)e;  if (instance == NULL) return;  instance->reschedule(nextTime);}extern "C" void SendRTCPReport(event e) {  RTCPInstance* instance = (RTCPInstance*)e;  if (instance == NULL) return;  instance->sendReport();}extern "C" void SendBYEPacket(event e) {  RTCPInstance* instance = (RTCPInstance*)e;  if (instance == NULL) return;  instance->sendBYE();}extern "C" int TypeOfEvent(event e) {  RTCPInstance* instance = (RTCPInstance*)e;  if (instance == NULL) return EVENT_UNKNOWN;  return instance->typeOfEvent();}extern "C" int SentPacketSize(event e) {  RTCPInstance* instance = (RTCPInstance*)e;  if (instance == NULL) return 0;  return instance->sentPacketSize();}extern "C" int PacketType(packet p) {  RTCPInstance* instance = (RTCPInstance*)p;  if (instance == NULL) return PACKET_UNKNOWN_TYPE;  return instance->packetType();}extern "C" int ReceivedPacketSize(packet p) {  RTCPInstance* instance = (RTCPInstance*)p;  if (instance == NULL) return 0;  return instance->receivedPacketSize();}extern "C" int NewMember(packet p) {  RTCPInstance* instance = (RTCPInstance*)p;  if (instance == NULL) return 0;  return instance->checkNewSSRC();}extern "C" int NewSender(packet /*p*/) {  return 0; // we don't yet recognize senders other than ourselves #####}extern "C" void AddMember(packet /*p*/) {  // Do nothing; all of the real work was done when NewMember() was called}extern "C" void AddSender(packet /*p*/) {  // we don't yet recognize senders other than ourselves #####}extern "C" void RemoveMember(packet p) {  RTCPInstance* instance = (RTCPInstance*)p;  if (instance == NULL) return;  instance->removeLastReceivedSSRC();}extern "C" void RemoveSender(packet /*p*/) {  // we don't yet recognize senders other than ourselves #####}extern "C" double drand30() {  unsigned tmp = our_random()&0x3FFFFFFF; // a random 30-bit integer  return tmp/(double)(1024*1024*1024);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -