From b8147ffacc8bab8f7ca563ab7d3eab6a32957f81 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 25 Feb 2018 19:31:15 +0100 Subject: [PATCH] qrtplib: draft (2) --- qrtplib/CMakeLists.txt | 23 +- qrtplib/rtppacket.cpp | 441 +++++++++++++++++++++++++++++++++++ qrtplib/rtppacket.h | 288 +++++++++++++++++++++++ qrtplib/rtppacketbuilder.cpp | 37 ++- qrtplib/rtprandom.cpp | 33 +-- qrtplib/rtprawpacket.h | 183 +++++++++++++++ qrtplib/rtpstructs.h | 130 +++++++++++ qrtplib/rtptimeutilities.cpp | 4 +- qrtplib/rtptimeutilities.h | 26 +-- 9 files changed, 1107 insertions(+), 58 deletions(-) create mode 100644 qrtplib/rtppacket.cpp create mode 100644 qrtplib/rtppacket.h create mode 100644 qrtplib/rtprawpacket.h create mode 100644 qrtplib/rtpstructs.h diff --git a/qrtplib/CMakeLists.txt b/qrtplib/CMakeLists.txt index 65dcc3bb7..2de5f94ac 100644 --- a/qrtplib/CMakeLists.txt +++ b/qrtplib/CMakeLists.txt @@ -1,22 +1,25 @@ project(qrtplib) set(qrtplib_SOURCES - rtptimeutilities.cpp - rtprandomurandom.cpp - rtprandomrand48.cpp - rtprandom.cpp rtperrors.cpp + rtppacket.cpp + rtprandom.cpp + rtprandomrand48.cpp + rtprandomurandom.cpp + rtptimeutilities.cpp ) set(qrtplib_HEADERS - rtptimeutilities.h - rtprandom.h - rtprandomurandom.h - rtprandomrand48.h - rtprandom.h - rtpinternalutils.h rtperrors.h rtpdefines.h + rtpinternalutils.h + rtppacket.h + rtprandom.h + rtprandomrand48.h + rtprandomurandom.h + rtprawpacket.h + rtpstructs.h + rtptimeutilities.h ) include_directories( diff --git a/qrtplib/rtppacket.cpp b/qrtplib/rtppacket.cpp new file mode 100644 index 000000000..15a28b8fe --- /dev/null +++ b/qrtplib/rtppacket.cpp @@ -0,0 +1,441 @@ +/* + Rewritten to fit into the Qt Network framework + Copyright (c) 2018 Edouard Griffiths, F4EXB + + This file is a part of JRTPLIB + Copyright (c) 1999-2017 Jori Liesenborgs + + Contact: jori.liesenborgs@gmail.com + + This library was developed at the Expertise Centre for Digital Media + (http://www.edm.uhasselt.be), a research center of the Hasselt University + (http://www.uhasselt.be). The library is based upon work done for + my thesis at the School for Knowledge Technology (Belgium/The Netherlands). + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. + +*/ + +#include "rtppacket.h" +#include "rtpstructs.h" +#include "rtpdefines.h" +#include "rtperrors.h" +#include "rtprawpacket.h" +#include + +#ifdef RTPDEBUG + #include +#endif // RTPDEBUG + +//#include "rtpdebug.h" + +namespace qrtplib +{ + +void RTPPacket::Clear() +{ + hasextension = false; + hasmarker = false; + numcsrcs = 0; + payloadtype = 0; + extseqnr = 0; + timestamp = 0; + ssrc = 0; + packet = 0; + payload = 0; + packetlength = 0; + payloadlength = 0; + extid = 0; + extension = 0; + extensionlength = 0; + error = 0; + externalbuffer = false; + + uint32_t endianTest32 = 1; + uint8_t *ptr = (uint8_t*) &endianTest32; + m_littleEndian = (*ptr == 1); +} + +RTPPacket::RTPPacket(RTPRawPacket &rawpack) : receivetime(rawpack.GetReceiveTime()) +{ + Clear(); + error = ParseRawPacket(rawpack); +} + +RTPPacket::RTPPacket( + uint8_t payloadtype, + const void *payloaddata, + std::size_t payloadlen, + uint16_t seqnr, + uint32_t timestamp, + uint32_t ssrc, + bool gotmarker, + uint8_t numcsrcs, + const uint32_t *csrcs, + bool gotextension, + uint16_t extensionid, + uint16_t extensionlen_numwords, + const void *extensiondata, + std::size_t maxpacksize) : receivetime(0,0) +{ + Clear(); + + error = BuildPacket( + payloadtype, + payloaddata, + payloadlen, + seqnr, + timestamp, + ssrc, + gotmarker, + numcsrcs, + csrcs, + gotextension, + extensionid, + extensionlen_numwords, + extensiondata, + 0, + maxpacksize); +} + +RTPPacket::RTPPacket( + uint8_t payloadtype, + const void *payloaddata, + std::size_t payloadlen, + uint16_t seqnr, + uint32_t timestamp, + uint32_t ssrc, + bool gotmarker, + uint8_t numcsrcs, + const uint32_t *csrcs, + bool gotextension, + uint16_t extensionid, + uint16_t extensionlen_numwords, + const void *extensiondata, + void *buffer, + std::size_t buffersize) : receivetime(0,0) +{ + Clear(); + + if (buffer == 0) { + error = ERR_RTP_PACKET_EXTERNALBUFFERNULL; + } else if (buffersize <= 0) { + error = ERR_RTP_PACKET_ILLEGALBUFFERSIZE; + } else { + error = BuildPacket( + payloadtype, + payloaddata, + payloadlen, + seqnr, + timestamp, + ssrc, + gotmarker, + numcsrcs, + csrcs, + gotextension, + extensionid, + extensionlen_numwords, + extensiondata, + buffer, + buffersize); + } +} + +int RTPPacket::ParseRawPacket(RTPRawPacket &rawpack) +{ + uint8_t *packetbytes; + std::size_t packetlen; + uint8_t payloadtype; + RTPHeader *rtpheader; + bool marker; + int csrccount; + bool hasextension; + int payloadoffset,payloadlength; + int numpadbytes; + RTPExtensionHeader *rtpextheader; + + if (!rawpack.IsRTP()) { // If we didn't receive it on the RTP port, we'll ignore it + return ERR_RTP_PACKET_INVALIDPACKET; + } + + // The length should be at least the size of the RTP header + packetlen = rawpack.GetDataLength(); + + if (packetlen < sizeof(RTPHeader)) { + return ERR_RTP_PACKET_INVALIDPACKET; + } + + packetbytes = (uint8_t *)rawpack.GetData(); + rtpheader = (RTPHeader *)packetbytes; + + // The version number should be correct + if (rtpheader->version != RTP_VERSION) { + return ERR_RTP_PACKET_INVALIDPACKET; + } + + // We'll check if this is possibly a RTCP packet. For this to be possible + // the marker bit and payload type combined should be either an SR or RR + // identifier + marker = (rtpheader->marker == 0)?false:true; + payloadtype = rtpheader->payloadtype; + + if (marker) + { + if (payloadtype == (RTP_RTCPTYPE_SR & 127)) { // don't check high bit (this was the marker!!) + return ERR_RTP_PACKET_INVALIDPACKET; + } + if (payloadtype == (RTP_RTCPTYPE_RR & 127)) { + return ERR_RTP_PACKET_INVALIDPACKET; + } + } + + csrccount = rtpheader->csrccount; + payloadoffset = sizeof(RTPHeader)+(int)(csrccount*sizeof(uint32_t)); + + if (rtpheader->padding) // adjust payload length to take padding into account + { + numpadbytes = (int)packetbytes[packetlen-1]; // last byte contains number of padding bytes + if (numpadbytes <= 0) { + return ERR_RTP_PACKET_INVALIDPACKET; + } + } + else + { + numpadbytes = 0; + } + + hasextension = (rtpheader->extension != 0); + + if (hasextension) // got header extension + { + rtpextheader = (RTPExtensionHeader *)(packetbytes+payloadoffset); + payloadoffset += sizeof(RTPExtensionHeader); + + uint16_t exthdrlen = qToHost(rtpextheader->length); // ntohs(rtpextheader->length); + payloadoffset += ((int)exthdrlen)*sizeof(uint32_t); + } + else + { + rtpextheader = 0; + } + + payloadlength = packetlen-numpadbytes-payloadoffset; + + if (payloadlength < 0) { + return ERR_RTP_PACKET_INVALIDPACKET; + } + + // Now, we've got a valid packet, so we can create a new instance of RTPPacket + // and fill in the members + + RTPPacket::hasextension = hasextension; + + if (hasextension) + { + RTPPacket::extid = qToHost(rtpextheader->extid); // ntohs(rtpextheader->extid); + RTPPacket::extensionlength = ((int)qToHost(rtpextheader->length))*sizeof(uint32_t); // ((int)ntohs(rtpextheader->length))*sizeof(uint32_t); + RTPPacket::extension = ((uint8_t *)rtpextheader)+sizeof(RTPExtensionHeader); + } + + RTPPacket::hasmarker = marker; + RTPPacket::numcsrcs = csrccount; + RTPPacket::payloadtype = payloadtype; + + // Note: we don't fill in the EXTENDED sequence number here, since we + // don't have information about the source here. We just fill in the low + // 16 bits + RTPPacket::extseqnr = (uint32_t) qToHost(rtpheader->sequencenumber); // ntohs(rtpheader->sequencenumber); + + RTPPacket::timestamp = qToHost(rtpheader->timestamp); // ntohl(rtpheader->timestamp); + RTPPacket::ssrc = qToHost(rtpheader->ssrc); // ntohl(rtpheader->ssrc); + RTPPacket::packet = packetbytes; + RTPPacket::payload = packetbytes+payloadoffset; + RTPPacket::packetlength = packetlen; + RTPPacket::payloadlength = payloadlength; + + // We'll zero the data of the raw packet, since we're using it here now! + rawpack.ZeroData(); + + return 0; +} + +uint32_t RTPPacket::GetCSRC(int num) const +{ + if (num >= numcsrcs) { + return 0; + } + + uint8_t *csrcpos; + uint32_t *csrcval_nbo; + uint32_t csrcval_hbo; + + csrcpos = packet+sizeof(RTPHeader)+num*sizeof(uint32_t); + csrcval_nbo = (uint32_t *)csrcpos; + csrcval_hbo = qToHost(*csrcval_nbo); // ntohl(*csrcval_nbo); + return csrcval_hbo; +} + +int RTPPacket::BuildPacket( + uint8_t payloadtype, + const void *payloaddata, + std::size_t payloadlen, + uint16_t seqnr, + uint32_t timestamp, + uint32_t ssrc, + bool gotmarker, + uint8_t numcsrcs, + const uint32_t *csrcs, + bool gotextension, + uint16_t extensionid, + uint16_t extensionlen_numwords, + const void *extensiondata, + void *buffer, + std::size_t maxsize) +{ + if (numcsrcs > RTP_MAXCSRCS) { + return ERR_RTP_PACKET_TOOMANYCSRCS; + } + + if (payloadtype > 127) { // high bit should not be used + return ERR_RTP_PACKET_BADPAYLOADTYPE; + } + if (payloadtype == 72 || payloadtype == 73) { // could cause confusion with rtcp types + return ERR_RTP_PACKET_BADPAYLOADTYPE; + } + + packetlength = sizeof(RTPHeader); + packetlength += sizeof(uint32_t)*((std::size_t)numcsrcs); + + if (gotextension) + { + packetlength += sizeof(RTPExtensionHeader); + packetlength += sizeof(uint32_t)*((size_t)extensionlen_numwords); + } + + packetlength += payloadlen; + + if (maxsize > 0 && packetlength > maxsize) + { + packetlength = 0; + return ERR_RTP_PACKET_DATAEXCEEDSMAXSIZE; + } + + // Ok, now we'll just fill in... + + RTPHeader *rtphdr; + + if (buffer == 0) + { + packet = new uint8_t[packetlength]; + if (packet == 0) + { + packetlength = 0; + return ERR_RTP_OUTOFMEM; + } + externalbuffer = false; + } + else + { + packet = (uint8_t *)buffer; + externalbuffer = true; + } + + RTPPacket::hasmarker = gotmarker; + RTPPacket::hasextension = gotextension; + RTPPacket::numcsrcs = numcsrcs; + RTPPacket::payloadtype = payloadtype; + RTPPacket::extseqnr = (uint32_t)seqnr; + RTPPacket::timestamp = timestamp; + RTPPacket::ssrc = ssrc; + RTPPacket::payloadlength = payloadlen; + RTPPacket::extid = extensionid; + RTPPacket::extensionlength = ((std::size_t)extensionlen_numwords)*sizeof(uint32_t); + + rtphdr = (RTPHeader *)packet; + rtphdr->version = RTP_VERSION; + rtphdr->padding = 0; + if (gotmarker) + rtphdr->marker = 1; + else + rtphdr->marker = 0; + if (gotextension) + rtphdr->extension = 1; + else + rtphdr->extension = 0; + rtphdr->csrccount = numcsrcs; + rtphdr->payloadtype = payloadtype&127; // make sure high bit isn't set + rtphdr->sequencenumber = qToBigEndian(seqnr); // htons(seqnr); + rtphdr->timestamp = qToBigEndian(timestamp); // htonl(timestamp); + rtphdr->ssrc = qToBigEndian(ssrc); // htonl(ssrc); + + uint32_t *curcsrc; + int i; + curcsrc = (uint32_t *)(packet+sizeof(RTPHeader)); + + for (i = 0 ; i < numcsrcs ; i++,curcsrc++) { + *curcsrc = qToBigEndian(csrcs[i]); // htonl(csrcs[i]); + } + + payload = packet+sizeof(RTPHeader)+((std::size_t)numcsrcs)*sizeof(uint32_t); + + if (gotextension) + { + RTPExtensionHeader *rtpexthdr = (RTPExtensionHeader *)payload; + + rtpexthdr->extid = qToBigEndian(extensionid); // htons(extensionid); + rtpexthdr->length = qToBigEndian((uint16_t)extensionlen_numwords); // htons((uint16_t)extensionlen_numwords); + + payload += sizeof(RTPExtensionHeader); + memcpy(payload,extensiondata,RTPPacket::extensionlength); + + payload += RTPPacket::extensionlength; + } + + memcpy(payload,payloaddata,payloadlen); + return 0; +} + +#ifdef RTPDEBUG +void RTPPacket::Dump() +{ + int i; + + printf("Payload type: %d\n",(int)GetPayloadType()); + printf("Extended sequence number: 0x%08x\n",GetExtendedSequenceNumber()); + printf("Timestamp: 0x%08x\n",GetTimestamp()); + printf("SSRC: 0x%08x\n",GetSSRC()); + printf("Marker: %s\n",HasMarker()?"yes":"no"); + printf("CSRC count: %d\n",GetCSRCCount()); + for (i = 0 ; i < GetCSRCCount() ; i++) + printf(" CSRC[%02d]: 0x%08x\n",i,GetCSRC(i)); + printf("Payload: %s\n",GetPayloadData()); + printf("Payload length: %d\n",GetPayloadLength()); + printf("Packet length: %d\n",GetPacketLength()); + printf("Extension: %s\n",HasExtension()?"yes":"no"); + if (HasExtension()) + { + printf(" Extension ID: 0x%04x\n",GetExtensionID()); + printf(" Extension data: %s\n",GetExtensionData()); + printf(" Extension length: %d\n",GetExtensionLength()); + } +} +#endif // RTPDEBUG + +} // end namespace + diff --git a/qrtplib/rtppacket.h b/qrtplib/rtppacket.h new file mode 100644 index 000000000..6728d21e8 --- /dev/null +++ b/qrtplib/rtppacket.h @@ -0,0 +1,288 @@ +/* + Rewritten to fit into the Qt Network framework + Copyright (c) 2018 Edouard Griffiths, F4EXB + + This file is a part of JRTPLIB + Copyright (c) 1999-2017 Jori Liesenborgs + + Contact: jori.liesenborgs@gmail.com + + This library was developed at the Expertise Centre for Digital Media + (http://www.edm.uhasselt.be), a research center of the Hasselt University + (http://www.uhasselt.be). The library is based upon work done for + my thesis at the School for Knowledge Technology (Belgium/The Netherlands). + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. + +*/ + +/** + * \file rtppacket.h + */ + +#ifndef RTPPACKET_H + +#define RTPPACKET_H + +//#include "rtpconfig.h" +//#include "rtptypes.h" +#include "rtptimeutilities.h" +//#include "rtpmemoryobject.h" +#include +#include + +namespace qrtplib +{ + +class RTPRawPacket; + +/** Represents an RTP Packet. + * The RTPPacket class can be used to parse a RTPRawPacket instance if it represents RTP data. + * The class can also be used to create a new RTP packet according to the parameters specified by + * the user. + */ +class RTPPacket +{ +public: + /** Creates an RTPPacket instance based upon the data in \c rawpack. + * Creates an RTPPacket instance based upon the data in \c rawpack. + * If successful, the data is moved from the raw packet to the RTPPacket instance. + */ + RTPPacket(RTPRawPacket &rawpack); + + /** Creates a new buffer for an RTP packet and fills in the fields according to the specified parameters. + * Creates a new buffer for an RTP packet and fills in the fields according to the specified parameters. + * If \c maxpacksize is not equal to zero, an error is generated if the total packet size would exceed + * \c maxpacksize. The arguments of the constructor are self-explanatory. Note that the size of a header + * extension is specified in a number of 32-bit words. + */ + RTPPacket( + uint8_t payloadtype, + const void *payloaddata, + std::size_t payloadlen, + uint16_t seqnr, + uint32_t timestamp, + uint32_t ssrc, + bool gotmarker, + uint8_t numcsrcs, + const uint32_t *csrcs, + bool gotextension, + uint16_t extensionid, + uint16_t extensionlen_numwords, + const void *extensiondata, + std::size_t maxpacksize); + + /** This constructor is similar to the other constructor, but here data is stored in an external buffer + * \c buffer with size \c buffersize. */ + RTPPacket(uint8_t payloadtype, + const void *payloaddata, + std::size_t payloadlen, + uint16_t seqnr, + uint32_t timestamp, + uint32_t ssrc, + bool gotmarker, + uint8_t numcsrcs, + const uint32_t *csrcs, + bool gotextension, + uint16_t extensionid, + uint16_t extensionlen_numwords, + const void *extensiondata, + void *buffer, + std::size_t buffersize); + + virtual ~RTPPacket() + { + if (packet && !externalbuffer){ + delete[] packet; + //RTPDeleteByteArray(packet); + } + } + + /** If an error occurred in one of the constructors, this function returns the error code. */ + int GetCreationError() const + { + return error; + } + + /** Returns \c true if the RTP packet has a header extension and \c false otherwise. */ + bool HasExtension() const + { + return hasextension; + } + + /** Returns \c true if the marker bit was set and \c false otherwise. */ + bool HasMarker() const + { + return hasmarker; + } + + /** Returns the number of CSRCs contained in this packet. */ + int GetCSRCCount() const + { + return numcsrcs; + } + + /** Returns a specific CSRC identifier. + * Returns a specific CSRC identifier. The parameter \c num can go from 0 to GetCSRCCount()-1. + */ + uint32_t GetCSRC(int num) const; + + /** Returns the payload type of the packet. */ + uint8_t GetPayloadType() const + { + return payloadtype; + } + + /** Returns the extended sequence number of the packet. + * Returns the extended sequence number of the packet. When the packet is just received, + * only the low $16$ bits will be set. The high 16 bits can be filled in later. + */ + uint32_t GetExtendedSequenceNumber() const + { + return extseqnr; + } + + /** Returns the sequence number of this packet. */ + uint16_t GetSequenceNumber() const + { + return (uint16_t)(extseqnr&0x0000FFFF); + } + + /** Sets the extended sequence number of this packet to \c seq. */ + void SetExtendedSequenceNumber(uint32_t seq) + { + extseqnr = seq; + } + + /** Returns the timestamp of this packet. */ + uint32_t GetTimestamp() const + { + return timestamp; + } + + /** Returns the SSRC identifier stored in this packet. */ + uint32_t GetSSRC() const + { + return ssrc; + } + + /** Returns a pointer to the data of the entire packet. */ + uint8_t *GetPacketData() const + { + return packet; + } + + /** Returns a pointer to the actual payload data. */ + uint8_t *GetPayloadData() const + { + return payload; + } + + /** Returns the length of the entire packet. */ + std::size_t GetPacketLength() const + { + return packetlength; + } + + /** Returns the payload length. */ + std::size_t GetPayloadLength() const + { + return payloadlength; + } + + /** If a header extension is present, this function returns the extension identifier. */ + uint16_t GetExtensionID() const + { + return extid; + } + + /** Returns the length of the header extension data. */ + uint8_t *GetExtensionData() const + { + return extension; + } + + /** Returns the length of the header extension data. */ + std::size_t GetExtensionLength() const + { + return extensionlength; + } +#ifdef RTPDEBUG + void Dump(); +#endif // RTPDEBUG + + /** Returns the time at which this packet was received. + * When an RTPPacket instance is created from an RTPRawPacket instance, the raw packet's + * reception time is stored in the RTPPacket instance. This function then retrieves that + * time. + */ + RTPTime GetReceiveTime() const + { + return receivetime; + } + +private: + void Clear(); + int ParseRawPacket(RTPRawPacket &rawpack); + int BuildPacket( + uint8_t payloadtype, + const void *payloaddata, + std::size_t payloadlen, + uint16_t seqnr, + uint32_t timestamp, + uint32_t ssrc, + bool gotmarker, + uint8_t numcsrcs, + const uint32_t *csrcs, + bool gotextension, + uint16_t extensionid, + uint16_t extensionlen_numwords, + const void *extensiondata, + void *buffer, + std::size_t maxsize); + + template + T qToHost(const T& x) const { + return m_littleEndian ? qToLittleEndian(x) : qToBigEndian(x); + } + + int error; + bool m_littleEndian; + + bool hasextension,hasmarker; + int numcsrcs; + + uint8_t payloadtype; + uint32_t extseqnr,timestamp,ssrc; + uint8_t *packet,*payload; + std::size_t packetlength,payloadlength; + + uint16_t extid; + uint8_t *extension; + std::size_t extensionlength; + + bool externalbuffer; + + RTPTime receivetime; +}; + +} // end namespace + +#endif // RTPPACKET_H + diff --git a/qrtplib/rtppacketbuilder.cpp b/qrtplib/rtppacketbuilder.cpp index bc91c3583..5cee190d8 100644 --- a/qrtplib/rtppacketbuilder.cpp +++ b/qrtplib/rtppacketbuilder.cpp @@ -9,7 +9,7 @@ This library was developed at the Expertise Centre for Digital Media (http://www.edm.uhasselt.be), a research center of the Hasselt University - (http://www.uhasselt.be). The library is based upon work done for + (http://www.uhasselt.be). The library is based upon work done for my thesis at the School for Knowledge Technology (Belgium/The Netherlands). Permission is hereby granted, free of charge, to any person obtaining a @@ -46,6 +46,21 @@ namespace qrtplib RTPPacketBuilder::RTPPacketBuilder(RTPRandom &r) : rtprnd(r), lastwallclocktime(0,0) { init = false; + deftsset = false; + defaultpayloadtype = 0; + lastrtptimestamp = 0; + ssrc = 0; + numcsrcs = 0; + defmarkset = false; + defaultmark = false; + defaulttimestampinc = 0; + timestamp = 0; + buffer = 0; + numpackets = 0; + seqnr = 0; + numpayloadbytes = 0; + prevrtptimestamp = 0; + defptset = false; } RTPPacketBuilder::~RTPPacketBuilder() @@ -62,22 +77,22 @@ int RTPPacketBuilder::Init(std::size_t max) if (max <= 0) { return ERR_RTP_PACKBUILD_INVALIDMAXPACKETSIZE; } - + maxpacksize = max; buffer = new uint8_t[max]; if (buffer == 0) { return ERR_RTP_OUTOFMEM; } packetlength = 0; - + CreateNewSSRC(); deftsset = false; defptset = false; defmarkset = false; - + numcsrcs = 0; - + init = true; return 0; } @@ -102,7 +117,7 @@ int RTPPacketBuilder::SetMaximumPacketSize(std::size_t max) if (newbuf == 0) { return ERR_RTP_OUTOFMEM; } - + delete[] buffer; buffer = newbuf; maxpacksize = max; @@ -135,7 +150,7 @@ int RTPPacketBuilder::DeleteCSRC(uint32_t csrc) if (!init) { return ERR_RTP_PACKBUILD_NOTINIT; } - + int i = 0; bool found = false; @@ -151,7 +166,7 @@ int RTPPacketBuilder::DeleteCSRC(uint32_t csrc) if (!found) { return ERR_RTP_PACKBUILD_CSRCNOTINLIST; } - + // move the last csrc in the place of the deleted one numcsrcs--; if (numcsrcs > 0 && numcsrcs != i) { @@ -184,13 +199,13 @@ uint32_t RTPPacketBuilder::CreateNewSSRC() uint32_t RTPPacketBuilder::CreateNewSSRC(RTPSources &sources) { bool found; - + do { ssrc = rtprnd.GetRandom32(); found = sources.GotEntry(ssrc); } while (found); - + timestamp = rtprnd.GetRandom32(); seqnr = rtprnd.GetRandom16(); @@ -273,7 +288,7 @@ int RTPPacketBuilder::PrivateBuildPacket(const void *data, std::size_t len, lastrtptimestamp = timestamp; prevrtptimestamp = timestamp; } - + numpayloadbytes += (uint32_t)p.GetPayloadLength(); numpackets++; timestamp += timestampinc; diff --git a/qrtplib/rtprandom.cpp b/qrtplib/rtprandom.cpp index 56b3bd165..1c28c5df4 100644 --- a/qrtplib/rtprandom.cpp +++ b/qrtplib/rtprandom.cpp @@ -9,7 +9,7 @@ This library was developed at the Expertise Centre for Digital Media (http://www.edm.uhasselt.be), a research center of the Hasselt University - (http://www.uhasselt.be). The library is based upon work done for + (http://www.uhasselt.be). The library is based upon work done for my thesis at the School for Knowledge Technology (Belgium/The Netherlands). Permission is hereby granted, free of charge, to any person obtaining a @@ -35,13 +35,11 @@ #include "rtprandom.h" #include "rtprandomurandom.h" #include "rtprandomrand48.h" + #include -#ifndef WIN32 - #include -#else - #include - #include -#endif // WIN32 +#include + +#include //#include "rtpdebug.h" @@ -51,24 +49,15 @@ namespace qrtplib uint32_t RTPRandom::PickSeed() { uint32_t x; -// TODO: do it for MinGW see sdrbase/util/uid.h,cpp + x = (uint32_t) getpid(); + QDateTime currentDateTime = QDateTime::currentDateTime(); + x += currentDateTime.toTime_t(); #if defined(WIN32) - x = (uint32_t)GetCurrentProcessId(); - - FILETIME ft; - SYSTEMTIME st; - - GetSystemTime(&st); - SystemTimeToFileTime(&st,&ft); - - x += ft.dwLowDateTime; - x ^= (uint32_t)((uint8_t *)this - (uint8_t *)0); + x += QDateTime::currentMSecsSinceEpoch() % 1000; #else - x = (uint32_t)getpid(); - x += (uint32_t)time(0); x += (uint32_t)clock(); - x ^= (uint32_t)((uint8_t *)this - (uint8_t *)0); #endif + x ^= (uint32_t)((uint8_t *)this - (uint8_t *)0); return x; } @@ -82,7 +71,7 @@ RTPRandom *RTPRandom::CreateDefaultRandomNumberGenerator() delete r; rRet = new RTPRandomRand48(); } - + return rRet; } diff --git a/qrtplib/rtprawpacket.h b/qrtplib/rtprawpacket.h new file mode 100644 index 000000000..0c18caa26 --- /dev/null +++ b/qrtplib/rtprawpacket.h @@ -0,0 +1,183 @@ +/* + Rewritten to fit into the Qt Network framework + Copyright (c) 2018 Edouard Griffiths, F4EXB + + This file is a part of JRTPLIB + Copyright (c) 1999-2017 Jori Liesenborgs + + Contact: jori.liesenborgs@gmail.com + + This library was developed at the Expertise Centre for Digital Media + (http://www.edm.uhasselt.be), a research center of the Hasselt University + (http://www.uhasselt.be). The library is based upon work done for + my thesis at the School for Knowledge Technology (Belgium/The Netherlands). + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. + +*/ + +/** + * \file rtprawpacket.h + */ + +#ifndef RTPRAWPACKET_H + +#define RTPRAWPACKET_H + +//#include "rtpconfig.h" +#include "rtptimeutilities.h" +//#include "rtpaddress.h" +//#include "rtptypes.h" +//#include "rtpmemoryobject.h" +#include +#include + +namespace qrtplib +{ + +/** This class is used by the transmission component to store the incoming RTP and RTCP data in. */ +class RTPRawPacket +{ +public: + /** Creates an instance which stores data from \c data with length \c datalen. + * Creates an instance which stores data from \c data with length \c datalen. Only the pointer + * to the data is stored, no actual copy is made! The address from which this packet originated + * is set to \c address and the time at which the packet was received is set to \c recvtime. + * The flag which indicates whether this data is RTP or RTCP data is set to \c rtp. A memory + * manager can be installed as well. + */ + RTPRawPacket(uint8_t *data, std::size_t datalen, QHostAddress *address, RTPTime &recvtime, bool rtp); + ~RTPRawPacket(); + + /** Returns the pointer to the data which is contained in this packet. */ + uint8_t *GetData() + { + return packetdata; + } + + /** Returns the length of the packet described by this instance. */ + std::size_t GetDataLength() const + { + return packetdatalength; + } + + /** Returns the time at which this packet was received. */ + RTPTime GetReceiveTime() const + { + return receivetime; + } + + /** Returns the address stored in this packet. */ + const QHostAddress *GetSenderAddress() const + { + return senderaddress; + } + + /** Returns \c true if this data is RTP data, \c false if it is RTCP data. */ + bool IsRTP() const + { + return isrtp; + } + + /** Sets the pointer to the data stored in this packet to zero. + * Sets the pointer to the data stored in this packet to zero. This will prevent + * a \c delete call for the actual data when the destructor of RTPRawPacket is called. + * This function is used by the RTPPacket and RTCPCompoundPacket classes to obtain + * the packet data (without having to copy it) and to make sure the data isn't deleted + * when the destructor of RTPRawPacket is called. + */ + void ZeroData() + { + packetdata = 0; + packetdatalength = 0; + } + + /** Allocates a number of bytes for RTP or RTCP data using the memory manager that + * was used for this raw packet instance, can be useful if the RTPRawPacket::SetData + * function will be used. */ + uint8_t *AllocateBytes(bool isrtp, int recvlen) const; + + /** Deallocates the previously stored data and replaces it with the data that's + * specified, can be useful when e.g. decrypting data in RTPSession::OnChangeIncomingData */ + void SetData(uint8_t *data, std::size_t datalen); + + /** Deallocates the currently stored RTPAddress instance and replaces it + * with the one that's specified (you probably don't need this function). */ + void SetSenderAddress(QHostAddress *address); +private: + void DeleteData(); + + uint8_t *packetdata; + std::size_t packetdatalength; + RTPTime receivetime; + QHostAddress *senderaddress; + bool isrtp; +}; + +inline RTPRawPacket::RTPRawPacket( + uint8_t *data, + std::size_t datalen, + QHostAddress *address, + RTPTime &recvtime, + bool rtp): receivetime(recvtime) +{ + packetdata = data; + packetdatalength = datalen; + senderaddress = address; + isrtp = rtp; +} + +inline RTPRawPacket::~RTPRawPacket() +{ + DeleteData(); +} + +inline void RTPRawPacket::DeleteData() +{ + if (packetdata) { + delete[] packetdata; + } + + packetdata = 0; +} + +inline uint8_t *RTPRawPacket::AllocateBytes(bool isrtp __attribute__((unused)), int recvlen) const +{ + return new uint8_t[recvlen]; +} + +inline void RTPRawPacket::SetData(uint8_t *data, std::size_t datalen) +{ + if (packetdata) { + delete[] packetdata; + } + + packetdata = data; + packetdatalength = datalen; +} + +inline void RTPRawPacket::SetSenderAddress(QHostAddress *address) +{ + senderaddress = address; +} + +} // end namespace + +#endif // RTPRAWPACKET_H + diff --git a/qrtplib/rtpstructs.h b/qrtplib/rtpstructs.h new file mode 100644 index 000000000..859674fe7 --- /dev/null +++ b/qrtplib/rtpstructs.h @@ -0,0 +1,130 @@ +/* + Rewritten to fit into the Qt Network framework + Copyright (c) 2018 Edouard Griffiths, F4EXB + + This file is a part of JRTPLIB + Copyright (c) 1999-2017 Jori Liesenborgs + + Contact: jori.liesenborgs@gmail.com + + This library was developed at the Expertise Centre for Digital Media + (http://www.edm.uhasselt.be), a research center of the Hasselt University + (http://www.uhasselt.be). The library is based upon work done for + my thesis at the School for Knowledge Technology (Belgium/The Netherlands). + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. + +*/ + +/** + * \file rtpstructs.h + */ + +#ifndef RTPSTRUCTS_H + +#define RTPSTRUCTS_H + +//#include "rtpconfig.h" +//#include "rtptypes.h" + +namespace qrtplib +{ + +struct RTPHeader +{ +#ifdef RTP_BIG_ENDIAN + uint8_t version:2; + uint8_t padding:1; + uint8_t extension:1; + uint8_t csrccount:4; + + uint8_t marker:1; + uint8_t payloadtype:7; +#else // little endian + uint8_t csrccount:4; + uint8_t extension:1; + uint8_t padding:1; + uint8_t version:2; + + uint8_t payloadtype:7; + uint8_t marker:1; +#endif // RTP_BIG_ENDIAN + + uint16_t sequencenumber; + uint32_t timestamp; + uint32_t ssrc; +}; + +struct RTPExtensionHeader +{ + uint16_t extid; + uint16_t length; +}; + +struct RTPSourceIdentifier +{ + uint32_t ssrc; +}; + +struct RTCPCommonHeader +{ +#ifdef RTP_BIG_ENDIAN + uint8_t version:2; + uint8_t padding:1; + uint8_t count:5; +#else // little endian + uint8_t count:5; + uint8_t padding:1; + uint8_t version:2; +#endif // RTP_BIG_ENDIAN + + uint8_t packettype; + uint16_t length; +}; + +struct RTCPSenderReport +{ + uint32_t ntptime_msw; + uint32_t ntptime_lsw; + uint32_t rtptimestamp; + uint32_t packetcount; + uint32_t octetcount; +}; + +struct RTCPReceiverReport +{ + uint32_t ssrc; // Identifies about which SSRC's data this report is... + uint8_t fractionlost; + uint8_t packetslost[3]; + uint32_t exthighseqnr; + uint32_t jitter; + uint32_t lsr; + uint32_t dlsr; +}; + +struct RTCPSDESHeader +{ + uint8_t sdesid; + uint8_t length; +}; + +} // end namespace + +#endif // RTPSTRUCTS + diff --git a/qrtplib/rtptimeutilities.cpp b/qrtplib/rtptimeutilities.cpp index 9554d57fd..451a6d8cf 100644 --- a/qrtplib/rtptimeutilities.cpp +++ b/qrtplib/rtptimeutilities.cpp @@ -9,7 +9,7 @@ This library was developed at the Expertise Centre for Digital Media (http://www.edm.uhasselt.be), a research center of the Hasselt University - (http://www.uhasselt.be). The library is based upon work done for + (http://www.uhasselt.be). The library is based upon work done for my thesis at the School for Knowledge Technology (Belgium/The Netherlands). Permission is hereby granted, free of charge, to any person obtaining a @@ -35,7 +35,7 @@ //#include "rtpconfig.h" #include "rtptimeutilities.h" -namespace jrtplib +namespace qrtplib { RTPTimeInitializerObject::RTPTimeInitializerObject() diff --git a/qrtplib/rtptimeutilities.h b/qrtplib/rtptimeutilities.h index 9c1078efa..ffdd93fb7 100644 --- a/qrtplib/rtptimeutilities.h +++ b/qrtplib/rtptimeutilities.h @@ -9,7 +9,7 @@ This library was developed at the Expertise Centre for Digital Media (http://www.edm.uhasselt.be), a research center of the Hasselt University - (http://www.uhasselt.be). The library is based upon work done for + (http://www.uhasselt.be). The library is based upon work done for my thesis at the School for Knowledge Technology (Belgium/The Netherlands). Permission is hereby granted, free of charge, to any person obtaining a @@ -51,11 +51,11 @@ #define C1000000 1000000ULL #define CEPOCH 11644473600000000ULL -namespace jrtplib +namespace qrtplib { /** - * This is a simple wrapper for the most significant word (MSW) and least + * This is a simple wrapper for the most significant word (MSW) and least * significant word (LSW) of an NTP timestamp. */ class RTPNTPTime @@ -74,25 +74,25 @@ private: }; /** This class is used to specify wallclock time, delay intervals etc. - * This class is used to specify wallclock time, delay intervals etc. + * This class is used to specify wallclock time, delay intervals etc. * It stores a number of seconds and a number of microseconds. */ class RTPTime { public: - /** Returns an RTPTime instance representing the current wallclock time. - * Returns an RTPTime instance representing the current wallclock time. This is expressed + /** Returns an RTPTime instance representing the current wallclock time. + * Returns an RTPTime instance representing the current wallclock time. This is expressed * as a number of seconds since 00:00:00 UTC, January 1, 1970. */ static RTPTime CurrentTime(); /** This function waits the amount of time specified in \c delay. */ static void Wait(const RTPTime &delay); - + /** Creates an RTPTime instance representing \c t, which is expressed in units of seconds. */ RTPTime(double t); - /** Creates an instance that corresponds to \c ntptime. + /** Creates an instance that corresponds to \c ntptime. * Creates an instance that corresponds to \c ntptime. If * the conversion cannot be made, both the seconds and the * microseconds are set to zero. @@ -155,7 +155,7 @@ inline RTPTime::RTPTime(RTPNTPTime ntptime) else { uint32_t sec = ntptime.GetMSW() - RTP_NTPTIMEOFFSET; - + double x = (double)ntptime.GetLSW(); x /= (65536.0*65536.0); x *= 1000000.0; @@ -233,7 +233,7 @@ inline RTPTime RTPTime::CurrentTime() inline RTPTime RTPTime::CurrentTime() { struct timeval tv; - + gettimeofday(&tv,0); return RTPTime((uint64_t)tv.tv_sec,(uint32_t)tv.tv_usec); } @@ -260,13 +260,13 @@ inline void RTPTime::Wait(const RTPTime &delay) } inline RTPTime &RTPTime::operator-=(const RTPTime &t) -{ +{ m_t -= t.m_t; return *this; } inline RTPTime &RTPTime::operator+=(const RTPTime &t) -{ +{ m_t += t.m_t; return *this; } @@ -279,7 +279,7 @@ inline RTPNTPTime RTPTime::GetNTPTime() const uint32_t msw = sec+RTP_NTPTIMEOFFSET; uint32_t lsw; double x; - + x = microsec/1000000.0; x *= (65536.0*65536.0); lsw = (uint32_t)x;