mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-25 01:50:21 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			633 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			633 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| 
 | |
|  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 "rtcpcompoundpacketbuilder.h"
 | |
| #include "rtcpsrpacket.h"
 | |
| #include "rtcprrpacket.h"
 | |
| #include "rtcpsdespacket.h"
 | |
| #include "rtcpbyepacket.h"
 | |
| #include "rtcpapppacket.h"
 | |
| #include <string.h>
 | |
| 
 | |
| namespace qrtplib
 | |
| {
 | |
| 
 | |
| RTCPCompoundPacketBuilder::RTCPCompoundPacketBuilder()
 | |
| {
 | |
|     byesize = 0;
 | |
|     appsize = 0;
 | |
|     maximumpacketsize = 0;
 | |
|     buffer = 0;
 | |
|     external = false;
 | |
|     arebuilding = false;
 | |
| }
 | |
| 
 | |
| RTCPCompoundPacketBuilder::~RTCPCompoundPacketBuilder()
 | |
| {
 | |
|     if (external)
 | |
|         compoundpacket = 0; // make sure RTCPCompoundPacket doesn't delete the external buffer
 | |
|     ClearBuildBuffers();
 | |
| }
 | |
| 
 | |
| void RTCPCompoundPacketBuilder::ClearBuildBuffers()
 | |
| {
 | |
|     report.Clear();
 | |
|     sdes.Clear();
 | |
| 
 | |
|     std::list<Buffer>::const_iterator it;
 | |
|     for (it = byepackets.begin(); it != byepackets.end(); it++)
 | |
|     {
 | |
|         if ((*it).packetdata)
 | |
|             delete[] (*it).packetdata;
 | |
|     }
 | |
|     for (it = apppackets.begin(); it != apppackets.end(); it++)
 | |
|     {
 | |
|         if ((*it).packetdata)
 | |
|             delete[] (*it).packetdata;
 | |
|     }
 | |
|     byepackets.clear();
 | |
|     apppackets.clear();
 | |
|     byesize = 0;
 | |
|     appsize = 0;
 | |
| }
 | |
| 
 | |
| int RTCPCompoundPacketBuilder::InitBuild(std::size_t maxpacketsize)
 | |
| {
 | |
|     if (arebuilding)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_ALREADYBUILDING;
 | |
|     if (compoundpacket)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_ALREADYBUILT;
 | |
| 
 | |
|     if (maxpacketsize < RTP_MINPACKETSIZE)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_MAXPACKETSIZETOOSMALL;
 | |
| 
 | |
|     maximumpacketsize = maxpacketsize;
 | |
|     buffer = 0;
 | |
|     external = false;
 | |
|     byesize = 0;
 | |
|     appsize = 0;
 | |
| 
 | |
|     arebuilding = true;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int RTCPCompoundPacketBuilder::InitBuild(void *externalbuffer, std::size_t buffersize)
 | |
| {
 | |
|     if (arebuilding)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_ALREADYBUILDING;
 | |
|     if (compoundpacket)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_ALREADYBUILT;
 | |
| 
 | |
|     if (buffersize < RTP_MINPACKETSIZE)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_BUFFERSIZETOOSMALL;
 | |
| 
 | |
|     maximumpacketsize = buffersize;
 | |
|     buffer = (uint8_t *) externalbuffer;
 | |
|     external = true;
 | |
|     byesize = 0;
 | |
|     appsize = 0;
 | |
| 
 | |
|     arebuilding = true;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int RTCPCompoundPacketBuilder::StartSenderReport(uint32_t senderssrc, const RTPNTPTime &ntptimestamp, uint32_t rtptimestamp, uint32_t packetcount, uint32_t octetcount)
 | |
| {
 | |
|     if (!arebuilding)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING;
 | |
| 
 | |
|     if (report.headerlength != 0)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_ALREADYGOTREPORT;
 | |
| 
 | |
|     std::size_t totalsize = byesize + appsize + sdes.NeededBytes();
 | |
|     std::size_t sizeleft = maximumpacketsize - totalsize;
 | |
|     std::size_t neededsize = sizeof(RTCPCommonHeader) + sizeof(uint32_t) + sizeof(RTCPSenderReport);
 | |
| 
 | |
|     if (neededsize > sizeleft)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT;
 | |
| 
 | |
|     // fill in some things
 | |
| 
 | |
|     report.headerlength = sizeof(uint32_t) + sizeof(RTCPSenderReport);
 | |
|     report.isSR = true;
 | |
| 
 | |
|     uint32_t *ssrc = (uint32_t *) report.headerdata;
 | |
|     *ssrc = qToBigEndian(senderssrc);
 | |
| 
 | |
|     RTCPSenderReport *sr = (RTCPSenderReport *) (report.headerdata + sizeof(uint32_t));
 | |
|     sr->ntptime_msw = qToBigEndian(ntptimestamp.GetMSW());
 | |
|     sr->ntptime_lsw = qToBigEndian(ntptimestamp.GetLSW());
 | |
|     sr->rtptimestamp = qToBigEndian(rtptimestamp);
 | |
|     sr->packetcount = qToBigEndian(packetcount);
 | |
|     sr->octetcount = qToBigEndian(octetcount);
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int RTCPCompoundPacketBuilder::StartReceiverReport(uint32_t senderssrc)
 | |
| {
 | |
|     if (!arebuilding)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING;
 | |
|     if (report.headerlength != 0)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_ALREADYGOTREPORT;
 | |
| 
 | |
|     std::size_t totalsize = byesize + appsize + sdes.NeededBytes();
 | |
|     std::size_t sizeleft = maximumpacketsize - totalsize;
 | |
|     std::size_t neededsize = sizeof(RTCPCommonHeader) + sizeof(uint32_t);
 | |
| 
 | |
|     if (neededsize > sizeleft)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT;
 | |
| 
 | |
|     // fill in some things
 | |
| 
 | |
|     report.headerlength = sizeof(uint32_t);
 | |
|     report.isSR = false;
 | |
| 
 | |
|     uint32_t *ssrc = (uint32_t *) report.headerdata;
 | |
|     *ssrc = qToBigEndian(senderssrc);
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int RTCPCompoundPacketBuilder::AddReportBlock(uint32_t ssrc, uint8_t fractionlost, int32_t packetslost, uint32_t exthighestseq, uint32_t jitter, uint32_t lsr, uint32_t dlsr)
 | |
| {
 | |
|     if (!arebuilding)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING;
 | |
|     if (report.headerlength == 0)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_REPORTNOTSTARTED;
 | |
| 
 | |
|     std::size_t totalothersize = byesize + appsize + sdes.NeededBytes();
 | |
|     std::size_t reportsizewithextrablock = report.NeededBytesWithExtraReportBlock();
 | |
| 
 | |
|     if ((totalothersize + reportsizewithextrablock) > maximumpacketsize)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT;
 | |
| 
 | |
|     uint8_t *buf = new uint8_t[sizeof(RTCPReceiverReport)];
 | |
| 
 | |
|     RTCPReceiverReport *rr = (RTCPReceiverReport *) buf;
 | |
|     uint32_t *packlost = (uint32_t *) &packetslost;
 | |
|     uint32_t packlost2 = (*packlost);
 | |
| 
 | |
|     rr->ssrc = qToBigEndian(ssrc);
 | |
|     rr->fractionlost = fractionlost;
 | |
|     rr->packetslost[2] = (uint8_t) (packlost2 & 0xFF);
 | |
|     rr->packetslost[1] = (uint8_t) ((packlost2 >> 8) & 0xFF);
 | |
|     rr->packetslost[0] = (uint8_t) ((packlost2 >> 16) & 0xFF);
 | |
|     rr->exthighseqnr = qToBigEndian(exthighestseq);
 | |
|     rr->jitter = qToBigEndian(jitter);
 | |
|     rr->lsr = qToBigEndian(lsr);
 | |
|     rr->dlsr = qToBigEndian(dlsr);
 | |
| 
 | |
|     report.reportblocks.push_back(Buffer(buf, sizeof(RTCPReceiverReport)));
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int RTCPCompoundPacketBuilder::AddSDESSource(uint32_t ssrc)
 | |
| {
 | |
|     if (!arebuilding)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING;
 | |
| 
 | |
|     std::size_t totalotherbytes = byesize + appsize + report.NeededBytes();
 | |
|     std::size_t sdessizewithextrasource = sdes.NeededBytesWithExtraSource();
 | |
| 
 | |
|     if ((totalotherbytes + sdessizewithextrasource) > maximumpacketsize)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT;
 | |
| 
 | |
|     int status;
 | |
| 
 | |
|     if ((status = sdes.AddSSRC(ssrc)) < 0)
 | |
|         return status;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int RTCPCompoundPacketBuilder::AddSDESNormalItem(RTCPSDESPacket::ItemType t, const void *itemdata, uint8_t itemlength)
 | |
| {
 | |
|     if (!arebuilding)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING;
 | |
|     if (sdes.sdessources.empty())
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOCURRENTSOURCE;
 | |
| 
 | |
|     uint8_t itemid;
 | |
| 
 | |
|     switch (t)
 | |
|     {
 | |
|     case RTCPSDESPacket::CNAME:
 | |
|         itemid = RTCP_SDES_ID_CNAME;
 | |
|         break;
 | |
|     case RTCPSDESPacket::NAME:
 | |
|         itemid = RTCP_SDES_ID_NAME;
 | |
|         break;
 | |
|     case RTCPSDESPacket::EMAIL:
 | |
|         itemid = RTCP_SDES_ID_EMAIL;
 | |
|         break;
 | |
|     case RTCPSDESPacket::PHONE:
 | |
|         itemid = RTCP_SDES_ID_PHONE;
 | |
|         break;
 | |
|     case RTCPSDESPacket::LOC:
 | |
|         itemid = RTCP_SDES_ID_LOCATION;
 | |
|         break;
 | |
|     case RTCPSDESPacket::TOOL:
 | |
|         itemid = RTCP_SDES_ID_TOOL;
 | |
|         break;
 | |
|     case RTCPSDESPacket::NOTE:
 | |
|         itemid = RTCP_SDES_ID_NOTE;
 | |
|         break;
 | |
|     default:
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_INVALIDITEMTYPE;
 | |
|     }
 | |
| 
 | |
|     std::size_t totalotherbytes = byesize + appsize + report.NeededBytes();
 | |
|     std::size_t sdessizewithextraitem = sdes.NeededBytesWithExtraItem(itemlength);
 | |
| 
 | |
|     if ((sdessizewithextraitem + totalotherbytes) > maximumpacketsize)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT;
 | |
| 
 | |
|     uint8_t *buf;
 | |
|     std::size_t len;
 | |
| 
 | |
|     buf = new uint8_t[sizeof(RTCPSDESHeader) + (std::size_t) itemlength];
 | |
|     len = sizeof(RTCPSDESHeader) + (std::size_t) itemlength;
 | |
| 
 | |
|     RTCPSDESHeader *sdeshdr = (RTCPSDESHeader *) (buf);
 | |
| 
 | |
|     sdeshdr->sdesid = itemid;
 | |
|     sdeshdr->length = itemlength;
 | |
|     if (itemlength != 0)
 | |
|         memcpy((buf + sizeof(RTCPSDESHeader)), itemdata, (std::size_t) itemlength);
 | |
| 
 | |
|     sdes.AddItem(buf, len);
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| #ifdef RTP_SUPPORT_SDESPRIV
 | |
| int RTCPCompoundPacketBuilder::AddSDESPrivateItem(const void *prefixdata, uint8_t prefixlength, const void *valuedata, uint8_t valuelength)
 | |
| {
 | |
|     if (!arebuilding)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING;
 | |
|     if (sdes.sdessources.empty())
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOCURRENTSOURCE;
 | |
| 
 | |
|     std::size_t itemlength = ((std::size_t) prefixlength) + 1 + ((std::size_t) valuelength);
 | |
|     if (itemlength > 255)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_TOTALITEMLENGTHTOOBIG;
 | |
| 
 | |
|     std::size_t totalotherbytes = byesize + appsize + report.NeededBytes();
 | |
|     std::size_t sdessizewithextraitem = sdes.NeededBytesWithExtraItem(itemlength);
 | |
| 
 | |
|     if ((sdessizewithextraitem + totalotherbytes) > maximumpacketsize)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT;
 | |
| 
 | |
|     uint8_t *buf;
 | |
|     std::size_t len;
 | |
| 
 | |
|     buf = new uint8_t[sizeof(RTCPSDESHeader) + itemlength];
 | |
|     len = sizeof(RTCPSDESHeader) + (std::size_t) itemlength;
 | |
| 
 | |
|     RTCPSDESHeader *sdeshdr = (RTCPSDESHeader *) (buf);
 | |
| 
 | |
|     sdeshdr->sdesid = RTCP_SDES_ID_PRIVATE;
 | |
|     sdeshdr->length = itemlength;
 | |
| 
 | |
|     buf[sizeof(RTCPSDESHeader)] = prefixlength;
 | |
|     if (prefixlength != 0)
 | |
|         memcpy((buf + sizeof(RTCPSDESHeader) + 1), prefixdata, (std::size_t) prefixlength);
 | |
|     if (valuelength != 0)
 | |
|         memcpy((buf + sizeof(RTCPSDESHeader) + 1 + (std::size_t) prefixlength), valuedata, (std::size_t) valuelength);
 | |
| 
 | |
|     sdes.AddItem(buf, len);
 | |
|     return 0;
 | |
| }
 | |
| #endif // RTP_SUPPORT_SDESPRIV
 | |
| 
 | |
| int RTCPCompoundPacketBuilder::AddBYEPacket(uint32_t *ssrcs, uint8_t numssrcs, const void *reasondata, uint8_t reasonlength)
 | |
| {
 | |
|     if (!arebuilding)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING;
 | |
| 
 | |
|     if (numssrcs > 31)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_TOOMANYSSRCS;
 | |
| 
 | |
|     std::size_t packsize = sizeof(RTCPCommonHeader) + sizeof(uint32_t) * ((std::size_t) numssrcs);
 | |
|     std::size_t zerobytes = 0;
 | |
| 
 | |
|     if (reasonlength > 0)
 | |
|     {
 | |
|         packsize += 1; // 1 byte for the length;
 | |
|         packsize += (std::size_t) reasonlength;
 | |
| 
 | |
|         std::size_t r = (packsize & 0x03);
 | |
|         if (r != 0)
 | |
|         {
 | |
|             zerobytes = 4 - r;
 | |
|             packsize += zerobytes;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     std::size_t totalotherbytes = appsize + byesize + sdes.NeededBytes() + report.NeededBytes();
 | |
| 
 | |
|     if ((totalotherbytes + packsize) > maximumpacketsize)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT;
 | |
| 
 | |
|     uint8_t *buf;
 | |
|     std::size_t numwords;
 | |
| 
 | |
|     buf = new uint8_t[packsize];
 | |
| 
 | |
|     RTCPCommonHeader *hdr = (RTCPCommonHeader *) buf;
 | |
| 
 | |
|     hdr->version = 2;
 | |
|     hdr->padding = 0;
 | |
|     hdr->count = numssrcs;
 | |
| 
 | |
|     numwords = packsize / sizeof(uint32_t);
 | |
|     hdr->length = qToBigEndian((uint16_t) (numwords - 1));
 | |
|     hdr->packettype = RTP_RTCPTYPE_BYE;
 | |
| 
 | |
|     uint32_t *sources = (uint32_t *) (buf + sizeof(RTCPCommonHeader));
 | |
|     uint8_t srcindex;
 | |
| 
 | |
|     for (srcindex = 0; srcindex < numssrcs; srcindex++)
 | |
|         sources[srcindex] = qToBigEndian(ssrcs[srcindex]);
 | |
| 
 | |
|     if (reasonlength != 0)
 | |
|     {
 | |
|         std::size_t offset = sizeof(RTCPCommonHeader) + ((std::size_t) numssrcs) * sizeof(uint32_t);
 | |
| 
 | |
|         buf[offset] = reasonlength;
 | |
|         memcpy((buf + offset + 1), reasondata, (std::size_t) reasonlength);
 | |
|         for (std::size_t i = 0; i < zerobytes; i++)
 | |
|             buf[packsize - 1 - i] = 0;
 | |
|     }
 | |
| 
 | |
|     byepackets.push_back(Buffer(buf, packsize));
 | |
|     byesize += packsize;
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int RTCPCompoundPacketBuilder::AddAPPPacket(uint8_t subtype, uint32_t ssrc, const uint8_t name[4], const void *appdata, std::size_t appdatalen)
 | |
| {
 | |
|     if (!arebuilding)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING;
 | |
|     if (subtype > 31)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_ILLEGALSUBTYPE;
 | |
|     if ((appdatalen % 4) != 0)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_ILLEGALAPPDATALENGTH;
 | |
| 
 | |
|     std::size_t appdatawords = appdatalen / 4;
 | |
| 
 | |
|     if ((appdatawords + 2) > 65535)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_APPDATALENTOOBIG;
 | |
| 
 | |
|     std::size_t packsize = sizeof(RTCPCommonHeader) + sizeof(uint32_t) * 2 + appdatalen;
 | |
|     std::size_t totalotherbytes = appsize + byesize + sdes.NeededBytes() + report.NeededBytes();
 | |
| 
 | |
|     if ((totalotherbytes + packsize) > maximumpacketsize)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT;
 | |
| 
 | |
|     uint8_t *buf;
 | |
| 
 | |
|     buf = new uint8_t[packsize];
 | |
| 
 | |
|     RTCPCommonHeader *hdr = (RTCPCommonHeader *) buf;
 | |
| 
 | |
|     hdr->version = 2;
 | |
|     hdr->padding = 0;
 | |
|     hdr->count = subtype;
 | |
| 
 | |
|     hdr->length = qToBigEndian((uint16_t) (appdatawords + 2));
 | |
|     hdr->packettype = RTP_RTCPTYPE_APP;
 | |
| 
 | |
|     uint32_t *source = (uint32_t *) (buf + sizeof(RTCPCommonHeader));
 | |
|     *source = qToBigEndian(ssrc);
 | |
| 
 | |
|     buf[sizeof(RTCPCommonHeader) + sizeof(uint32_t) + 0] = name[0];
 | |
|     buf[sizeof(RTCPCommonHeader) + sizeof(uint32_t) + 1] = name[1];
 | |
|     buf[sizeof(RTCPCommonHeader) + sizeof(uint32_t) + 2] = name[2];
 | |
|     buf[sizeof(RTCPCommonHeader) + sizeof(uint32_t) + 3] = name[3];
 | |
| 
 | |
|     if (appdatalen > 0)
 | |
|         memcpy((buf + sizeof(RTCPCommonHeader) + sizeof(uint32_t) * 2), appdata, appdatalen);
 | |
| 
 | |
|     apppackets.push_back(Buffer(buf, packsize));
 | |
|     appsize += packsize;
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int RTCPCompoundPacketBuilder::EndBuild()
 | |
| {
 | |
|     if (!arebuilding)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOTBUILDING;
 | |
|     if (report.headerlength == 0)
 | |
|         return ERR_RTP_RTCPCOMPPACKBUILDER_NOREPORTPRESENT;
 | |
| 
 | |
|     uint8_t *buf;
 | |
|     std::size_t len;
 | |
| 
 | |
|     len = appsize + byesize + report.NeededBytes() + sdes.NeededBytes();
 | |
| 
 | |
|     if (!external)
 | |
|     {
 | |
|         buf = new uint8_t[len];
 | |
|     }
 | |
|     else
 | |
|         buf = buffer;
 | |
| 
 | |
|     uint8_t *curbuf = buf;
 | |
|     RTCPPacket *p;
 | |
| 
 | |
|     // first, we'll add all report info
 | |
| 
 | |
|     {
 | |
|         bool firstpacket = true;
 | |
|         bool done = false;
 | |
|         std::list<Buffer>::const_iterator it = report.reportblocks.begin();
 | |
|         do
 | |
|         {
 | |
|             RTCPCommonHeader *hdr = (RTCPCommonHeader *) curbuf;
 | |
|             std::size_t offset;
 | |
| 
 | |
|             hdr->version = 2;
 | |
|             hdr->padding = 0;
 | |
| 
 | |
|             if (firstpacket && report.isSR)
 | |
|             {
 | |
|                 hdr->packettype = RTP_RTCPTYPE_SR;
 | |
|                 memcpy((curbuf + sizeof(RTCPCommonHeader)), report.headerdata, report.headerlength);
 | |
|                 offset = sizeof(RTCPCommonHeader) + report.headerlength;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 hdr->packettype = RTP_RTCPTYPE_RR;
 | |
|                 memcpy((curbuf + sizeof(RTCPCommonHeader)), report.headerdata, sizeof(uint32_t));
 | |
|                 offset = sizeof(RTCPCommonHeader) + sizeof(uint32_t);
 | |
|             }
 | |
|             firstpacket = false;
 | |
| 
 | |
|             uint8_t count = 0;
 | |
| 
 | |
|             while (it != report.reportblocks.end() && count < 31)
 | |
|             {
 | |
|                 memcpy(curbuf + offset, (*it).packetdata, (*it).packetlength);
 | |
|                 offset += (*it).packetlength;
 | |
|                 count++;
 | |
|                 it++;
 | |
|             }
 | |
| 
 | |
|             std::size_t numwords = offset / sizeof(uint32_t);
 | |
| 
 | |
|             hdr->length = qToBigEndian((uint16_t) (numwords - 1));
 | |
|             hdr->count = count;
 | |
| 
 | |
|             // add entry in parent's list
 | |
|             if (hdr->packettype == RTP_RTCPTYPE_SR)
 | |
|                 p = new RTCPSRPacket(curbuf, offset);
 | |
|             else
 | |
|                 p = new RTCPRRPacket(curbuf, offset);
 | |
|             rtcppacklist.push_back(p);
 | |
| 
 | |
|             curbuf += offset;
 | |
|             if (it == report.reportblocks.end())
 | |
|                 done = true;
 | |
|         } while (!done);
 | |
|     }
 | |
| 
 | |
|     // then, we'll add the sdes info
 | |
| 
 | |
|     if (!sdes.sdessources.empty())
 | |
|     {
 | |
|         bool done = false;
 | |
|         std::list<SDESSource *>::const_iterator sourceit = sdes.sdessources.begin();
 | |
| 
 | |
|         do
 | |
|         {
 | |
|             RTCPCommonHeader *hdr = (RTCPCommonHeader *) curbuf;
 | |
|             std::size_t offset = sizeof(RTCPCommonHeader);
 | |
| 
 | |
|             hdr->version = 2;
 | |
|             hdr->padding = 0;
 | |
|             hdr->packettype = RTP_RTCPTYPE_SDES;
 | |
| 
 | |
|             uint8_t sourcecount = 0;
 | |
| 
 | |
|             while (sourceit != sdes.sdessources.end() && sourcecount < 31)
 | |
|             {
 | |
|                 uint32_t *ssrc = (uint32_t *) (curbuf + offset);
 | |
|                 *ssrc = qToBigEndian((*sourceit)->ssrc);
 | |
|                 offset += sizeof(uint32_t);
 | |
| 
 | |
|                 std::list<Buffer>::const_iterator itemit, itemend;
 | |
| 
 | |
|                 itemit = (*sourceit)->items.begin();
 | |
|                 itemend = (*sourceit)->items.end();
 | |
|                 while (itemit != itemend)
 | |
|                 {
 | |
|                     memcpy(curbuf + offset, (*itemit).packetdata, (*itemit).packetlength);
 | |
|                     offset += (*itemit).packetlength;
 | |
|                     itemit++;
 | |
|                 }
 | |
| 
 | |
|                 curbuf[offset] = 0; // end of item list;
 | |
|                 offset++;
 | |
| 
 | |
|                 std::size_t r = offset & 0x03;
 | |
|                 if (r != 0) // align to 32 bit boundary
 | |
|                 {
 | |
|                     std::size_t num = 4 - r;
 | |
|                     std::size_t i;
 | |
| 
 | |
|                     for (i = 0; i < num; i++)
 | |
|                         curbuf[offset + i] = 0;
 | |
|                     offset += num;
 | |
|                 }
 | |
| 
 | |
|                 sourceit++;
 | |
|                 sourcecount++;
 | |
|             }
 | |
| 
 | |
|             std::size_t numwords = offset / 4;
 | |
| 
 | |
|             hdr->count = sourcecount;
 | |
|             hdr->length = qToBigEndian((uint16_t) (numwords - 1));
 | |
| 
 | |
|             p = new RTCPSDESPacket(curbuf, offset);
 | |
|             rtcppacklist.push_back(p);
 | |
| 
 | |
|             curbuf += offset;
 | |
|             if (sourceit == sdes.sdessources.end())
 | |
|                 done = true;
 | |
|         } while (!done);
 | |
|     }
 | |
| 
 | |
|     // adding the app data
 | |
| 
 | |
|     {
 | |
|         std::list<Buffer>::const_iterator it;
 | |
| 
 | |
|         for (it = apppackets.begin(); it != apppackets.end(); it++)
 | |
|         {
 | |
|             memcpy(curbuf, (*it).packetdata, (*it).packetlength);
 | |
| 
 | |
|             p = new RTCPAPPPacket(curbuf, (*it).packetlength);
 | |
|             rtcppacklist.push_back(p);
 | |
| 
 | |
|             curbuf += (*it).packetlength;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // adding bye packets
 | |
| 
 | |
|     {
 | |
|         std::list<Buffer>::const_iterator it;
 | |
| 
 | |
|         for (it = byepackets.begin(); it != byepackets.end(); it++)
 | |
|         {
 | |
|             memcpy(curbuf, (*it).packetdata, (*it).packetlength);
 | |
| 
 | |
|             p = new RTCPBYEPacket(curbuf, (*it).packetlength);
 | |
|             rtcppacklist.push_back(p);
 | |
| 
 | |
|             curbuf += (*it).packetlength;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     compoundpacket = buf;
 | |
|     compoundpacketlength = len;
 | |
|     arebuilding = false;
 | |
|     ClearBuildBuffers();
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| } // end namespace
 | |
| 
 |