mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-11-03 21:20:31 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			673 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			673 lines
		
	
	
		
			20 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)];
 | 
						|
    if (buf == 0)
 | 
						|
        return ERR_RTP_OUTOFMEM;
 | 
						|
 | 
						|
    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];
 | 
						|
    if (buf == 0)
 | 
						|
        return ERR_RTP_OUTOFMEM;
 | 
						|
    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];
 | 
						|
    if (buf == 0)
 | 
						|
        return ERR_RTP_OUTOFMEM;
 | 
						|
    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];
 | 
						|
    if (buf == 0)
 | 
						|
        return ERR_RTP_OUTOFMEM;
 | 
						|
 | 
						|
    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];
 | 
						|
    if (buf == 0)
 | 
						|
        return ERR_RTP_OUTOFMEM;
 | 
						|
 | 
						|
    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];
 | 
						|
        if (buf == 0)
 | 
						|
            return ERR_RTP_OUTOFMEM;
 | 
						|
    }
 | 
						|
    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);
 | 
						|
            if (p == 0)
 | 
						|
            {
 | 
						|
                if (!external)
 | 
						|
                    delete[] buf;
 | 
						|
                ClearPacketList();
 | 
						|
                return ERR_RTP_OUTOFMEM;
 | 
						|
            }
 | 
						|
            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);
 | 
						|
            if (p == 0)
 | 
						|
            {
 | 
						|
                if (!external)
 | 
						|
                    delete[] buf;
 | 
						|
                ClearPacketList();
 | 
						|
                return ERR_RTP_OUTOFMEM;
 | 
						|
            }
 | 
						|
            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);
 | 
						|
            if (p == 0)
 | 
						|
            {
 | 
						|
                if (!external)
 | 
						|
                    delete[] buf;
 | 
						|
                ClearPacketList();
 | 
						|
                return ERR_RTP_OUTOFMEM;
 | 
						|
            }
 | 
						|
            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);
 | 
						|
            if (p == 0)
 | 
						|
            {
 | 
						|
                if (!external)
 | 
						|
                    delete[] buf;
 | 
						|
                ClearPacketList();
 | 
						|
                return ERR_RTP_OUTOFMEM;
 | 
						|
            }
 | 
						|
            rtcppacklist.push_back(p);
 | 
						|
 | 
						|
            curbuf += (*it).packetlength;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    compoundpacket = buf;
 | 
						|
    compoundpacketlength = len;
 | 
						|
    arebuilding = false;
 | 
						|
    ClearBuildBuffers();
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
} // end namespace
 | 
						|
 |