예제 #1
0
int MediaStream::sendPLI() {
  RtcpHeader thePLI;
  thePLI.setPacketType(RTCP_PS_Feedback_PT);
  thePLI.setBlockCount(1);
  thePLI.setSSRC(this->getVideoSinkSSRC());
  thePLI.setSourceSSRC(this->getVideoSourceSSRC());
  thePLI.setLength(2);
  char *buf = reinterpret_cast<char*>(&thePLI);
  int len = (thePLI.getLength() + 1) * 4;
  sendPacketAsync(std::make_shared<DataPacket>(0, buf, len, VIDEO_PACKET));
  return len;
}
예제 #2
0
 int WebRtcConnection::sendPLI() {
   RtcpHeader thePLI;
   thePLI.setPacketType(RTCP_PS_Feedback_PT);
   thePLI.setBlockCount(1);
   thePLI.setSSRC(this->getVideoSinkSSRC());
   thePLI.setSourceSSRC(this->getVideoSourceSSRC());
   thePLI.setLength(2);
   char *buf = reinterpret_cast<char*>(&thePLI);
   int len = (thePLI.getLength()+1)*4;
   this->queueData(0, buf, len , videoTransport_, OTHER_PACKET);
   return len; 
   
 }
예제 #3
0
int ExternalOutput::sendFirPacket() {
    if (fbSink_ != NULL) {
      RtcpHeader thePLI;
      thePLI.setPacketType(RTCP_PS_Feedback_PT);
      thePLI.setBlockCount(1);
      thePLI.setSSRC(55543);
      thePLI.setSourceSSRC(videoSourceSsrc_);
      thePLI.setLength(2);
      char *buf = reinterpret_cast<char*>(&thePLI);
      int len = (thePLI.getLength() + 1) * 4;
      fbSink_->deliverFeedback(reinterpret_cast<char*>(buf), len);
      return len;
    }
    return -1;
}
예제 #4
0
  int RtcpForwarder::addNACK(char* buf, int len, uint16_t seqNum, uint16_t blp, uint32_t sourceSsrc, uint32_t sinkSsrc){
    buf+=len;
    ELOG_DEBUG("Setting PID %u, BLP %u", seqNum , blp);
    RtcpHeader theNACK;
    theNACK.setPacketType(RTCP_RTP_Feedback_PT);
    theNACK.setBlockCount(1);
    theNACK.setNackPid(seqNum);
    theNACK.setNackBlp(blp);
    theNACK.setSSRC(sinkSsrc);    
    theNACK.setSourceSSRC(sourceSsrc);
    theNACK.setLength(3);
    int nackLength = (theNACK.getLength()+1)*4;

    memcpy(buf, (uint8_t*)&theNACK, nackLength);
    return (len+nackLength); 
  }
예제 #5
0
int ExternalOutput::sendFirPacket() {
    if (fb_sink_ != nullptr) {
      RtcpHeader thePLI;
      thePLI.setPacketType(RTCP_PS_Feedback_PT);
      thePLI.setBlockCount(1);
      thePLI.setSSRC(55543);
      thePLI.setSourceSSRC(videoSourceSsrc_);
      thePLI.setLength(2);
      char *buf = reinterpret_cast<char*>(&thePLI);
      int len = (thePLI.getLength() + 1) * 4;
      std::shared_ptr<dataPacket> pli_packet = std::make_shared<dataPacket>(0, buf, len, VIDEO_PACKET);
      fb_sink_->deliverFeedback(pli_packet);
      return len;
    }
    return -1;
}
예제 #6
0
  int RtcpForwarder::addREMB(char* buf, int len, uint32_t bitrate){
    buf+=len;
    RtcpHeader theREMB;
    theREMB.setPacketType(RTCP_PS_Feedback_PT);
    theREMB.setBlockCount(RTCP_AFB);
    memcpy(&theREMB.report.rembPacket.uniqueid, "REMB", 4);

    theREMB.setSSRC(rtcpSink_->getVideoSinkSSRC());
    theREMB.setSourceSSRC(rtcpSource_->getVideoSourceSSRC());
    theREMB.setLength(5);
    theREMB.setREMBBitRate(bitrate);
    theREMB.setREMBNumSSRC(1);
    theREMB.setREMBFeedSSRC(rtcpSource_->getVideoSourceSSRC());
    int rembLength = (theREMB.getLength()+1)*4;

    memcpy(buf, (uint8_t*)&theREMB, rembLength);
    return (len+rembLength); 
  }
예제 #7
0
  int RtcpForwarder::analyzeFeedback(char *buf, int len) {
    RtcpHeader *chead = reinterpret_cast<RtcpHeader*>(buf);
    if (chead->isFeedback()) {      
      uint32_t sourceSsrc = chead->getSourceSSRC();
      // We try to add it just in case it is not there yet (otherwise its noop)
      this->addSourceSsrc(sourceSsrc);

      struct timeval now;
      gettimeofday(&now, NULL);
      char* movingBuf = buf;
      int rtcpLength = 0;
      int totalLength = 0;
      int currentBlock = 0;

      do {
        movingBuf+=rtcpLength;
        chead = reinterpret_cast<RtcpHeader*>(movingBuf);
        rtcpLength = (ntohs(chead->length)+1) * 4;
        totalLength += rtcpLength;
        switch(chead->packettype){
          case RTCP_SDES_PT:
            ELOG_DEBUG("SDES");
            break;
          case RTCP_BYE:
            ELOG_DEBUG("BYE");
            break;
          case RTCP_Receiver_PT:
            if (chead->getSourceSSRC() == rtcpSource_->getVideoSourceSSRC()){
              ELOG_DEBUG("Analyzing Video RR: PacketLost %u, Ratio %u, currentBlock %d, blocks %d, sourceSSRC %u, ssrc %u changed to %u", 
                  chead->getLostPackets(), 
                  chead->getFractionLost(), 
                  currentBlock, 
                  chead->getBlockCount(), 
                  chead->getSourceSSRC(), 
                  chead->getSSRC(),
                  rtcpSink_->getVideoSinkSSRC());
              chead->setSSRC(rtcpSink_->getVideoSinkSSRC());
            }else{
              ELOG_DEBUG("Analyzing Audio RR: PacketLost %u, Ratio %u, currentBlock %d, blocks %d, sourceSSRC %u, ssrc %u changed to %u", 
                  chead->getLostPackets(), 
                  chead->getFractionLost(), 
                  currentBlock, 
                  chead->getBlockCount(), 
                  chead->getSourceSSRC(), 
                  chead->getSSRC(),
                  rtcpSink_->getAudioSinkSSRC());
              chead->setSSRC(rtcpSink_->getAudioSinkSSRC());
            }
            break;
          case RTCP_RTP_Feedback_PT:
            ELOG_DEBUG("RTP FB: Usually NACKs: %u, currentBlock %d", chead->getBlockCount(), currentBlock);
            ELOG_DEBUG("NACK PID %u BLP %u", chead->getNackPid(), chead->getNackBlp());
            // We analyze NACK to avoid sending repeated NACKs
            break;
          case RTCP_PS_Feedback_PT:
            //            ELOG_DEBUG("RTCP PS FB TYPE: %u", chead->getBlockCount() );
            switch(chead->getBlockCount()){
              case RTCP_PLI_FMT:
                ELOG_DEBUG("PLI Message, currentBlock %d", currentBlock);
                // 1: PLI, 4: FIR
                break;
              case RTCP_SLI_FMT:
                ELOG_WARN("SLI Message");
                break;
              case RTCP_FIR_FMT:
                ELOG_WARN("FIR Message");
                break;
              case RTCP_AFB:
                {
                  char *uniqueId = (char*)&chead->report.rembPacket.uniqueid;
                  if (!strncmp(uniqueId,"REMB", 4)){
                    uint64_t bitrate = chead->getBrMantis() << chead->getBrExp();
                    uint64_t cappedBitrate = 0;
                    cappedBitrate = bitrate < maxVideoBw_? bitrate: maxVideoBw_;
                    if (bitrate < maxVideoBw_){
                      cappedBitrate = bitrate;
                    }else{
                      cappedBitrate = maxVideoBw_;
                    }
                    ELOG_DEBUG("Received REMB %lu, partnum %u, cappedBitrate %lu", bitrate, currentBlock, cappedBitrate);
                    chead->setREMBBitRate(cappedBitrate);
                  }
                  else{
                    ELOG_WARN("Unsupported AFB Packet not REMB")
                  }
                  break;
                }
              default:
                ELOG_WARN("Unsupported RTCP_PS FB TYPE %u",chead->getBlockCount());
                break;
            }
            break;
          default:
            ELOG_WARN("Unknown RTCP Packet, %d", chead->packettype);
            break;
        }
        currentBlock++;
      } while (totalLength < len);
      return len;
    }
예제 #8
0
void RtcpAggregator::checkRtcpFb() {
  boost::mutex::scoped_lock mlock(mapLock_);
  std::map<uint32_t, boost::shared_ptr<RtcpData>>::iterator it;
  for (it = rtcpData_.begin(); it != rtcpData_.end(); it++) {
    boost::shared_ptr<RtcpData> rtcpData = it->second;
    boost::mutex::scoped_lock lock(rtcpData->dataLock);
    uint32_t sourceSsrc = it->first;
    uint32_t sinkSsrc;
    uint64_t now = ClockUtils::timePointToMs(clock::now());

    unsigned int dt = now - rtcpData->last_rr_sent;
    unsigned int edlsr = now - rtcpData->last_sr_updated;
    unsigned int dt_scheduled = now - rtcpData->last_rr_was_scheduled;

    // Generate Full RTCP Packet
    if ((rtcpData->requestRr || dt >= rtcpData->nextPacketInMs ||rtcpData->shouldSendREMB) && rtcpData->lastSr > 0) {
      rtcpData->requestRr = false;
      RtcpHeader rtcpHead;
      rtcpHead.setPacketType(RTCP_Receiver_PT);
      if (sourceSsrc == rtcpSource_->getAudioSourceSSRC()) {
        sinkSsrc = rtcpSink_->getAudioSinkSSRC();
        ELOG_DEBUG("Sending Audio RR: PacketLost %u, Ratio %u, DLSR %u"
                   ", lastSR %u, DLSR Adjusted %u dt %u, rrsSinceLast %u highestSeqNum %u",
                  rtcpData->totalPacketsLost,
                  rtcpData->ratioLost,
                  rtcpData->delaySinceLastSr,
                  rtcpData->lastSr,
                  (rtcpData->delaySinceLastSr+edlsr),
                  dt,
                  rtcpData->rrsReceivedInPeriod,
                  rtcpData->highestSeqNumReceived);
        rtcpHead.setSSRC(rtcpSink_->getAudioSinkSSRC());
        rtcpHead.setSourceSSRC(rtcpSource_->getAudioSourceSSRC());
      } else {
        sinkSsrc = rtcpSink_->getVideoSinkSSRC();
        ELOG_DEBUG("Sending Video RR: SOurcessrc %u sinkSsrc %u PacketLost %u, Ratio %u, DLSR %u, lastSR %u"
                   ", DLSR Adjusted %u dt %u, rrsSinceLast %u highestSeqNum %u jitter %u",
                   sourceSsrc,
                   rtcpSink_->getVideoSinkSSRC(),
                   rtcpData->totalPacketsLost,
                   rtcpData->ratioLost,
                   rtcpData->delaySinceLastSr,
                   rtcpData->lastSr,
                   (rtcpData->delaySinceLastSr+edlsr),
                   dt, rtcpData->rrsReceivedInPeriod,
                   rtcpData->highestSeqNumReceived,
                   rtcpData->jitter);
        rtcpHead.setSSRC(rtcpSink_->getVideoSinkSSRC());
        rtcpHead.setSourceSSRC(rtcpSource_->getVideoSourceSSRC());
      }

      // rtcpHead.setFractionLost(rtcpData->ratioLost);
      // Calculate ratioLost
      uint32_t packetsReceivedinInterval = rtcpData->extendedSeqNo - rtcpData->prevExtendedSeqNo;
      uint32_t packetsLostInInterval = rtcpData->totalPacketsLost - rtcpData->prevTotalPacketsLost;
      double ratio = static_cast<double>(packetsLostInInterval/packetsReceivedinInterval);
      rtcpHead.setFractionLost(ratio*256);
      rtcpData->prevTotalPacketsLost = rtcpData->totalPacketsLost;
      rtcpData->prevExtendedSeqNo = rtcpData->extendedSeqNo;

      rtcpHead.setHighestSeqnum(rtcpData->highestSeqNumReceived);
      rtcpHead.setSeqnumCycles(rtcpData->seqNumCycles);
      rtcpHead.setLostPackets(rtcpData->totalPacketsLost);
      rtcpHead.setJitter(rtcpData->jitter);
      rtcpHead.setLastSr(rtcpData->lastSr);
      rtcpHead.setDelaySinceLastSr(rtcpData->delaySinceLastSr + ((edlsr*65536)/1000));
      rtcpHead.setLength(7);
      rtcpHead.setBlockCount(1);
      int length = (rtcpHead.getLength()+1)*4;
      memcpy(packet_, reinterpret_cast<uint8_t*>(&rtcpHead), length);
      if (rtcpData->shouldSendNACK) {
        ELOG_DEBUG("SEND NACK, SENDING with Seqno: %u", rtcpData->nackSeqnum);
        int theLen = this->addNACK(reinterpret_cast<char*>(packet_), length, rtcpData->nackSeqnum,
                        rtcpData->nackBlp, sourceSsrc, sinkSsrc);
        rtcpData->shouldSendNACK = false;
        rtcpData->nackSeqnum = 0;
        rtcpData->nackBlp = 0;
        length = theLen;
      }
      if (rtcpData->mediaType == VIDEO_TYPE) {
        unsigned int sincelastREMB = now - rtcpData->last_remb_sent;
        if (sincelastREMB > REMB_TIMEOUT) {
          // We dont have any more RRs, we follow what the publisher is doing to avoid congestion
          rtcpData->shouldSendREMB = true;
        }

        if (rtcpData->shouldSendREMB) {
          ELOG_DEBUG("Sending REMB, since last %u ms, sending with BW: %lu",
                      sincelastREMB, rtcpData->reportedBandwidth);
          int theLen = this->addREMB(reinterpret_cast<char*>(packet_), length, rtcpData->reportedBandwidth);
          rtcpData->shouldSendREMB = false;
          rtcpData->last_remb_sent = now;
          length = theLen;
        }
      }
      if  (rtcpSource_->isVideoSourceSSRC(sourceSsrc)) {
        rtcpSink_->deliverVideoData(std::make_shared<DataPacket>(0, reinterpret_cast<char*>(packet_),
              length, VIDEO_PACKET));
      } else {
        rtcpSink_->deliverAudioData(std::make_shared<DataPacket>(0, reinterpret_cast<char*>(packet_),
              length, AUDIO_PACKET));
      }
      rtcpData->last_rr_sent = now;
      if (dt_scheduled > rtcpData->nextPacketInMs) {  // Every scheduled packet we reset
        rtcpData->shouldReset = true;
      }
      rtcpData->last_rr_was_scheduled = now;
      // schedule next packet
      std::string thread_id = boost::lexical_cast<std::string>(boost::this_thread::get_id());
      unsigned int thread_number = 0;
      sscanf(thread_id.c_str(), "%x", &thread_number);

      float random = (rand_r(&thread_number) % 100 + 50) / 100.0;
      if (rtcpData->mediaType == AUDIO_TYPE) {
        rtcpData->nextPacketInMs = RTCP_AUDIO_INTERVAL*random;
        ELOG_DEBUG("Scheduled next Audio RR in %u ms", rtcpData->nextPacketInMs);
      } else {
        rtcpData->nextPacketInMs = (RTCP_VIDEO_INTERVAL)*random;
        ELOG_DEBUG("Scheduled next Video RR in %u ms", rtcpData->nextPacketInMs);
      }

      if (rtcpData->shouldReset) {
        this->resetData(rtcpData, this->defaultVideoBw_);
      }
    }
    if (rtcpData->shouldSendPli) {
      rtcpSource_->sendPLI();
      rtcpData->shouldSendPli = false;
    }
  }
}