/* * 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 #include // rand #include #ifdef WIN32 #include #else #include // 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(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(_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(_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(&rtp_data[i_startPosition >> 1]); } return static_cast(_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(_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(_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(_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(_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(rand()); } }