diff options
Diffstat (limited to 'src/rtpsession.cpp')
-rw-r--r-- | src/rtpsession.cpp | 1477 |
1 files changed, 1477 insertions, 0 deletions
diff --git a/src/rtpsession.cpp b/src/rtpsession.cpp new file mode 100644 index 0000000..cce6195 --- /dev/null +++ b/src/rtpsession.cpp @@ -0,0 +1,1477 @@ +/* + + 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 "rtpsession.h" +#include "rtperrors.h" +#include "rtppollthread.h" +#include "rtpudpv4transmitter.h" +#include "rtpudpv6transmitter.h" +#include "rtpsessionparams.h" +#include "rtpdefines.h" +#include "rtprawpacket.h" +#include "rtppacket.h" +#include "rtptimeutilities.h" +#include "rtpmemorymanager.h" +#ifdef RTP_SUPPORT_SENDAPP + #include "rtcpcompoundpacket.h" +#endif // RTP_SUPPORT_SENDAPP +#ifndef WIN32 + #include <unistd.h> + #include <stdlib.h> +#else + #include <winbase.h> +#endif // WIN32 + +#ifdef RTPDEBUG + #include <iostream> +#endif // RTPDEBUG + +#include "rtpdebug.h" + +#ifdef RTP_SUPPORT_THREAD + #define SOURCES_LOCK { if (usingpollthread) sourcesmutex.Lock(); } + #define SOURCES_UNLOCK { if (usingpollthread) sourcesmutex.Unlock(); } + #define BUILDER_LOCK { if (usingpollthread) buildermutex.Lock(); } + #define BUILDER_UNLOCK { if (usingpollthread) buildermutex.Unlock(); } + #define SCHED_LOCK { if (usingpollthread) schedmutex.Lock(); } + #define SCHED_UNLOCK { if (usingpollthread) schedmutex.Unlock(); } + #define PACKSENT_LOCK { if (usingpollthread) packsentmutex.Lock(); } + #define PACKSENT_UNLOCK { if (usingpollthread) packsentmutex.Unlock(); } +#else + #define SOURCES_LOCK + #define SOURCES_UNLOCK + #define BUILDER_LOCK + #define BUILDER_UNLOCK + #define SCHED_LOCK + #define SCHED_UNLOCK + #define PACKSENT_LOCK + #define PACKSENT_UNLOCK +#endif // RTP_SUPPORT_THREAD + +RTPSession::RTPSession(RTPMemoryManager *mgr) + : RTPMemoryObject(mgr),sources(*this,mgr),packetbuilder(mgr),rtcpsched(sources),rtcpbuilder(sources,packetbuilder,mgr), + collisionlist(mgr) +{ + created = false; +#if (defined(WIN32) || defined(_WIN32_WCE)) + timeinit.Dummy(); +#endif // WIN32 || _WIN32_WCE +} + +RTPSession::~RTPSession() +{ + Destroy(); +} + +int RTPSession::Create(const RTPSessionParams &sessparams,const RTPTransmissionParams *transparams /* = 0 */, + RTPTransmitter::TransmissionProtocol protocol) +{ + int status; + + if (created) + return ERR_RTP_SESSION_ALREADYCREATED; + + usingpollthread = sessparams.IsUsingPollThread(); + useSR_BYEifpossible = sessparams.GetSenderReportForBYE(); + sentpackets = false; + + // Check max packet size + + if ((maxpacksize = sessparams.GetMaximumPacketSize()) < RTP_MINPACKETSIZE) + return ERR_RTP_SESSION_MAXPACKETSIZETOOSMALL; + + // Initialize the transmission component + + rtptrans = 0; + switch(protocol) + { + case RTPTransmitter::IPv4UDPProto: + rtptrans = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPTRANSMITTER) RTPUDPv4Transmitter(GetMemoryManager()); + break; +#ifdef RTP_SUPPORT_IPV6 + case RTPTransmitter::IPv6UDPProto: + rtptrans = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPTRANSMITTER) RTPUDPv6Transmitter(GetMemoryManager()); + break; +#endif // RTP_SUPPORT_IPV6 + case RTPTransmitter::UserDefinedProto: + rtptrans = NewUserDefinedTransmitter(); + if (rtptrans == 0) + return ERR_RTP_SESSION_USERDEFINEDTRANSMITTERNULL; + break; + default: + return ERR_RTP_SESSION_UNSUPPORTEDTRANSMISSIONPROTOCOL; + } + + if (rtptrans == 0) + return ERR_RTP_OUTOFMEM; + if ((status = rtptrans->Init(usingpollthread)) < 0) + { + RTPDelete(rtptrans,GetMemoryManager()); + return status; + } + if ((status = rtptrans->Create(maxpacksize,transparams)) < 0) + { + RTPDelete(rtptrans,GetMemoryManager()); + return status; + } + + deletetransmitter = true; + return InternalCreate(sessparams); +} + +int RTPSession::Create(const RTPSessionParams &sessparams,RTPTransmitter *transmitter) +{ + int status; + + if (created) + return ERR_RTP_SESSION_ALREADYCREATED; + + usingpollthread = sessparams.IsUsingPollThread(); + useSR_BYEifpossible = sessparams.GetSenderReportForBYE(); + sentpackets = false; + + // Check max packet size + + if ((maxpacksize = sessparams.GetMaximumPacketSize()) < RTP_MINPACKETSIZE) + return ERR_RTP_SESSION_MAXPACKETSIZETOOSMALL; + + rtptrans = transmitter; + + if ((status = rtptrans->SetMaximumPacketSize(maxpacksize)) < 0) + return status; + + deletetransmitter = false; + return InternalCreate(sessparams); +} + +int RTPSession::InternalCreate(const RTPSessionParams &sessparams) +{ + int status; + + // Initialize packet builder + + if ((status = packetbuilder.Init(maxpacksize)) < 0) + { + if (deletetransmitter) + RTPDelete(rtptrans,GetMemoryManager()); + return status; + } + +#ifdef RTP_SUPPORT_PROBATION + + // Set probation type + sources.SetProbationType(sessparams.GetProbationType()); + +#endif // RTP_SUPPORT_PROBATION + + // Add our own ssrc to the source table + + if ((status = sources.CreateOwnSSRC(packetbuilder.GetSSRC())) < 0) + { + packetbuilder.Destroy(); + if (deletetransmitter) + RTPDelete(rtptrans,GetMemoryManager()); + return status; + } + + // Set the initial receive mode + + if ((status = rtptrans->SetReceiveMode(sessparams.GetReceiveMode())) < 0) + { + packetbuilder.Destroy(); + sources.Clear(); + if (deletetransmitter) + RTPDelete(rtptrans,GetMemoryManager()); + return status; + } + + // Init the RTCP packet builder + + double timestampunit = sessparams.GetOwnTimestampUnit(); + uint8_t buf[1024]; + size_t buflen = 1024; + + if ((status = CreateCNAME(buf,&buflen,sessparams.GetResolveLocalHostname())) < 0) + { + packetbuilder.Destroy(); + sources.Clear(); + if (deletetransmitter) + RTPDelete(rtptrans,GetMemoryManager()); + return status; + } + + if ((status = rtcpbuilder.Init(maxpacksize,timestampunit,buf,buflen)) < 0) + { + packetbuilder.Destroy(); + sources.Clear(); + if (deletetransmitter) + RTPDelete(rtptrans,GetMemoryManager()); + return status; + } + + // Set scheduler parameters + + rtcpsched.Reset(); + rtcpsched.SetHeaderOverhead(rtptrans->GetHeaderOverhead()); + + RTCPSchedulerParams schedparams; + + sessionbandwidth = sessparams.GetSessionBandwidth(); + controlfragment = sessparams.GetControlTrafficFraction(); + + if ((status = schedparams.SetRTCPBandwidth(sessionbandwidth*controlfragment)) < 0) + { + if (deletetransmitter) + RTPDelete(rtptrans,GetMemoryManager()); + packetbuilder.Destroy(); + sources.Clear(); + rtcpbuilder.Destroy(); + return status; + } + if ((status = schedparams.SetSenderBandwidthFraction(sessparams.GetSenderControlBandwidthFraction())) < 0) + { + if (deletetransmitter) + RTPDelete(rtptrans,GetMemoryManager()); + packetbuilder.Destroy(); + sources.Clear(); + rtcpbuilder.Destroy(); + return status; + } + if ((status = schedparams.SetMinimumTransmissionInterval(sessparams.GetMinimumRTCPTransmissionInterval())) < 0) + { + if (deletetransmitter) + RTPDelete(rtptrans,GetMemoryManager()); + packetbuilder.Destroy(); + sources.Clear(); + rtcpbuilder.Destroy(); + return status; + } + schedparams.SetUseHalfAtStartup(sessparams.GetUseHalfRTCPIntervalAtStartup()); + schedparams.SetRequestImmediateBYE(sessparams.GetRequestImmediateBYE()); + + rtcpsched.SetParameters(schedparams); + + // copy other parameters + + acceptownpackets = sessparams.AcceptOwnPackets(); + membermultiplier = sessparams.GetSourceTimeoutMultiplier(); + sendermultiplier = sessparams.GetSenderTimeoutMultiplier(); + byemultiplier = sessparams.GetBYETimeoutMultiplier(); + collisionmultiplier = sessparams.GetCollisionTimeoutMultiplier(); + notemultiplier = sessparams.GetNoteTimeoutMultiplier(); + + // Do thread stuff if necessary + +#ifdef RTP_SUPPORT_THREAD + pollthread = 0; + if (usingpollthread) + { + if (!sourcesmutex.IsInitialized()) + { + if (sourcesmutex.Init() < 0) + { + if (deletetransmitter) + RTPDelete(rtptrans,GetMemoryManager()); + packetbuilder.Destroy(); + sources.Clear(); + rtcpbuilder.Destroy(); + return ERR_RTP_SESSION_CANTINITMUTEX; + } + } + if (!buildermutex.IsInitialized()) + { + if (buildermutex.Init() < 0) + { + if (deletetransmitter) + RTPDelete(rtptrans,GetMemoryManager()); + packetbuilder.Destroy(); + sources.Clear(); + rtcpbuilder.Destroy(); + return ERR_RTP_SESSION_CANTINITMUTEX; + } + } + if (!schedmutex.IsInitialized()) + { + if (schedmutex.Init() < 0) + { + if (deletetransmitter) + RTPDelete(rtptrans,GetMemoryManager()); + packetbuilder.Destroy(); + sources.Clear(); + rtcpbuilder.Destroy(); + return ERR_RTP_SESSION_CANTINITMUTEX; + } + } + if (!packsentmutex.IsInitialized()) + { + if (packsentmutex.Init() < 0) + { + if (deletetransmitter) + RTPDelete(rtptrans,GetMemoryManager()); + packetbuilder.Destroy(); + sources.Clear(); + rtcpbuilder.Destroy(); + return ERR_RTP_SESSION_CANTINITMUTEX; + } + } + + pollthread = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPPOLLTHREAD) RTPPollThread(*this,rtcpsched); + if (pollthread == 0) + { + if (deletetransmitter) + RTPDelete(rtptrans,GetMemoryManager()); + packetbuilder.Destroy(); + sources.Clear(); + rtcpbuilder.Destroy(); + return ERR_RTP_OUTOFMEM; + } + if ((status = pollthread->Start(rtptrans)) < 0) + { + if (deletetransmitter) + RTPDelete(rtptrans,GetMemoryManager()); + RTPDelete(pollthread,GetMemoryManager()); + packetbuilder.Destroy(); + sources.Clear(); + rtcpbuilder.Destroy(); + return status; + } + } +#endif // RTP_SUPPORT_THREAD + + created = true; + return 0; +} + + +void RTPSession::Destroy() +{ + if (!created) + return; + +#ifdef RTP_SUPPORT_THREAD + if (pollthread) + RTPDelete(pollthread,GetMemoryManager()); +#endif // RTP_SUPPORT_THREAD + + if (deletetransmitter) + RTPDelete(rtptrans,GetMemoryManager()); + packetbuilder.Destroy(); + rtcpbuilder.Destroy(); + rtcpsched.Reset(); + collisionlist.Clear(); + sources.Clear(); + + std::list<RTCPCompoundPacket *>::const_iterator it; + + for (it = byepackets.begin() ; it != byepackets.end() ; it++) + RTPDelete(*it,GetMemoryManager()); + byepackets.clear(); + + created = false; +} + +void RTPSession::BYEDestroy(const RTPTime &maxwaittime,const void *reason,size_t reasonlength) +{ + if (!created) + return; + + // first, stop the thread so we have full control over all components + +#ifdef RTP_SUPPORT_THREAD + if (pollthread) + RTPDelete(pollthread,GetMemoryManager()); +#endif // RTP_SUPPORT_THREAD + + RTPTime stoptime = RTPTime::CurrentTime(); + stoptime += maxwaittime; + + // add bye packet to the list if we've sent data + + RTCPCompoundPacket *pack; + + if (sentpackets) + { + int status; + + reasonlength = (reasonlength>RTCP_BYE_MAXREASONLENGTH)?RTCP_BYE_MAXREASONLENGTH:reasonlength; + status = rtcpbuilder.BuildBYEPacket(&pack,reason,reasonlength,useSR_BYEifpossible); + if (status >= 0) + { + byepackets.push_back(pack); + + if (byepackets.size() == 1) + rtcpsched.ScheduleBYEPacket(pack->GetCompoundPacketLength()); + } + } + + if (!byepackets.empty()) + { + bool done = false; + + while (!done) + { + RTPTime curtime = RTPTime::CurrentTime(); + + if (curtime >= stoptime) + done = true; + + if (rtcpsched.IsTime()) + { + pack = *(byepackets.begin()); + byepackets.pop_front(); + + rtptrans->SendRTCPData(pack->GetCompoundPacketData(),pack->GetCompoundPacketLength()); + + OnSendRTCPCompoundPacket(pack); // we'll place this after the actual send to avoid tampering + + RTPDelete(pack,GetMemoryManager()); + if (!byepackets.empty()) // more bye packets to send, schedule them + rtcpsched.ScheduleBYEPacket((*(byepackets.begin()))->GetCompoundPacketLength()); + else + done = true; + } + if (!done) + RTPTime::Wait(RTPTime(0,100000)); + } + } + + if (deletetransmitter) + RTPDelete(rtptrans,GetMemoryManager()); + packetbuilder.Destroy(); + rtcpbuilder.Destroy(); + rtcpsched.Reset(); + collisionlist.Clear(); + sources.Clear(); + + // clear rest of bye packets + std::list<RTCPCompoundPacket *>::const_iterator it; + + for (it = byepackets.begin() ; it != byepackets.end() ; it++) + RTPDelete(*it,GetMemoryManager()); + byepackets.clear(); + + created = false; +} + +bool RTPSession::IsActive() +{ + return created; +} + +uint32_t RTPSession::GetLocalSSRC() +{ + if (!created) + return 0; + + uint32_t ssrc; + + BUILDER_LOCK + ssrc = packetbuilder.GetSSRC(); + BUILDER_UNLOCK + return ssrc; +} + +int RTPSession::AddDestination(const RTPAddress &addr) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + return rtptrans->AddDestination(addr); +} + +int RTPSession::DeleteDestination(const RTPAddress &addr) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + return rtptrans->DeleteDestination(addr); +} + +void RTPSession::ClearDestinations() +{ + if (!created) + return; + rtptrans->ClearDestinations(); +} + +bool RTPSession::SupportsMulticasting() +{ + if (!created) + return false; + return rtptrans->SupportsMulticasting(); +} + +int RTPSession::JoinMulticastGroup(const RTPAddress &addr) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + return rtptrans->JoinMulticastGroup(addr); +} + +int RTPSession::LeaveMulticastGroup(const RTPAddress &addr) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + return rtptrans->LeaveMulticastGroup(addr); +} + +void RTPSession::LeaveAllMulticastGroups() +{ + if (!created) + return; + rtptrans->LeaveAllMulticastGroups(); +} + +int RTPSession::SendPacket(const void *data,size_t len) +{ + int status; + + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + BUILDER_LOCK + if ((status = packetbuilder.BuildPacket(data,len)) < 0) + { + BUILDER_UNLOCK + return status; + } + if ((status = rtptrans->SendRTPData(packetbuilder.GetPacket(),packetbuilder.GetPacketLength())) < 0) + { + BUILDER_UNLOCK + return status; + } + BUILDER_UNLOCK + + SOURCES_LOCK + sources.SentRTPPacket(); + SOURCES_UNLOCK + PACKSENT_LOCK + sentpackets = true; + PACKSENT_UNLOCK + return 0; +} + +int RTPSession::SendPacket(const void *data,size_t len, + uint8_t pt,bool mark,uint32_t timestampinc) +{ + int status; + + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + BUILDER_LOCK + if ((status = packetbuilder.BuildPacket(data,len,pt,mark,timestampinc)) < 0) + { + BUILDER_UNLOCK + return status; + } + if ((status = rtptrans->SendRTPData(packetbuilder.GetPacket(),packetbuilder.GetPacketLength())) < 0) + { + BUILDER_UNLOCK + return status; + } + BUILDER_UNLOCK + + SOURCES_LOCK + sources.SentRTPPacket(); + SOURCES_UNLOCK + PACKSENT_LOCK + sentpackets = true; + PACKSENT_UNLOCK + return 0; +} + +int RTPSession::SendPacketEx(const void *data,size_t len, + uint16_t hdrextID,const void *hdrextdata,size_t numhdrextwords) +{ + int status; + + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + BUILDER_LOCK + if ((status = packetbuilder.BuildPacketEx(data,len,hdrextID,hdrextdata,numhdrextwords)) < 0) + { + BUILDER_UNLOCK + return status; + } + if ((status = rtptrans->SendRTPData(packetbuilder.GetPacket(),packetbuilder.GetPacketLength())) < 0) + { + BUILDER_UNLOCK + return status; + } + BUILDER_UNLOCK + + SOURCES_LOCK + sources.SentRTPPacket(); + SOURCES_UNLOCK + PACKSENT_LOCK + sentpackets = true; + PACKSENT_UNLOCK + return 0; +} + +int RTPSession::SendPacketEx(const void *data,size_t len, + uint8_t pt,bool mark,uint32_t timestampinc, + uint16_t hdrextID,const void *hdrextdata,size_t numhdrextwords) +{ + int status; + + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + BUILDER_LOCK + if ((status = packetbuilder.BuildPacketEx(data,len,pt,mark,timestampinc,hdrextID,hdrextdata,numhdrextwords)) < 0) + { + BUILDER_UNLOCK + return status; + } + if ((status = rtptrans->SendRTPData(packetbuilder.GetPacket(),packetbuilder.GetPacketLength())) < 0) + { + BUILDER_UNLOCK + return status; + } + BUILDER_UNLOCK + + SOURCES_LOCK + sources.SentRTPPacket(); + SOURCES_UNLOCK + PACKSENT_LOCK + sentpackets = true; + PACKSENT_UNLOCK + return 0; +} + +#ifdef RTP_SUPPORT_SENDAPP + +int RTPSession::SendRTCPAPPPacket(uint8_t subtype, const uint8_t name[4], const void *appdata, size_t appdatalen) +{ + int status; + + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + BUILDER_LOCK + uint32_t ssrc = packetbuilder.GetSSRC(); + BUILDER_UNLOCK + + RTCPCompoundPacketBuilder pb(GetMemoryManager()); + + status = pb.InitBuild(maxpacksize); + + if(status < 0) + return status; + + //first packet in an rtcp compound packet should always be SR or RR + if((status = pb.StartReceiverReport(ssrc)) < 0) + return status; + + //add SDES packet with CNAME item + if ((status = pb.AddSDESSource(ssrc)) < 0) + return status; + + BUILDER_LOCK + size_t owncnamelen = 0; + uint8_t *owncname = rtcpbuilder.GetLocalCNAME(&owncnamelen); + + if ((status = pb.AddSDESNormalItem(RTCPSDESPacket::CNAME,owncname,owncnamelen)) < 0) + { + BUILDER_UNLOCK + return status; + } + BUILDER_UNLOCK + + //add our application specific packet + if((status = pb.AddAPPPacket(subtype, ssrc, name, appdata, appdatalen)) < 0) + return status; + + if((status = pb.EndBuild()) < 0) + return status; + + //send packet + status = rtptrans->SendRTCPData(pb.GetCompoundPacketData(),pb.GetCompoundPacketLength()); + if(status < 0) + return status; + + PACKSENT_LOCK + sentpackets = true; + PACKSENT_UNLOCK + + return pb.GetCompoundPacketLength(); +} + +#endif // RTP_SUPPORT_SENDAPP + +int RTPSession::SetDefaultPayloadType(uint8_t pt) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + int status; + + BUILDER_LOCK + status = packetbuilder.SetDefaultPayloadType(pt); + BUILDER_UNLOCK + return status; +} + +int RTPSession::SetDefaultMark(bool m) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + int status; + + BUILDER_LOCK + status = packetbuilder.SetDefaultMark(m); + BUILDER_UNLOCK + return status; +} + +int RTPSession::SetDefaultTimestampIncrement(uint32_t timestampinc) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + int status; + + BUILDER_LOCK + status = packetbuilder.SetDefaultTimestampIncrement(timestampinc); + BUILDER_UNLOCK + return status; +} + +int RTPSession::IncrementTimestamp(uint32_t inc) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + int status; + + BUILDER_LOCK + status = packetbuilder.IncrementTimestamp(inc); + BUILDER_UNLOCK + return status; +} + +int RTPSession::IncrementTimestampDefault() +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + int status; + + BUILDER_LOCK + status = packetbuilder.IncrementTimestampDefault(); + BUILDER_UNLOCK + return status; +} + +int RTPSession::SetPreTransmissionDelay(const RTPTime &delay) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + int status; + + BUILDER_LOCK + status = rtcpbuilder.SetPreTransmissionDelay(delay); + BUILDER_UNLOCK + return status; +} + +RTPTransmissionInfo *RTPSession::GetTransmissionInfo() +{ + if (!created) + return 0; + return rtptrans->GetTransmissionInfo(); +} + +void RTPSession::DeleteTransmissionInfo(RTPTransmissionInfo *inf) +{ + RTPDelete(inf,GetMemoryManager()); +} + +int RTPSession::Poll() +{ + int status; + + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + if (usingpollthread) + return ERR_RTP_SESSION_USINGPOLLTHREAD; + if ((status = rtptrans->Poll()) < 0) + return status; + return ProcessPolledData(); +} + +int RTPSession::WaitForIncomingData(const RTPTime &delay,bool *dataavailable) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + if (usingpollthread) + return ERR_RTP_SESSION_USINGPOLLTHREAD; + return rtptrans->WaitForIncomingData(delay,dataavailable); +} + +int RTPSession::AbortWait() +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + if (usingpollthread) + return ERR_RTP_SESSION_USINGPOLLTHREAD; + return rtptrans->AbortWait(); +} + +RTPTime RTPSession::GetRTCPDelay() +{ + if (!created) + return RTPTime(0,0); + if (usingpollthread) + return RTPTime(0,0); + + SOURCES_LOCK + SCHED_LOCK + RTPTime t = rtcpsched.GetTransmissionDelay(); + SCHED_UNLOCK + SOURCES_UNLOCK + return t; +} + +int RTPSession::BeginDataAccess() +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + SOURCES_LOCK + return 0; +} + +bool RTPSession::GotoFirstSource() +{ + if (!created) + return false; + return sources.GotoFirstSource(); +} + +bool RTPSession::GotoNextSource() +{ + if (!created) + return false; + return sources.GotoNextSource(); +} + +bool RTPSession::GotoPreviousSource() +{ + if (!created) + return false; + return sources.GotoPreviousSource(); +} + +bool RTPSession::GotoFirstSourceWithData() +{ + if (!created) + return false; + return sources.GotoFirstSourceWithData(); +} + +bool RTPSession::GotoNextSourceWithData() +{ + if (!created) + return false; + return sources.GotoNextSourceWithData(); +} + +bool RTPSession::GotoPreviousSourceWithData() +{ + if (!created) + return false; + return sources.GotoPreviousSourceWithData(); +} + +RTPSourceData *RTPSession::GetCurrentSourceInfo() +{ + if (!created) + return 0; + return sources.GetCurrentSourceInfo(); +} + +RTPSourceData *RTPSession::GetSourceInfo(uint32_t ssrc) +{ + if (!created) + return 0; + return sources.GetSourceInfo(ssrc); +} + +RTPPacket *RTPSession::GetNextPacket() +{ + if (!created) + return 0; + return sources.GetNextPacket(); +} + +void RTPSession::DeletePacket(RTPPacket *p) +{ + RTPDelete(p,GetMemoryManager()); +} + +int RTPSession::EndDataAccess() +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + SOURCES_UNLOCK + return 0; +} + +int RTPSession::SetReceiveMode(RTPTransmitter::ReceiveMode m) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + return rtptrans->SetReceiveMode(m); +} + +int RTPSession::AddToIgnoreList(const RTPAddress &addr) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + return rtptrans->AddToIgnoreList(addr); +} + +int RTPSession::DeleteFromIgnoreList(const RTPAddress &addr) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + return rtptrans->DeleteFromIgnoreList(addr); +} + +void RTPSession::ClearIgnoreList() +{ + if (!created) + return; + rtptrans->ClearIgnoreList(); +} + +int RTPSession::AddToAcceptList(const RTPAddress &addr) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + return rtptrans->AddToAcceptList(addr); +} + +int RTPSession::DeleteFromAcceptList(const RTPAddress &addr) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + return rtptrans->DeleteFromAcceptList(addr); +} + +void RTPSession::ClearAcceptList() +{ + if (!created) + return; + rtptrans->ClearAcceptList(); +} + +int RTPSession::SetMaximumPacketSize(size_t s) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + if (s < RTP_MINPACKETSIZE) + return ERR_RTP_SESSION_MAXPACKETSIZETOOSMALL; + + int status; + + if ((status = rtptrans->SetMaximumPacketSize(s)) < 0) + return status; + + BUILDER_LOCK + if ((status = packetbuilder.SetMaximumPacketSize(s)) < 0) + { + BUILDER_UNLOCK + // restore previous max packet size + rtptrans->SetMaximumPacketSize(maxpacksize); + return status; + } + if ((status = rtcpbuilder.SetMaximumPacketSize(s)) < 0) + { + // restore previous max packet size + packetbuilder.SetMaximumPacketSize(maxpacksize); + BUILDER_UNLOCK + rtptrans->SetMaximumPacketSize(maxpacksize); + return status; + } + BUILDER_UNLOCK + maxpacksize = s; + return 0; +} + +int RTPSession::SetSessionBandwidth(double bw) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + int status; + SCHED_LOCK + RTCPSchedulerParams p = rtcpsched.GetParameters(); + status = p.SetRTCPBandwidth(bw*controlfragment); + if (status >= 0) + { + rtcpsched.SetParameters(p); + sessionbandwidth = bw; + } + SCHED_UNLOCK + return status; +} + +int RTPSession::SetTimestampUnit(double u) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + int status; + + BUILDER_LOCK + status = rtcpbuilder.SetTimestampUnit(u); + BUILDER_UNLOCK + return status; +} + +void RTPSession::SetNameInterval(int count) +{ + if (!created) + return; + BUILDER_LOCK + rtcpbuilder.SetNameInterval(count); + BUILDER_UNLOCK +} + +void RTPSession::SetEMailInterval(int count) +{ + if (!created) + return; + BUILDER_LOCK + rtcpbuilder.SetEMailInterval(count); + BUILDER_UNLOCK +} + +void RTPSession::SetLocationInterval(int count) +{ + if (!created) + return; + BUILDER_LOCK + rtcpbuilder.SetLocationInterval(count); + BUILDER_UNLOCK +} + +void RTPSession::SetPhoneInterval(int count) +{ + if (!created) + return; + BUILDER_LOCK + rtcpbuilder.SetPhoneInterval(count); + BUILDER_UNLOCK +} + +void RTPSession::SetToolInterval(int count) +{ + if (!created) + return; + BUILDER_LOCK + rtcpbuilder.SetToolInterval(count); + BUILDER_UNLOCK +} + +void RTPSession::SetNoteInterval(int count) +{ + if (!created) + return; + BUILDER_LOCK + rtcpbuilder.SetNoteInterval(count); + BUILDER_UNLOCK +} + +int RTPSession::SetLocalName(const void *s,size_t len) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + int status; + BUILDER_LOCK + status = rtcpbuilder.SetLocalName(s,len); + BUILDER_UNLOCK + return status; +} + +int RTPSession::SetLocalEMail(const void *s,size_t len) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + int status; + BUILDER_LOCK + status = rtcpbuilder.SetLocalEMail(s,len); + BUILDER_UNLOCK + return status; +} + +int RTPSession::SetLocalLocation(const void *s,size_t len) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + int status; + BUILDER_LOCK + status = rtcpbuilder.SetLocalLocation(s,len); + BUILDER_UNLOCK + return status; +} + +int RTPSession::SetLocalPhone(const void *s,size_t len) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + int status; + BUILDER_LOCK + status = rtcpbuilder.SetLocalPhone(s,len); + BUILDER_UNLOCK + return status; +} + +int RTPSession::SetLocalTool(const void *s,size_t len) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + int status; + BUILDER_LOCK + status = rtcpbuilder.SetLocalTool(s,len); + BUILDER_UNLOCK + return status; +} + +int RTPSession::SetLocalNote(const void *s,size_t len) +{ + if (!created) + return ERR_RTP_SESSION_NOTCREATED; + + int status; + BUILDER_LOCK + status = rtcpbuilder.SetLocalNote(s,len); + BUILDER_UNLOCK + return status; +} + +int RTPSession::ProcessPolledData() +{ + RTPRawPacket *rawpack; + int status; + + SOURCES_LOCK + while ((rawpack = rtptrans->GetNextPacket()) != 0) + { + sources.ClearOwnCollisionFlag(); + + // since our sources instance also uses the scheduler (analysis of incoming packets) + // we'll lock it + SCHED_LOCK + if ((status = sources.ProcessRawPacket(rawpack,rtptrans,acceptownpackets)) < 0) + { + SCHED_UNLOCK + SOURCES_UNLOCK + RTPDelete(rawpack,GetMemoryManager()); + return status; + } + SCHED_UNLOCK + + if (sources.DetectedOwnCollision()) // collision handling! + { + bool created; + + if ((status = collisionlist.UpdateAddress(rawpack->GetSenderAddress(),rawpack->GetReceiveTime(),&created)) < 0) + { + SOURCES_UNLOCK + RTPDelete(rawpack,GetMemoryManager()); + return status; + } + + if (created) // first time we've encountered this address, send bye packet and + { // change our own SSRC + PACKSENT_LOCK + bool hassentpackets = sentpackets; + PACKSENT_UNLOCK + + if (hassentpackets) + { + // Only send BYE packet if we've actually sent data using this + // SSRC + + RTCPCompoundPacket *rtcpcomppack; + + BUILDER_LOCK + if ((status = rtcpbuilder.BuildBYEPacket(&rtcpcomppack,0,0,useSR_BYEifpossible)) < 0) + { + BUILDER_UNLOCK + SOURCES_UNLOCK + RTPDelete(rawpack,GetMemoryManager()); + return status; + } + BUILDER_UNLOCK + + byepackets.push_back(rtcpcomppack); + if (byepackets.size() == 1) // was the first packet, schedule a BYE packet (otherwise there's already one scheduled) + { + SCHED_LOCK + rtcpsched.ScheduleBYEPacket(rtcpcomppack->GetCompoundPacketLength()); + SCHED_UNLOCK + } + } + // bye packet is built and scheduled, now change our SSRC + // and reset the packet count in the transmitter + + BUILDER_LOCK + uint32_t newssrc = packetbuilder.CreateNewSSRC(sources); + BUILDER_UNLOCK + + PACKSENT_LOCK + sentpackets = false; + PACKSENT_UNLOCK + + // remove old entry in source table and add new one + + if ((status = sources.DeleteOwnSSRC()) < 0) + { + SOURCES_UNLOCK + RTPDelete(rawpack,GetMemoryManager()); + return status; + } + if ((status = sources.CreateOwnSSRC(newssrc)) < 0) + { + SOURCES_UNLOCK + RTPDelete(rawpack,GetMemoryManager()); + return status; + } + } + } + RTPDelete(rawpack,GetMemoryManager()); + } + + SCHED_LOCK + RTPTime d = rtcpsched.CalculateDeterministicInterval(false); + SCHED_UNLOCK + + RTPTime t = RTPTime::CurrentTime(); + double Td = d.GetDouble(); + RTPTime sendertimeout = RTPTime(Td*sendermultiplier); + RTPTime generaltimeout = RTPTime(Td*membermultiplier); + RTPTime byetimeout = RTPTime(Td*byemultiplier); + RTPTime colltimeout = RTPTime(Td*collisionmultiplier); + RTPTime notetimeout = RTPTime(Td*notemultiplier); + + sources.MultipleTimeouts(t,sendertimeout,byetimeout,generaltimeout,notetimeout); + collisionlist.Timeout(t,colltimeout); + + // We'll check if it's time for RTCP stuff + + SCHED_LOCK + bool istime = rtcpsched.IsTime(); + SCHED_UNLOCK + + if (istime) + { + RTCPCompoundPacket *pack; + + // we'll check if there's a bye packet to send, or just a normal packet + + if (byepackets.empty()) + { + BUILDER_LOCK + if ((status = rtcpbuilder.BuildNextPacket(&pack)) < 0) + { + BUILDER_UNLOCK + SOURCES_UNLOCK + return status; + } + BUILDER_UNLOCK + if ((status = rtptrans->SendRTCPData(pack->GetCompoundPacketData(),pack->GetCompoundPacketLength())) < 0) + { + SOURCES_UNLOCK + RTPDelete(pack,GetMemoryManager()); + return status; + } + + PACKSENT_LOCK + sentpackets = true; + PACKSENT_UNLOCK + + OnSendRTCPCompoundPacket(pack); // we'll place this after the actual send to avoid tampering + } + else + { + pack = *(byepackets.begin()); + byepackets.pop_front(); + + if ((status = rtptrans->SendRTCPData(pack->GetCompoundPacketData(),pack->GetCompoundPacketLength())) < 0) + { + SOURCES_UNLOCK + RTPDelete(pack,GetMemoryManager()); + return status; + } + + PACKSENT_LOCK + sentpackets = true; + PACKSENT_UNLOCK + + OnSendRTCPCompoundPacket(pack); // we'll place this after the actual send to avoid tampering + + if (!byepackets.empty()) // more bye packets to send, schedule them + { + SCHED_LOCK + rtcpsched.ScheduleBYEPacket((*(byepackets.begin()))->GetCompoundPacketLength()); + SCHED_UNLOCK + } + } + + SCHED_LOCK + rtcpsched.AnalyseOutgoing(*pack); + SCHED_UNLOCK + + RTPDelete(pack,GetMemoryManager()); + } + SOURCES_UNLOCK + return 0; +} + +int RTPSession::CreateCNAME(uint8_t *buffer,size_t *bufferlength,bool resolve) +{ +#ifndef WIN32 + bool gotlogin = true; +#ifdef RTP_SUPPORT_GETLOGINR + buffer[0] = 0; + if (getlogin_r((char *)buffer,*bufferlength) != 0) + gotlogin = false; + else + { + if (buffer[0] == 0) + gotlogin = false; + } + + if (!gotlogin) // try regular getlogin + { + char *loginname = getlogin(); + if (loginname == 0) + gotlogin = false; + else + strncpy((char *)buffer,loginname,*bufferlength); + } +#else + char *loginname = getlogin(); + if (loginname == 0) + gotlogin = false; + else + strncpy((char *)buffer,loginname,*bufferlength); +#endif // RTP_SUPPORT_GETLOGINR + if (!gotlogin) + { + char *logname = getenv("LOGNAME"); + if (logname == 0) + return ERR_RTP_SESSION_CANTGETLOGINNAME; + strncpy((char *)buffer,logname,*bufferlength); + } +#else // Win32 version + +#ifndef _WIN32_WCE + DWORD len = *bufferlength; + if (!GetUserName((LPTSTR)buffer,&len)) +#if (defined(_MSC_VER) && _MSC_VER >= 1400 ) // Check if we can use the secure strncpy_s + strncpy_s((char *)buffer,*bufferlength,"unknown",_TRUNCATE); +#else + strncpy((char *)buffer,"unknown",*bufferlength); +#endif // Less secure version + +#else + strncpy((char *)buffer,"unknown",*bufferlength); +#endif // _WIN32_WCE + +#endif // WIN32 + buffer[*bufferlength-1] = 0; + + size_t offset = strlen((const char *)buffer); + if (offset < (*bufferlength-1)) + buffer[offset] = (uint8_t)'@'; + offset++; + + size_t buflen2 = *bufferlength-offset; + int status; + + if (resolve) + { + if ((status = rtptrans->GetLocalHostName(buffer+offset,&buflen2)) < 0) + return status; + *bufferlength = buflen2+offset; + } + else + { + char hostname[1024]; + +#if defined(WIN32) && !defined(_WIN32_WCE) && (defined(_MSC_VER) && _MSC_VER >= 1400 ) // Check if we can use the secure strncpy_s + strncpy_s(hostname,1024,"localhost",_TRUNCATE); // just in case gethostname fails +#else + strncpy(hostname,"localhost",1024); // just in case gethostname fails +#endif + gethostname(hostname,1024); +#if defined(WIN32) && !defined(_WIN32_WCE) && (defined(_MSC_VER) && _MSC_VER >= 1400 ) // Check if we can use the secure strncpy_s + strncpy_s((char *)(buffer+offset),buflen2,hostname,_TRUNCATE); +#else + strncpy((char *)(buffer+offset),hostname,buflen2); +#endif + *bufferlength = offset+strlen(hostname); + } + if (*bufferlength > RTCP_SDES_MAXITEMLENGTH) + *bufferlength = RTCP_SDES_MAXITEMLENGTH; + return 0; +} + +#ifdef RTPDEBUG +void RTPSession::DumpSources() +{ + BeginDataAccess(); + std::cout << "----------------------------------------------------------------" << std::endl; + sources.Dump(); + EndDataAccess(); +} + +void RTPSession::DumpTransmitter() +{ + if (created) + rtptrans->Dump(); +} +#endif // RTPDEBUG + |