diff options
author | Jeffrey C. Ollie <jeff@ocjtech.us> | 2009-02-27 09:05:15 -0600 |
---|---|---|
committer | Jeffrey C. Ollie <jeff@ocjtech.us> | 2009-02-27 09:05:15 -0600 |
commit | db73f0bb24b3b810b365b746a6e94d55be1e6450 (patch) | |
tree | b706ce257622e4498e738f1c23496a89b642219a /src/rtcppacketbuilder.cpp | |
download | jrtplib-db73f0bb24b3b810b365b746a6e94d55be1e6450.tar.gz jrtplib-db73f0bb24b3b810b365b746a6e94d55be1e6450.tar.xz jrtplib-db73f0bb24b3b810b365b746a6e94d55be1e6450.zip |
initial import of 3.7.1 files
Diffstat (limited to 'src/rtcppacketbuilder.cpp')
-rw-r--r-- | src/rtcppacketbuilder.cpp | 736 |
1 files changed, 736 insertions, 0 deletions
diff --git a/src/rtcppacketbuilder.cpp b/src/rtcppacketbuilder.cpp new file mode 100644 index 0000000..7e07d8f --- /dev/null +++ b/src/rtcppacketbuilder.cpp @@ -0,0 +1,736 @@ +/* + + This file is a part of JRTPLIB + Copyright (c) 1999-2007 Jori Liesenborgs + + Contact: jori.liesenborgs@gmail.com + + This library was developed at the "Expertisecentrum Digitale 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 "rtcppacketbuilder.h" +#include "rtpsources.h" +#include "rtppacketbuilder.h" +#include "rtcpscheduler.h" +#include "rtpsourcedata.h" +#include "rtcpcompoundpacketbuilder.h" +#include "rtpmemorymanager.h" + +#include "rtpdebug.h" + +RTCPPacketBuilder::RTCPPacketBuilder(RTPSources &s,RTPPacketBuilder &pb,RTPMemoryManager *mgr) + : RTPMemoryObject(mgr),sources(s),rtppacketbuilder(pb),prevbuildtime(0,0),transmissiondelay(0,0),ownsdesinfo(mgr) +{ + init = false; +#if (defined(WIN32) || defined(_WIN32_WCE)) + timeinit.Dummy(); +#endif // WIN32 || _WIN32_WCE +} + +RTCPPacketBuilder::~RTCPPacketBuilder() +{ + Destroy(); +} + +int RTCPPacketBuilder::Init(size_t maxpacksize,double tsunit,const void *cname,size_t cnamelen) +{ + if (init) + return ERR_RTP_RTCPPACKETBUILDER_ALREADYINIT; + if (maxpacksize < RTP_MINPACKETSIZE) + return ERR_RTP_RTCPPACKETBUILDER_ILLEGALMAXPACKSIZE; + if (tsunit < 0.0) + return ERR_RTP_RTCPPACKETBUILDER_ILLEGALTIMESTAMPUNIT; + + if (cnamelen>255) + cnamelen = 255; + + maxpacketsize = maxpacksize; + timestampunit = tsunit; + + int status; + + if ((status = ownsdesinfo.SetCNAME((const uint8_t *)cname,cnamelen)) < 0) + return status; + + ClearAllSourceFlags(); + + interval_name = -1; + interval_email = -1; + interval_location = -1; + interval_phone = -1; + interval_tool = -1; + interval_note = -1; + + sdesbuildcount = 0; + transmissiondelay = RTPTime(0,0); + + firstpacket = true; + processingsdes = false; + init = true; + return 0; +} + +void RTCPPacketBuilder::Destroy() +{ + if (!init) + return; + ownsdesinfo.Clear(); + init = false; +} + +int RTCPPacketBuilder::BuildNextPacket(RTCPCompoundPacket **pack) +{ + if (!init) + return ERR_RTP_RTCPPACKETBUILDER_NOTINIT; + + RTCPCompoundPacketBuilder *rtcpcomppack; + int status; + bool sender = false; + RTPSourceData *srcdat; + + *pack = 0; + + rtcpcomppack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPCOMPOUNDPACKETBUILDER) RTCPCompoundPacketBuilder(GetMemoryManager()); + if (rtcpcomppack == 0) + return ERR_RTP_OUTOFMEM; + + if ((status = rtcpcomppack->InitBuild(maxpacketsize)) < 0) + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + return status; + } + + if ((srcdat = sources.GetOwnSourceInfo()) != 0) + { + if (srcdat->IsSender()) + sender = true; + } + + uint32_t ssrc = rtppacketbuilder.GetSSRC(); + RTPTime curtime = RTPTime::CurrentTime(); + + if (sender) + { + RTPTime rtppacktime = rtppacketbuilder.GetPacketTime(); + uint32_t rtppacktimestamp = rtppacketbuilder.GetPacketTimestamp(); + uint32_t packcount = rtppacketbuilder.GetPacketCount(); + uint32_t octetcount = rtppacketbuilder.GetPayloadOctetCount(); + RTPTime diff = curtime; + diff -= rtppacktime; + diff += transmissiondelay; // the sample being sampled at this very instant will need a larger timestamp + + uint32_t tsdiff = (uint32_t)((diff.GetDouble()/timestampunit)+0.5); + uint32_t rtptimestamp = rtppacktimestamp+tsdiff; + RTPNTPTime ntptimestamp = curtime.GetNTPTime(); + + if ((status = rtcpcomppack->StartSenderReport(ssrc,ntptimestamp,rtptimestamp,packcount,octetcount)) < 0) + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT) + return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON; + return status; + } + } + else + { + if ((status = rtcpcomppack->StartReceiverReport(ssrc)) < 0) + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT) + return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON; + return status; + } + } + + uint8_t *owncname; + size_t owncnamelen; + + owncname = ownsdesinfo.GetCNAME(&owncnamelen); + + if ((status = rtcpcomppack->AddSDESSource(ssrc)) < 0) + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT) + return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON; + return status; + } + if ((status = rtcpcomppack->AddSDESNormalItem(RTCPSDESPacket::CNAME,owncname,owncnamelen)) < 0) + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT) + return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON; + return status; + } + + if (!processingsdes) + { + int added,skipped; + bool full,atendoflist; + + if ((status = FillInReportBlocks(rtcpcomppack,curtime,sources.GetTotalCount(),&full,&added,&skipped,&atendoflist)) < 0) + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + return status; + } + + if (full && added == 0) + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON; + } + + if (!full) + { + processingsdes = true; + sdesbuildcount++; + + ClearAllSourceFlags(); + + doname = false; + doemail = false; + doloc = false; + dophone = false; + dotool = false; + donote = false; + if (interval_name > 0 && ((sdesbuildcount%interval_name) == 0)) doname = true; + if (interval_email > 0 && ((sdesbuildcount%interval_email) == 0)) doemail = true; + if (interval_location > 0 && ((sdesbuildcount%interval_location) == 0)) doloc = true; + if (interval_phone > 0 && ((sdesbuildcount%interval_phone) == 0)) dophone = true; + if (interval_tool > 0 && ((sdesbuildcount%interval_tool) == 0)) dotool = true; + if (interval_note > 0 && ((sdesbuildcount%interval_note) == 0)) donote = true; + + bool processedall; + int itemcount; + + if ((status = FillInSDES(rtcpcomppack,&full,&processedall,&itemcount)) < 0) + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + return status; + } + + if (processedall) + { + processingsdes = false; + ClearAllSDESFlags(); + if (!full && skipped > 0) + { + // if the packet isn't full and we skipped some + // sources that we already got in a previous packet, + // we can add some of them now + + bool atendoflist; + + if ((status = FillInReportBlocks(rtcpcomppack,curtime,skipped,&full,&added,&skipped,&atendoflist)) < 0) + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + return status; + } + } + } + } + } + else // previous sdes processing wasn't finished + { + bool processedall; + int itemcount; + bool full; + + if ((status = FillInSDES(rtcpcomppack,&full,&processedall,&itemcount)) < 0) + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + return status; + } + + if (itemcount == 0) // Big problem: packet size is too small to let any progress happen + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON; + } + + if (processedall) + { + processingsdes = false; + ClearAllSDESFlags(); + if (!full) + { + // if the packet isn't full and we skipped some + // we can add some report blocks + + int added,skipped; + bool atendoflist; + + if ((status = FillInReportBlocks(rtcpcomppack,curtime,sources.GetTotalCount(),&full,&added,&skipped,&atendoflist)) < 0) + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + return status; + } + if (atendoflist) // filled in all possible sources + ClearAllSourceFlags(); + } + } + } + + if ((status = rtcpcomppack->EndBuild()) < 0) + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + return status; + } + + *pack = rtcpcomppack; + firstpacket = false; + prevbuildtime = curtime; + return 0; +} + +void RTCPPacketBuilder::ClearAllSourceFlags() +{ + if (sources.GotoFirstSource()) + { + do + { + RTPSourceData *srcdat = sources.GetCurrentSourceInfo(); + srcdat->SetProcessedInRTCP(false); + } while (sources.GotoNextSource()); + } +} + +int RTCPPacketBuilder::FillInReportBlocks(RTCPCompoundPacketBuilder *rtcpcomppack,const RTPTime &curtime,int maxcount,bool *full,int *added,int *skipped,bool *atendoflist) +{ + RTPSourceData *srcdat; + int addedcount = 0; + int skippedcount = 0; + bool done = false; + bool filled = false; + bool atend = false; + int status; + + if (sources.GotoFirstSource()) + { + do + { + bool shouldprocess = false; + + srcdat = sources.GetCurrentSourceInfo(); + if (!srcdat->IsOwnSSRC()) // don't send to ourselves + { + if (!srcdat->IsCSRC()) // p 35: no reports should go to CSRCs + { + if (srcdat->INF_HasSentData()) // if this isn't true, INF_GetLastRTPPacketTime() won't make any sense + { + if (firstpacket) + shouldprocess = true; + else + { + // p 35: only if rtp packets were received since the last RTP packet, a report block + // should be added + + RTPTime lastrtptime = srcdat->INF_GetLastRTPPacketTime(); + + if (lastrtptime > prevbuildtime) + shouldprocess = true; + } + } + } + } + + if (shouldprocess) + { + if (srcdat->IsProcessedInRTCP()) // already covered this one + { + skippedcount++; + } + else + { + uint32_t rr_ssrc = srcdat->GetSSRC(); + uint32_t num = srcdat->INF_GetNumPacketsReceivedInInterval(); + uint32_t prevseq = srcdat->INF_GetSavedExtendedSequenceNumber(); + uint32_t curseq = srcdat->INF_GetExtendedHighestSequenceNumber(); + uint32_t expected = curseq-prevseq; + uint8_t fraclost; + + if (expected < num) // got duplicates + fraclost = 0; + else + { + double lost = (double)(expected-num); + double frac = lost/((double)expected); + fraclost = (uint8_t)(frac*256.0); + } + + expected = curseq-srcdat->INF_GetBaseSequenceNumber(); + num = srcdat->INF_GetNumPacketsReceived(); + + uint32_t diff = expected-num; + int32_t *packlost = (int32_t *)&diff; + + uint32_t jitter = srcdat->INF_GetJitter(); + uint32_t lsr; + uint32_t dlsr; + + if (!srcdat->SR_HasInfo()) + { + lsr = 0; + dlsr = 0; + } + else + { + RTPNTPTime srtime = srcdat->SR_GetNTPTimestamp(); + uint32_t m = (srtime.GetMSW()&0xFFFF); + uint32_t l = ((srtime.GetLSW()>>16)&0xFFFF); + lsr = ((m<<16)|l); + + RTPTime diff = curtime; + diff -= srcdat->SR_GetReceiveTime(); + double diff2 = diff.GetDouble(); + diff2 *= 65536.0; + dlsr = (uint32_t)diff2; + } + + status = rtcpcomppack->AddReportBlock(rr_ssrc,fraclost,*packlost,curseq,jitter,lsr,dlsr); + if (status < 0) + { + if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT) + { + done = true; + filled = true; + } + else + return status; + } + else + { + addedcount++; + if (addedcount >= maxcount) + { + done = true; + if (!sources.GotoNextSource()) + atend = true; + } + srcdat->INF_StartNewInterval(); + srcdat->SetProcessedInRTCP(true); + } + } + } + + if (!done) + { + if (!sources.GotoNextSource()) + { + atend = true; + done = true; + } + } + + } while (!done); + } + + *added = addedcount; + *skipped = skippedcount; + *full = filled; + + if (!atend) // search for available sources + { + bool shouldprocess = false; + + do + { + srcdat = sources.GetCurrentSourceInfo(); + if (!srcdat->IsOwnSSRC()) // don't send to ourselves + { + if (!srcdat->IsCSRC()) // p 35: no reports should go to CSRCs + { + if (srcdat->INF_HasSentData()) // if this isn't true, INF_GetLastRTPPacketTime() won't make any sense + { + if (firstpacket) + shouldprocess = true; + else + { + // p 35: only if rtp packets were received since the last RTP packet, a report block + // should be added + + RTPTime lastrtptime = srcdat->INF_GetLastRTPPacketTime(); + + if (lastrtptime > prevbuildtime) + shouldprocess = true; + } + } + } + } + + if (shouldprocess) + { + if (srcdat->IsProcessedInRTCP()) + shouldprocess = false; + } + + if (!shouldprocess) + { + if (!sources.GotoNextSource()) + atend = true; + } + + } while (!atend && !shouldprocess); + } + + *atendoflist = atend; + return 0; +} + +int RTCPPacketBuilder::FillInSDES(RTCPCompoundPacketBuilder *rtcpcomppack,bool *full,bool *processedall,int *added) +{ + int status; + uint8_t *data; + size_t datalen; + + *full = false; + *processedall = false; + *added = 0; + + // We don't need to add a SSRC for our own data, this is still set + // from adding the CNAME + if (doname) + { + if (!ownsdesinfo.ProcessedName()) + { + data = ownsdesinfo.GetName(&datalen); + if ((status = rtcpcomppack->AddSDESNormalItem(RTCPSDESPacket::NAME,data,datalen)) < 0) + { + if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT) + { + *full = true; + return 0; + } + } + (*added)++; + ownsdesinfo.SetProcessedName(true); + } + } + if (doemail) + { + if (!ownsdesinfo.ProcessedEMail()) + { + data = ownsdesinfo.GetEMail(&datalen); + if ((status = rtcpcomppack->AddSDESNormalItem(RTCPSDESPacket::EMAIL,data,datalen)) < 0) + { + if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT) + { + *full = true; + return 0; + } + } + (*added)++; + ownsdesinfo.SetProcessedEMail(true); + } + } + if (doloc) + { + if (!ownsdesinfo.ProcessedLocation()) + { + data = ownsdesinfo.GetLocation(&datalen); + if ((status = rtcpcomppack->AddSDESNormalItem(RTCPSDESPacket::LOC,data,datalen)) < 0) + { + if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT) + { + *full = true; + return 0; + } + } + (*added)++; + ownsdesinfo.SetProcessedLocation(true); + } + } + if (dophone) + { + if (!ownsdesinfo.ProcessedPhone()) + { + data = ownsdesinfo.GetPhone(&datalen); + if ((status = rtcpcomppack->AddSDESNormalItem(RTCPSDESPacket::PHONE,data,datalen)) < 0) + { + if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT) + { + *full = true; + return 0; + } + } + (*added)++; + ownsdesinfo.SetProcessedPhone(true); + } + } + if (dotool) + { + if (!ownsdesinfo.ProcessedTool()) + { + data = ownsdesinfo.GetTool(&datalen); + if ((status = rtcpcomppack->AddSDESNormalItem(RTCPSDESPacket::TOOL,data,datalen)) < 0) + { + if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT) + { + *full = true; + return 0; + } + } + (*added)++; + ownsdesinfo.SetProcessedTool(true); + } + } + if (donote) + { + if (!ownsdesinfo.ProcessedNote()) + { + data = ownsdesinfo.GetNote(&datalen); + if ((status = rtcpcomppack->AddSDESNormalItem(RTCPSDESPacket::NOTE,data,datalen)) < 0) + { + if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT) + { + *full = true; + return 0; + } + } + (*added)++; + ownsdesinfo.SetProcessedNote(true); + } + } + + *processedall = true; + return 0; +} + +void RTCPPacketBuilder::ClearAllSDESFlags() +{ + ownsdesinfo.ClearFlags(); +} + +int RTCPPacketBuilder::BuildBYEPacket(RTCPCompoundPacket **pack,const void *reason,size_t reasonlength,bool useSRifpossible) +{ + if (!init) + return ERR_RTP_RTCPPACKETBUILDER_NOTINIT; + + RTCPCompoundPacketBuilder *rtcpcomppack; + int status; + + if (reasonlength > 255) + reasonlength = 255; + + *pack = 0; + + rtcpcomppack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTCPCOMPOUNDPACKETBUILDER) RTCPCompoundPacketBuilder(GetMemoryManager()); + if (rtcpcomppack == 0) + return ERR_RTP_OUTOFMEM; + + if ((status = rtcpcomppack->InitBuild(maxpacketsize)) < 0) + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + return status; + } + + uint32_t ssrc = rtppacketbuilder.GetSSRC(); + bool useSR = false; + + if (useSRifpossible) + { + RTPSourceData *srcdat; + + if ((srcdat = sources.GetOwnSourceInfo()) != 0) + { + if (srcdat->IsSender()) + useSR = true; + } + } + + if (useSR) + { + RTPTime curtime = RTPTime::CurrentTime(); + RTPTime rtppacktime = rtppacketbuilder.GetPacketTime(); + uint32_t rtppacktimestamp = rtppacketbuilder.GetPacketTimestamp(); + uint32_t packcount = rtppacketbuilder.GetPacketCount(); + uint32_t octetcount = rtppacketbuilder.GetPayloadOctetCount(); + RTPTime diff = curtime; + diff -= rtppacktime; + + uint32_t tsdiff = (uint32_t)((diff.GetDouble()/timestampunit)+0.5); + uint32_t rtptimestamp = rtppacktimestamp+tsdiff; + RTPNTPTime ntptimestamp = curtime.GetNTPTime(); + + if ((status = rtcpcomppack->StartSenderReport(ssrc,ntptimestamp,rtptimestamp,packcount,octetcount)) < 0) + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT) + return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON; + return status; + } + } + else + { + if ((status = rtcpcomppack->StartReceiverReport(ssrc)) < 0) + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT) + return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON; + return status; + } + } + + uint8_t *owncname; + size_t owncnamelen; + + owncname = ownsdesinfo.GetCNAME(&owncnamelen); + + if ((status = rtcpcomppack->AddSDESSource(ssrc)) < 0) + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT) + return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON; + return status; + } + if ((status = rtcpcomppack->AddSDESNormalItem(RTCPSDESPacket::CNAME,owncname,owncnamelen)) < 0) + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT) + return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON; + return status; + } + + uint32_t ssrcs[1]; + + ssrcs[0] = ssrc; + + if ((status = rtcpcomppack->AddBYEPacket(ssrcs,1,(const uint8_t *)reason,reasonlength)) < 0) + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + if (status == ERR_RTP_RTCPCOMPPACKBUILDER_NOTENOUGHBYTESLEFT) + return ERR_RTP_RTCPPACKETBUILDER_PACKETFILLEDTOOSOON; + return status; + } + + if ((status = rtcpcomppack->EndBuild()) < 0) + { + RTPDelete(rtcpcomppack,GetMemoryManager()); + return status; + } + + *pack = rtcpcomppack; + return 0; +} + |