text: /*
   *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
   *
   *  Use of this source code is governed by a BSD-style license
   *  that can be found in the LICENSE file in the root of the source
   *  tree. An additional intellectual property rights grant can be found
   *  in the file PATENTS.  All contributing project authors may
   *  be found in the AUTHORS file in the root of the source tree.
   */
  
  #include "NETEQTEST_RTPpacket.h"
  
  #include <assert.h>
  #include <stdlib.h>  // rand
  #include <string.h>
  
  #ifdef WIN32
  #include <winsock2.h>
  #else
  #include <netinet/in.h> // for htons, htonl, etc
  #endif
  
  const int NETEQTEST_RTPpacket::_kRDHeaderLen = 8;
  const int NETEQTEST_RTPpacket::_kBasicHeaderLen = 12;
  
  NETEQTEST_RTPpacket::NETEQTEST_RTPpacket()
  :
  _datagram(NULL),
  _payloadPtr(NULL),
  _memSize(0),
  _datagramLen(-1),
  _payloadLen(0),
  _rtpParsed(false),
  _receiveTime(0),
  _lost(false)
  {
      memset(&_rtpInfo, 0, sizeof(_rtpInfo));
      _blockList.clear();
  }
  
  NETEQTEST_RTPpacket::~NETEQTEST_RTPpacket()
  {
      if(_datagram)
      {
          delete [] _datagram;
      }
  }
  
  void NETEQTEST_RTPpacket::reset()
  {
      if(_datagram) {
          delete [] _datagram;
      }
      _datagram = NULL;
      _memSize = 0;
      _datagramLen = -1;
      _payloadLen = 0;
      _payloadPtr = NULL;
      _receiveTime = 0;
      memset(&_rtpInfo, 0, sizeof(_rtpInfo));
      _rtpParsed = false;
  
  }
  
  int NETEQTEST_RTPpacket::skipFileHeader(FILE *fp)
  {
      if (!fp) {
          return -1;
      }
  
      const int kFirstLineLength = 40;
      char firstline[kFirstLineLength];
      if (fgets(firstline, kFirstLineLength, fp) == NULL) {
          return -1;
      }
      if (strncmp(firstline, "#!rtpplay", 9) == 0) {
          if (strncmp(firstline, "#!rtpplay1.0", 12) != 0) {
              return -1;
          }
      }
      else if (strncmp(firstline, "#!RTPencode", 11) == 0) {
          if (strncmp(firstline, "#!RTPencode1.0", 14) != 0) {
              return -1;
          }
      }
      else
      {
          return -1;
      }
  
      const int kRtpDumpHeaderSize = 4 + 4 + 4 + 2 + 2;
      if (fseek(fp, kRtpDumpHeaderSize, SEEK_CUR) != 0)
      {
          return -1;
      }
      return 0;
  }
  
  int NETEQTEST_RTPpacket::readFromFile(FILE *fp)
  {
      if(!fp)
      {
          return(-1);
      }
  
      uint16_t length, plen;
      uint32_t offset;
      int packetLen = 0;
  
      bool readNextPacket = true;
      while (readNextPacket) {
          readNextPacket = false;
          if (fread(&length,2,1,fp)==0)
          {
              reset();
              return(-2);
          }
          length = ntohs(length);
  
          if (fread(&plen,2,1,fp)==0)
          {
              reset();
              return(-1);
          }
          packetLen = ntohs(plen);
  
          if (fread(&offset,4,1,fp)==0)
          {
              reset();
              return(-1);
          }
          // store in local variable until we have passed the reset below
          uint32_t receiveTime = ntohl(offset);
  
          // Use length here because a plen of 0 specifies rtcp
          length = (uint16_t) (length - _kRDHeaderLen);
  
          // check buffer size
          if (_datagram && _memSize < length)
          {
              reset();
          }
  
          if (!_datagram)
          {
              _datagram = new uint8_t[length];
              _memSize = length;
          }
  
          if (fread((unsigned short *) _datagram,1,length,fp) != length)
          {
              reset();
              return(-1);
          }
  
          _datagramLen = length;
          _receiveTime = receiveTime;
  
          if (!_blockList.empty() && _blockList.count(payloadType()) > 0)
          {
              readNextPacket = true;
          }
      }
  
      _rtpParsed = false;
      return(packetLen);
  
  }
  
  
  int NETEQTEST_RTPpacket::readFixedFromFile(FILE *fp, size_t length)
  {
      if (!fp)
      {
          return -1;
      }
  
      // check buffer size
      if (_datagram && _memSize < static_cast<int>(length))
      {
          reset();
      }
  
      if (!_datagram)
      {
          _datagram = new uint8_t[length];
          _memSize = length;
      }
  
      if (fread(_datagram, 1, length, fp) != length)
      {
          reset();
          return -1;
      }
  
      _datagramLen = length;
      _receiveTime = 0;
  
      if (!_blockList.empty() && _blockList.count(payloadType()) > 0)
      {
          // discard this payload
          return readFromFile(fp);
      }
  
      _rtpParsed = false;
      return length;
  
  }
  
  
  int NETEQTEST_RTPpacket::writeToFile(FILE *fp)
  {
      if (!fp)
      {
          return -1;
      }
  
      uint16_t length, plen;
      uint32_t offset;
  
      // length including RTPplay header
      length = htons(_datagramLen + _kRDHeaderLen);
      if (fwrite(&length, 2, 1, fp) != 1)
      {
          return -1;
      }
  
      // payload length
      plen = htons(_datagramLen);
      if (fwrite(&plen, 2, 1, fp) != 1)
      {
          return -1;
      }
  
      // offset (=receive time)
      offset = htonl(_receiveTime);
      if (fwrite(&offset, 4, 1, fp) != 1)
      {
          return -1;
      }
  
  
      // write packet data
      if (fwrite(_datagram, 1, _datagramLen, fp) !=
              static_cast<size_t>(_datagramLen))
      {
          return -1;
      }
  
      return _datagramLen + _kRDHeaderLen; // total number of bytes written
  
  }
  
  
  void NETEQTEST_RTPpacket::blockPT(uint8_t pt)
  {
      _blockList[pt] = true;
  }
  
  
  void NETEQTEST_RTPpacket::parseHeader()
  {
      if (_rtpParsed)
      {
          // nothing to do
          return;
      }
  
      if (_datagramLen < _kBasicHeaderLen)
      {
          // corrupt packet?
          return;
      }
  
      _payloadLen = parseRTPheader(&_payloadPtr);
  
      _rtpParsed = true;
  
      return;
  
  }
  
  void NETEQTEST_RTPpacket::parseHeader(webrtc::WebRtcRTPHeader* rtp_header) {
    if (!_rtpParsed) {
      parseHeader();
    }
    if (rtp_header) {
      rtp_header->header.markerBit = _rtpInfo.header.markerBit;
      rtp_header->header.payloadType = _rtpInfo.header.payloadType;
      rtp_header->header.sequenceNumber = _rtpInfo.header.sequenceNumber;
      rtp_header->header.timestamp = _rtpInfo.header.timestamp;
      rtp_header->header.ssrc = _rtpInfo.header.ssrc;
    }
  }
  
  const webrtc::WebRtcRTPHeader* NETEQTEST_RTPpacket::RTPinfo() const
  {
      if (_rtpParsed)
      {
          return &_rtpInfo;
      }
      else
      {
          return NULL;
      }
  }
  
  uint8_t * NETEQTEST_RTPpacket::datagram() const
  {
      if (_datagramLen > 0)
      {
          return _datagram;
      }
      else
      {
          return NULL;
      }
  }
  
  uint8_t * NETEQTEST_RTPpacket::payload() const
  {
      if (_payloadLen > 0)
      {
          return _payloadPtr;
      }
      else
      {
          return NULL;
      }
  }
  
  size_t NETEQTEST_RTPpacket::payloadLen()
  {
      parseHeader();
      return _payloadLen;
  }
  
  int16_t NETEQTEST_RTPpacket::dataLen() const
  {
      return _datagramLen;
  }
  
  bool NETEQTEST_RTPpacket::isParsed() const
  {
      return _rtpParsed;
  }
  
  bool NETEQTEST_RTPpacket::isLost() const
  {
      return _lost;
  }
  
  uint8_t  NETEQTEST_RTPpacket::payloadType() const
  {
      webrtc::WebRtcRTPHeader tempRTPinfo;
  
      if(_datagram && _datagramLen >= _kBasicHeaderLen)
      {
          parseRTPheader(&tempRTPinfo);
      }
      else
      {
          return 0;
      }
  
      return tempRTPinfo.header.payloadType;
  }
  
  uint16_t NETEQTEST_RTPpacket::sequenceNumber() const
  {
      webrtc::WebRtcRTPHeader tempRTPinfo;
  
      if(_datagram && _datagramLen >= _kBasicHeaderLen)
      {
          parseRTPheader(&tempRTPinfo);
      }
      else
      {
          return 0;
      }
  
      return tempRTPinfo.header.sequenceNumber;
  }
  
  uint32_t NETEQTEST_RTPpacket::timeStamp() const
  {
      webrtc::WebRtcRTPHeader tempRTPinfo;
  
      if(_datagram && _datagramLen >= _kBasicHeaderLen)
      {
          parseRTPheader(&tempRTPinfo);
      }
      else
      {
          return 0;
      }
  
      return tempRTPinfo.header.timestamp;
  }
  
  uint32_t NETEQTEST_RTPpacket::SSRC() const
  {
      webrtc::WebRtcRTPHeader tempRTPinfo;
  
      if(_datagram && _datagramLen >= _kBasicHeaderLen)
      {
          parseRTPheader(&tempRTPinfo);
      }
      else
      {
          return 0;
      }
  
      return tempRTPinfo.header.ssrc;
  }
  
  uint8_t  NETEQTEST_RTPpacket::markerBit() const
  {
      webrtc::WebRtcRTPHeader tempRTPinfo;
  
      if(_datagram && _datagramLen >= _kBasicHeaderLen)
      {
          parseRTPheader(&tempRTPinfo);
      }
      else
      {
          return 0;
      }
  
      return tempRTPinfo.header.markerBit;
  }
  
  
  
  int NETEQTEST_RTPpacket::setPayloadType(uint8_t pt)
  {
  
      if (_datagramLen < 12)
      {
          return -1;
      }
  
      if (!_rtpParsed)
      {
          _rtpInfo.header.payloadType = pt;
      }
  
      _datagram[1]=(unsigned char)(pt & 0xFF);
  
      return 0;
  
  }
  
  int NETEQTEST_RTPpacket::setSequenceNumber(uint16_t sn)
  {
  
      if (_datagramLen < 12)
      {
          return -1;
      }
  
      if (!_rtpParsed)
      {
          _rtpInfo.header.sequenceNumber = sn;
      }
  
      _datagram[2]=(unsigned char)((sn>>8)&0xFF);
      _datagram[3]=(unsigned char)((sn)&0xFF);
  
      return 0;
  
  }
  
  int NETEQTEST_RTPpacket::setTimeStamp(uint32_t ts)
  {
  
      if (_datagramLen < 12)
      {
          return -1;
      }
  
      if (!_rtpParsed)
      {
          _rtpInfo.header.timestamp = ts;
      }
  
      _datagram[4]=(unsigned char)((ts>>24)&0xFF);
      _datagram[5]=(unsigned char)((ts>>16)&0xFF);
      _datagram[6]=(unsigned char)((ts>>8)&0xFF);
      _datagram[7]=(unsigned char)(ts & 0xFF);
  
      return 0;
  
  }
  
  int NETEQTEST_RTPpacket::setSSRC(uint32_t ssrc)
  {
  
      if (_datagramLen < 12)
      {
          return -1;
      }
  
      if (!_rtpParsed)
      {
          _rtpInfo.header.ssrc = ssrc;
      }
  
      _datagram[8]=(unsigned char)((ssrc>>24)&0xFF);
      _datagram[9]=(unsigned char)((ssrc>>16)&0xFF);
      _datagram[10]=(unsigned char)((ssrc>>8)&0xFF);
      _datagram[11]=(unsigned char)(ssrc & 0xFF);
  
      return 0;
  
  }
  
  int NETEQTEST_RTPpacket::setMarkerBit(uint8_t mb)
  {
  
      if (_datagramLen < 12)
      {
          return -1;
      }
  
      if (_rtpParsed)
      {
          _rtpInfo.header.markerBit = mb;
      }
  
      if (mb)
      {
          _datagram[0] |= 0x01;
      }
      else
      {
          _datagram[0] &= 0xFE;
      }
  
      return 0;
  
  }
  
  int NETEQTEST_RTPpacket::setRTPheader(const webrtc::WebRtcRTPHeader* RTPinfo)
  {
      if (_datagramLen < 12)
      {
          // this packet is not ok
          return -1;
      }
  
      makeRTPheader(_datagram,
          RTPinfo->header.payloadType,
          RTPinfo->header.sequenceNumber,
          RTPinfo->header.timestamp,
          RTPinfo->header.ssrc,
          RTPinfo->header.markerBit);
  
      return 0;
  }
  
  
  int NETEQTEST_RTPpacket::splitStereo(NETEQTEST_RTPpacket* slaveRtp,
                                       enum stereoModes mode)
  {
      // if mono, do nothing
      if (mode == stereoModeMono)
      {
          return 0;
      }
  
      // check that the RTP header info is parsed
      parseHeader();
  
      // start by copying the main rtp packet
      *slaveRtp = *this;
  
      if(_payloadLen == 0)
      {
          // do no more
          return 0;
      }
  
      if(_payloadLen%2 != 0)
      {
          // length must be a factor of 2
          return -1;
      }
  
      switch(mode)
      {
      case stereoModeSample1:
          {
              // sample based codec with 1-byte samples
              splitStereoSample(slaveRtp, 1 /* 1 byte/sample */);
              break;
          }
      case stereoModeSample2:
          {
              // sample based codec with 2-byte samples
              splitStereoSample(slaveRtp, 2 /* 2 bytes/sample */);
              break;
          }
      case stereoModeFrame:
          {
              // frame based codec
              splitStereoFrame(slaveRtp);
              break;
          }
      case stereoModeDuplicate:
          {
              // frame based codec, send the whole packet to both master and slave
              splitStereoDouble(slaveRtp);
              break;
          }
      case stereoModeMono:
          {
              assert(false);
              return -1;
          }
      }
  
      return 0;
  }
  
  
  void NETEQTEST_RTPpacket::makeRTPheader(unsigned char* rtp_data, uint8_t payloadType, uint16_t seqNo, uint32_t timestamp, uint32_t ssrc, uint8_t markerBit) const
  {
      rtp_data[0]=(unsigned char)0x80;
      if (markerBit)
      {
          rtp_data[0] |= 0x01;
      }
      else
      {
          rtp_data[0] &= 0xFE;
      }
      rtp_data[1]=(unsigned char)(payloadType & 0xFF);
      rtp_data[2]=(unsigned char)((seqNo>>8)&0xFF);
      rtp_data[3]=(unsigned char)((seqNo)&0xFF);
      rtp_data[4]=(unsigned char)((timestamp>>24)&0xFF);
      rtp_data[5]=(unsigned char)((timestamp>>16)&0xFF);
  
      rtp_data[6]=(unsigned char)((timestamp>>8)&0xFF);
      rtp_data[7]=(unsigned char)(timestamp & 0xFF);
  
      rtp_data[8]=(unsigned char)((ssrc>>24)&0xFF);
      rtp_data[9]=(unsigned char)((ssrc>>16)&0xFF);
  
      rtp_data[10]=(unsigned char)((ssrc>>8)&0xFF);
      rtp_data[11]=(unsigned char)(ssrc & 0xFF);
  }
  
  uint16_t
      NETEQTEST_RTPpacket::parseRTPheader(webrtc::WebRtcRTPHeader* RTPinfo,
                                          uint8_t **payloadPtr) const
  {
      int16_t *rtp_data = (int16_t *) _datagram;
      int i_P, i_X, i_CC;
  
      assert(_datagramLen >= 12);
      parseBasicHeader(RTPinfo, &i_P, &i_X, &i_CC);
  
      int i_startPosition = calcHeaderLength(i_X, i_CC);
  
      int i_padlength = calcPadLength(i_P);
  
      if (payloadPtr)
      {
          *payloadPtr = (uint8_t*) &rtp_data[i_startPosition >> 1];
      }
  
      return (uint16_t) (_datagramLen - i_startPosition - i_padlength);
  }
  
  
  void NETEQTEST_RTPpacket::parseBasicHeader(webrtc::WebRtcRTPHeader* RTPinfo,
                                             int *i_P, int *i_X, int *i_CC) const
  {
      int16_t *rtp_data = (int16_t *) _datagram;
      if (_datagramLen < 12)
      {
          assert(false);
          return;
      }
  
      *i_P=(((uint16_t)(rtp_data[0] & 0x20))>>5); /* Extract the P bit */
      *i_X=(((uint16_t)(rtp_data[0] & 0x10))>>4); /* Extract the X bit */
      *i_CC=(uint16_t)(rtp_data[0] & 0xF); /* Get the CC number  */
      /* Get the marker bit */
      RTPinfo->header.markerBit = (uint8_t) ((rtp_data[0] >> 15) & 0x01);
      /* Get the coder type */
      RTPinfo->header.payloadType = (uint8_t) ((rtp_data[0] >> 8) & 0x7F);
      /* Get the packet number */
      RTPinfo->header.sequenceNumber =
          ((( ((uint16_t)rtp_data[1]) >> 8) & 0xFF) |
          ( ((uint16_t)(rtp_data[1] & 0xFF)) << 8));
      /* Get timestamp */
      RTPinfo->header.timestamp = ((((uint16_t)rtp_data[2]) & 0xFF) << 24) |
          ((((uint16_t)rtp_data[2]) & 0xFF00) << 8) |
          ((((uint16_t)rtp_data[3]) >> 8) & 0xFF) |
          ((((uint16_t)rtp_data[3]) & 0xFF) << 8);
      /* Get the SSRC */
      RTPinfo->header.ssrc = ((((uint16_t)rtp_data[4]) & 0xFF) << 24) |
          ((((uint16_t)rtp_data[4]) & 0xFF00) << 8) |
          ((((uint16_t)rtp_data[5]) >> 8) & 0xFF) |
          ((((uint16_t)rtp_data[5]) & 0xFF) << 8);
  }
  
  int NETEQTEST_RTPpacket::calcHeaderLength(int i_X, int i_CC) const
  {
      int i_extlength = 0;
      int16_t *rtp_data = (int16_t *) _datagram;
  
      if (i_X == 1)
      {
          // Extension header exists.
          // Find out how many int32_t it consists of.
          assert(_datagramLen > 2 * (7 + 2 * i_CC));
          if (_datagramLen > 2 * (7 + 2 * i_CC))
          {
              i_extlength = (((((uint16_t) rtp_data[7 + 2 * i_CC]) >> 8)
                  & 0xFF) | (((uint16_t) (rtp_data[7 + 2 * i_CC] & 0xFF))
                  << 8)) + 1;
          }
      }
  
      return 12 + 4 * i_extlength + 4 * i_CC;
  }
  
  int NETEQTEST_RTPpacket::calcPadLength(int i_P) const
  {
      int16_t *rtp_data = (int16_t *) _datagram;
      if (i_P == 1)
      {
          /* Padding exists. Find out how many bytes the padding consists of. */
          if (_datagramLen & 0x1)
          {
              /* odd number of bytes => last byte in higher byte */
              return rtp_data[_datagramLen >> 1] & 0xFF;
          }
          else
          {
              /* even number of bytes => last byte in lower byte */
              return ((uint16_t) rtp_data[(_datagramLen >> 1) - 1]) >> 8;
          }
      }
      return 0;
  }
  
  void NETEQTEST_RTPpacket::splitStereoSample(NETEQTEST_RTPpacket* slaveRtp,
                                              int stride)
  {
      if(!_payloadPtr || !slaveRtp || !slaveRtp->_payloadPtr
          || _payloadLen == 0 || slaveRtp->_memSize < _memSize)
      {
          return;
      }
  
      uint8_t *readDataPtr = _payloadPtr;
      uint8_t *writeDataPtr = _payloadPtr;
      uint8_t *slaveData = slaveRtp->_payloadPtr;
  
      while (readDataPtr - _payloadPtr < static_cast<ptrdiff_t>(_payloadLen))
      {
          // master data
          for (int ix = 0; ix < stride; ix++) {
              *writeDataPtr = *readDataPtr;
              writeDataPtr++;
              readDataPtr++;
          }
  
          // slave data
          for (int ix = 0; ix < stride; ix++) {
              *slaveData = *readDataPtr;
              slaveData++;
              readDataPtr++;
          }
      }
  
      _payloadLen /= 2;
      slaveRtp->_payloadLen = _payloadLen;
  }
  
  
  void NETEQTEST_RTPpacket::splitStereoFrame(NETEQTEST_RTPpacket* slaveRtp)
  {
      if(!_payloadPtr || !slaveRtp || !slaveRtp->_payloadPtr
          || _payloadLen == 0 || slaveRtp->_memSize < _memSize)
      {
          return;
      }
  
      memmove(slaveRtp->_payloadPtr, _payloadPtr + _payloadLen/2, _payloadLen/2);
  
      _payloadLen /= 2;
      slaveRtp->_payloadLen = _payloadLen;
  }
  void NETEQTEST_RTPpacket::splitStereoDouble(NETEQTEST_RTPpacket* slaveRtp)
  {
      if(!_payloadPtr || !slaveRtp || !slaveRtp->_payloadPtr
          || _payloadLen == 0 || slaveRtp->_memSize < _memSize)
      {
          return;
      }
  
      memcpy(slaveRtp->_payloadPtr, _payloadPtr, _payloadLen);
      slaveRtp->_payloadLen = _payloadLen;
  }
  
  // Get the RTP header for the RED payload indicated by argument index.
  // The first RED payload is index = 0.
  int NETEQTEST_RTPpacket::extractRED(int index, webrtc::WebRtcRTPHeader& red)
  {
  //
  //  0                   1                    2                   3
  //  0 1 2 3 4 5 6 7 8 9 0 1 2 3  4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  // |1|   block PT  |  timestamp offset         |   block length    |
  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  // |1|    ...                                                      |
  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  // |0|   block PT  |
  // +-+-+-+-+-+-+-+-+
  //
  
      parseHeader();
  
      uint8_t* ptr = payload();
      uint8_t* payloadEndPtr = ptr + payloadLen();
      int num_encodings = 0;
      int total_len = 0;
  
      while ((ptr < payloadEndPtr) && (*ptr & 0x80))
      {
          int len = ((ptr[2] & 0x03) << 8) + ptr[3];
          if (num_encodings == index)
          {
              // Header found.
              red.header.payloadType = ptr[0] & 0x7F;
              uint32_t offset = (ptr[1] << 6) + ((ptr[2] & 0xFC) >> 2);
              red.header.sequenceNumber = sequenceNumber();
              red.header.timestamp = timeStamp() - offset;
              red.header.markerBit = markerBit();
              red.header.ssrc = SSRC();
              return len;
          }
          ++num_encodings;
          total_len += len;
          ptr += 4;
      }
      if ((ptr < payloadEndPtr) && (num_encodings == index))
      {
          // Last header.
          red.header.payloadType = ptr[0] & 0x7F;
          red.header.sequenceNumber = sequenceNumber();
          red.header.timestamp = timeStamp();
          red.header.markerBit = markerBit();
          red.header.ssrc = SSRC();
          ++ptr;
          return payloadLen() - (ptr - payload()) - total_len;
      }
      return -1;
  }
  
  // Randomize the payload, not the RTP header.
  void NETEQTEST_RTPpacket::scramblePayload(void)
  {
      parseHeader();
  
      for (size_t i = 0; i < _payloadLen; ++i)
      {
          _payloadPtr[i] = static_cast<uint8_t>(rand());
      }
  }
  