diff options
Diffstat (limited to 'src/rtpsources.cpp')
-rw-r--r-- | src/rtpsources.cpp | 1412 |
1 files changed, 1412 insertions, 0 deletions
diff --git a/src/rtpsources.cpp b/src/rtpsources.cpp new file mode 100644 index 0000000..7318bc6 --- /dev/null +++ b/src/rtpsources.cpp @@ -0,0 +1,1412 @@ +/* + + 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 "rtpsources.h" +#include "rtperrors.h" +#include "rtprawpacket.h" +#include "rtpinternalsourcedata.h" +#include "rtptimeutilities.h" +#include "rtpdefines.h" +#include "rtcpcompoundpacket.h" +#include "rtcppacket.h" +#include "rtcpapppacket.h" +#include "rtcpbyepacket.h" +#include "rtcpsdespacket.h" +#include "rtcpsrpacket.h" +#include "rtcprrpacket.h" +#include "rtptransmitter.h" + +#ifdef RTPDEBUG + #include <iostream> +#endif // RTPDEBUG + +#include "rtpdebug.h" + +RTPSources::RTPSources(ProbationType probtype,RTPMemoryManager *mgr) : RTPMemoryObject(mgr),sourcelist(mgr,RTPMEM_TYPE_CLASS_SOURCETABLEHASHELEMENT) +{ + totalcount = 0; + sendercount = 0; + activecount = 0; + owndata = 0; +#ifdef RTP_SUPPORT_PROBATION + probationtype = probtype; +#endif // RTP_SUPPORT_PROBATION +} + +RTPSources::~RTPSources() +{ + Clear(); +} + +void RTPSources::Clear() +{ + ClearSourceList(); +} + +void RTPSources::ClearSourceList() +{ + sourcelist.GotoFirstElement(); + while (sourcelist.HasCurrentElement()) + { + RTPInternalSourceData *sourcedata; + + sourcedata = sourcelist.GetCurrentElement(); + RTPDelete(sourcedata,GetMemoryManager()); + sourcelist.GotoNextElement(); + } + sourcelist.Clear(); + owndata = 0; + totalcount = 0; + sendercount = 0; + activecount = 0; +} + +int RTPSources::CreateOwnSSRC(uint32_t ssrc) +{ + if (owndata != 0) + return ERR_RTP_SOURCES_ALREADYHAVEOWNSSRC; + if (GotEntry(ssrc)) + return ERR_RTP_SOURCES_SSRCEXISTS; + + int status; + bool created; + + status = ObtainSourceDataInstance(ssrc,&owndata,&created); + if (status < 0) + { + owndata = 0; // just to make sure + return status; + } + owndata->SetOwnSSRC(); + owndata->SetRTPDataAddress(0); + owndata->SetRTCPDataAddress(0); + + // we've created a validated ssrc, so we should increase activecount + activecount++; + + OnNewSource(owndata); + return 0; +} + +int RTPSources::DeleteOwnSSRC() +{ + if (owndata == 0) + return ERR_RTP_SOURCES_DONTHAVEOWNSSRC; + + uint32_t ssrc = owndata->GetSSRC(); + + sourcelist.GotoElement(ssrc); + sourcelist.DeleteCurrentElement(); + + totalcount--; + if (owndata->IsSender()) + sendercount--; + if (owndata->IsActive()) + activecount--; + + OnRemoveSource(owndata); + + RTPDelete(owndata,GetMemoryManager()); + owndata = 0; + return 0; +} + +void RTPSources::SentRTPPacket() +{ + if (owndata == 0) + return; + + bool prevsender = owndata->IsSender(); + + owndata->SentRTPPacket(); + if (!prevsender && owndata->IsSender()) + sendercount++; +} + +int RTPSources::ProcessRawPacket(RTPRawPacket *rawpack,RTPTransmitter *rtptrans,bool acceptownpackets) +{ + RTPTransmitter *transmitters[1]; + int num; + + transmitters[0] = rtptrans; + if (rtptrans == 0) + num = 0; + else + num = 1; + return ProcessRawPacket(rawpack,transmitters,num,acceptownpackets); +} + +int RTPSources::ProcessRawPacket(RTPRawPacket *rawpack,RTPTransmitter *rtptrans[],int numtrans,bool acceptownpackets) +{ + int status; + + if (rawpack->IsRTP()) // RTP packet + { + RTPPacket *rtppack; + + // First, we'll see if the packet can be parsed + rtppack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPPACKET) RTPPacket(*rawpack,GetMemoryManager()); + if (rtppack == 0) + return ERR_RTP_OUTOFMEM; + if ((status = rtppack->GetCreationError()) < 0) + { + if (status == ERR_RTP_PACKET_INVALIDPACKET) + { + RTPDelete(rtppack,GetMemoryManager()); + rtppack = 0; + } + else + { + RTPDelete(rtppack,GetMemoryManager()); + return status; + } + } + + // Check if the packet was valid + if (rtppack != 0) + { + bool stored = false; + bool ownpacket = false; + int i; + const RTPAddress *senderaddress = rawpack->GetSenderAddress(); + + for (i = 0 ; !ownpacket && i < numtrans ; i++) + { + if (rtptrans[i]->ComesFromThisTransmitter(senderaddress)) + ownpacket = true; + } + + // Check if the packet is our own. + if (ownpacket) + { + // Now it depends on the user's preference + // what to do with this packet: + if (acceptownpackets) + { + // sender addres for own packets has to be NULL! + if ((status = ProcessRTPPacket(rtppack,rawpack->GetReceiveTime(),0,&stored)) < 0) + { + if (!stored) + RTPDelete(rtppack,GetMemoryManager()); + return status; + } + } + } + else + { + if ((status = ProcessRTPPacket(rtppack,rawpack->GetReceiveTime(),senderaddress,&stored)) < 0) + { + if (!stored) + RTPDelete(rtppack,GetMemoryManager()); + return status; + } + } + if (!stored) + RTPDelete(rtppack,GetMemoryManager()); + } + } + else // RTCP packet + { + RTCPCompoundPacket rtcpcomppack(*rawpack,GetMemoryManager()); + bool valid = false; + + if ((status = rtcpcomppack.GetCreationError()) < 0) + { + if (status != ERR_RTP_RTCPCOMPOUND_INVALIDPACKET) + return status; + } + else + valid = true; + + + if (valid) + { + bool ownpacket = false; + int i; + const RTPAddress *senderaddress = rawpack->GetSenderAddress(); + + for (i = 0 ; !ownpacket && i < numtrans ; i++) + { + if (rtptrans[i]->ComesFromThisTransmitter(senderaddress)) + ownpacket = true; + } + + // First check if it's a packet of this session. + if (ownpacket) + { + if (acceptownpackets) + { + // sender address for own packets has to be NULL + status = ProcessRTCPCompoundPacket(&rtcpcomppack,rawpack->GetReceiveTime(),0); + if (status < 0) + return status; + } + } + else // not our own packet + { + status = ProcessRTCPCompoundPacket(&rtcpcomppack,rawpack->GetReceiveTime(),rawpack->GetSenderAddress()); + if (status < 0) + return status; + } + } + } + + return 0; +} + +int RTPSources::ProcessRTPPacket(RTPPacket *rtppack,const RTPTime &receivetime,const RTPAddress *senderaddress,bool *stored) +{ + uint32_t ssrc; + RTPInternalSourceData *srcdat; + int status; + bool created; + + OnRTPPacket(rtppack,receivetime,senderaddress); + + *stored = false; + + ssrc = rtppack->GetSSRC(); + if ((status = ObtainSourceDataInstance(ssrc,&srcdat,&created)) < 0) + return status; + + if (created) + { + if ((status = srcdat->SetRTPDataAddress(senderaddress)) < 0) + return status; + } + else // got a previously existing source + { + if (CheckCollision(srcdat,senderaddress,true)) + return 0; // ignore packet on collision + } + + bool prevsender = srcdat->IsSender(); + bool prevactive = srcdat->IsActive(); + + // The packet comes from a valid source, we can process it further now + // The following function should delete rtppack itself if something goes + // wrong + if ((status = srcdat->ProcessRTPPacket(rtppack,receivetime,stored)) < 0) + return status; + + if (!prevsender && srcdat->IsSender()) + sendercount++; + if (!prevactive && srcdat->IsActive()) + activecount++; + + if (created) + OnNewSource(srcdat); + + if (srcdat->IsValidated()) // process the CSRCs + { + RTPInternalSourceData *csrcdat; + bool createdcsrc; + + int num = rtppack->GetCSRCCount(); + int i; + + for (i = 0 ; i < num ; i++) + { + if ((status = ObtainSourceDataInstance(rtppack->GetCSRC(i),&csrcdat,&createdcsrc)) < 0) + return status; + if (createdcsrc) + { + csrcdat->SetCSRC(); + if (csrcdat->IsActive()) + activecount++; + OnNewSource(csrcdat); + } + else // already found an entry, possibly because of RTCP data + { + if (!CheckCollision(csrcdat,senderaddress,true)) + csrcdat->SetCSRC(); + } + } + } + + return 0; +} + +int RTPSources::ProcessRTCPCompoundPacket(RTCPCompoundPacket *rtcpcomppack,const RTPTime &receivetime,const RTPAddress *senderaddress) +{ + RTCPPacket *rtcppack; + int status; + bool gotownssrc = ((owndata == 0)?false:true); + uint32_t ownssrc = ((owndata != 0)?owndata->GetSSRC():0); + + OnRTCPCompoundPacket(rtcpcomppack,receivetime,senderaddress); + + rtcpcomppack->GotoFirstPacket(); + while ((rtcppack = rtcpcomppack->GetNextPacket()) != 0) + { + if (rtcppack->IsKnownFormat()) + { + switch (rtcppack->GetPacketType()) + { + case RTCPPacket::SR: + { + RTCPSRPacket *p = (RTCPSRPacket *)rtcppack; + uint32_t senderssrc = p->GetSenderSSRC(); + + status = ProcessRTCPSenderInfo(senderssrc,p->GetNTPTimestamp(),p->GetRTPTimestamp(), + p->GetSenderPacketCount(),p->GetSenderOctetCount(), + receivetime,senderaddress); + if (status < 0) + return status; + + bool gotinfo = false; + if (gotownssrc) + { + int i; + int num = p->GetReceptionReportCount(); + for (i = 0 ; i < num ; i++) + { + if (p->GetSSRC(i) == ownssrc) // data is meant for us + { + gotinfo = true; + status = ProcessRTCPReportBlock(senderssrc,p->GetFractionLost(i),p->GetLostPacketCount(i), + p->GetExtendedHighestSequenceNumber(i),p->GetJitter(i),p->GetLSR(i), + p->GetDLSR(i),receivetime,senderaddress); + if (status < 0) + return status; + } + } + } + if (!gotinfo) + { + status = UpdateReceiveTime(senderssrc,receivetime,senderaddress); + if (status < 0) + return status; + } + } + break; + case RTCPPacket::RR: + { + RTCPRRPacket *p = (RTCPRRPacket *)rtcppack; + uint32_t senderssrc = p->GetSenderSSRC(); + + bool gotinfo = false; + + if (gotownssrc) + { + int i; + int num = p->GetReceptionReportCount(); + for (i = 0 ; i < num ; i++) + { + if (p->GetSSRC(i) == ownssrc) + { + gotinfo = true; + status = ProcessRTCPReportBlock(senderssrc,p->GetFractionLost(i),p->GetLostPacketCount(i), + p->GetExtendedHighestSequenceNumber(i),p->GetJitter(i),p->GetLSR(i), + p->GetDLSR(i),receivetime,senderaddress); + if (status < 0) + return status; + } + } + } + if (!gotinfo) + { + status = UpdateReceiveTime(senderssrc,receivetime,senderaddress); + if (status < 0) + return status; + } + } + break; + case RTCPPacket::SDES: + { + RTCPSDESPacket *p = (RTCPSDESPacket *)rtcppack; + + if (p->GotoFirstChunk()) + { + do + { + uint32_t sdesssrc = p->GetChunkSSRC(); + bool updated = false; + if (p->GotoFirstItem()) + { + do + { + RTCPSDESPacket::ItemType t; + + if ((t = p->GetItemType()) != RTCPSDESPacket::PRIV) + { + updated = true; + status = ProcessSDESNormalItem(sdesssrc,t,p->GetItemLength(),p->GetItemData(),receivetime,senderaddress); + if (status < 0) + return status; + } +#ifdef RTP_SUPPORT_SDESPRIV + else + { + updated = true; + status = ProcessSDESPrivateItem(sdesssrc,p->GetPRIVPrefixLength(),p->GetPRIVPrefixData(),p->GetPRIVValueLength(), + p->GetPRIVValueData(),receivetime,senderaddress); + if (status < 0) + return status; + } +#endif // RTP_SUPPORT_SDESPRIV + } while (p->GotoNextItem()); + } + if (!updated) + { + status = UpdateReceiveTime(sdesssrc,receivetime,senderaddress); + if (status < 0) + return status; + } + } while (p->GotoNextChunk()); + } + } + break; + case RTCPPacket::BYE: + { + RTCPBYEPacket *p = (RTCPBYEPacket *)rtcppack; + int i; + int num = p->GetSSRCCount(); + + for (i = 0 ; i < num ; i++) + { + uint32_t byessrc = p->GetSSRC(i); + status = ProcessBYE(byessrc,p->GetReasonLength(),p->GetReasonData(),receivetime,senderaddress); + if (status < 0) + return status; + } + } + break; + case RTCPPacket::APP: + { + RTCPAPPPacket *p = (RTCPAPPPacket *)rtcppack; + + OnAPPPacket(p,receivetime,senderaddress); + } + break; + case RTCPPacket::Unknown: + default: + { + OnUnknownPacketType(rtcppack,receivetime,senderaddress); + } + break; + } + } + else + { + OnUnknownPacketFormat(rtcppack,receivetime,senderaddress); + } + } + + return 0; +} + +bool RTPSources::GotoFirstSource() +{ + sourcelist.GotoFirstElement(); + if (sourcelist.HasCurrentElement()) + return true; + return false; +} + +bool RTPSources::GotoNextSource() +{ + sourcelist.GotoNextElement(); + if (sourcelist.HasCurrentElement()) + return true; + return false; +} + +bool RTPSources::GotoPreviousSource() +{ + sourcelist.GotoPreviousElement(); + if (sourcelist.HasCurrentElement()) + return true; + return false; +} + +bool RTPSources::GotoFirstSourceWithData() +{ + bool found = false; + + sourcelist.GotoFirstElement(); + while (!found && sourcelist.HasCurrentElement()) + { + RTPInternalSourceData *srcdat; + + srcdat = sourcelist.GetCurrentElement(); + if (srcdat->HasData()) + found = true; + else + sourcelist.GotoNextElement(); + } + + return found; +} + +bool RTPSources::GotoNextSourceWithData() +{ + bool found = false; + + sourcelist.GotoNextElement(); + while (!found && sourcelist.HasCurrentElement()) + { + RTPInternalSourceData *srcdat; + + srcdat = sourcelist.GetCurrentElement(); + if (srcdat->HasData()) + found = true; + else + sourcelist.GotoNextElement(); + } + + return found; +} + +bool RTPSources::GotoPreviousSourceWithData() +{ + bool found = false; + + sourcelist.GotoPreviousElement(); + while (!found && sourcelist.HasCurrentElement()) + { + RTPInternalSourceData *srcdat; + + srcdat = sourcelist.GetCurrentElement(); + if (srcdat->HasData()) + found = true; + else + sourcelist.GotoNextElement(); + } + + return found; +} + +RTPSourceData *RTPSources::GetCurrentSourceInfo() +{ + if (!sourcelist.HasCurrentElement()) + return 0; + return sourcelist.GetCurrentElement(); +} + +RTPSourceData *RTPSources::GetSourceInfo(uint32_t ssrc) +{ + if (sourcelist.GotoElement(ssrc) < 0) + return 0; + if (!sourcelist.HasCurrentElement()) + return 0; + return sourcelist.GetCurrentElement(); +} + +bool RTPSources::GotEntry(uint32_t ssrc) +{ + return sourcelist.HasElement(ssrc); +} + +RTPPacket *RTPSources::GetNextPacket() +{ + if (!sourcelist.HasCurrentElement()) + return 0; + + RTPInternalSourceData *srcdat = sourcelist.GetCurrentElement(); + RTPPacket *pack = srcdat->GetNextPacket(); + return pack; +} + +int RTPSources::ProcessRTCPSenderInfo(uint32_t ssrc,const RTPNTPTime &ntptime,uint32_t rtptime, + uint32_t packetcount,uint32_t octetcount,const RTPTime &receivetime, + const RTPAddress *senderaddress) +{ + RTPInternalSourceData *srcdat; + bool created; + int status; + + status = GetRTCPSourceData(ssrc,senderaddress,&srcdat,&created); + if (status < 0) + return status; + if (srcdat == 0) + return 0; + + srcdat->ProcessSenderInfo(ntptime,rtptime,packetcount,octetcount,receivetime); + + // Call the callback + if (created) + OnNewSource(srcdat); + + return 0; +} + +int RTPSources::ProcessRTCPReportBlock(uint32_t ssrc,uint8_t fractionlost,int32_t lostpackets, + uint32_t exthighseqnr,uint32_t jitter,uint32_t lsr, + uint32_t dlsr,const RTPTime &receivetime,const RTPAddress *senderaddress) +{ + RTPInternalSourceData *srcdat; + bool created; + int status; + + status = GetRTCPSourceData(ssrc,senderaddress,&srcdat,&created); + if (status < 0) + return status; + if (srcdat == 0) + return 0; + + srcdat->ProcessReportBlock(fractionlost,lostpackets,exthighseqnr,jitter,lsr,dlsr,receivetime); + + // Call the callback + if (created) + OnNewSource(srcdat); + + return 0; +} + +int RTPSources::ProcessSDESNormalItem(uint32_t ssrc,RTCPSDESPacket::ItemType t,size_t itemlength, + const void *itemdata,const RTPTime &receivetime,const RTPAddress *senderaddress) +{ + RTPInternalSourceData *srcdat; + bool created,cnamecollis; + int status; + uint8_t sdesid; + bool prevactive; + + switch(t) + { + case RTCPSDESPacket::CNAME: + sdesid = RTCP_SDES_ID_CNAME; + break; + case RTCPSDESPacket::NAME: + sdesid = RTCP_SDES_ID_NAME; + break; + case RTCPSDESPacket::EMAIL: + sdesid = RTCP_SDES_ID_EMAIL; + break; + case RTCPSDESPacket::PHONE: + sdesid = RTCP_SDES_ID_PHONE; + break; + case RTCPSDESPacket::LOC: + sdesid = RTCP_SDES_ID_LOCATION; + break; + case RTCPSDESPacket::TOOL: + sdesid = RTCP_SDES_ID_TOOL; + break; + case RTCPSDESPacket::NOTE: + sdesid = RTCP_SDES_ID_NOTE; + break; + default: + return ERR_RTP_SOURCES_ILLEGALSDESTYPE; + } + + status = GetRTCPSourceData(ssrc,senderaddress,&srcdat,&created); + if (status < 0) + return status; + if (srcdat == 0) + return 0; + + prevactive = srcdat->IsActive(); + status = srcdat->ProcessSDESItem(sdesid,(const uint8_t *)itemdata,itemlength,receivetime,&cnamecollis); + if (!prevactive && srcdat->IsActive()) + activecount++; + + // Call the callback + if (created) + OnNewSource(srcdat); + if (cnamecollis) + OnCNAMECollision(srcdat,senderaddress,(const uint8_t *)itemdata,itemlength); + + return status; +} + +#ifdef RTP_SUPPORT_SDESPRIV +int RTPSources::ProcessSDESPrivateItem(uint32_t ssrc,size_t prefixlen,const void *prefixdata, + size_t valuelen,const void *valuedata,const RTPTime &receivetime, + const RTPAddress *senderaddress) +{ + RTPInternalSourceData *srcdat; + bool created; + int status; + + status = GetRTCPSourceData(ssrc,senderaddress,&srcdat,&created); + if (status < 0) + return status; + if (srcdat == 0) + return 0; + + status = srcdat->ProcessPrivateSDESItem((const uint8_t *)prefixdata,prefixlen,(const uint8_t *)valuedata,valuelen,receivetime); + // Call the callback + if (created) + OnNewSource(srcdat); + return status; +} +#endif //RTP_SUPPORT_SDESPRIV + +int RTPSources::ProcessBYE(uint32_t ssrc,size_t reasonlength,const void *reasondata, + const RTPTime &receivetime,const RTPAddress *senderaddress) +{ + RTPInternalSourceData *srcdat; + bool created; + int status; + bool prevactive; + + status = GetRTCPSourceData(ssrc,senderaddress,&srcdat,&created); + if (status < 0) + return status; + if (srcdat == 0) + return 0; + + // we'll ignore BYE packets for our own ssrc + if (srcdat == owndata) + return 0; + + prevactive = srcdat->IsActive(); + srcdat->ProcessBYEPacket((const uint8_t *)reasondata,reasonlength,receivetime); + if (prevactive && !srcdat->IsActive()) + activecount--; + + // Call the callback + if (created) + OnNewSource(srcdat); + OnBYEPacket(srcdat); + return 0; +} + +int RTPSources::ObtainSourceDataInstance(uint32_t ssrc,RTPInternalSourceData **srcdat,bool *created) +{ + RTPInternalSourceData *srcdat2; + int status; + + if (sourcelist.GotoElement(ssrc) < 0) // No entry for this source + { +#ifdef RTP_SUPPORT_PROBATION + srcdat2 = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPINTERNALSOURCEDATA) RTPInternalSourceData(ssrc,probationtype,GetMemoryManager()); +#else + srcdat2 = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPINTERNALSOURCEDATA) RTPInternalSourceData(ssrc,RTPSources::NoProbation,GetMemoryManager()); +#endif // RTP_SUPPORT_PROBATION + if (srcdat2 == 0) + return ERR_RTP_OUTOFMEM; + if ((status = sourcelist.AddElement(ssrc,srcdat2)) < 0) + { + RTPDelete(srcdat2,GetMemoryManager()); + return status; + } + *srcdat = srcdat2; + *created = true; + totalcount++; + } + else + { + *srcdat = sourcelist.GetCurrentElement(); + *created = false; + } + return 0; +} + + +int RTPSources::GetRTCPSourceData(uint32_t ssrc,const RTPAddress *senderaddress, + RTPInternalSourceData **srcdat2,bool *newsource) +{ + int status; + bool created; + RTPInternalSourceData *srcdat; + + *srcdat2 = 0; + + if ((status = ObtainSourceDataInstance(ssrc,&srcdat,&created)) < 0) + return status; + + if (created) + { + if ((status = srcdat->SetRTCPDataAddress(senderaddress)) < 0) + return status; + } + else // got a previously existing source + { + if (CheckCollision(srcdat,senderaddress,false)) + return 0; // ignore packet on collision + } + + *srcdat2 = srcdat; + *newsource = created; + + return 0; +} + +int RTPSources::UpdateReceiveTime(uint32_t ssrc,const RTPTime &receivetime,const RTPAddress *senderaddress) +{ + RTPInternalSourceData *srcdat; + bool created; + int status; + + status = GetRTCPSourceData(ssrc,senderaddress,&srcdat,&created); + if (status < 0) + return status; + if (srcdat == 0) + return 0; + + // We got valid SSRC info + srcdat->UpdateMessageTime(receivetime); + + // Call the callback + if (created) + OnNewSource(srcdat); + + return 0; +} + +void RTPSources::Timeout(const RTPTime &curtime,const RTPTime &timeoutdelay) +{ + int newtotalcount = 0; + int newsendercount = 0; + int newactivecount = 0; + RTPTime checktime = curtime; + checktime -= timeoutdelay; + + sourcelist.GotoFirstElement(); + while (sourcelist.HasCurrentElement()) + { + RTPInternalSourceData *srcdat = sourcelist.GetCurrentElement(); + RTPTime lastmsgtime = srcdat->INF_GetLastMessageTime(); + + // we don't want to time out ourselves + if ((srcdat != owndata) && (lastmsgtime < checktime)) // timeout + { + + totalcount--; + if (srcdat->IsSender()) + sendercount--; + if (srcdat->IsActive()) + activecount--; + + sourcelist.DeleteCurrentElement(); + + OnTimeout(srcdat); + OnRemoveSource(srcdat); + RTPDelete(srcdat,GetMemoryManager()); + } + else + { + newtotalcount++; + if (srcdat->IsSender()) + newsendercount++; + if (srcdat->IsActive()) + newactivecount++; + sourcelist.GotoNextElement(); + } + } + +#ifdef RTPDEBUG + if (newtotalcount != totalcount) + { + std::cout << "New total count " << newtotalcount << " doesnt match old total count " << totalcount << std::endl; + SafeCountTotal(); + } + if (newsendercount != sendercount) + { + std::cout << "New sender count " << newsendercount << " doesnt match old sender count " << sendercount << std::endl; + SafeCountSenders(); + } + if (newactivecount != activecount) + { + std::cout << "New active count " << newactivecount << " doesnt match old active count " << activecount << std::endl; + SafeCountActive(); + } +#endif // RTPDEBUG + + totalcount = newtotalcount; // just to play it safe + sendercount = newsendercount; + activecount = newactivecount; +} + +void RTPSources::SenderTimeout(const RTPTime &curtime,const RTPTime &timeoutdelay) +{ + int newtotalcount = 0; + int newsendercount = 0; + int newactivecount = 0; + RTPTime checktime = curtime; + checktime -= timeoutdelay; + + sourcelist.GotoFirstElement(); + while (sourcelist.HasCurrentElement()) + { + RTPInternalSourceData *srcdat = sourcelist.GetCurrentElement(); + + newtotalcount++; + if (srcdat->IsActive()) + newactivecount++; + + if (srcdat->IsSender()) + { + RTPTime lastrtppacktime = srcdat->INF_GetLastRTPPacketTime(); + + if (lastrtppacktime < checktime) // timeout + { + srcdat->ClearSenderFlag(); + sendercount--; + } + else + newsendercount++; + } + sourcelist.GotoNextElement(); + } + +#ifdef RTPDEBUG + if (newtotalcount != totalcount) + { + std::cout << "New total count " << newtotalcount << " doesnt match old total count " << totalcount << std::endl; + SafeCountTotal(); + } + if (newsendercount != sendercount) + { + std::cout << "New sender count " << newsendercount << " doesnt match old sender count " << sendercount << std::endl; + SafeCountSenders(); + } + if (newactivecount != activecount) + { + std::cout << "New active count " << newactivecount << " doesnt match old active count " << activecount << std::endl; + SafeCountActive(); + } +#endif // RTPDEBUG + + totalcount = newtotalcount; // just to play it safe + sendercount = newsendercount; + activecount = newactivecount; +} + +void RTPSources::BYETimeout(const RTPTime &curtime,const RTPTime &timeoutdelay) +{ + int newtotalcount = 0; + int newsendercount = 0; + int newactivecount = 0; + RTPTime checktime = curtime; + checktime -= timeoutdelay; + + sourcelist.GotoFirstElement(); + while (sourcelist.HasCurrentElement()) + { + RTPInternalSourceData *srcdat = sourcelist.GetCurrentElement(); + + if (srcdat->ReceivedBYE()) + { + RTPTime byetime = srcdat->GetBYETime(); + + if ((srcdat != owndata) && (checktime > byetime)) + { + totalcount--; + if (srcdat->IsSender()) + sendercount--; + if (srcdat->IsActive()) + activecount--; + sourcelist.DeleteCurrentElement(); + OnBYETimeout(srcdat); + OnRemoveSource(srcdat); + RTPDelete(srcdat,GetMemoryManager()); + } + else + { + newtotalcount++; + if (srcdat->IsSender()) + newsendercount++; + if (srcdat->IsActive()) + newactivecount++; + sourcelist.GotoNextElement(); + } + } + else + { + newtotalcount++; + if (srcdat->IsSender()) + newsendercount++; + if (srcdat->IsActive()) + newactivecount++; + sourcelist.GotoNextElement(); + } + } + +#ifdef RTPDEBUG + if (newtotalcount != totalcount) + { + std::cout << "New total count " << newtotalcount << " doesnt match old total count " << totalcount << std::endl; + SafeCountTotal(); + } + if (newsendercount != sendercount) + { + std::cout << "New sender count " << newsendercount << " doesnt match old sender count " << sendercount << std::endl; + SafeCountSenders(); + } + if (newactivecount != activecount) + { + std::cout << "New active count " << newactivecount << " doesnt match old active count " << activecount << std::endl; + SafeCountActive(); + } +#endif // RTPDEBUG + + totalcount = newtotalcount; // just to play it safe + sendercount = newsendercount; + activecount = newactivecount; +} + +void RTPSources::NoteTimeout(const RTPTime &curtime,const RTPTime &timeoutdelay) +{ + int newtotalcount = 0; + int newsendercount = 0; + int newactivecount = 0; + RTPTime checktime = curtime; + checktime -= timeoutdelay; + + sourcelist.GotoFirstElement(); + while (sourcelist.HasCurrentElement()) + { + RTPInternalSourceData *srcdat = sourcelist.GetCurrentElement(); + uint8_t *note; + size_t notelen; + + note = srcdat->SDES_GetNote(¬elen); + if (notelen != 0) // Note has been set + { + RTPTime notetime = srcdat->INF_GetLastSDESNoteTime(); + + if (checktime > notetime) + { + srcdat->ClearNote(); + OnNoteTimeout(srcdat); + } + } + + newtotalcount++; + if (srcdat->IsSender()) + newsendercount++; + if (srcdat->IsActive()) + newactivecount++; + sourcelist.GotoNextElement(); + } + +#ifdef RTPDEBUG + if (newtotalcount != totalcount) + { + std::cout << "New total count " << newtotalcount << " doesnt match old total count " << totalcount << std::endl; + SafeCountTotal(); + } + if (newsendercount != sendercount) + { + std::cout << "New sender count " << newsendercount << " doesnt match old sender count " << sendercount << std::endl; + SafeCountSenders(); + } + if (newactivecount != activecount) + { + std::cout << "New active count " << newactivecount << " doesnt match old active count " << activecount << std::endl; + SafeCountActive(); + } +#endif // RTPDEBUG + + totalcount = newtotalcount; // just to play it safe + sendercount = newsendercount; + activecount = newactivecount; + +} + +void RTPSources::MultipleTimeouts(const RTPTime &curtime,const RTPTime &sendertimeout,const RTPTime &byetimeout,const RTPTime &generaltimeout,const RTPTime ¬etimeout) +{ + int newtotalcount = 0; + int newsendercount = 0; + int newactivecount = 0; + RTPTime senderchecktime = curtime; + RTPTime byechecktime = curtime; + RTPTime generaltchecktime = curtime; + RTPTime notechecktime = curtime; + senderchecktime -= sendertimeout; + byechecktime -= byetimeout; + generaltchecktime -= generaltimeout; + notechecktime -= notetimeout; + + sourcelist.GotoFirstElement(); + while (sourcelist.HasCurrentElement()) + { + RTPInternalSourceData *srcdat = sourcelist.GetCurrentElement(); + bool deleted,issender,isactive; + bool byetimeout,normaltimeout,notetimeout; + uint8_t *note; + size_t notelen; + + issender = srcdat->IsSender(); + isactive = srcdat->IsActive(); + deleted = false; + byetimeout = false; + normaltimeout = false; + notetimeout = false; + + note = srcdat->SDES_GetNote(¬elen); + if (notelen != 0) // Note has been set + { + RTPTime notetime = srcdat->INF_GetLastSDESNoteTime(); + + if (notechecktime > notetime) + { + notetimeout = true; + srcdat->ClearNote(); + } + } + + if (srcdat->ReceivedBYE()) + { + RTPTime byetime = srcdat->GetBYETime(); + + if ((srcdat != owndata) && (byechecktime > byetime)) + { + sourcelist.DeleteCurrentElement(); + deleted = true; + byetimeout = true; + } + } + + if (!deleted) + { + RTPTime lastmsgtime = srcdat->INF_GetLastMessageTime(); + + if ((srcdat != owndata) && (lastmsgtime < generaltchecktime)) + { + sourcelist.DeleteCurrentElement(); + deleted = true; + normaltimeout = true; + } + } + + if (!deleted) + { + newtotalcount++; + + if (issender) + { + RTPTime lastrtppacktime = srcdat->INF_GetLastRTPPacketTime(); + + if (lastrtppacktime < senderchecktime) + { + srcdat->ClearSenderFlag(); + sendercount--; + } + else + newsendercount++; + } + + if (isactive) + newactivecount++; + + if (notetimeout) + OnNoteTimeout(srcdat); + + sourcelist.GotoNextElement(); + } + else // deleted entry + { + if (issender) + sendercount--; + if (isactive) + activecount--; + totalcount--; + + if (byetimeout) + OnBYETimeout(srcdat); + if (normaltimeout) + OnTimeout(srcdat); + OnRemoveSource(srcdat); + RTPDelete(srcdat,GetMemoryManager()); + } + } + +#ifdef RTPDEBUG + if (newtotalcount != totalcount) + { + SafeCountTotal(); + std::cout << "New total count " << newtotalcount << " doesnt match old total count " << totalcount << std::endl; + } + if (newsendercount != sendercount) + { + SafeCountSenders(); + std::cout << "New sender count " << newsendercount << " doesnt match old sender count " << sendercount << std::endl; + } + if (newactivecount != activecount) + { + std::cout << "New active count " << newactivecount << " doesnt match old active count " << activecount << std::endl; + SafeCountActive(); + } +#endif // RTPDEBUG + + totalcount = newtotalcount; // just to play it safe + sendercount = newsendercount; + activecount = newactivecount; +} + +#ifdef RTPDEBUG +void RTPSources::Dump() +{ + std::cout << "Total count: " << totalcount << std::endl; + std::cout << "Sender count: " << sendercount << std::endl; + std::cout << "Active count: " << activecount << std::endl; + if (GotoFirstSource()) + { + do + { + RTPSourceData *s; + s = GetCurrentSourceInfo(); + s->Dump(); + std::cout << std::endl; + } while (GotoNextSource()); + } +} + +void RTPSources::SafeCountTotal() +{ + int count = 0; + + if (GotoFirstSource()) + { + do + { + count++; + } while (GotoNextSource()); + } + std::cout << "Actual total count: " << count << std::endl; +} + +void RTPSources::SafeCountSenders() +{ + int count = 0; + + if (GotoFirstSource()) + { + do + { + RTPSourceData *s; + s = GetCurrentSourceInfo(); + if (s->IsSender()) + count++; + } while (GotoNextSource()); + } + std::cout << "Actual sender count: " << count << std::endl; +} + +void RTPSources::SafeCountActive() +{ + int count = 0; + + if (GotoFirstSource()) + { + do + { + RTPSourceData *s; + s = GetCurrentSourceInfo(); + if (s->IsActive()) + count++; + } while (GotoNextSource()); + } + std::cout << "Actual active count: " << count << std::endl; +} + +#endif // RTPDEBUG + +bool RTPSources::CheckCollision(RTPInternalSourceData *srcdat,const RTPAddress *senderaddress,bool isrtp) +{ + bool isset,otherisset; + const RTPAddress *addr,*otheraddr; + + if (isrtp) + { + isset = srcdat->IsRTPAddressSet(); + addr = srcdat->GetRTPDataAddress(); + otherisset = srcdat->IsRTCPAddressSet(); + otheraddr = srcdat->GetRTCPDataAddress(); + } + else + { + isset = srcdat->IsRTCPAddressSet(); + addr = srcdat->GetRTCPDataAddress(); + otherisset = srcdat->IsRTPAddressSet(); + otheraddr = srcdat->GetRTPDataAddress(); + } + + if (!isset) + { + if (otherisset) // got other address, can check if it comes from same host + { + if (otheraddr == 0) // other came from our own session + { + if (senderaddress != 0) + { + OnSSRCCollision(srcdat,senderaddress,isrtp); + return true; + } + + // Ok, store it + + if (isrtp) + srcdat->SetRTPDataAddress(senderaddress); + else + srcdat->SetRTCPDataAddress(senderaddress); + } + else + { + if (!otheraddr->IsFromSameHost(senderaddress)) + { + OnSSRCCollision(srcdat,senderaddress,isrtp); + return true; + } + + // Ok, comes from same host, store the address + + if (isrtp) + srcdat->SetRTPDataAddress(senderaddress); + else + srcdat->SetRTCPDataAddress(senderaddress); + } + } + else // no other address, store this one + { + if (isrtp) + srcdat->SetRTPDataAddress(senderaddress); + else + srcdat->SetRTCPDataAddress(senderaddress); + } + } + else // already got an address + { + if (addr == 0) + { + if (senderaddress != 0) + { + OnSSRCCollision(srcdat,senderaddress,isrtp); + return true; + } + } + else + { + if (!addr->IsSameAddress(senderaddress)) + { + OnSSRCCollision(srcdat,senderaddress,isrtp); + return true; + } + } + } + + return false; +} |