| /* |
| * 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 |
| { |
| if(_datagram && _datagramLen >= _kBasicHeaderLen) |
| { |
| webrtc::WebRtcRTPHeader tempRTPinfo; |
| parseRTPheader(&tempRTPinfo); |
| return tempRTPinfo.header.payloadType; |
| } |
| else |
| { |
| return 0; |
| } |
| } |
| |
| uint16_t NETEQTEST_RTPpacket::sequenceNumber() const |
| { |
| if(_datagram && _datagramLen >= _kBasicHeaderLen) |
| { |
| webrtc::WebRtcRTPHeader tempRTPinfo; |
| parseRTPheader(&tempRTPinfo); |
| return tempRTPinfo.header.sequenceNumber; |
| } |
| else |
| { |
| return 0; |
| } |
| } |
| |
| uint32_t NETEQTEST_RTPpacket::timeStamp() const |
| { |
| if(_datagram && _datagramLen >= _kBasicHeaderLen) |
| { |
| webrtc::WebRtcRTPHeader tempRTPinfo; |
| parseRTPheader(&tempRTPinfo); |
| return tempRTPinfo.header.timestamp; |
| } |
| else |
| { |
| return 0; |
| } |
| } |
| |
| uint32_t NETEQTEST_RTPpacket::SSRC() const |
| { |
| if(_datagram && _datagramLen >= _kBasicHeaderLen) |
| { |
| webrtc::WebRtcRTPHeader tempRTPinfo; |
| parseRTPheader(&tempRTPinfo); |
| return tempRTPinfo.header.ssrc; |
| } |
| else |
| { |
| return 0; |
| } |
| } |
| |
| uint8_t NETEQTEST_RTPpacket::markerBit() const |
| { |
| if(_datagram && _datagramLen >= _kBasicHeaderLen) |
| { |
| webrtc::WebRtcRTPHeader tempRTPinfo; |
| parseRTPheader(&tempRTPinfo); |
| return tempRTPinfo.header.markerBit; |
| } |
| else |
| { |
| return 0; |
| } |
| } |
| |
| |
| |
| int NETEQTEST_RTPpacket::setPayloadType(uint8_t pt) |
| { |
| |
| if (_datagramLen < 12) |
| { |
| return -1; |
| } |
| |
| if (!_rtpParsed) |
| { |
| _rtpInfo.header.payloadType = pt; |
| } |
| |
| _datagram[1] = pt; |
| |
| 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] = markerBit ? 0x81 : 0x80; |
| rtp_data[1] = payloadType; |
| rtp_data[2] = seqNo >> 8; |
| rtp_data[3] = seqNo & 0xFF; |
| rtp_data[4] = timestamp >> 24; |
| rtp_data[5] = (timestamp >> 16) & 0xFF; |
| rtp_data[6] = (timestamp >> 8) & 0xFF; |
| rtp_data[7] = timestamp & 0xFF; |
| rtp_data[8] = ssrc >> 24; |
| rtp_data[9] = (ssrc >> 16) & 0xFF; |
| rtp_data[10] = (ssrc >> 8) & 0xFF; |
| rtp_data[11] = ssrc & 0xFF; |
| } |
| |
| uint16_t NETEQTEST_RTPpacket::parseRTPheader(webrtc::WebRtcRTPHeader* RTPinfo, |
| uint8_t **payloadPtr) const |
| { |
| uint16_t* rtp_data = reinterpret_cast<uint16_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 = |
| reinterpret_cast<uint8_t*>(&rtp_data[i_startPosition >> 1]); |
| } |
| |
| return static_cast<uint16_t>(_datagramLen - i_startPosition - i_padlength); |
| } |
| |
| |
| void NETEQTEST_RTPpacket::parseBasicHeader(webrtc::WebRtcRTPHeader* RTPinfo, |
| int *i_P, int *i_X, int *i_CC) const |
| { |
| uint16_t* rtp_data = reinterpret_cast<uint16_t*>(_datagram); |
| if (_datagramLen < 12) |
| { |
| assert(false); |
| return; |
| } |
| |
| *i_P = (rtp_data[0] >> 5) & 0x01; |
| *i_X = (rtp_data[0] >> 4) & 0x01; |
| *i_CC = rtp_data[0] & 0xF; |
| RTPinfo->header.markerBit = (rtp_data[0] >> 15) & 0x01; |
| RTPinfo->header.payloadType = (rtp_data[0] >> 8) & 0x7F; |
| RTPinfo->header.sequenceNumber = |
| (rtp_data[1] >> 8) | ((rtp_data[1] & 0xFF) << 8); |
| RTPinfo->header.timestamp = |
| ((rtp_data[2] & 0xFF) << 24) | ((rtp_data[2] & 0xFF00) << 8) | |
| (rtp_data[3] >> 8) | ((rtp_data[3] & 0xFF) << 8); |
| RTPinfo->header.ssrc = |
| ((rtp_data[4] & 0xFF) << 24) | ((rtp_data[4] & 0xFF00) << 8) | |
| (rtp_data[5] >> 8) | ((rtp_data[5] & 0xFF) << 8); |
| } |
| |
| int NETEQTEST_RTPpacket::calcHeaderLength(int i_X, int i_CC) const |
| { |
| int i_extlength = 0; |
| uint16_t* rtp_data = reinterpret_cast<uint16_t*>(_datagram); |
| |
| if (i_X == 1) |
| { |
| // Extension header exists. |
| // Find out how many int32_t it consists of. |
| int offset = 7 + 2 * i_CC; |
| assert(_datagramLen > 2 * offset); |
| if (_datagramLen > 2 * offset) |
| { |
| i_extlength = 1 + |
| (((rtp_data[offset]) >> 8) | ((rtp_data[offset] & 0xFF) << 8)); |
| } |
| } |
| |
| return 12 + 4 * i_extlength + 4 * i_CC; |
| } |
| |
| int NETEQTEST_RTPpacket::calcPadLength(int i_P) const |
| { |
| uint16_t* rtp_data = reinterpret_cast<uint16_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 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] >> 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()); |
| } |
| } |