mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-28 20:45:17 +00:00
d83a3d71bc
Merge in RedPhone // FREEBIE
876 lines
19 KiB
C++
876 lines
19 KiB
C++
/*
|
|
* 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;
|
|
}
|
|
}
|
|
|
|
int16_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 < _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 (int i = 0; i < _payloadLen; ++i)
|
|
{
|
|
_payloadPtr[i] = static_cast<uint8_t>(rand());
|
|
}
|
|
}
|