diff --git a/src/engine/helper/HL_PoolAllocator.h b/src/engine/helper/HL_PoolAllocator.h new file mode 100644 index 00000000..0e151723 --- /dev/null +++ b/src/engine/helper/HL_PoolAllocator.h @@ -0,0 +1,179 @@ +#pragma once + +/// @file +/// @brief A thread-local fixed-block memory pool plus a std-conforming Allocator wrapper, used to +/// pool the small, short-lived, per-RTP-packet shared_ptr nodes produced by std::allocate_shared +/// (e.g. allocate_shared on the capture path and allocate_shared in the jitter buffer). Those objects are fixed-size and churn at the packet rate, so a +/// pool removes them from the general allocator's hot path. +/// +/// Pooling is active by default. Define HL_RTP_POOL=0 at compile time to make hl::PoolAllocator a +/// transparent passthrough to the global allocator (i.e. allocate_shared behaves like make_shared) +/// for A/B benchmarking without touching the call sites. + +#include +#include +#include +#include +#include + +#ifndef HL_RTP_POOL +# define HL_RTP_POOL 1 +#endif + +namespace hl +{ +#if HL_RTP_POOL + /// @class FixedBlockPool + /// A process-wide, fixed-block pool with a lock-free thread-local fast path. Identical in + /// design to the pcpp Layer pool: uniform 256-byte blocks carved from 64 KB chunks, an + /// intrusive thread-local free list, and a per-block header tag so deallocate() is O(1) and + /// lock-free for any block (and can tell pooled blocks from the global-allocator fallback used + /// for oversized requests) regardless of the freeing thread. Uniform block size makes a block + /// allocated on one thread safe to free on another (it joins the freeing thread's free list). + class FixedBlockPool + { + public: + /// Usable bytes handed back to the caller from a pooled block. Comfortably covers the + /// shared_ptr nodes we pool (control block + RTPPacket / RtpBuffer::Packet, ~90-130 bytes). + static constexpr std::size_t PayloadSize = 240; + static constexpr std::size_t BlocksPerChunk = 256; + + static void* allocate(std::size_t size) + { + if (size > PayloadSize) + { + uint8_t* raw = static_cast(::operator new(size + HeaderSize)); + tagOf(raw) = TagGlobal; + return raw + HeaderSize; + } + + void*& head = freeListHead(); + if (head == nullptr) + head = registry().refill(); + + uint8_t* block = static_cast(head); + head = nextOf(block); + return block + HeaderSize; + } + + static void deallocate(void* ptr) noexcept + { + if (ptr == nullptr) + return; + + uint8_t* block = static_cast(ptr) - HeaderSize; + if (tagOf(block) == TagPool) + { + void*& head = freeListHead(); + nextOf(block) = head; + head = block; + } + else + { + ::operator delete(static_cast(block)); + } + } + + private: + static constexpr std::size_t HeaderSize = + alignof(std::max_align_t) >= sizeof(uint64_t) ? alignof(std::max_align_t) : sizeof(uint64_t); + static constexpr std::size_t BlockSize = HeaderSize + PayloadSize; + + static constexpr uint64_t TagPool = 0x504F4F4C52545008ULL; // "POOLRTP\b" + static constexpr uint64_t TagGlobal = 0x474C4F42524C0808ULL; // "GLOBRL\b\b" + + static uint64_t& tagOf(void* block) noexcept + { + return *reinterpret_cast(block); + } + + static void*& nextOf(void* block) noexcept + { + return *reinterpret_cast(static_cast(block) + HeaderSize); + } + + static void*& freeListHead() noexcept + { + static thread_local void* head = nullptr; + return head; + } + + class ChunkRegistry + { + public: + ~ChunkRegistry() + { + std::lock_guard lock(m_Mutex); + for (uint8_t* chunk : m_Chunks) + ::operator delete(chunk); + m_Chunks.clear(); + } + + void* refill() + { + const std::size_t chunkBytes = BlockSize * BlocksPerChunk; + uint8_t* chunk = static_cast(::operator new(chunkBytes)); + + { + std::lock_guard lock(m_Mutex); + m_Chunks.push_back(chunk); + } + + void* list = nullptr; + for (std::size_t i = 0; i < BlocksPerChunk; ++i) + { + uint8_t* block = chunk + i * BlockSize; + tagOf(block) = TagPool; + nextOf(block) = list; + list = block; + } + return list; + } + + private: + std::mutex m_Mutex; + std::vector m_Chunks; + }; + + static ChunkRegistry& registry() + { + static ChunkRegistry instance; + return instance; + } + }; +#endif // HL_RTP_POOL + + /// @class PoolAllocator + /// A stateless, std-conforming Allocator suitable for std::allocate_shared. When HL_RTP_POOL is + /// enabled it serves single-node allocations from FixedBlockPool; otherwise (and for any request + /// that does not fit a pooled block) it delegates to the global allocator, matching make_shared. + template struct PoolAllocator + { + using value_type = T; + + PoolAllocator() noexcept = default; + template PoolAllocator(const PoolAllocator&) noexcept {} + + T* allocate(std::size_t n) + { +#if HL_RTP_POOL + return static_cast(FixedBlockPool::allocate(n * sizeof(T))); +#else + return static_cast(::operator new(n * sizeof(T))); +#endif + } + + void deallocate(T* p, std::size_t /*n*/) noexcept + { +#if HL_RTP_POOL + FixedBlockPool::deallocate(p); +#else + ::operator delete(static_cast(p)); +#endif + } + + template bool operator==(const PoolAllocator&) const noexcept { return true; } + template bool operator!=(const PoolAllocator&) const noexcept { return false; } + }; +} // namespace hl diff --git a/src/engine/helper/HL_Rtp.cpp b/src/engine/helper/HL_Rtp.cpp index 37d5ff21..a68e3d27 100644 --- a/src/engine/helper/HL_Rtp.cpp +++ b/src/engine/helper/HL_Rtp.cpp @@ -188,11 +188,11 @@ std::shared_ptr RtpDump::parseRtpData(const uint8_t* data, s try { // Both are heap-allocated; RTPRawPacket takes ownership and deletes them - auto* addr = new jrtplib::RTPIPv4Address(uint32_t(0), uint16_t(0)); + jrtplib::RTPIPAddress senderAddress = {jrtplib::RTPIPv4Address(uint32_t(0), uint16_t(0))}; uint8_t* dataCopy = new uint8_t[len]; std::memcpy(dataCopy, data, len); - jrtplib::RTPRawPacket raw(dataCopy, len, addr, jrtplib::RTPTime(0), true); + jrtplib::RTPRawPacket raw(dataCopy, len, senderAddress, jrtplib::RTPTime(0), true); auto packet = std::make_shared(raw); if (packet->GetCreationError() != 0) diff --git a/src/engine/media/MT_AmrCodec.h b/src/engine/media/MT_AmrCodec.h index 18018880..c15f4b06 100644 --- a/src/engine/media/MT_AmrCodec.h +++ b/src/engine/media/MT_AmrCodec.h @@ -50,9 +50,9 @@ public: int samplerate() override; int payloadType() override; - void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; - int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; - void create(CodecMap& codecs) override; + void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; + int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; + void create(CodecMap& codecs) override; PCodec create() override; diff --git a/src/engine/media/MT_AudioReceiver.cpp b/src/engine/media/MT_AudioReceiver.cpp index 6550012c..900d5a3f 100644 --- a/src/engine/media/MT_AudioReceiver.cpp +++ b/src/engine/media/MT_AudioReceiver.cpp @@ -10,6 +10,7 @@ #include "MT_Dtmf.h" #include "../helper/HL_Log.h" #include "../helper/HL_Time.h" +#include "../helper/HL_PoolAllocator.h" #include "../audio/Audio_Interface.h" #include "../audio/Audio_Resampler.h" #include @@ -158,8 +159,9 @@ std::shared_ptr RtpBuffer::add(const std::shared_ptr minno || (available < mHigh)) { - // Insert into queue - auto p = std::make_shared(packet, timelength, rate); + // Insert into queue. Pool the per-packet Packet node (object + shared_ptr control block) + // via allocate_shared; this churns at the RTP packet rate even on network-MOS-only streams. + auto p = std::allocate_shared(hl::PoolAllocator{}, packet, timelength, rate); mPacketList.push_back(p); // Sort again @@ -411,13 +413,38 @@ void AudioReceiver::setCodecSettings(const CodecList::Settings& codecSettings) if (mCodecSettings == codecSettings) return; + // Preserve the lazy-codec-map policy across SDP-driven updates: codecSettings comes from + // parseSdp()/per-call negotiation and defaults mLazyCodecMap to false, but the policy is + // set by the owner (vq-core) and must not be lost mid-stream. + const bool lazy = mCodecSettings.mLazyCodecMap; mCodecSettings = codecSettings; + mCodecSettings.mLazyCodecMap = lazy; mCodecList.setSettings(mCodecSettings); // This builds factory list with proper payload types according to payload types in settings // Rebuild codec map from factory list mCodecList.fillCodecMap(mCodecMap); } +Codec* AudioReceiver::ensureCodec(int payloadType) +{ + auto codecIter = mCodecMap.find(payloadType); + if (codecIter == mCodecMap.end()) + return nullptr; + + // mLazyCodecMap leaves the value null until first use - create it now. + if (!codecIter->second) + codecIter->second = mCodecList.createCodecByPayloadType(payloadType); + + return codecIter->second.get(); +} + +CngDecoder& AudioReceiver::cng() +{ + if (!mCngDecoder) + mCngDecoder = std::make_unique(); + return *mCngDecoder; +} + CodecList::Settings& AudioReceiver::getCodecSettings() { return mCodecSettings; @@ -548,7 +575,7 @@ void AudioReceiver::produceCNG(std::chrono::milliseconds length, Audio::DataWind if (options.mSkipDecode) mDecodedLength = 0; else - mDecodedLength = mCngDecoder.produce(mCodec->samplerate(), 100, mDecodedFrame.data(), false); + mDecodedLength = cng().produce(mCodec->samplerate(), 100, mDecodedFrame.data(), false); if (mDecodedLength) processDecoded(output, options); @@ -561,7 +588,7 @@ void AudioReceiver::produceCNG(std::chrono::milliseconds length, Audio::DataWind if (options.mSkipDecode) mDecodedLength = 0; else - mDecodedLength = mCngDecoder.produce(mCodec->samplerate(), tail, reinterpret_cast(mDecodedFrame.data()), false); + mDecodedLength = cng().produce(mCodec->samplerate(), tail, reinterpret_cast(mDecodedFrame.data()), false); if (mDecodedLength) processDecoded(output, options); @@ -579,7 +606,7 @@ AudioReceiver::DecodeResult AudioReceiver::decodeGapTo(Audio::DataWindow& output { // Synthesize comfort noise. It will be done on AUDIO_SAMPLERATE rate directly to mResampledFrame buffer. // Do not forget to send this noise to analysis - mDecodedLength = mCngDecoder.produce(mCodec->samplerate(), mLastPacketTimeLength, reinterpret_cast(mDecodedFrame.data()), false); + mDecodedLength = cng().produce(mCodec->samplerate(), mLastPacketTimeLength, reinterpret_cast(mDecodedFrame.data()), false); } else decodePacketTo(output, options, mCngPacket); @@ -668,10 +695,10 @@ AudioReceiver::DecodeResult AudioReceiver::decodePacketTo(Audio::DataWindow& out { ICELogDebug(<< "Decoding CNG"); mCngPacket = packet; - mCngDecoder.decode3389(rtp.GetPayloadData(), rtp.GetPayloadLength()); + cng().decode3389(rtp.GetPayloadData(), rtp.GetPayloadLength()); // Emit CNG mLastPacketLength milliseconds - mDecodedLength = mCngDecoder.produce(mCodec->samplerate(), mLastPacketTimeLength, (short*)mDecodedFrame.data(), true); + mDecodedLength = cng().produce(mCodec->samplerate(), mLastPacketTimeLength, (short*)mDecodedFrame.data(), true); if (mDecodedLength) processDecoded(output, options); } @@ -758,7 +785,7 @@ AudioReceiver::DecodeResult AudioReceiver::decodeEmptyTo(Audio::DataWindow& outp int ms = bytesPerMs ? (int)std::min(options.mElapsed.count(), (int64_t)(room / bytesPerMs)) : 0; if (ms <= 0) return {.mStatus = DecodeResult::Status::Skip}; - auto produced = mCngDecoder.produce(fmt.rate(), ms, (short*)(output.mutableData() + output.filled()), false); + auto produced = cng().produce(fmt.rate(), ms, (short*)(output.mutableData() + output.filled()), false); output.setFilled(output.filled() + produced); return {.mStatus = DecodeResult::Status::Ok, .mSamplerate = fmt.rate(), .mChannels = fmt.channels()}; } @@ -946,11 +973,7 @@ void AudioReceiver::makeMonoAndResample(int rate, int channels) Codec* AudioReceiver::findCodec(int payloadType) { - MT::CodecMap::const_iterator codecIter = mCodecMap.find(payloadType); - if (codecIter == mCodecMap.end()) - return nullptr; - - return codecIter->second.get(); + return ensureCodec(payloadType); } @@ -987,10 +1010,7 @@ int AudioReceiver::getSize() const AudioReceiver::MediaInfo AudioReceiver::infoFor(jrtplib::RTPPacket& p) { - CodecMap::iterator codecIter = mCodecMap.find(p.GetPayloadType()); - if (codecIter == mCodecMap.end()) - return {}; - PCodec codec = codecIter->second; + Codec* codec = ensureCodec(p.GetPayloadType()); if (!codec) return {}; @@ -1007,7 +1027,7 @@ AudioReceiver::MediaInfo AudioReceiver::infoFor(jrtplib::RTPPacket& p) else if (typeid(*codec) == typeid(OpusCodec)) { - OpusCodec* oc = dynamic_cast(codec.get()); + OpusCodec* oc = dynamic_cast(codec); assert(oc); size_t samplesCount = oc->getNumberOfSamples({p.GetPayloadData(), p.GetPayloadLength()}); int sampleratePerMs = codec->samplerate() / 1000; diff --git a/src/engine/media/MT_AudioReceiver.h b/src/engine/media/MT_AudioReceiver.h index 77b55bb6..d01eeca9 100644 --- a/src/engine/media/MT_AudioReceiver.h +++ b/src/engine/media/MT_AudioReceiver.h @@ -237,6 +237,13 @@ public: void updateDecodingTimeStatistics(); protected: + // Resolve (and lazily create) the codec for a payload type. Returns null when no + // factory handles it. Used by add()/findCodec()/infoFor() so mLazyCodecMap works. + Codec* ensureCodec(int payloadType); + + // Lazily create the comfort-noise decoder on first use. + CngDecoder& cng(); + RtpBuffer mRtpBuffer; // RTP jitter buffer itself; here are audio packets RtpBuffer mDtmfBuffer; // These two (mDtmfBuffer / mDtmfReceiver) are for our analyzer stack only; in normal softphone logic DTMF packets goes via SingleAudioStream::mDtmfReceiver DtmfReceiver mDtmfReceiver; @@ -248,7 +255,9 @@ protected: CodecList mCodecList; JitterStatistics mJitterStats; std::shared_ptr mCngPacket; - CngDecoder mCngDecoder; + // Lazily created on first CNG use (getAudioTo); its ctor calls WebRtcCng_CreateDec, + // which is wasted for the many streams that never decode comfort noise. Access via cng(). + std::unique_ptr mCngDecoder; size_t mDTXSamplesToEmit = 0; // How much silence (or CNG) should be emited before next RTP packet gets into the action // Already decoded data that can be retrieved without actual decoding - it may happen because of getAudioTo() may be limited by time interval diff --git a/src/engine/media/MT_CodecList.cpp b/src/engine/media/MT_CodecList.cpp index 0f4f9546..7e00a542 100644 --- a/src/engine/media/MT_CodecList.cpp +++ b/src/engine/media/MT_CodecList.cpp @@ -410,8 +410,10 @@ void CodecList::fillCodecMap(CodecMap& cm) cm.clear(); for (auto& factory: mFactoryList) { - // Create codec here. Although they are not needed right now - they can be needed to find codec's info. - PCodec c = factory->create(); + // Register the payload-type key. With mLazyCodecMap the codec object is left null + // and created on first use (see AudioReceiver::add/findCodec/infoFor); otherwise it + // is created eagerly so codec info is available without a packet. + PCodec c = mSettings.mLazyCodecMap ? PCodec{} : factory->create(); cm.insert({factory->payloadType(), c}); } } diff --git a/src/engine/media/MT_CodecList.h b/src/engine/media/MT_CodecList.h index c8a107c0..79b034cf 100644 --- a/src/engine/media/MT_CodecList.h +++ b/src/engine/media/MT_CodecList.h @@ -28,6 +28,14 @@ public: bool mWrapIuUP = false; bool mSkipDecode = false; + // When set, fillCodecMap() registers the payload-type keys but leaves the codec + // objects null; each codec is created on first use (add()/findCodec()/infoFor()). + // A passive monitor (vq-core) creates one AudioReceiver per media stream and most + // streams use only 1-2 payload types, so eagerly creating every registered codec + // (G722 enc+dec, G729, Opus, AMR, EVS, ...) per stream is pure waste. Default false + // keeps the eager behaviour for all other consumers (softphone, etc.). + bool mLazyCodecMap = false; + // RFC2833 DTMF int mTelephoneEvent = -1; diff --git a/src/libs/jrtplib/src/rtpaddress.h b/src/libs/jrtplib/src/rtpaddress.h index 0cef0113..609ed784 100644 --- a/src/libs/jrtplib/src/rtpaddress.h +++ b/src/libs/jrtplib/src/rtpaddress.h @@ -86,9 +86,9 @@ public: #endif // RTPDEBUG virtual ~RTPAddress() { } + // only allow subclasses to be created + RTPAddress(const AddressType t) : addresstype(t) { } protected: - // only allow subclasses to be created - RTPAddress(const AddressType t) : addresstype(t) { } private: const AddressType addresstype; }; diff --git a/src/libs/jrtplib/src/rtpexternaltransmitter.cpp b/src/libs/jrtplib/src/rtpexternaltransmitter.cpp index fd9ad5f8..1c83e220 100644 --- a/src/libs/jrtplib/src/rtpexternaltransmitter.cpp +++ b/src/libs/jrtplib/src/rtpexternaltransmitter.cpp @@ -772,6 +772,16 @@ void RTPExternalTransmitter::AbortWaitInternal() #endif // WIN32 } +// Convert a polymorphic RTPAddress into the RTPIPAddress variant that RTPRawPacket +// now stores by value. Only IPv4 / IPv6 are representable; the external transmitter +// is only ever fed IP addresses in this codebase. +static RTPIPAddress ToRTPIPAddress(const RTPAddress *addr) +{ + if (addr->GetAddressType() == RTPAddress::IPv6Address) + return RTPIPAddress{ *static_cast(addr) }; + return RTPIPAddress{ *static_cast(addr) }; +} + void RTPExternalTransmitter::InjectRTP(const void *data, size_t len, const RTPAddress &a) { if (!init) @@ -801,13 +811,16 @@ void RTPExternalTransmitter::InjectRTP(const void *data, size_t len, const RTPAd RTPTime curtime = RTPTime::CurrentTime(); RTPRawPacket *pack; - pack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPRAWPACKET) RTPRawPacket(datacopy,len,addr,curtime,true,GetMemoryManager()); + // RTPRawPacket now stores the address by value (RTPIPAddress variant), so it no + // longer takes ownership of addr; release it on every path. + pack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPRAWPACKET) RTPRawPacket(datacopy,len,ToRTPIPAddress(addr),curtime,true,GetMemoryManager()); if (pack == 0) { RTPDelete(addr,GetMemoryManager()); RTPDeleteByteArray(localhostname,GetMemoryManager()); return; } + RTPDelete(addr,GetMemoryManager()); rawpacketlist.push_back(pack); AbortWaitInternal(); @@ -843,13 +856,16 @@ void RTPExternalTransmitter::InjectRTCP(const void *data, size_t len, const RTPA RTPTime curtime = RTPTime::CurrentTime(); RTPRawPacket *pack; - pack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPRAWPACKET) RTPRawPacket(datacopy,len,addr,curtime,false,GetMemoryManager()); + // RTPRawPacket now stores the address by value (RTPIPAddress variant), so it no + // longer takes ownership of addr; release it on every path. + pack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPRAWPACKET) RTPRawPacket(datacopy,len,ToRTPIPAddress(addr),curtime,false,GetMemoryManager()); if (pack == 0) { RTPDelete(addr,GetMemoryManager()); RTPDeleteByteArray(localhostname,GetMemoryManager()); return; } + RTPDelete(addr,GetMemoryManager()); rawpacketlist.push_back(pack); AbortWaitInternal(); @@ -893,13 +909,16 @@ void RTPExternalTransmitter::InjectRTPorRTCP(const void *data, size_t len, const RTPTime curtime = RTPTime::CurrentTime(); RTPRawPacket *pack; - pack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPRAWPACKET) RTPRawPacket(datacopy,len,addr,curtime,rtp,GetMemoryManager()); + // RTPRawPacket now stores the address by value (RTPIPAddress variant), so it no + // longer takes ownership of addr; release it on every path. + pack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPRAWPACKET) RTPRawPacket(datacopy,len,ToRTPIPAddress(addr),curtime,rtp,GetMemoryManager()); if (pack == 0) { RTPDelete(addr,GetMemoryManager()); RTPDeleteByteArray(localhostname,GetMemoryManager()); return; } + RTPDelete(addr,GetMemoryManager()); rawpacketlist.push_back(pack); AbortWaitInternal(); diff --git a/src/libs/jrtplib/src/rtpipv6address.h b/src/libs/jrtplib/src/rtpipv6address.h index dfbbbb5e..92e6f612 100644 --- a/src/libs/jrtplib/src/rtpipv6address.h +++ b/src/libs/jrtplib/src/rtpipv6address.h @@ -97,6 +97,7 @@ public: #ifdef RTPDEBUG std::string GetAddressString() const; #endif // RTPDEBUG + private: in6_addr ip; uint16_t port; diff --git a/src/libs/jrtplib/src/rtprawpacket.h b/src/libs/jrtplib/src/rtprawpacket.h index d6eb2660..c966d319 100644 --- a/src/libs/jrtplib/src/rtprawpacket.h +++ b/src/libs/jrtplib/src/rtprawpacket.h @@ -41,11 +41,16 @@ #include "rtpconfig.h" #include "rtptimeutilities.h" #include "rtpaddress.h" +#include "rtpipv4address.h" +#include "rtpipv6address.h" #include "rtptypes.h" #include "rtpmemoryobject.h" +#include +#include namespace jrtplib { +typedef std::variant RTPIPAddress; /** This class is used by the transmission component to store the incoming RTP and RTCP data in. */ class JRTPLIB_IMPORTEXPORT RTPRawPacket : public RTPMemoryObject @@ -58,7 +63,7 @@ public: * The flag which indicates whether this data is RTP or RTCP data is set to \c rtp. A memory * manager can be installed as well. */ - RTPRawPacket(uint8_t *data, size_t datalen, RTPAddress *address, const RTPTime &recvtime, bool rtp, RTPMemoryManager *mgr = 0); + RTPRawPacket(uint8_t *data, size_t datalen, RTPIPAddress address, const RTPTime &recvtime, bool rtp, RTPMemoryManager *mgr = 0); ~RTPRawPacket(); /** Returns the pointer to the data which is contained in this packet. */ @@ -71,7 +76,14 @@ public: RTPTime GetReceiveTime() const { return receivetime; } /** Returns the address stored in this packet. */ - const RTPAddress *GetSenderAddress() const { return senderaddress; } + const RTPAddress* GetSenderAddress() const { + switch (senderaddress.index()) { + case 0: return std::get_if(&senderaddress); + case 1: return std::get_if(&senderaddress); + default: + return nullptr; + } + } /** Returns \c true if this data is RTP data, \c false if it is RTCP data. */ bool IsRTP() const { return isrtp; } @@ -88,25 +100,21 @@ private: uint8_t *packetdata; size_t packetdatalength; RTPTime receivetime; - RTPAddress *senderaddress; + RTPIPAddress senderaddress; bool isrtp; }; -inline RTPRawPacket::RTPRawPacket(uint8_t *data, size_t datalen, RTPAddress *address, const RTPTime &recvtime, bool rtp, RTPMemoryManager *mgr):RTPMemoryObject(mgr),receivetime(recvtime) +inline RTPRawPacket::RTPRawPacket(uint8_t *data, size_t datalen, RTPIPAddress address, const RTPTime &recvtime, bool rtp, RTPMemoryManager *mgr):RTPMemoryObject(mgr),receivetime(recvtime),senderaddress(std::move(address)) { packetdata = data; packetdatalength = datalen; - senderaddress = address; isrtp = rtp; - receivetime = recvtime; } inline RTPRawPacket::~RTPRawPacket() { if (packetdata) RTPDeleteByteArray(packetdata,GetMemoryManager()); - if (senderaddress) - RTPDelete(senderaddress,GetMemoryManager()); } } // end namespace diff --git a/src/libs/jrtplib/src/rtpsources.cpp b/src/libs/jrtplib/src/rtpsources.cpp index 0d586eff..62d6b240 100644 --- a/src/libs/jrtplib/src/rtpsources.cpp +++ b/src/libs/jrtplib/src/rtpsources.cpp @@ -278,7 +278,7 @@ int RTPSources::ProcessRawPacket(RTPRawPacket *rawpack,RTPTransmitter *rtptrans[ } else // not our own packet { - status = ProcessRTCPCompoundPacket(&rtcpcomppack,rawpack->GetReceiveTime(),rawpack->GetSenderAddress()); + status = ProcessRTCPCompoundPacket(&rtcpcomppack, rawpack->GetReceiveTime(), rawpack->GetSenderAddress()); if (status < 0) return status; } diff --git a/src/libs/jrtplib/src/rtpudpv4transmitter.cpp b/src/libs/jrtplib/src/rtpudpv4transmitter.cpp index e32ef877..c2e0f82a 100644 --- a/src/libs/jrtplib/src/rtpudpv4transmitter.cpp +++ b/src/libs/jrtplib/src/rtpudpv4transmitter.cpp @@ -1316,14 +1316,17 @@ int RTPUDPv4Transmitter::PollSocket(bool rtp) } memcpy(datacopy,packetbuffer,recvlen); - pack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPRAWPACKET) RTPRawPacket(datacopy,recvlen,addr,curtime,rtp,GetMemoryManager()); + // RTPRawPacket now stores the address by value (RTPIPAddress variant), + // so it no longer takes ownership of addr; release it on every path. + pack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPRAWPACKET) RTPRawPacket(datacopy,recvlen,*addr,curtime,rtp,GetMemoryManager()); if (pack == 0) { RTPDelete(addr,GetMemoryManager()); RTPDeleteByteArray(datacopy,GetMemoryManager()); return ERR_RTP_OUTOFMEM; } - rawpacketlist.push_back(pack); + RTPDelete(addr,GetMemoryManager()); + rawpacketlist.push_back(pack); } } len = 0; diff --git a/src/libs/jrtplib/src/rtpudpv6transmitter.cpp b/src/libs/jrtplib/src/rtpudpv6transmitter.cpp index 075e585c..6089ba42 100644 --- a/src/libs/jrtplib/src/rtpudpv6transmitter.cpp +++ b/src/libs/jrtplib/src/rtpudpv6transmitter.cpp @@ -1325,14 +1325,17 @@ int RTPUDPv6Transmitter::PollSocket(bool rtp) } memcpy(datacopy,packetbuffer,recvlen); - pack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPRAWPACKET) RTPRawPacket(datacopy,recvlen,addr,curtime,rtp,GetMemoryManager()); + // RTPRawPacket now stores the address by value (RTPIPAddress variant), + // so it no longer takes ownership of addr; release it on every path. + pack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPRAWPACKET) RTPRawPacket(datacopy,recvlen,*addr,curtime,rtp,GetMemoryManager()); if (pack == 0) { RTPDelete(addr,GetMemoryManager()); RTPDeleteByteArray(datacopy,GetMemoryManager()); return ERR_RTP_OUTOFMEM; } - rawpacketlist.push_back(pack); + RTPDelete(addr,GetMemoryManager()); + rawpacketlist.push_back(pack); } } len = 0;