text: /**********
  This library is free software; you can redistribute it and/or modify it under
  the terms of the GNU Lesser General Public License as published by the
  Free Software Foundation; either version 3 of the License, or (at your
  option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
  
  This library is distributed in the hope that it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
  more details.
  
  You should have received a copy of the GNU Lesser General Public License
  along with this library; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
  **********/
  // "liveMedia"
  // Copyright (c) 1996-2017 Live Networks, Inc.  All rights reserved.
  // RTP Sources
  // Implementation
  
  #include "RTPSource.hh"
  #include "GroupsockHelper.hh"
  
  ////////// RTPSource //////////
  
  Boolean RTPSource::lookupByName(UsageEnvironment& env,
  				char const* sourceName,
  				RTPSource*& resultSource) {
    resultSource = NULL; // unless we succeed
  
    MediaSource* source;
    if (!MediaSource::lookupByName(env, sourceName, source)) return False;
  
    if (!source->isRTPSource()) {
      env.setResultMsg(sourceName, " is not a RTP source");
      return False;
    }
  
    resultSource = (RTPSource*)source;
    return True;
  }
  
  Boolean RTPSource::hasBeenSynchronizedUsingRTCP() {
    return fCurPacketHasBeenSynchronizedUsingRTCP;
  }
  
  Boolean RTPSource::isRTPSource() const {
    return True;
  }
  
  RTPSource::RTPSource(UsageEnvironment& env, Groupsock* RTPgs,
  		     unsigned char rtpPayloadFormat,
  		     u_int32_t rtpTimestampFrequency)
    : FramedSource(env),
      fRTPInterface(this, RTPgs),
      fCurPacketHasBeenSynchronizedUsingRTCP(False), fLastReceivedSSRC(0),
      fRTCPInstanceForMultiplexedRTCPPackets(NULL),
      fRTPPayloadFormat(rtpPayloadFormat), fTimestampFrequency(rtpTimestampFrequency),
      fSSRC(our_random32()), fEnableRTCPReports(True) {
    fReceptionStatsDB = new RTPReceptionStatsDB();
  }
  
  RTPSource::~RTPSource() {
    delete fReceptionStatsDB;
  }
  
  void RTPSource::getAttributes() const {
    envir().setResultMsg(""); // Fix later to get attributes from  header #####
  }
  
  
  ////////// RTPReceptionStatsDB //////////
  
  RTPReceptionStatsDB::RTPReceptionStatsDB()
    : fTable(HashTable::create(ONE_WORD_HASH_KEYS)), fTotNumPacketsReceived(0) {
    reset();
  }
  
  void RTPReceptionStatsDB::reset() {
    fNumActiveSourcesSinceLastReset = 0;
  
    Iterator iter(*this);
    RTPReceptionStats* stats;
    while ((stats = iter.next()) != NULL) {
      stats->reset();
    }
  }
  
  RTPReceptionStatsDB::~RTPReceptionStatsDB() {
    // First, remove and delete all stats records from the table:
    RTPReceptionStats* stats;
    while ((stats = (RTPReceptionStats*)fTable->RemoveNext()) != NULL) {
      delete stats;
    }
  
    // Then, delete the table itself:
    delete fTable;
  }
  
  void RTPReceptionStatsDB
  ::noteIncomingPacket(u_int32_t SSRC, u_int16_t seqNum,
  		     u_int32_t rtpTimestamp, unsigned timestampFrequency,
  		     Boolean useForJitterCalculation,
  		     struct timeval& resultPresentationTime,
  		     Boolean& resultHasBeenSyncedUsingRTCP,
  		     unsigned packetSize) {
    ++fTotNumPacketsReceived;
    RTPReceptionStats* stats = lookup(SSRC);
    if (stats == NULL) {
      // This is the first time we've heard from this SSRC.
      // Create a new record for it:
      stats = new RTPReceptionStats(SSRC, seqNum);
      if (stats == NULL) return;
      add(SSRC, stats);
    }
  
    if (stats->numPacketsReceivedSinceLastReset() == 0) {
      ++fNumActiveSourcesSinceLastReset;
    }
  
    stats->noteIncomingPacket(seqNum, rtpTimestamp, timestampFrequency,
  			    useForJitterCalculation,
  			    resultPresentationTime,
  			    resultHasBeenSyncedUsingRTCP, packetSize);
  }
  
  void RTPReceptionStatsDB
  ::noteIncomingSR(u_int32_t SSRC,
  		 u_int32_t ntpTimestampMSW, u_int32_t ntpTimestampLSW,
  		 u_int32_t rtpTimestamp) {
    RTPReceptionStats* stats = lookup(SSRC);
    if (stats == NULL) {
      // This is the first time we've heard of this SSRC.
      // Create a new record for it:
      stats = new RTPReceptionStats(SSRC);
      if (stats == NULL) return;
      add(SSRC, stats);
    }
  
    stats->noteIncomingSR(ntpTimestampMSW, ntpTimestampLSW, rtpTimestamp);
  }
  
  void RTPReceptionStatsDB::removeRecord(u_int32_t SSRC) {
    RTPReceptionStats* stats = lookup(SSRC);
    if (stats != NULL) {
      long SSRC_long = (long)SSRC;
      fTable->Remove((char const*)SSRC_long);
      delete stats;
    }
  }
  
  RTPReceptionStatsDB::Iterator
  ::Iterator(RTPReceptionStatsDB& receptionStatsDB)
    : fIter(HashTable::Iterator::create(*(receptionStatsDB.fTable))) {
  }
  
  RTPReceptionStatsDB::Iterator::~Iterator() {
    delete fIter;
  }
  
  RTPReceptionStats*
  RTPReceptionStatsDB::Iterator::next(Boolean includeInactiveSources) {
    char const* key; // dummy
  
    // If asked, skip over any sources that haven't been active
    // since the last reset:
    RTPReceptionStats* stats;
    do {
      stats = (RTPReceptionStats*)(fIter->next(key));
    } while (stats != NULL && !includeInactiveSources
  	   && stats->numPacketsReceivedSinceLastReset() == 0);
  
    return stats;
  }
  
  RTPReceptionStats* RTPReceptionStatsDB::lookup(u_int32_t SSRC) const {
    long SSRC_long = (long)SSRC;
    return (RTPReceptionStats*)(fTable->Lookup((char const*)SSRC_long));
  }
  
  void RTPReceptionStatsDB::add(u_int32_t SSRC, RTPReceptionStats* stats) {
    long SSRC_long = (long)SSRC;
    fTable->Add((char const*)SSRC_long, stats);
  }
  
  ////////// RTPReceptionStats //////////
  
  RTPReceptionStats::RTPReceptionStats(u_int32_t SSRC, u_int16_t initialSeqNum) {
    initSeqNum(initialSeqNum);
    init(SSRC);
  }
  
  RTPReceptionStats::RTPReceptionStats(u_int32_t SSRC) {
    init(SSRC);
  }
  
  RTPReceptionStats::~RTPReceptionStats() {
  }
  
  void RTPReceptionStats::init(u_int32_t SSRC) {
    fSSRC = SSRC;
    fTotNumPacketsReceived = 0;
    fTotBytesReceived_hi = fTotBytesReceived_lo = 0;
    fBaseExtSeqNumReceived = 0;
    fHighestExtSeqNumReceived = 0;
    fHaveSeenInitialSequenceNumber = False;
    fLastTransit = ~0;
    fPreviousPacketRTPTimestamp = 0;
    fJitter = 0.0;
    fLastReceivedSR_NTPmsw = fLastReceivedSR_NTPlsw = 0;
    fLastReceivedSR_time.tv_sec = fLastReceivedSR_time.tv_usec = 0;
    fLastPacketReceptionTime.tv_sec = fLastPacketReceptionTime.tv_usec = 0;
    fMinInterPacketGapUS = 0x7FFFFFFF;
    fMaxInterPacketGapUS = 0;
    fTotalInterPacketGaps.tv_sec = fTotalInterPacketGaps.tv_usec = 0;
    fHasBeenSynchronized = False;
    fSyncTime.tv_sec = fSyncTime.tv_usec = 0;
    reset();
  }
  
  void RTPReceptionStats::initSeqNum(u_int16_t initialSeqNum) {
      fBaseExtSeqNumReceived = 0x10000 | initialSeqNum;
      fHighestExtSeqNumReceived = 0x10000 | initialSeqNum;
      fHaveSeenInitialSequenceNumber = True;
  }
  
  #ifndef MILLION
  #define MILLION 1000000
  #endif
  
  void RTPReceptionStats
  ::noteIncomingPacket(u_int16_t seqNum, u_int32_t rtpTimestamp,
  		     unsigned timestampFrequency,
  		     Boolean useForJitterCalculation,
  		     struct timeval& resultPresentationTime,
  		     Boolean& resultHasBeenSyncedUsingRTCP,
  		     unsigned packetSize) {
    if (!fHaveSeenInitialSequenceNumber) initSeqNum(seqNum);
  
    ++fNumPacketsReceivedSinceLastReset;
    ++fTotNumPacketsReceived;
    u_int32_t prevTotBytesReceived_lo = fTotBytesReceived_lo;
    fTotBytesReceived_lo += packetSize;
    if (fTotBytesReceived_lo < prevTotBytesReceived_lo) { // wrap-around
      ++fTotBytesReceived_hi;
    }
  
    // Check whether the new sequence number is the highest yet seen:
    unsigned oldSeqNum = (fHighestExtSeqNumReceived&0xFFFF);
    unsigned seqNumCycle = (fHighestExtSeqNumReceived&0xFFFF0000);
    unsigned seqNumDifference = (unsigned)((int)seqNum-(int)oldSeqNum);
    unsigned newSeqNum = 0;
    if (seqNumLT((u_int16_t)oldSeqNum, seqNum)) {
      // This packet was not an old packet received out of order, so check it:
      
      if (seqNumDifference >= 0x8000) {
        // The sequence number wrapped around, so start a new cycle:
        seqNumCycle += 0x10000;
      }
      
      newSeqNum = seqNumCycle|seqNum;
      if (newSeqNum > fHighestExtSeqNumReceived) {
        fHighestExtSeqNumReceived = newSeqNum;
      }
    } else if (fTotNumPacketsReceived > 1) {
      // This packet was an old packet received out of order
      
      if ((int)seqNumDifference >= 0x8000) {
        // The sequence number wrapped around, so switch to an old cycle:
        seqNumCycle -= 0x10000;
      }
      
      newSeqNum = seqNumCycle|seqNum;
      if (newSeqNum < fBaseExtSeqNumReceived) {
        fBaseExtSeqNumReceived = newSeqNum;
      }
    }
  
    // Record the inter-packet delay
    struct timeval timeNow;
    gettimeofday(&timeNow, NULL);
    if (fLastPacketReceptionTime.tv_sec != 0
        || fLastPacketReceptionTime.tv_usec != 0) {
      unsigned gap
        = (timeNow.tv_sec - fLastPacketReceptionTime.tv_sec)*MILLION
        + timeNow.tv_usec - fLastPacketReceptionTime.tv_usec; 
      if (gap > fMaxInterPacketGapUS) {
        fMaxInterPacketGapUS = gap;
      }
      if (gap < fMinInterPacketGapUS) {
        fMinInterPacketGapUS = gap;
      }
      fTotalInterPacketGaps.tv_usec += gap;
      if (fTotalInterPacketGaps.tv_usec >= MILLION) {
        ++fTotalInterPacketGaps.tv_sec;
        fTotalInterPacketGaps.tv_usec -= MILLION;
      }
    }
    fLastPacketReceptionTime = timeNow;
  
    // Compute the current 'jitter' using the received packet's RTP timestamp,
    // and the RTP timestamp that would correspond to the current time.
    // (Use the code from appendix A.8 in the RTP spec.)
    // Note, however, that we don't use this packet if its timestamp is
    // the same as that of the previous packet (this indicates a multi-packet
    // fragment), or if we've been explicitly told not to use this packet.
    if (useForJitterCalculation
        && rtpTimestamp != fPreviousPacketRTPTimestamp) {
      unsigned arrival = (timestampFrequency*timeNow.tv_sec);
      arrival += (unsigned)
        ((2.0*timestampFrequency*timeNow.tv_usec + 1000000.0)/2000000);
              // note: rounding
      int transit = arrival - rtpTimestamp;
      if (fLastTransit == (~0)) fLastTransit = transit; // hack for first time
      int d = transit - fLastTransit;
      fLastTransit = transit;
      if (d < 0) d = -d;
      fJitter += (1.0/16.0) * ((double)d - fJitter);
    }
  
    // Return the 'presentation time' that corresponds to "rtpTimestamp":
    if (fSyncTime.tv_sec == 0 && fSyncTime.tv_usec == 0) {
      // This is the first timestamp that we've seen, so use the current
      // 'wall clock' time as the synchronization time.  (This will be
      // corrected later when we receive RTCP SRs.)
      fSyncTimestamp = rtpTimestamp;
      fSyncTime = timeNow;
    }
  
    int timestampDiff = rtpTimestamp - fSyncTimestamp;
        // Note: This works even if the timestamp wraps around
        // (as long as "int" is 32 bits)
  
    // Divide this by the timestamp frequency to get real time:
    double timeDiff = timestampDiff/(double)timestampFrequency;
  
    // Add this to the 'sync time' to get our result:
    unsigned const million = 1000000;
    unsigned seconds, uSeconds;
    if (timeDiff >= 0.0) {
      seconds = fSyncTime.tv_sec + (unsigned)(timeDiff);
      uSeconds = fSyncTime.tv_usec
        + (unsigned)((timeDiff - (unsigned)timeDiff)*million);
      if (uSeconds >= million) {
        uSeconds -= million;
        ++seconds;
      }
    } else {
      timeDiff = -timeDiff;
      seconds = fSyncTime.tv_sec - (unsigned)(timeDiff);
      uSeconds = fSyncTime.tv_usec
        - (unsigned)((timeDiff - (unsigned)timeDiff)*million);
      if ((int)uSeconds < 0) {
        uSeconds += million;
        --seconds;
      }
    }
    resultPresentationTime.tv_sec = seconds;
    resultPresentationTime.tv_usec = uSeconds;
    resultHasBeenSyncedUsingRTCP = fHasBeenSynchronized;
  
    // Save these as the new synchronization timestamp & time:
    fSyncTimestamp = rtpTimestamp;
    fSyncTime = resultPresentationTime;
  
    fPreviousPacketRTPTimestamp = rtpTimestamp;
  }
  
  void RTPReceptionStats::noteIncomingSR(u_int32_t ntpTimestampMSW,
  				       u_int32_t ntpTimestampLSW,
  				       u_int32_t rtpTimestamp) {
    fLastReceivedSR_NTPmsw = ntpTimestampMSW;
    fLastReceivedSR_NTPlsw = ntpTimestampLSW;
  
    gettimeofday(&fLastReceivedSR_time, NULL);
  
    // Use this SR to update time synchronization information:
    fSyncTimestamp = rtpTimestamp;
    fSyncTime.tv_sec = ntpTimestampMSW - 0x83AA7E80; // 1/1/1900 -> 1/1/1970
    double microseconds = (ntpTimestampLSW*15625.0)/0x04000000; // 10^6/2^32
    fSyncTime.tv_usec = (unsigned)(microseconds+0.5);
    fHasBeenSynchronized = True;
  }
  
  double RTPReceptionStats::totNumKBytesReceived() const {
    double const hiMultiplier = 0x20000000/125.0; // == (2^32)/(10^3)
    return fTotBytesReceived_hi*hiMultiplier + fTotBytesReceived_lo/1000.0;
  }
  
  unsigned RTPReceptionStats::jitter() const {
    return (unsigned)fJitter;
  }
  
  void RTPReceptionStats::reset() {
    fNumPacketsReceivedSinceLastReset = 0;
    fLastResetExtSeqNumReceived = fHighestExtSeqNumReceived;
  }
  
  Boolean seqNumLT(u_int16_t s1, u_int16_t s2) {
    // a 'less-than' on 16-bit sequence numbers
    int diff = s2-s1;
    if (diff > 0) {
      return (diff < 0x8000);
    } else if (diff < 0) {
      return (diff < -0x8000);
    } else { // diff == 0
      return False;
    }
  }
  