From 7ffd00a6ef53b69691e02d4d2d85c5f33eb6c709 Mon Sep 17 00:00:00 2001 From: Paul-Louis Ageneau Date: Sat, 1 Jul 2023 00:46:16 +0200 Subject: [PATCH] Refactor media handlers --- CMakeLists.txt | 17 +- include/rtc/aacrtppacketizer.hpp | 40 ++--- include/rtc/av1packetizationhandler.hpp | 32 ---- include/rtc/av1rtppacketizer.hpp | 43 +++-- include/rtc/description.hpp | 4 + include/rtc/h264packetizationhandler.hpp | 32 ---- include/rtc/h264rtppacketizer.hpp | 48 ++++-- include/rtc/h265packetizationhandler.hpp | 32 ---- include/rtc/h265rtppacketizer.hpp | 49 ++++-- include/rtc/mediachainablehandler.hpp | 48 ------ include/rtc/mediahandler.hpp | 33 ++-- include/rtc/mediahandlerelement.hpp | 112 ------------ include/rtc/mediahandlerrootelement.hpp | 36 ---- include/rtc/message.hpp | 1 + include/rtc/opuspacketizationhandler.hpp | 32 ---- include/rtc/opusrtppacketizer.hpp | 47 ++--- include/rtc/rtc.hpp | 16 +- include/rtc/rtcpnackresponder.hpp | 39 ++--- include/rtc/rtcpreceivingsession.hpp | 15 +- include/rtc/rtcpsrreporter.hpp | 30 ++-- include/rtc/rtppacketizationconfig.hpp | 8 +- include/rtc/rtppacketizer.hpp | 34 ++-- include/rtc/track.hpp | 1 + src/aacrtppacketizer.cpp | 21 +-- src/av1packetizationhandler.cpp | 20 --- src/av1rtppacketizer.cpp | 40 ++--- src/capi.cpp | 120 +++++-------- src/description.cpp | 16 ++ src/h264packetizationhandler.cpp | 20 --- src/h264rtppacketizer.cpp | 35 ++-- src/h265packetizationhandler.cpp | 20 --- src/h265rtppacketizer.cpp | 32 ++-- src/impl/peerconnection.cpp | 37 +++- src/impl/peerconnection.hpp | 1 + src/impl/track.cpp | 66 +++---- src/impl/track.hpp | 4 +- src/mediachainablehandler.cpp | 163 ----------------- src/mediahandler.cpp | 63 +++++++ src/mediahandlerelement.cpp | 211 ----------------------- src/mediahandlerrootelement.cpp | 34 ---- src/opuspacketizationhandler.cpp | 20 --- src/opusrtppacketizer.cpp | 19 +- src/rtcpnackresponder.cpp | 112 ++++++------ src/rtcpreceivingsession.cpp | 144 ++++++++-------- src/rtcpsrreporter.cpp | 53 +++--- src/rtppacketizer.cpp | 22 ++- src/track.cpp | 7 + 47 files changed, 671 insertions(+), 1358 deletions(-) delete mode 100644 include/rtc/av1packetizationhandler.hpp delete mode 100644 include/rtc/h264packetizationhandler.hpp delete mode 100644 include/rtc/h265packetizationhandler.hpp delete mode 100644 include/rtc/mediachainablehandler.hpp delete mode 100644 include/rtc/mediahandlerelement.hpp delete mode 100644 include/rtc/mediahandlerrootelement.hpp delete mode 100644 include/rtc/opuspacketizationhandler.hpp delete mode 100644 src/av1packetizationhandler.cpp delete mode 100644 src/h264packetizationhandler.cpp delete mode 100644 src/h265packetizationhandler.cpp delete mode 100644 src/mediachainablehandler.cpp create mode 100644 src/mediahandler.cpp delete mode 100644 src/mediahandlerelement.cpp delete mode 100644 src/mediahandlerrootelement.cpp delete mode 100644 src/opuspacketizationhandler.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 71e3af961..8620c990b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,7 @@ set(LIBDATACHANNEL_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/configuration.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/datachannel.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/description.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/mediahandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/global.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/message.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/peerconnection.cpp @@ -76,19 +77,13 @@ set(LIBDATACHANNEL_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpsrreporter.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/rtppacketizer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/opusrtppacketizer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/opuspacketizationhandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/aacrtppacketizer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/h264rtppacketizer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/nalunit.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/h264packetizationhandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/h265rtppacketizer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/h265nalunit.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/h265packetizationhandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/av1rtppacketizer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/av1packetizationhandler.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/mediachainablehandler.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/mediahandlerelement.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/mediahandlerrootelement.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/nalunit.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpnackresponder.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/rtp.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/capi.cpp @@ -117,19 +112,13 @@ set(LIBDATACHANNEL_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rtcpsrreporter.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rtppacketizer.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/opusrtppacketizer.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/opuspacketizationhandler.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/aacrtppacketizer.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h264rtppacketizer.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/nalunit.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h264packetizationhandler.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h265rtppacketizer.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h265nalunit.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h265packetizationhandler.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/av1rtppacketizer.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/av1packetizationhandler.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/mediachainablehandler.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/mediahandlerelement.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/mediahandlerrootelement.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/nalunit.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rtcpnackresponder.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/utils.hpp ) diff --git a/include/rtc/aacrtppacketizer.hpp b/include/rtc/aacrtppacketizer.hpp index 7417f552e..434321591 100644 --- a/include/rtc/aacrtppacketizer.hpp +++ b/include/rtc/aacrtppacketizer.hpp @@ -11,14 +11,12 @@ #if RTC_ENABLE_MEDIA -#include "mediachainablehandler.hpp" -#include "mediahandlerrootelement.hpp" #include "rtppacketizer.hpp" namespace rtc { -/// RTP packetizer for aac -class RTC_CPP_EXPORT AACRtpPacketizer final : public RtpPacketizer, public MediaHandlerRootElement { +// RTP packetizer for AAC +class RTC_CPP_EXPORT AACRtpPacketizer final : public RtpPacketizer { public: /// default clock rate used in aac RTP communication inline static const uint32_t defaultClockRate = 48 * 1000; @@ -29,30 +27,28 @@ class RTC_CPP_EXPORT AACRtpPacketizer final : public RtpPacketizer, public Media /// @param rtpConfig RTP configuration AACRtpPacketizer(shared_ptr rtpConfig); - /// Creates RTP packet for given payload based on `rtpConfig`. - /// @note This function increase sequence number after packetization. - /// @param payload RTP payload - /// @param setMark This needs to be `false` for all RTP packets with aac payload - binary_ptr packetize(binary_ptr payload, bool setMark) override; - - /// Creates RTP packet for given samples (all samples share same RTP timesamp) - /// @param messages aac samples - /// @param control RTCP - /// @returns RTP packets and unchanged `control` - ChainedOutgoingProduct processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) override; + void incoming(message_vector &messages, const message_callback &send) override; + void outgoing(message_vector &messages, const message_callback &send) override; }; -/// Handler for aac packetization -class RTC_CPP_EXPORT AACPacketizationHandler final : public MediaChainableHandler { - +// Dummy wrapper for backward compatibility +class RTC_CPP_EXPORT AACPacketizationHandler final : public MediaHandler { public: - /// Construct handler for aac packetization. - /// @param packetizer RTP packetizer for aac AACPacketizationHandler(shared_ptr packetizer) - : MediaChainableHandler(packetizer) {} + : mPacketizer(std::move(packetizer)) {} + + inline void incoming(message_vector &messages, const message_callback &send) { + return mPacketizer->incoming(messages, send); + } + inline void outgoing(message_vector &messages, const message_callback &send) { + return mPacketizer->outgoing(messages, send); + } + +private: + shared_ptr mPacketizer; }; + } // namespace rtc #endif /* RTC_ENABLE_MEDIA */ diff --git a/include/rtc/av1packetizationhandler.hpp b/include/rtc/av1packetizationhandler.hpp deleted file mode 100644 index ed7941de6..000000000 --- a/include/rtc/av1packetizationhandler.hpp +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2023 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_AV1_PACKETIZATION_HANDLER_H -#define RTC_AV1_PACKETIZATION_HANDLER_H - -#if RTC_ENABLE_MEDIA - -#include "av1rtppacketizer.hpp" -#include "mediachainablehandler.hpp" -#include "nalunit.hpp" - -namespace rtc { - -/// Handler for AV1 packetization -class RTC_CPP_EXPORT AV1PacketizationHandler final : public MediaChainableHandler { -public: - /// Construct handler for AV1 packetization. - /// @param packetizer RTP packetizer for AV1 - AV1PacketizationHandler(shared_ptr packetizer); -}; - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ - -#endif /* RTC_AV1_PACKETIZATION_HANDLER_H */ diff --git a/include/rtc/av1rtppacketizer.hpp b/include/rtc/av1rtppacketizer.hpp index 9e7432a0f..36f170491 100644 --- a/include/rtc/av1rtppacketizer.hpp +++ b/include/rtc/av1rtppacketizer.hpp @@ -11,19 +11,16 @@ #if RTC_ENABLE_MEDIA -#include "mediahandlerrootelement.hpp" +#include "mediahandler.hpp" #include "nalunit.hpp" #include "rtppacketizer.hpp" namespace rtc { -/// RTP packetization of AV1 payload -class RTC_CPP_EXPORT AV1RtpPacketizer final : public RtpPacketizer, public MediaHandlerRootElement { - shared_ptr splitMessage(binary_ptr message); - const uint16_t maximumFragmentSize; - +// RTP packetization of AV1 payload +class RTC_CPP_EXPORT AV1RtpPacketizer final : public RtpPacketizer { public: - /// Default clock rate for AV1 in RTP + // Default clock rate for AV1 in RTP inline static const uint32_t defaultClockRate = 90 * 1000; // Define how OBUs are seperated in a AV1 Sample @@ -32,21 +29,39 @@ class RTC_CPP_EXPORT AV1RtpPacketizer final : public RtpPacketizer, public Media TemporalUnit = RTC_OBU_PACKETIZED_TEMPORAL_UNIT, }; - /// Constructs AV1 payload packetizer with given RTP configuration. - /// @note RTP configuration is used in packetization process which may change some configuration - /// properties such as sequence number. - /// @param rtpConfig RTP configuration + // Constructs AV1 payload packetizer with given RTP configuration. + // @note RTP configuration is used in packetization process which may change some configuration + // properties such as sequence number. AV1RtpPacketizer(Packetization packetization, shared_ptr rtpConfig, uint16_t maximumFragmentSize = NalUnits::defaultMaximumFragmentSize); - ChainedOutgoingProduct processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) override; + void incoming(message_vector &messages, const message_callback &send) override; + void outgoing(message_vector &messages, const message_callback &send) override; private: + shared_ptr splitMessage(binary_ptr message); + std::vector> packetizeObu(binary_ptr message, uint16_t maximumFragmentSize); + + const uint16_t maximumFragmentSize; const Packetization packetization; std::shared_ptr sequenceHeader; +}; - std::vector> packetizeObu(binary_ptr message, uint16_t maximumFragmentSize); +// Dummy wrapper for backward compatibility +class RTC_CPP_EXPORT AV1PacketizationHandler final : public MediaHandler { +public: + AV1PacketizationHandler(shared_ptr packetizer) + : mPacketizer(std::move(packetizer)) {} + + inline void incoming(message_vector &messages, const message_callback &send) { + return mPacketizer->incoming(messages, send); + } + inline void outgoing(message_vector &messages, const message_callback &send) { + return mPacketizer->outgoing(messages, send); + } + +private: + shared_ptr mPacketizer; }; } // namespace rtc diff --git a/include/rtc/description.hpp b/include/rtc/description.hpp index 22174a782..b89838a53 100644 --- a/include/rtc/description.hpp +++ b/include/rtc/description.hpp @@ -109,6 +109,7 @@ class RTC_CPP_EXPORT Description { std::vector extIds(); ExtMap *extMap(int id); + const ExtMap *extMap(int id) const; void addExtMap(ExtMap map); void removeExtMap(int id); @@ -208,6 +209,7 @@ class RTC_CPP_EXPORT Description { bool hasPayloadType(int payloadType) const; std::vector payloadTypes() const; RtpMap *rtpMap(int payloadType); + const RtpMap *rtpMap(int payloadType) const; void addRtpMap(RtpMap map); void removeRtpMap(int payloadType); void removeFormat(const string &format); @@ -233,7 +235,9 @@ class RTC_CPP_EXPORT Description { void addAudioCodec(int payloadType, string codec, optional profile = std::nullopt); void addOpusCodec(int payloadType, optional profile = DEFAULT_OPUS_AUDIO_PROFILE); + void addPCMACodec(int payloadType, optional profile = std::nullopt); + void addPCMUCodec(int payloadType, optional profile = std::nullopt); void addAacCodec(int payloadType, optional profile = std::nullopt); }; diff --git a/include/rtc/h264packetizationhandler.hpp b/include/rtc/h264packetizationhandler.hpp deleted file mode 100644 index fe4859bee..000000000 --- a/include/rtc/h264packetizationhandler.hpp +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_H264_PACKETIZATION_HANDLER_H -#define RTC_H264_PACKETIZATION_HANDLER_H - -#if RTC_ENABLE_MEDIA - -#include "h264rtppacketizer.hpp" -#include "mediachainablehandler.hpp" -#include "nalunit.hpp" - -namespace rtc { - -/// Handler for H264 packetization -class RTC_CPP_EXPORT H264PacketizationHandler final : public MediaChainableHandler { -public: - /// Construct handler for H264 packetization. - /// @param packetizer RTP packetizer for h264 - H264PacketizationHandler(shared_ptr packetizer); -}; - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ - -#endif /* RTC_H264_PACKETIZATION_HANDLER_H */ diff --git a/include/rtc/h264rtppacketizer.hpp b/include/rtc/h264rtppacketizer.hpp index 63f01e981..744a56590 100644 --- a/include/rtc/h264rtppacketizer.hpp +++ b/include/rtc/h264rtppacketizer.hpp @@ -1,5 +1,6 @@ /** * Copyright (c) 2020 Filip Klembara (in2core) + * Copyright (c) 2023 Paul-Louis Ageneau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -11,42 +12,59 @@ #if RTC_ENABLE_MEDIA -#include "mediahandlerrootelement.hpp" #include "nalunit.hpp" #include "rtppacketizer.hpp" namespace rtc { -/// RTP packetization of h264 payload -class RTC_CPP_EXPORT H264RtpPacketizer final : public RtpPacketizer, - public MediaHandlerRootElement { - shared_ptr splitMessage(binary_ptr message); - const uint16_t maximumFragmentSize; - +// RTP packetization for H264 +class RTC_CPP_EXPORT H264RtpPacketizer final : public RtpPacketizer { public: using Separator = NalUnit::Separator; - /// Default clock rate for H264 in RTP + // Default clock rate for H264 in RTP inline static const uint32_t defaultClockRate = 90 * 1000; + // Constructs h264 payload packetizer with given RTP configuration. + // @note RTP configuration is used in packetization process which may change some configuration + // properties such as sequence number. + // @param separator NAL unit separator + // @param rtpConfig RTP configuration + // @param maximumFragmentSize maximum size of one NALU fragment H264RtpPacketizer(Separator separator, shared_ptr rtpConfig, uint16_t maximumFragmentSize = NalUnits::defaultMaximumFragmentSize); - /// Constructs h264 payload packetizer with given RTP configuration. - /// @note RTP configuration is used in packetization process which may change some configuration - /// properties such as sequence number. - /// @param rtpConfig RTP configuration - /// @param maximumFragmentSize maximum size of one NALU fragment + // TODO: deprecate H264RtpPacketizer(shared_ptr rtpConfig, uint16_t maximumFragmentSize = NalUnits::defaultMaximumFragmentSize); - ChainedOutgoingProduct processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) override; + void incoming(message_vector &messages, const message_callback &send) override; + void outgoing(message_vector &messages, const message_callback &send) override; private: + shared_ptr splitMessage(binary_ptr message); + + const uint16_t maximumFragmentSize; const Separator separator; }; +// Dummy wrapper for backward compatibility +class RTC_CPP_EXPORT H264PacketizationHandler final : public MediaHandler { +public: + H264PacketizationHandler(shared_ptr packetizer) + : mPacketizer(std::move(packetizer)) {} + + inline void incoming(message_vector &messages, const message_callback &send) { + return mPacketizer->incoming(messages, send); + } + inline void outgoing(message_vector &messages, const message_callback &send) { + return mPacketizer->outgoing(messages, send); + } + +private: + shared_ptr mPacketizer; +}; + } // namespace rtc #endif /* RTC_ENABLE_MEDIA */ diff --git a/include/rtc/h265packetizationhandler.hpp b/include/rtc/h265packetizationhandler.hpp deleted file mode 100644 index 17fb25b8c..000000000 --- a/include/rtc/h265packetizationhandler.hpp +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2023 Zita Liao (Dolby) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_H265_PACKETIZATION_HANDLER_H -#define RTC_H265_PACKETIZATION_HANDLER_H - -#if RTC_ENABLE_MEDIA - -#include "h265nalunit.hpp" -#include "h265rtppacketizer.hpp" -#include "mediachainablehandler.hpp" - -namespace rtc { - -/// Handler for H265 packetization -class RTC_CPP_EXPORT H265PacketizationHandler final : public MediaChainableHandler { -public: - /// Construct handler for H265 packetization. - /// @param packetizer RTP packetizer for h265 - H265PacketizationHandler(shared_ptr packetizer); -}; - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ - -#endif /* RTC_H265_PACKETIZATION_HANDLER_H */ diff --git a/include/rtc/h265rtppacketizer.hpp b/include/rtc/h265rtppacketizer.hpp index 02e68692d..018cf40f9 100644 --- a/include/rtc/h265rtppacketizer.hpp +++ b/include/rtc/h265rtppacketizer.hpp @@ -12,41 +12,58 @@ #if RTC_ENABLE_MEDIA #include "h265nalunit.hpp" -#include "mediahandlerrootelement.hpp" #include "rtppacketizer.hpp" namespace rtc { -/// RTP packetization of h265 payload -class RTC_CPP_EXPORT H265RtpPacketizer final : public RtpPacketizer, - public MediaHandlerRootElement { - shared_ptr splitMessage(binary_ptr message); - const uint16_t maximumFragmentSize; - +// RTP packetization for H265 +class RTC_CPP_EXPORT H265RtpPacketizer final : public RtpPacketizer { public: using Separator = NalUnit::Separator; - /// Default clock rate for H265 in RTP + // Default clock rate for H265 in RTP inline static const uint32_t defaultClockRate = 90 * 1000; - H265RtpPacketizer(NalUnit::Separator separator, shared_ptr rtpConfig, + // Constructs h265 payload packetizer with given RTP configuration. + // @note RTP configuration is used in packetization process which may change some configuration + // properties such as sequence number. + // @param separator NAL unit separator + // @param rtpConfig RTP configuration + // @param maximumFragmentSize maximum size of one NALU fragment + H265RtpPacketizer(Separator separator, shared_ptr rtpConfig, uint16_t maximumFragmentSize = H265NalUnits::defaultMaximumFragmentSize); - /// Constructs h265 payload packetizer with given RTP configuration. - /// @note RTP configuration is used in packetization process which may change some configuration - /// properties such as sequence number. - /// @param rtpConfig RTP configuration - /// @param maximumFragmentSize maximum size of one NALU fragment + // TODO: deprecate H265RtpPacketizer(shared_ptr rtpConfig, uint16_t maximumFragmentSize = H265NalUnits::defaultMaximumFragmentSize); - ChainedOutgoingProduct processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) override; + void incoming(message_vector &messages, const message_callback &send) override; + void outgoing(message_vector &messages, const message_callback &send) override; private: + shared_ptr splitMessage(binary_ptr message); + + const uint16_t maximumFragmentSize; const NalUnit::Separator separator; }; +// Dummy wrapper for backward compatibility +class RTC_CPP_EXPORT H265PacketizationHandler final : public MediaHandler { +public: + H265PacketizationHandler(shared_ptr packetizer) + : mPacketizer(std::move(packetizer)) {} + + inline void incoming(message_vector &messages, const message_callback &send) { + return mPacketizer->incoming(messages, send); + } + inline void outgoing(message_vector &messages, const message_callback &send) { + return mPacketizer->outgoing(messages, send); + } + +private: + shared_ptr mPacketizer; +}; + } // namespace rtc #endif /* RTC_ENABLE_MEDIA */ diff --git a/include/rtc/mediachainablehandler.hpp b/include/rtc/mediachainablehandler.hpp deleted file mode 100644 index 05ca3ef23..000000000 --- a/include/rtc/mediachainablehandler.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_MEDIA_CHAINABLE_HANDLER_H -#define RTC_MEDIA_CHAINABLE_HANDLER_H - -#if RTC_ENABLE_MEDIA - -#include "mediahandler.hpp" -#include "mediahandlerrootelement.hpp" - -namespace rtc { - -class RTC_CPP_EXPORT MediaChainableHandler : public MediaHandler { - const shared_ptr root; - shared_ptr leaf; - mutable std::mutex mutex; - - message_ptr handleIncomingBinary(message_ptr); - message_ptr handleIncomingControl(message_ptr); - message_ptr handleOutgoingBinary(message_ptr); - message_ptr handleOutgoingControl(message_ptr); - bool sendProduct(ChainedOutgoingProduct product); - shared_ptr getLeaf() const; - -public: - MediaChainableHandler(shared_ptr root); - ~MediaChainableHandler(); - message_ptr incoming(message_ptr ptr) override; - message_ptr outgoing(message_ptr ptr) override; - - bool send(message_ptr msg); - - /// Adds element to chain - /// @param chainable Chainable element - void addToChain(shared_ptr chainable); -}; - -} // namespace rtc - -#endif // RTC_ENABLE_MEDIA - -#endif // RTC_MEDIA_CHAINABLE_HANDLER_H diff --git a/include/rtc/mediahandler.hpp b/include/rtc/mediahandler.hpp index 4dbc717a0..76548ae7a 100644 --- a/include/rtc/mediahandler.hpp +++ b/include/rtc/mediahandler.hpp @@ -11,28 +11,37 @@ #define RTC_MEDIA_HANDLER_H #include "common.hpp" +#include "description.hpp" #include "message.hpp" namespace rtc { -class RTC_CPP_EXPORT MediaHandler { -protected: - // Use this callback when trying to send custom data (such as RTCP) to the client. - synchronized_callback outgoingCallback; - +class RTC_CPP_EXPORT MediaHandler : std::enable_shared_from_this { public: + // Called when a media is added or updated + virtual void media([[maybe_unused]] const Description::Media &desc) {} + // Called when there is traffic coming from the peer - virtual message_ptr incoming(message_ptr ptr) = 0; + virtual void incoming(message_vector &messages, const message_callback &send) = 0; // Called when there is traffic that needs to be sent to the peer - virtual message_ptr outgoing(message_ptr ptr) = 0; + virtual void outgoing(message_vector &messages, const message_callback &send) = 0; + + void addToChain(shared_ptr handler); + void setNext(shared_ptr handler); + shared_ptr next(); + shared_ptr next() const; + shared_ptr last(); // never null + shared_ptr last() const; // never null + + virtual bool requestKeyframe(); // TODO - // This callback is used to send traffic back to the peer. - void onOutgoing(const std::function &cb) { - this->outgoingCallback = synchronized_callback(cb); - } + void mediaChain(const Description::Media &desc); + void incomingChain(message_vector &messages, const message_callback &send); + void outgoingChain(message_vector &messages, const message_callback &send); - virtual bool requestKeyframe() { return false; } +private: + shared_ptr mNext; }; } // namespace rtc diff --git a/include/rtc/mediahandlerelement.hpp b/include/rtc/mediahandlerelement.hpp deleted file mode 100644 index bead429e8..000000000 --- a/include/rtc/mediahandlerelement.hpp +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_MEDIA_HANDLER_ELEMENT_H -#define RTC_MEDIA_HANDLER_ELEMENT_H - -#if RTC_ENABLE_MEDIA - -#include "common.hpp" -#include "message.hpp" -#include "rtp.hpp" - -namespace rtc { - -using ChainedMessagesProduct = shared_ptr>; - -RTC_CPP_EXPORT ChainedMessagesProduct make_chained_messages_product(); -RTC_CPP_EXPORT ChainedMessagesProduct make_chained_messages_product(message_ptr msg); - -/// Ougoing messages -struct RTC_CPP_EXPORT ChainedOutgoingProduct { - ChainedOutgoingProduct(ChainedMessagesProduct messages = nullptr, - message_ptr control = nullptr); - const ChainedMessagesProduct messages; - const message_ptr control; -}; - -/// Incoming messages with response -struct RTC_CPP_EXPORT ChainedIncomingProduct { - ChainedIncomingProduct(ChainedMessagesProduct incoming = nullptr, - ChainedMessagesProduct outgoing = nullptr); - const ChainedMessagesProduct incoming; - const ChainedOutgoingProduct outgoing; -}; - -/// Incoming control messages with response -struct RTC_CPP_EXPORT ChainedIncomingControlProduct { - ChainedIncomingControlProduct(message_ptr incoming, - optional outgoing = nullopt); - const message_ptr incoming; - const optional outgoing; -}; - -/// Chainable handler -class RTC_CPP_EXPORT MediaHandlerElement - : public std::enable_shared_from_this { - shared_ptr upstream = nullptr; - shared_ptr downstream = nullptr; - - void prepareAndSendResponse(optional outgoing, - std::function send); - - void removeFromChain(); - -public: - MediaHandlerElement(); - - /// Creates response to incoming message - /// @param messages Current repsonse - /// @returns New response - optional processOutgoingResponse(ChainedOutgoingProduct messages); - - // Process incoming and ougoing messages - message_ptr formIncomingControlMessage(message_ptr message, - std::function send); - ChainedMessagesProduct - formIncomingBinaryMessage(ChainedMessagesProduct messages, - std::function send); - message_ptr formOutgoingControlMessage(message_ptr message); - optional formOutgoingBinaryMessage(ChainedOutgoingProduct product); - - /// Process current control message - /// @param messages current message - /// @returns Modified message and response - virtual ChainedIncomingControlProduct processIncomingControlMessage(message_ptr messages); - - /// Process current control message - /// @param messages current message - /// @returns Modified message - virtual message_ptr processOutgoingControlMessage(message_ptr messages); - - /// Process current binary message - /// @param messages current message - /// @returns Modified message and response - virtual ChainedIncomingProduct processIncomingBinaryMessage(ChainedMessagesProduct messages); - - /// Process current binary message - /// @param messages current message - /// @param control current control message - /// @returns Modified binary message and control message - virtual ChainedOutgoingProduct processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control); - - /// Set given element as upstream to this - /// @param upstream Upstream element - /// @returns Upstream element - shared_ptr chainWith(shared_ptr upstream); - - /// Remove all downstream elements from chain - void recursiveRemoveChain(); -}; - -} // namespace rtc - -#endif // RTC_ENABLE_MEDIA - -#endif // RTC_MEDIA_HANDLER_ELEMENT_H diff --git a/include/rtc/mediahandlerrootelement.hpp b/include/rtc/mediahandlerrootelement.hpp deleted file mode 100644 index 74ee28392..000000000 --- a/include/rtc/mediahandlerrootelement.hpp +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_MEDIA_HANDLER_ROOT_ELEMENT_H -#define RTC_MEDIA_HANDLER_ROOT_ELEMENT_H - -#if RTC_ENABLE_MEDIA - -#include "mediahandlerelement.hpp" - -namespace rtc { - -/// Chainable message handler -class RTC_CPP_EXPORT MediaHandlerRootElement : public MediaHandlerElement { -public: - MediaHandlerRootElement() {} - - /// Reduce multiple messages into one message - /// @param messages Messages to reduce - virtual message_ptr reduce(ChainedMessagesProduct messages); - - /// Splits message into multiple messages - /// @param message Message to split - virtual ChainedMessagesProduct split(message_ptr message); -}; - -} // namespace rtc - -#endif // RTC_ENABLE_MEDIA - -#endif // RTC_MEDIA_HANDLER_ROOT_ELEMENT_H diff --git a/include/rtc/message.hpp b/include/rtc/message.hpp index 9a064f235..eeddb9e19 100644 --- a/include/rtc/message.hpp +++ b/include/rtc/message.hpp @@ -36,6 +36,7 @@ struct RTC_CPP_EXPORT Message : binary { using message_ptr = shared_ptr; using message_callback = std::function; +using message_vector = std::vector; inline size_t message_size_func(const message_ptr &m) { return m->type == Message::Binary || m->type == Message::String ? m->size() : 0; diff --git a/include/rtc/opuspacketizationhandler.hpp b/include/rtc/opuspacketizationhandler.hpp deleted file mode 100644 index 624058d18..000000000 --- a/include/rtc/opuspacketizationhandler.hpp +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#ifndef RTC_OPUS_PACKETIZATION_HANDLER_H -#define RTC_OPUS_PACKETIZATION_HANDLER_H - -#if RTC_ENABLE_MEDIA - -#include "mediachainablehandler.hpp" -#include "opusrtppacketizer.hpp" - -namespace rtc { - -/// Handler for opus packetization -class RTC_CPP_EXPORT OpusPacketizationHandler final : public MediaChainableHandler { - -public: - /// Construct handler for opus packetization. - /// @param packetizer RTP packetizer for opus - OpusPacketizationHandler(shared_ptr packetizer); -}; - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ - -#endif /* RTC_OPUS_PACKETIZATION_HANDLER_H */ diff --git a/include/rtc/opusrtppacketizer.hpp b/include/rtc/opusrtppacketizer.hpp index 2cddf4691..a5e1f6e78 100644 --- a/include/rtc/opusrtppacketizer.hpp +++ b/include/rtc/opusrtppacketizer.hpp @@ -11,36 +11,41 @@ #if RTC_ENABLE_MEDIA -#include "mediahandlerrootelement.hpp" #include "rtppacketizer.hpp" namespace rtc { -/// RTP packetizer for opus -class RTC_CPP_EXPORT OpusRtpPacketizer final : public RtpPacketizer, - public MediaHandlerRootElement { +// RTP packetizer for Opus +class RTC_CPP_EXPORT OpusRtpPacketizer final : public RtpPacketizer { public: - /// default clock rate used in opus RTP communication + // default clock rate used in opus RTP communication inline static const uint32_t defaultClockRate = 48 * 1000; - /// Constructs opus packetizer with given RTP configuration. - /// @note RTP configuration is used in packetization process which may change some configuration - /// properties such as sequence number. - /// @param rtpConfig RTP configuration + // Constructs opus packetizer with given RTP configuration. + // @note RTP configuration is used in packetization process which may change some configuration + // properties such as sequence number. + // @param rtpConfig RTP configuration OpusRtpPacketizer(shared_ptr rtpConfig); - /// Creates RTP packet for given payload based on `rtpConfig`. - /// @note This function increase sequence number after packetization. - /// @param payload RTP payload - /// @param setMark This needs to be `false` for all RTP packets with opus payload - binary_ptr packetize(binary_ptr payload, bool setMark) override; - - /// Creates RTP packet for given samples (all samples share same RTP timesamp) - /// @param messages opus samples - /// @param control RTCP - /// @returns RTP packets and unchanged `control` - ChainedOutgoingProduct processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) override; + void incoming(message_vector &messages, const message_callback &send) override; + void outgoing(message_vector &messages, const message_callback &send) override; +}; + +// Dummy wrapper for backward compatibility +class RTC_CPP_EXPORT OpusPacketizationHandler final : public MediaHandler { +public: + OpusPacketizationHandler(shared_ptr packetizer) + : mPacketizer(std::move(packetizer)) {} + + inline void incoming(message_vector &messages, const message_callback &send) { + return mPacketizer->incoming(messages, send); + } + inline void outgoing(message_vector &messages, const message_callback &send) { + return mPacketizer->outgoing(messages, send); + } + +private: + shared_ptr mPacketizer; }; } // namespace rtc diff --git a/include/rtc/rtc.hpp b/include/rtc/rtc.hpp index 5fdb7fcd7..eb760d282 100644 --- a/include/rtc/rtc.hpp +++ b/include/rtc/rtc.hpp @@ -27,17 +27,15 @@ #if RTC_ENABLE_MEDIA -// Media handling -#include "mediachainablehandler.hpp" +// Media +#include "aacrtppacketizer.hpp" +#include "av1rtppacketizer.hpp" +#include "h264rtppacketizer.hpp" +#include "h265rtppacketizer.hpp" +#include "mediahandler.hpp" +#include "opusrtppacketizer.hpp" #include "rtcpnackresponder.hpp" #include "rtcpreceivingsession.hpp" #include "rtcpsrreporter.hpp" -// Opus/AAC/h264/h265/AV1 streaming -#include "aacrtppacketizer.hpp" -#include "av1packetizationhandler.hpp" -#include "h264packetizationhandler.hpp" -#include "h265packetizationhandler.hpp" -#include "opuspacketizationhandler.hpp" - #endif // RTC_ENABLE_MEDIA diff --git a/include/rtc/rtcpnackresponder.hpp b/include/rtc/rtcpnackresponder.hpp index 10f4cfeee..71ced1320 100644 --- a/include/rtc/rtcpnackresponder.hpp +++ b/include/rtc/rtcpnackresponder.hpp @@ -11,16 +11,24 @@ #if RTC_ENABLE_MEDIA -#include "mediahandlerelement.hpp" +#include "mediahandler.hpp" #include #include namespace rtc { -class RTC_CPP_EXPORT RtcpNackResponder final : public MediaHandlerElement { +class RTC_CPP_EXPORT RtcpNackResponder final : public MediaHandler { +public: + static const size_t DefaultMaxSize = 512; + + RtcpNackResponder(size_t maxSize = DefaultMaxSize); + + void incoming(message_vector &messages, const message_callback &send) override; + void outgoing(message_vector &messages, const message_callback &send) override; - /// Packet storage +private: + // Packet storage class RTC_CPP_EXPORT Storage { /// Packet storage element @@ -42,15 +50,13 @@ class RTC_CPP_EXPORT RtcpNackResponder final : public MediaHandlerElement { std::mutex mutex; /// Maximum storage size - const unsigned maximumSize; + const size_t maxSize; /// Returns current size - unsigned size(); + size_t size(); public: - static const unsigned defaultMaximumSize = 512; - - Storage(unsigned _maximumSize); + Storage(size_t _maxSize); /// Returns packet with given sequence number optional get(uint16_t sequenceNumber); @@ -60,22 +66,7 @@ class RTC_CPP_EXPORT RtcpNackResponder final : public MediaHandlerElement { void store(binary_ptr packet); }; - const shared_ptr storage; - -public: - RtcpNackResponder(unsigned maxStoredPacketCount = Storage::defaultMaximumSize); - - /// Checks for RTCP NACK and handles it, - /// @param message RTCP message - /// @returns unchanged RTCP message and requested RTP packets - ChainedIncomingControlProduct processIncomingControlMessage(message_ptr message) override; - - /// Stores RTP packets in internal storage - /// @param messages RTP packets - /// @param control RTCP - /// @returns Unchanged RTP and RTCP - ChainedOutgoingProduct processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) override; + const shared_ptr mStorage; }; } // namespace rtc diff --git a/include/rtc/rtcpreceivingsession.hpp b/include/rtc/rtcpreceivingsession.hpp index 0760495cb..fef7d4cab 100644 --- a/include/rtc/rtcpreceivingsession.hpp +++ b/include/rtc/rtcpreceivingsession.hpp @@ -22,19 +22,20 @@ namespace rtc { // An RtcpSession can be plugged into a Track to handle the whole RTCP session class RTC_CPP_EXPORT RtcpReceivingSession : public MediaHandler { public: - message_ptr incoming(message_ptr ptr) override; - message_ptr outgoing(message_ptr ptr) override; - bool send(message_ptr ptr); + RtcpReceivingSession() = default; + virtual ~RtcpReceivingSession() = default; void requestBitrate(unsigned int newBitrate); + void incoming(message_vector &messages, const message_callback &send) override; + void outgoing(message_vector &messages, const message_callback &send) override; + bool requestKeyframe() override; protected: - void pushREMB(unsigned int bitrate); - void pushRR(unsigned int lastSR_delay); - - void pushPLI(); + void pushREMB(const message_callback &send, unsigned int bitrate); + void pushRR(const message_callback &send,unsigned int lastSrDelay); + void pushPLI(const message_callback &send); unsigned int mRequestedBitrate = 0; SSRC mSsrc = 0; diff --git a/include/rtc/rtcpsrreporter.hpp b/include/rtc/rtcpsrreporter.hpp index ddd2cf85e..e3a51e61e 100644 --- a/include/rtc/rtcpsrreporter.hpp +++ b/include/rtc/rtcpsrreporter.hpp @@ -6,34 +6,34 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -#ifndef RTC_RTCP_SENDER_REPORTABLE_H -#define RTC_RTCP_SENDER_REPORTABLE_H +#ifndef RTC_RTCP_SR_REPORTER_H +#define RTC_RTCP_SR_REPORTER_H #if RTC_ENABLE_MEDIA -#include "mediahandlerelement.hpp" -#include "message.hpp" +#include "mediahandler.hpp" #include "rtppacketizationconfig.hpp" +#include "rtp.hpp" namespace rtc { -class RTC_CPP_EXPORT RtcpSrReporter final : public MediaHandlerElement { - void addToReport(RtpHeader *rtp, uint32_t rtpSize); - message_ptr getSenderReport(uint32_t timestamp); - +class RTC_CPP_EXPORT RtcpSrReporter final : public MediaHandler { public: - /// RTP configuration - const shared_ptr rtpConfig; - RtcpSrReporter(shared_ptr rtpConfig); - ChainedOutgoingProduct processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) override; - uint32_t lastReportedTimestamp() const; void setNeedsToReport(); + void incoming(message_vector &messages, const message_callback &send) override; + void outgoing(message_vector &messages, const message_callback &send) override; + + // TODO + const shared_ptr rtpConfig; + private: + void addToReport(RtpHeader *rtp, uint32_t rtpSize); + message_ptr getSenderReport(uint32_t timestamp); + uint32_t mPacketCount = 0; uint32_t mPayloadOctets = 0; uint32_t mLastReportedTimestamp = 0; @@ -44,4 +44,4 @@ class RTC_CPP_EXPORT RtcpSrReporter final : public MediaHandlerElement { #endif /* RTC_ENABLE_MEDIA */ -#endif /* RTC_RTCP_SENDER_REPORTABLE_H */ +#endif /* RTC_RTCP_SR_REPORTER_H */ diff --git a/include/rtc/rtppacketizationconfig.hpp b/include/rtc/rtppacketizationconfig.hpp index ce0a180da..0e6dcada2 100644 --- a/include/rtc/rtppacketizationconfig.hpp +++ b/include/rtc/rtppacketizationconfig.hpp @@ -19,10 +19,10 @@ namespace rtc { class RTC_CPP_EXPORT RtpPacketizationConfig { public: SSRC ssrc; - const std::string cname; - const uint8_t payloadType; - const uint32_t clockRate; - const uint8_t videoOrientationId; + std::string cname; + uint8_t payloadType; + uint32_t clockRate; + uint8_t videoOrientationId; // current sequence number uint16_t sequenceNumber; diff --git a/include/rtc/rtppacketizer.hpp b/include/rtc/rtppacketizer.hpp index cf096e9d1..c0ea1d1d4 100644 --- a/include/rtc/rtppacketizer.hpp +++ b/include/rtc/rtppacketizer.hpp @@ -11,31 +11,35 @@ #if RTC_ENABLE_MEDIA +#include "mediahandler.hpp" #include "message.hpp" #include "rtppacketizationconfig.hpp" namespace rtc { -/// Class responsible for RTP packetization -class RTC_CPP_EXPORT RtpPacketizer { - static const auto rtpHeaderSize = 12; - static const auto rtpExtHeaderCvoSize = 8; - +// RTP packetizer +class RTC_CPP_EXPORT RtpPacketizer : public MediaHandler { public: - // RTP configuration + // RTP packetization config const shared_ptr rtpConfig; - /// Constructs packetizer with given RTP configuration. - /// @note RTP configuration is used in packetization process which may change some configuration - /// properties such as sequence number. - /// @param rtpConfig RTP configuration + // Constructs packetizer with given RTP configuration. + // @note RTP configuration is used in packetization process which may change some configuration + // properties such as sequence number. + // @param rtpConfig RTP configuration RtpPacketizer(shared_ptr rtpConfig); - /// Creates RTP packet for given payload based on `rtpConfig`. - /// @note This function increase sequence number after packetization. - /// @param payload RTP payload - /// @param setMark Set marker flag in RTP packet if true - virtual shared_ptr packetize(shared_ptr payload, bool setMark); + // Creates RTP packet for given payload based on `rtpConfig`. + // @note This function increase sequence number after packetization. + // @param payload RTP payload + // @param setMark Set marker flag in RTP packet if true + virtual message_ptr packetize(shared_ptr payload, bool mark); + +private: + static const auto RtpHeaderSize = 12; + static const auto RtpExtHeaderCvoSize = 8; + + virtual void media(const Description::Media &desc) override; }; } // namespace rtc diff --git a/include/rtc/track.hpp b/include/rtc/track.hpp index a47ba5ae6..72b03f359 100644 --- a/include/rtc/track.hpp +++ b/include/rtc/track.hpp @@ -44,6 +44,7 @@ class RTC_CPP_EXPORT Track final : private CheshireCat, public Chan bool requestKeyframe(); void setMediaHandler(shared_ptr handler); + void chainMediaHandler(shared_ptr handler); shared_ptr getMediaHandler(); // Deprecated, use setMediaHandler() and getMediaHandler() diff --git a/src/aacrtppacketizer.cpp b/src/aacrtppacketizer.cpp index 3d11c29f1..ac9b540c8 100644 --- a/src/aacrtppacketizer.cpp +++ b/src/aacrtppacketizer.cpp @@ -15,22 +15,15 @@ namespace rtc { AACRtpPacketizer::AACRtpPacketizer(shared_ptr rtpConfig) - : RtpPacketizer(rtpConfig), MediaHandlerRootElement() {} + : RtpPacketizer(std::move(rtpConfig)) {} -binary_ptr AACRtpPacketizer::packetize(binary_ptr payload, [[maybe_unused]] bool setMark) { - assert(!setMark); - return RtpPacketizer::packetize(payload, false); -} +void AACRtpPacketizer::incoming([[maybe_unused]] message_vector &messages, + [[maybe_unused]] const message_callback &send) {} -ChainedOutgoingProduct -AACRtpPacketizer::processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) { - ChainedMessagesProduct packets = make_chained_messages_product(); - packets->reserve(messages->size()); - for (auto message : *messages) { - packets->push_back(packetize(message, false)); - } - return {packets, control}; +void AACRtpPacketizer::outgoing(message_vector &messages, + [[maybe_unused]] const message_callback &send) { + for (auto &message : messages) + message = packetize(message, false); } } // namespace rtc diff --git a/src/av1packetizationhandler.cpp b/src/av1packetizationhandler.cpp deleted file mode 100644 index 0e29d1394..000000000 --- a/src/av1packetizationhandler.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2023 Paul-Louis Ageneau - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#if RTC_ENABLE_MEDIA - -#include "av1packetizationhandler.hpp" - -namespace rtc { - -AV1PacketizationHandler::AV1PacketizationHandler(shared_ptr packetizer) - : MediaChainableHandler(packetizer) {} - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ diff --git a/src/av1rtppacketizer.cpp b/src/av1rtppacketizer.cpp index ebc1e2536..6a48652a7 100644 --- a/src/av1rtppacketizer.cpp +++ b/src/av1rtppacketizer.cpp @@ -188,41 +188,39 @@ std::vector AV1RtpPacketizer::packetizeObu(binary_ptr message, AV1RtpPacketizer::AV1RtpPacketizer(AV1RtpPacketizer::Packetization packetization, shared_ptr rtpConfig, uint16_t maximumFragmentSize) - : RtpPacketizer(rtpConfig), MediaHandlerRootElement(), maximumFragmentSize(maximumFragmentSize), + : RtpPacketizer(rtpConfig), maximumFragmentSize(maximumFragmentSize), packetization(packetization) {} -ChainedOutgoingProduct -AV1RtpPacketizer::processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) { - ChainedMessagesProduct packets = std::make_shared>(); - for (auto message : *messages) { - std::vector obus; +void AV1RtpPacketizer::incoming([[maybe_unused]] message_vector &messages, + [[maybe_unused]] const message_callback &send) {} +void AV1RtpPacketizer::outgoing(message_vector &messages, + [[maybe_unused]] const message_callback &send) { + message_vector result; + for (const auto &message : messages) { + std::vector obus; if (packetization == AV1RtpPacketizer::Packetization::TemporalUnit) { obus = extractTemporalUnitObus(message); } else { obus.push_back(message); } + std::vector fragments; for (auto obu : obus) { - auto payloads = packetizeObu(obu, maximumFragmentSize); - if (payloads.size() == 0) { - continue; - } - - unsigned i = 0; - for (; i < payloads.size() - 1; i++) { - packets->push_back(packetize(payloads[i], false)); - } - packets->push_back(packetize(payloads[i], true)); + auto p = packetizeObu(obu, maximumFragmentSize); + fragments.insert(fragments.end(), p.begin(), p.end()); } - } - if (packets->size() == 0) { - return ChainedOutgoingProduct(); + if (fragments.size() == 0) + continue; + + for (size_t i = 0; i < fragments.size() - 1; i++) + result.push_back(packetize(fragments[i], false)); + + result.push_back(packetize(fragments[fragments.size() - 1], true)); } - return {packets, control}; + messages.swap(result); } } // namespace rtc diff --git a/src/capi.cpp b/src/capi.cpp index ffea82c29..864de6e62 100644 --- a/src/capi.cpp +++ b/src/capi.cpp @@ -29,7 +29,6 @@ std::unordered_map> peerConnectionMap; std::unordered_map> dataChannelMap; std::unordered_map> trackMap; #if RTC_ENABLE_MEDIA -std::unordered_map> rtcpChainableHandlerMap; std::unordered_map> rtcpSrReporterMap; std::unordered_map> rtpConfigMap; #endif @@ -120,7 +119,6 @@ void eraseTrack(int tr) { throw std::invalid_argument("Track ID does not exist"); #if RTC_ENABLE_MEDIA rtcpSrReporterMap.erase(tr); - rtcpChainableHandlerMap.erase(tr); rtpConfigMap.erase(tr); #endif userPointerMap.erase(tr); @@ -133,8 +131,7 @@ size_t eraseAll() { trackMap.clear(); peerConnectionMap.clear(); #if RTC_ENABLE_MEDIA - count += rtcpChainableHandlerMap.size() + rtcpSrReporterMap.size() + rtpConfigMap.size(); - rtcpChainableHandlerMap.clear(); + count += rtcpSrReporterMap.size() + rtpConfigMap.size(); rtcpSrReporterMap.clear(); rtpConfigMap.clear(); #endif @@ -170,7 +167,6 @@ void eraseChannel(int id) { userPointerMap.erase(id); #if RTC_ENABLE_MEDIA rtcpSrReporterMap.erase(id); - rtcpChainableHandlerMap.erase(id); rtpConfigMap.erase(id); #endif return; @@ -253,20 +249,6 @@ void emplaceRtcpSrReporter(shared_ptr ptr, int tr) { rtcpSrReporterMap.emplace(std::make_pair(tr, ptr)); } -shared_ptr getMediaChainableHandler(int id) { - std::lock_guard lock(mutex); - if (auto it = rtcpChainableHandlerMap.find(id); it != rtcpChainableHandlerMap.end()) { - return it->second; - } else { - throw std::invalid_argument("RTCP chainable handler ID does not exist"); - } -} - -void emplaceMediaChainableHandler(shared_ptr ptr, int tr) { - std::lock_guard lock(mutex); - rtcpChainableHandlerMap.emplace(std::make_pair(tr, ptr)); -} - shared_ptr getRtpConfig(int id) { std::lock_guard lock(mutex); if (auto it = rtpConfigMap.find(id); it != rtpConfigMap.end()) { @@ -303,31 +285,36 @@ class MediaInterceptor final : public MediaHandler { MediaInterceptor(MessageCallback cb) : incomingCallback(cb) {} // Called when there is traffic coming from the peer - message_ptr incoming(message_ptr msg) override { + + void incoming(message_vector &messages, + [[maybe_unused]] const message_callback &send) override { // If no callback is provided, just forward the message on - if (!incomingCallback) { - return msg; - } + if (!incomingCallback) + return; - auto res = incomingCallback(reinterpret_cast(msg->data()), int(msg->size())); + message_vector result; + for (auto &msg : messages) { + auto res = incomingCallback(reinterpret_cast(msg->data()), int(msg->size())); - // If a null pointer was returned, drop the incoming message - if (res == nullptr) { - return nullptr; - } + // If a null pointer was returned, drop the incoming message + if (!res) + continue; - // If the original data pointer was returned, forward the incoming message - if (res == msg->data()) { - return msg; + if (res == msg->data()) { + // If the original data pointer was returned, forward the incoming message + result.push_back(std::move(msg)); + } else { + // else construct a true message_ptr from the returned opaque pointer + result.push_back( + make_message_from_opaque_ptr(std::move(reinterpret_cast(res)))); + } } - - // Construct a true message_ptr from the returned opaque pointer - return make_message_from_opaque_ptr(std::move(reinterpret_cast(res))); - }; + } // Called when there is traffic that needs to be sent to the peer // This is a no-op for media interceptors - message_ptr outgoing(message_ptr ptr) override { return ptr; }; + void outgoing([[maybe_unused]] message_vector &messages, + [[maybe_unused]] const message_callback &send) override{}; private: MessageCallback incomingCallback; @@ -1224,18 +1211,14 @@ int rtcSetH264PacketizationHandler(int tr, const rtcPacketizationHandlerInit *in auto track = getTrack(tr); // create RTP configuration auto rtpConfig = createRtpPacketizationConfig(init); + emplaceRtpConfig(rtpConfig, tr); // create packetizer auto nalSeparator = init ? init->nalSeparator : RTC_NAL_SEPARATOR_LENGTH; auto maxFragmentSize = init && init->maxFragmentSize ? init->maxFragmentSize : RTC_DEFAULT_MAXIMUM_FRAGMENT_SIZE; auto packetizer = std::make_shared( static_cast(nalSeparator), rtpConfig, maxFragmentSize); - // create H264 handler - auto h264Handler = std::make_shared(packetizer); - emplaceMediaChainableHandler(h264Handler, tr); - emplaceRtpConfig(rtpConfig, tr); - // set handler - track->setMediaHandler(h264Handler); + track->setMediaHandler(packetizer); return RTC_ERR_SUCCESS; }); } @@ -1251,12 +1234,7 @@ int rtcSetH265PacketizationHandler(int tr, const rtcPacketizationHandlerInit *in : RTC_DEFAULT_MAXIMUM_FRAGMENT_SIZE; auto packetizer = std::make_shared( static_cast(nalSeparator), rtpConfig, maxFragmentSize); - // create H265 handler - auto h265Handler = std::make_shared(packetizer); - emplaceMediaChainableHandler(h265Handler, tr); - emplaceRtpConfig(rtpConfig, tr); - // set handler - track->setMediaHandler(h265Handler); + track->setMediaHandler(packetizer); return RTC_ERR_SUCCESS; }); } @@ -1274,12 +1252,7 @@ int rtcSetAV1PacketizationHandler(int tr, const rtcPacketizationHandlerInit *ini : AV1RtpPacketizer::Packetization::Obu; auto packetizer = std::make_shared(packetization, rtpConfig, maxFragmentSize); - // create AV1 handler - auto av1Handler = std::make_shared(packetizer); - emplaceMediaChainableHandler(av1Handler, tr); - emplaceRtpConfig(rtpConfig, tr); - // set handler - track->setMediaHandler(av1Handler); + track->setMediaHandler(packetizer); return RTC_ERR_SUCCESS; }); } @@ -1289,14 +1262,10 @@ int rtcSetOpusPacketizationHandler(int tr, const rtcPacketizationHandlerInit *in auto track = getTrack(tr); // create RTP configuration auto rtpConfig = createRtpPacketizationConfig(init); + emplaceRtpConfig(rtpConfig, tr); // create packetizer auto packetizer = std::make_shared(rtpConfig); - // create Opus handler - auto opusHandler = std::make_shared(packetizer); - emplaceMediaChainableHandler(opusHandler, tr); - emplaceRtpConfig(rtpConfig, tr); - // set handler - track->setMediaHandler(opusHandler); + track->setMediaHandler(packetizer); return RTC_ERR_SUCCESS; }); } @@ -1308,32 +1277,27 @@ int rtcSetAACPacketizationHandler(int tr, const rtcPacketizationHandlerInit *ini auto rtpConfig = createRtpPacketizationConfig(init); // create packetizer auto packetizer = std::make_shared(rtpConfig); - // create AAC handler - auto aacHandler = std::make_shared(packetizer); - emplaceMediaChainableHandler(aacHandler, tr); - emplaceRtpConfig(rtpConfig, tr); - // set handler - track->setMediaHandler(aacHandler); + track->setMediaHandler(packetizer); return RTC_ERR_SUCCESS; }); } int rtcChainRtcpSrReporter(int tr) { return wrap([tr] { + auto track = getTrack(tr); auto config = getRtpConfig(tr); auto reporter = std::make_shared(config); + track->chainMediaHandler(reporter); emplaceRtcpSrReporter(reporter, tr); - auto chainableHandler = getMediaChainableHandler(tr); - chainableHandler->addToChain(reporter); return RTC_ERR_SUCCESS; }); } int rtcChainRtcpNackResponder(int tr, unsigned int maxStoredPacketsCount) { return wrap([tr, maxStoredPacketsCount] { + auto track = getTrack(tr); auto responder = std::make_shared(maxStoredPacketsCount); - auto chainableHandler = getMediaChainableHandler(tr); - chainableHandler->addToChain(responder); + track->chainMediaHandler(responder); return RTC_ERR_SUCCESS; }); } @@ -1341,7 +1305,9 @@ int rtcChainRtcpNackResponder(int tr, unsigned int maxStoredPacketsCount) { int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp) { return wrap([&] { auto config = getRtpConfig(id); - *timestamp = config->secondsToTimestamp(seconds); + if (timestamp) + *timestamp = config->secondsToTimestamp(seconds); + return RTC_ERR_SUCCESS; }); } @@ -1349,7 +1315,9 @@ int rtcTransformSecondsToTimestamp(int id, double seconds, uint32_t *timestamp) int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double *seconds) { return wrap([&] { auto config = getRtpConfig(id); - *seconds = config->timestampToSeconds(timestamp); + if (seconds) + *seconds = config->timestampToSeconds(timestamp); + return RTC_ERR_SUCCESS; }); } @@ -1357,7 +1325,9 @@ int rtcTransformTimestampToSeconds(int id, uint32_t timestamp, double *seconds) int rtcGetCurrentTrackTimestamp(int id, uint32_t *timestamp) { return wrap([&] { auto config = getRtpConfig(id); - *timestamp = config->timestamp; + if (timestamp) + *timestamp = config->timestamp; + return RTC_ERR_SUCCESS; }); } @@ -1373,7 +1343,9 @@ int rtcSetTrackRtpTimestamp(int id, uint32_t timestamp) { int rtcGetLastTrackSenderReportTimestamp(int id, uint32_t *timestamp) { return wrap([&] { auto sender = getRtcpSrReporter(id); - *timestamp = sender->lastReportedTimestamp(); + if (timestamp) + *timestamp = sender->lastReportedTimestamp(); + return RTC_ERR_SUCCESS; }); } diff --git a/src/description.cpp b/src/description.cpp index 8587cf73d..3f179fc35 100644 --- a/src/description.cpp +++ b/src/description.cpp @@ -583,6 +583,14 @@ Description::Entry::ExtMap *Description::Entry::extMap(int id) { return &it->second; } +const Description::Entry::ExtMap *Description::Entry::extMap(int id) const { + auto it = mExtMaps.find(id); + if (it == mExtMaps.end()) + throw std::invalid_argument("extmap not found"); + + return &it->second; +} + void Description::Entry::addExtMap(ExtMap map) { auto id = map.id; mExtMaps.emplace(id, std::move(map)); @@ -953,6 +961,14 @@ Description::Media::RtpMap *Description::Media::rtpMap(int payloadType) { return &it->second; } +const Description::Media::RtpMap *Description::Media::rtpMap(int payloadType) const { + auto it = mRtpMaps.find(payloadType); + if (it == mRtpMaps.end()) + throw std::invalid_argument("rtpmap not found"); + + return &it->second; +} + void Description::Media::addRtpMap(RtpMap map) { auto payloadType = map.payloadType; mRtpMaps.emplace(payloadType, std::move(map)); diff --git a/src/h264packetizationhandler.cpp b/src/h264packetizationhandler.cpp deleted file mode 100644 index f22c6eb05..000000000 --- a/src/h264packetizationhandler.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#if RTC_ENABLE_MEDIA - -#include "h264packetizationhandler.hpp" - -namespace rtc { - -H264PacketizationHandler::H264PacketizationHandler(shared_ptr packetizer) - : MediaChainableHandler(packetizer) {} - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ diff --git a/src/h264rtppacketizer.cpp b/src/h264rtppacketizer.cpp index e64b983c7..5ceb03b32 100644 --- a/src/h264rtppacketizer.cpp +++ b/src/h264rtppacketizer.cpp @@ -82,32 +82,31 @@ shared_ptr H264RtpPacketizer::splitMessage(binary_ptr message) { H264RtpPacketizer::H264RtpPacketizer(shared_ptr rtpConfig, uint16_t maximumFragmentSize) - : RtpPacketizer(rtpConfig), MediaHandlerRootElement(), maximumFragmentSize(maximumFragmentSize), + : RtpPacketizer(std::move(rtpConfig)), maximumFragmentSize(maximumFragmentSize), separator(Separator::Length) {} H264RtpPacketizer::H264RtpPacketizer(Separator separator, shared_ptr rtpConfig, uint16_t maximumFragmentSize) - : RtpPacketizer(rtpConfig), MediaHandlerRootElement(), maximumFragmentSize(maximumFragmentSize), - separator(separator) {} - -ChainedOutgoingProduct -H264RtpPacketizer::processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) { - ChainedMessagesProduct packets = std::make_shared>(); - for (auto message : *messages) { + : RtpPacketizer(rtpConfig), maximumFragmentSize(maximumFragmentSize), separator(separator) {} + +void H264RtpPacketizer::incoming([[maybe_unused]] message_vector &messages, [[maybe_unused]] const message_callback &send) {} + +void H264RtpPacketizer::outgoing(message_vector &messages, [[maybe_unused]] const message_callback &send) { + message_vector result; + for(const auto &message : messages) { auto nalus = splitMessage(message); auto fragments = nalus->generateFragments(maximumFragmentSize); - if (fragments.size() == 0) { - return ChainedOutgoingProduct(); - } - unsigned i = 0; - for (; i < fragments.size() - 1; i++) { - packets->push_back(packetize(fragments[i], false)); - } - packets->push_back(packetize(fragments[i], true)); + if (fragments.size() == 0) + continue; + + for (size_t i = 0; i < fragments.size() - 1; i++) + result.push_back(packetize(fragments[i], false)); + + result.push_back(packetize(fragments[fragments.size() - 1], true)); } - return {packets, control}; + + messages.swap(result); } } // namespace rtc diff --git a/src/h265packetizationhandler.cpp b/src/h265packetizationhandler.cpp deleted file mode 100644 index e0783b6c7..000000000 --- a/src/h265packetizationhandler.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2023 Zita Liao (Dolby) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#if RTC_ENABLE_MEDIA - -#include "h265packetizationhandler.hpp" - -namespace rtc { - -H265PacketizationHandler::H265PacketizationHandler(shared_ptr packetizer) - : MediaChainableHandler(packetizer) {} - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ diff --git a/src/h265rtppacketizer.cpp b/src/h265rtppacketizer.cpp index 514aeeb18..f10a0ae15 100644 --- a/src/h265rtppacketizer.cpp +++ b/src/h265rtppacketizer.cpp @@ -82,32 +82,32 @@ shared_ptr H265RtpPacketizer::splitMessage(binary_ptr message) { H265RtpPacketizer::H265RtpPacketizer(shared_ptr rtpConfig, uint16_t maximumFragmentSize) - : RtpPacketizer(rtpConfig), MediaHandlerRootElement(), maximumFragmentSize(maximumFragmentSize), + : RtpPacketizer(std::move(rtpConfig)), maximumFragmentSize(maximumFragmentSize), separator(NalUnit::Separator::Length) {} H265RtpPacketizer::H265RtpPacketizer(NalUnit::Separator separator, shared_ptr rtpConfig, uint16_t maximumFragmentSize) - : RtpPacketizer(rtpConfig), MediaHandlerRootElement(), maximumFragmentSize(maximumFragmentSize), + : RtpPacketizer(std::move(rtpConfig)), maximumFragmentSize(maximumFragmentSize), separator(separator) {} -ChainedOutgoingProduct -H265RtpPacketizer::processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) { - ChainedMessagesProduct packets = std::make_shared>(); - for (auto message : *messages) { +void H265RtpPacketizer::incoming([[maybe_unused]] message_vector &messages, [[maybe_unused]] const message_callback &send) {} + +void H265RtpPacketizer::outgoing(message_vector &messages, [[maybe_unused]] const message_callback &send) { + message_vector result; + for (const auto &message : messages) { auto nalus = splitMessage(message); auto fragments = nalus->generateFragments(maximumFragmentSize); - if (fragments.size() == 0) { - return ChainedOutgoingProduct(); - } - unsigned i = 0; - for (; i < fragments.size() - 1; i++) { - packets->push_back(packetize(fragments[i], false)); - } - packets->push_back(packetize(fragments[i], true)); + if (fragments.size() == 0) + continue; + + for (size_t i = 0; i < fragments.size() - 1; i++) + result.push_back(packetize(fragments[i], false)); + + result.push_back(packetize(fragments[fragments.size() - 1], true)); } - return {packets, control}; + + messages.swap(result); } } // namespace rtc diff --git a/src/impl/peerconnection.cpp b/src/impl/peerconnection.cpp index c53469d98..6e0189c95 100644 --- a/src/impl/peerconnection.cpp +++ b/src/impl/peerconnection.cpp @@ -493,18 +493,32 @@ void PeerConnection::forwardMessage(message_ptr message) { } } -void PeerConnection::forwardMedia(message_ptr message) { +void PeerConnection::forwardMedia([[maybe_unused]] message_ptr message) { +#if RTC_ENABLE_MEDIA if (!message) return; - auto handler = getMediaHandler(); + // TODO: outgoing + if (auto handler = getMediaHandler()) { + message_vector messages{std::move(message)}; - if (handler) { - message = handler->incoming(message); - if (!message) - return; + handler->incoming(messages, [this](message_ptr message) { + auto transport = std::atomic_load(&mDtlsTransport); + if (auto srtpTransport = std::dynamic_pointer_cast(transport)) + srtpTransport->send(std::move(message)); + }); + + for (auto &m : messages) + dispatchMedia(std::move(m)); + + } else { + dispatchMedia(std::move(message)); } +#endif +} +void PeerConnection::dispatchMedia([[maybe_unused]] message_ptr message) { +#if RTC_ENABLE_MEDIA // Browsers like to compound their packets with a random SSRC. // we have to do this monstrosity to distribute the report blocks if (message->type == Message::Control) { @@ -581,6 +595,7 @@ void PeerConnection::forwardMedia(message_ptr message) { // PLOG_WARNING << "Track not found for SSRC " << ssrc << ", dropping"; return; } +#endif } void PeerConnection::forwardBufferedAmount(uint16_t stream, size_t amount) { @@ -741,6 +756,10 @@ shared_ptr PeerConnection::emplaceTrack(Description::Media description) { mTrackLines.emplace_back(track); } + auto handler = getMediaHandler(); + if (handler) + handler->media(track->description()); + if (track->description().isRemoved()) track->close(); @@ -910,6 +929,10 @@ void PeerConnection::processLocalDescription(Description description) { mTrackLines.emplace_back(track); triggerTrack(track); // The user may modify the track description + auto handler = getMediaHandler(); + if (handler) + handler->media(track->description()); + if (track->description().isRemoved()) track->close(); @@ -1091,8 +1114,6 @@ string PeerConnection::localBundleMid() const { void PeerConnection::setMediaHandler(shared_ptr handler) { std::unique_lock lock(mMediaHandlerMutex); - if (mMediaHandler) - mMediaHandler->onOutgoing(nullptr); mMediaHandler = handler; } diff --git a/src/impl/peerconnection.hpp b/src/impl/peerconnection.hpp index 79c6e5b42..ad6f41e28 100644 --- a/src/impl/peerconnection.hpp +++ b/src/impl/peerconnection.hpp @@ -127,6 +127,7 @@ struct PeerConnection : std::enable_shared_from_this { synchronized_callback> trackCallback; private: + void dispatchMedia(message_ptr message); void updateTrackSsrcCache(const Description &description); const init_token mInitToken = Init::Instance().token(); diff --git a/src/impl/track.cpp b/src/impl/track.cpp index 99cdd5acd..80927fd76 100644 --- a/src/impl/track.cpp +++ b/src/impl/track.cpp @@ -19,8 +19,8 @@ static LogCounter COUNTER_MEDIA_BAD_DIRECTION(plog::warning, static LogCounter COUNTER_QUEUE_FULL(plog::warning, "Number of media packets dropped due to a full queue"); -Track::Track(weak_ptr pc, Description::Media description) - : mPeerConnection(pc), mMediaDescription(std::move(description)), +Track::Track(weak_ptr pc, Description::Media desc) + : mPeerConnection(pc), mMediaDescription(std::move(desc)), mRecvQueue(RECV_QUEUE_LIMIT, [](const message_ptr &m) { return m->size(); }) { // Discard messages by default if track is send only @@ -52,12 +52,17 @@ Description::Media Track::description() const { return mMediaDescription; } -void Track::setDescription(Description::Media description) { - std::unique_lock lock(mMutex); - if (description.mid() != mMediaDescription.mid()) - throw std::logic_error("Media description mid does not match track mid"); +void Track::setDescription(Description::Media desc) { + { + std::unique_lock lock(mMutex); + if (desc.mid() != mMediaDescription.mid()) + throw std::logic_error("Media description mid does not match track mid"); + + mMediaDescription = std::move(desc); + } - mMediaDescription = std::move(description); + if (auto handler = getMediaHandler()) + handler->media(description()); } void Track::close() { @@ -129,8 +134,6 @@ void Track::incoming(message_ptr message) { if (!message) return; - auto handler = getMediaHandler(); - auto dir = direction(); if ((dir == Description::Direction::SendOnly || dir == Description::Direction::Inactive) && message->type != Message::Control) { @@ -138,20 +141,20 @@ void Track::incoming(message_ptr message) { return; } - if (handler) { - message = handler->incoming(message); - if (!message) + message_vector messages{std::move(message)}; + if (auto handler = getMediaHandler()) + handler->incomingChain(messages, [this](message_ptr m) { transportSend(m); }); + + for (auto &m : messages) { + // Tail drop if queue is full + if (mRecvQueue.full()) { + COUNTER_QUEUE_FULL++; return; - } + } - // Tail drop if queue is full - if (mRecvQueue.full()) { - COUNTER_QUEUE_FULL++; - return; + mRecvQueue.push(m); + triggerAvailable(mRecvQueue.size()); } - - mRecvQueue.push(message); - triggerAvailable(mRecvQueue.size()); } bool Track::outgoing(message_ptr message) { @@ -172,12 +175,17 @@ bool Track::outgoing(message_ptr message) { } if (handler) { - message = handler->outgoing(message); - if (!message) - return false; - } + message_vector messages{std::move(message)}; + handler->outgoingChain(messages, [this](message_ptr m) { transportSend(m); }); + bool ret = false; + for (auto &m : messages) + ret = transportSend(std::move(m)); - return transportSend(message); + return ret; + + } else { + return transportSend(std::move(message)); + } } bool Track::transportSend([[maybe_unused]] message_ptr message) { @@ -204,17 +212,13 @@ bool Track::transportSend([[maybe_unused]] message_ptr message) { } void Track::setMediaHandler(shared_ptr handler) { - auto currentHandler = getMediaHandler(); - if (currentHandler) - currentHandler->onOutgoing(nullptr); - { std::unique_lock lock(mMutex); mMediaHandler = handler; } - if (handler) - handler->onOutgoing(std::bind(&Track::transportSend, this, std::placeholders::_1)); + if(handler) + handler->media(description()); } shared_ptr Track::getMediaHandler() { diff --git a/src/impl/track.hpp b/src/impl/track.hpp index 8c35ba63e..a267a394d 100644 --- a/src/impl/track.hpp +++ b/src/impl/track.hpp @@ -28,7 +28,7 @@ struct PeerConnection; class Track final : public std::enable_shared_from_this, public Channel { public: - Track(weak_ptr pc, Description::Media description); + Track(weak_ptr pc, Description::Media desc); ~Track(); void close(); @@ -46,7 +46,7 @@ class Track final : public std::enable_shared_from_this, public Channel { string mid() const; Description::Direction direction() const; Description::Media description() const; - void setDescription(Description::Media description); + void setDescription(Description::Media desc); shared_ptr getMediaHandler(); void setMediaHandler(shared_ptr handler); diff --git a/src/mediachainablehandler.cpp b/src/mediachainablehandler.cpp deleted file mode 100644 index 5094b52a6..000000000 --- a/src/mediachainablehandler.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#if RTC_ENABLE_MEDIA - -#include "mediachainablehandler.hpp" - -#include "impl/internals.hpp" - -#include - -namespace rtc { - -MediaChainableHandler::MediaChainableHandler(shared_ptr root) - : MediaHandler(), root(root), leaf(root) {} - -MediaChainableHandler::~MediaChainableHandler() { leaf->recursiveRemoveChain(); } - -bool MediaChainableHandler::sendProduct(ChainedOutgoingProduct product) { - bool result = true; - if (product.control) { - assert(product.control->type == Message::Control); - auto sendResult = send(product.control); - if (!sendResult) { - LOG_DEBUG << "Failed to send control message"; - } - result = result && sendResult; - } - if (product.messages) { - auto messages = product.messages; - for (unsigned i = 0; i < messages->size(); i++) { - auto message = messages->at(i); - if (!message) { - LOG_DEBUG << "Invalid message to send " << i + 1 << "/" << messages->size(); - } - auto sendResult = send(make_message(*message)); - if (!sendResult) { - LOG_DEBUG << "Failed to send message " << i + 1 << "/" << messages->size(); - } - result = result && sendResult; - } - } - return result; -} - -message_ptr MediaChainableHandler::handleIncomingBinary(message_ptr msg) { - assert(msg->type == Message::Binary); - auto messages = root->split(msg); - auto incoming = getLeaf()->formIncomingBinaryMessage( - messages, [this](ChainedOutgoingProduct outgoing) { return sendProduct(outgoing); }); - if (incoming) { - return root->reduce(incoming); - } else { - return nullptr; - } -} - -message_ptr MediaChainableHandler::handleIncomingControl(message_ptr msg) { - assert(msg->type == Message::Control); - auto incoming = getLeaf()->formIncomingControlMessage( - msg, [this](ChainedOutgoingProduct outgoing) { return sendProduct(outgoing); }); - assert(!incoming || incoming->type == Message::Control); - return incoming; -} - -message_ptr MediaChainableHandler::handleOutgoingBinary(message_ptr msg) { - assert(msg->type == Message::Binary); - auto messages = make_chained_messages_product(msg); - auto optOutgoing = root->formOutgoingBinaryMessage(ChainedOutgoingProduct(messages)); - if (!optOutgoing.has_value()) { - LOG_ERROR << "Generating outgoing message failed"; - return nullptr; - } - auto outgoing = optOutgoing.value(); - if (outgoing.control) { - if (!send(outgoing.control)) { - LOG_DEBUG << "Failed to send control message"; - } - } - auto lastMessage = outgoing.messages->back(); - if (!lastMessage) { - LOG_DEBUG << "Invalid message to send"; - return nullptr; - } - for (unsigned i = 0; i < outgoing.messages->size() - 1; i++) { - auto message = outgoing.messages->at(i); - if (!message) { - LOG_DEBUG << "Invalid message to send " << i + 1 << "/" << outgoing.messages->size(); - } - if (!send(make_message(*message))) { - LOG_DEBUG << "Failed to send message " << i + 1 << "/" << outgoing.messages->size(); - } - } - return make_message(*lastMessage); -} - -message_ptr MediaChainableHandler::handleOutgoingControl(message_ptr msg) { - assert(msg->type == Message::Control); - auto outgoing = root->formOutgoingControlMessage(msg); - assert(!outgoing || outgoing->type == Message::Control); - if (!outgoing) { - LOG_ERROR << "Generating outgoing control message failed"; - return nullptr; - } - return outgoing; -} - -message_ptr MediaChainableHandler::outgoing(message_ptr ptr) { - assert(ptr); - if (!ptr) { - LOG_ERROR << "Outgoing message is nullptr, ignoring"; - return nullptr; - } - if (ptr->type == Message::Binary) { - return handleOutgoingBinary(ptr); - } else if (ptr->type == Message::Control) { - return handleOutgoingControl(ptr); - } - return ptr; -} - -message_ptr MediaChainableHandler::incoming(message_ptr ptr) { - if (!ptr) { - LOG_ERROR << "Incoming message is nullptr, ignoring"; - return nullptr; - } - if (ptr->type == Message::Binary) { - return handleIncomingBinary(ptr); - } else if (ptr->type == Message::Control) { - return handleIncomingControl(ptr); - } - return ptr; -} - -bool MediaChainableHandler::send(message_ptr msg) { - try { - outgoingCallback(std::move(msg)); - return true; - } catch (const std::exception &e) { - LOG_DEBUG << "Send in RTCP chain handler failed: " << e.what(); - } - return false; -} - -shared_ptr MediaChainableHandler::getLeaf() const { - std::lock_guard lock(mutex); - return leaf; -} - -void MediaChainableHandler::addToChain(shared_ptr chainable) { - std::lock_guard lock(mutex); - assert(leaf); - leaf = leaf->chainWith(chainable); -} - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ diff --git a/src/mediahandler.cpp b/src/mediahandler.cpp new file mode 100644 index 000000000..b78f70006 --- /dev/null +++ b/src/mediahandler.cpp @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2023 Paul-Louis Ageneau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "mediahandler.hpp" + +#include "impl/internals.hpp" + +namespace rtc { + +void MediaHandler::addToChain(shared_ptr handler) { last()->setNext(handler); } + +void MediaHandler::setNext(shared_ptr handler) { + return std::atomic_store(&mNext, handler); +} + +shared_ptr MediaHandler::next() { return std::atomic_load(&mNext); } + +shared_ptr MediaHandler::next() const { return std::atomic_load(&mNext); } + +shared_ptr MediaHandler::last() { + if (auto handler = next()) + return handler->last(); + else + return shared_from_this(); +} + +shared_ptr MediaHandler::last() const { + if (auto handler = next()) + return handler->last(); + else + return shared_from_this(); +} + +bool MediaHandler::requestKeyframe() { return false; } + +void MediaHandler::mediaChain(const Description::Media &desc) { + media(desc); + + if(auto handler = next()) + handler->mediaChain(desc); +} + +void MediaHandler::incomingChain(message_vector &messages, const message_callback &send) { + if (auto handler = next()) + handler->incomingChain(messages, send); + + incoming(messages, send); +} + +void MediaHandler::outgoingChain(message_vector &messages , const message_callback &send) { + outgoing(messages, send); + + if(auto handler = next()) + return handler->outgoingChain(messages, send); +} + +} // namespace rtc + diff --git a/src/mediahandlerelement.cpp b/src/mediahandlerelement.cpp deleted file mode 100644 index 5ec13ce2e..000000000 --- a/src/mediahandlerelement.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#if RTC_ENABLE_MEDIA - -#include "mediahandlerelement.hpp" - -#include "impl/internals.hpp" - -#include - -namespace rtc { - -ChainedMessagesProduct make_chained_messages_product() { - return std::make_shared>(); -} - -ChainedMessagesProduct make_chained_messages_product(message_ptr msg) { - std::vector msgs = {msg}; - return std::make_shared>(msgs); -} - -ChainedOutgoingProduct::ChainedOutgoingProduct(ChainedMessagesProduct messages, message_ptr control) - : messages(messages), control(control) {} - -ChainedIncomingProduct::ChainedIncomingProduct(ChainedMessagesProduct incoming, - ChainedMessagesProduct outgoing) - : incoming(incoming), outgoing(outgoing) {} - -ChainedIncomingControlProduct::ChainedIncomingControlProduct( - message_ptr incoming, optional outgoing) - : incoming(incoming), outgoing(outgoing) {} - -MediaHandlerElement::MediaHandlerElement() {} - -void MediaHandlerElement::removeFromChain() { - if (upstream) { - upstream->downstream = downstream; - } - if (downstream) { - downstream->upstream = upstream; - } - upstream = nullptr; - downstream = nullptr; -} - -void MediaHandlerElement::recursiveRemoveChain() { - if (downstream) { - // `recursiveRemoveChain` removes last strong reference to downstream element - // we need to keep strong reference to prevent deallocation of downstream element - // during `recursiveRemoveChain` - auto strongDownstreamPtr = downstream; - downstream->recursiveRemoveChain(); - } - removeFromChain(); -} - -optional -MediaHandlerElement::processOutgoingResponse(ChainedOutgoingProduct messages) { - if (messages.messages) { - if (upstream) { - auto msgs = upstream->formOutgoingBinaryMessage( - ChainedOutgoingProduct(messages.messages, messages.control)); - if (msgs.has_value()) { - return msgs.value(); - } else { - LOG_ERROR << "Generating outgoing message failed"; - return nullopt; - } - } else { - return messages; - } - } else if (messages.control) { - if (upstream) { - auto control = upstream->formOutgoingControlMessage(messages.control); - if (control) { - return ChainedOutgoingProduct(nullptr, control); - } else { - LOG_ERROR << "Generating outgoing control message failed"; - return nullopt; - } - } else { - return messages; - } - } else { - return ChainedOutgoingProduct(); - } -} - -void MediaHandlerElement::prepareAndSendResponse(optional outgoing, - std::function send) { - if (outgoing.has_value()) { - auto message = outgoing.value(); - auto response = processOutgoingResponse(message); - if (response.has_value()) { - if (!send(response.value())) { - LOG_DEBUG << "Send failed"; - } - } else { - LOG_DEBUG << "No response to send"; - } - } -} - -message_ptr -MediaHandlerElement::formIncomingControlMessage(message_ptr message, - std::function send) { - assert(message); - auto product = processIncomingControlMessage(message); - prepareAndSendResponse(product.outgoing, send); - if (product.incoming) { - if (downstream) { - return downstream->formIncomingControlMessage(product.incoming, send); - } else { - return product.incoming; - } - } else { - return nullptr; - } -} - -ChainedMessagesProduct -MediaHandlerElement::formIncomingBinaryMessage(ChainedMessagesProduct messages, - std::function send) { - assert(messages); - auto product = processIncomingBinaryMessage(messages); - prepareAndSendResponse(product.outgoing, send); - if (product.incoming) { - if (downstream) { - return downstream->formIncomingBinaryMessage(product.incoming, send); - } else { - return product.incoming; - } - } else { - return nullptr; - } -} - -message_ptr MediaHandlerElement::formOutgoingControlMessage(message_ptr message) { - assert(message); - auto newMessage = processOutgoingControlMessage(message); - assert(newMessage); - if (!newMessage) { - LOG_ERROR << "Failed to generate outgoing message"; - return nullptr; - } - if (upstream) { - return upstream->formOutgoingControlMessage(newMessage); - } else { - return newMessage; - } -} - -optional -MediaHandlerElement::formOutgoingBinaryMessage(ChainedOutgoingProduct product) { - assert(product.messages && !product.messages->empty()); - auto newProduct = processOutgoingBinaryMessage(product.messages, product.control); - assert(!product.control || newProduct.control); - assert(newProduct.messages && !newProduct.messages->empty()); - if (product.control && !newProduct.control) { - LOG_ERROR << "Outgoing message must not remove control message"; - return nullopt; - } - if (!newProduct.messages || newProduct.messages->empty()) { - LOG_ERROR << "Failed to generate message"; - return nullopt; - } - if (upstream) { - return upstream->formOutgoingBinaryMessage(newProduct); - } else { - return newProduct; - } -} - -ChainedIncomingControlProduct -MediaHandlerElement::processIncomingControlMessage(message_ptr messages) { - return {messages}; -} - -message_ptr MediaHandlerElement::processOutgoingControlMessage(message_ptr messages) { - return messages; -} - -ChainedIncomingProduct -MediaHandlerElement::processIncomingBinaryMessage(ChainedMessagesProduct messages) { - return {messages}; -} - -ChainedOutgoingProduct -MediaHandlerElement::processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) { - return {messages, control}; -} - -shared_ptr -MediaHandlerElement::chainWith(shared_ptr upstream) { - assert(this->upstream == nullptr); - assert(upstream->downstream == nullptr); - this->upstream = upstream; - upstream->downstream = shared_from_this(); - return upstream; -} - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ diff --git a/src/mediahandlerrootelement.cpp b/src/mediahandlerrootelement.cpp deleted file mode 100644 index ccdfc5d09..000000000 --- a/src/mediahandlerrootelement.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#if RTC_ENABLE_MEDIA - -#include "mediahandlerrootelement.hpp" - -namespace rtc { - -message_ptr MediaHandlerRootElement::reduce(ChainedMessagesProduct messages) { - if (messages && !messages->empty()) { - auto msg_ptr = messages->front(); - if (msg_ptr) { - return make_message(*msg_ptr); - } else { - return nullptr; - } - } else { - return nullptr; - } -} - -ChainedMessagesProduct MediaHandlerRootElement::split(message_ptr message) { - return make_chained_messages_product(message); -} - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ diff --git a/src/opuspacketizationhandler.cpp b/src/opuspacketizationhandler.cpp deleted file mode 100644 index f0d2fd086..000000000 --- a/src/opuspacketizationhandler.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2020 Filip Klembara (in2core) - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#if RTC_ENABLE_MEDIA - -#include "opuspacketizationhandler.hpp" - -namespace rtc { - -OpusPacketizationHandler::OpusPacketizationHandler(shared_ptr packetizer) - : MediaChainableHandler(packetizer) {} - -} // namespace rtc - -#endif /* RTC_ENABLE_MEDIA */ diff --git a/src/opusrtppacketizer.cpp b/src/opusrtppacketizer.cpp index 2379cff40..d35769940 100644 --- a/src/opusrtppacketizer.cpp +++ b/src/opusrtppacketizer.cpp @@ -15,22 +15,13 @@ namespace rtc { OpusRtpPacketizer::OpusRtpPacketizer(shared_ptr rtpConfig) - : RtpPacketizer(rtpConfig), MediaHandlerRootElement() {} + : RtpPacketizer(std::move(rtpConfig)) {} -binary_ptr OpusRtpPacketizer::packetize(binary_ptr payload, [[maybe_unused]] bool setMark) { - assert(!setMark); - return RtpPacketizer::packetize(payload, false); -} +void OpusRtpPacketizer::incoming([[maybe_unused]] message_vector &messages, [[maybe_unused]] const message_callback &send) {} -ChainedOutgoingProduct -OpusRtpPacketizer::processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) { - ChainedMessagesProduct packets = make_chained_messages_product(); - packets->reserve(messages->size()); - for (auto message : *messages) { - packets->push_back(packetize(message, false)); - } - return {packets, control}; +void OpusRtpPacketizer::outgoing(message_vector &messages, [[maybe_unused]] const message_callback &send) { + for(auto &message : messages) + message = packetize(message, false); } } // namespace rtc diff --git a/src/rtcpnackresponder.cpp b/src/rtcpnackresponder.cpp index efae6d94a..88d1face2 100644 --- a/src/rtcpnackresponder.cpp +++ b/src/rtcpnackresponder.cpp @@ -9,6 +9,7 @@ #if RTC_ENABLE_MEDIA #include "rtcpnackresponder.hpp" +#include "rtp.hpp" #include "impl/internals.hpp" @@ -16,15 +17,59 @@ namespace rtc { +RtcpNackResponder::RtcpNackResponder(size_t maxSize) + : mStorage(std::make_shared(maxSize)) {} + +void RtcpNackResponder::incoming(message_vector &messages, const message_callback &send) { + for (const auto &message : messages) { + if (message->type != Message::Control) + continue; + + size_t p = 0; + while (p + sizeof(RtcpNack) <= message->size()) { + auto nack = reinterpret_cast(message->data() + p); + p += nack->header.header.lengthInBytes(); + if (p > message->size()) + break; + + // check if RTCP is NACK + if (nack->header.header.payloadType() != 205 || nack->header.header.reportCount() != 1) + continue; + + unsigned int fieldsCount = nack->getSeqNoCount(); + std::vector missingSequenceNumbers; + for (unsigned int i = 0; i < fieldsCount; i++) { + auto field = nack->parts[i]; + auto newMissingSeqenceNumbers = field.getSequenceNumbers(); + missingSequenceNumbers.insert(missingSequenceNumbers.end(), + newMissingSeqenceNumbers.begin(), + newMissingSeqenceNumbers.end()); + } + + for (auto sequenceNumber : missingSequenceNumbers) { + if (auto optPacket = mStorage->get(sequenceNumber)) + send(make_message(*optPacket.value())); + } + } + } +} + +void RtcpNackResponder::outgoing(message_vector &messages, + [[maybe_unused]] const message_callback &send) { + for (const auto &message : messages) + if (message->type != Message::Control) + mStorage->store(message); +} + RtcpNackResponder::Storage::Element::Element(binary_ptr packet, uint16_t sequenceNumber, shared_ptr next) : packet(packet), sequenceNumber(sequenceNumber), next(next) {} -unsigned RtcpNackResponder::Storage::size() { return unsigned(storage.size()); } +size_t RtcpNackResponder::Storage::size() { return storage.size(); } -RtcpNackResponder::Storage::Storage(unsigned _maximumSize) : maximumSize(_maximumSize) { - assert(maximumSize > 0); - storage.reserve(maximumSize); +RtcpNackResponder::Storage::Storage(size_t _maxSize) : maxSize(_maxSize) { + assert(maxSize > 0); + storage.reserve(maxSize); } optional RtcpNackResponder::Storage::get(uint16_t sequenceNumber) { @@ -35,9 +80,9 @@ optional RtcpNackResponder::Storage::get(uint16_t sequenceNumber) { } void RtcpNackResponder::Storage::store(binary_ptr packet) { - if (!packet || packet->size() < 12) { + if (!packet || packet->size() < sizeof(RtpHeader)) return; - } + auto rtp = reinterpret_cast(packet->data()); auto sequenceNumber = rtp->seqNumber(); @@ -55,7 +100,7 @@ void RtcpNackResponder::Storage::store(binary_ptr packet) { storage.emplace(sequenceNumber, newest); - if (size() > maximumSize) { + if (size() > maxSize) { assert(oldest); if (oldest) { storage.erase(oldest->sequenceNumber); @@ -64,59 +109,6 @@ void RtcpNackResponder::Storage::store(binary_ptr packet) { } } -RtcpNackResponder::RtcpNackResponder(unsigned maxStoredPacketCount) - : MediaHandlerElement(), storage(std::make_shared(maxStoredPacketCount)) {} - -ChainedIncomingControlProduct -RtcpNackResponder::processIncomingControlMessage(message_ptr message) { - optional optPackets = ChainedOutgoingProduct(nullptr); - auto packets = make_chained_messages_product(); - - size_t p = 0; - while (p < message->size()) { - auto nack = reinterpret_cast(message->data() + p); - p += nack->header.header.lengthInBytes(); - // check if rtcp is nack - if (nack->header.header.payloadType() != 205 || nack->header.header.reportCount() != 1) { - continue; - } - - auto fieldsCount = nack->getSeqNoCount(); - - std::vector missingSequenceNumbers{}; - for (unsigned int i = 0; i < fieldsCount; i++) { - auto field = nack->parts[i]; - auto newMissingSeqenceNumbers = field.getSequenceNumbers(); - missingSequenceNumbers.insert(missingSequenceNumbers.end(), - newMissingSeqenceNumbers.begin(), - newMissingSeqenceNumbers.end()); - } - packets->reserve(packets->size() + missingSequenceNumbers.size()); - for (auto sequenceNumber : missingSequenceNumbers) { - auto optPacket = storage->get(sequenceNumber); - if (optPacket.has_value()) { - auto packet = optPacket.value(); - packets->push_back(packet); - } - } - } - - if (!packets->empty()) { - return {message, ChainedOutgoingProduct(packets)}; - } else { - return {message, nullopt}; - } -} - -ChainedOutgoingProduct -RtcpNackResponder::processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) { - for (auto message : *messages) { - storage->store(message); - } - return {messages, control}; -} - } // namespace rtc #endif /* RTC_ENABLE_MEDIA */ diff --git a/src/rtcpreceivingsession.cpp b/src/rtcpreceivingsession.cpp index 0ae719199..98c54e63a 100644 --- a/src/rtcpreceivingsession.cpp +++ b/src/rtcpreceivingsession.cpp @@ -32,102 +32,106 @@ static impl::LogCounter COUNTER_BAD_NOTIF_LEN(plog::warning, static impl::LogCounter COUNTER_BAD_SCTP_STATUS(plog::warning, "Number of unknown SCTP_STATUS errors"); -message_ptr RtcpReceivingSession::outgoing(message_ptr ptr) { return ptr; } - -message_ptr RtcpReceivingSession::incoming(message_ptr ptr) { - if (ptr->type == Message::Binary) { - auto rtp = reinterpret_cast(ptr->data()); - - // https://www.rfc-editor.org/rfc/rfc3550.html#appendix-A.1 - if (rtp->version() != 2) { - COUNTER_BAD_RTP_HEADER++; - PLOG_VERBOSE << "RTP packet is not version 2"; - - return nullptr; +void RtcpReceivingSession::incoming(message_vector &messages, const message_callback &send) { + message_vector result; + result.resize(messages.size()); + for (auto message : messages) { + switch (message->type) { + case Message::Binary: { + if (message->size() < sizeof(RtpHeader)) { + COUNTER_BAD_RTP_HEADER++; + PLOG_VERBOSE << "RTP packet is too small, size=" << message->size(); + continue; + } + + auto rtp = reinterpret_cast(message->data()); + + // https://www.rfc-editor.org/rfc/rfc3550.html#appendix-A.1 + if (rtp->version() != 2) { + COUNTER_BAD_RTP_HEADER++; + PLOG_VERBOSE << "RTP packet is not version 2"; + continue; + } + + if (rtp->payloadType() == 201 || rtp->payloadType() == 200) { + COUNTER_BAD_RTP_HEADER++; + PLOG_VERBOSE << "RTP packet has a payload type indicating RR/SR"; + continue; + } + + mSsrc = rtp->ssrc(); + result.push_back(std::move(message)); + break; } - if (rtp->payloadType() == 201 || rtp->payloadType() == 200) { - COUNTER_BAD_RTP_HEADER++; - PLOG_VERBOSE << "RTP packet has a payload type indicating RR/SR"; - return nullptr; + case Message::Control: { + auto rr = reinterpret_cast(message->data()); + if (rr->header.payloadType() == 201) { // RR + mSsrc = rr->senderSSRC(); + rr->log(); + } else if (rr->header.payloadType() == 200) { // SR + mSsrc = rr->senderSSRC(); + auto sr = reinterpret_cast(message->data()); + mSyncRTPTS = sr->rtpTimestamp(); + mSyncNTPTS = sr->ntpTimestamp(); + sr->log(); + + // TODO For the time being, we will send RR's/REMB's when we get an SR + pushRR(send, 0); + if (mRequestedBitrate > 0) + pushREMB(send, mRequestedBitrate); + } + break; } - // Padding-processing is a user-level thing - - mSsrc = rtp->ssrc(); - - return ptr; + default: + break; + } } - assert(ptr->type == Message::Control); - auto rr = reinterpret_cast(ptr->data()); - if (rr->header.payloadType() == 201) { - // RR - mSsrc = rr->senderSSRC(); - rr->log(); - } else if (rr->header.payloadType() == 200) { - // SR - mSsrc = rr->senderSSRC(); - auto sr = reinterpret_cast(ptr->data()); - mSyncRTPTS = sr->rtpTimestamp(); - mSyncNTPTS = sr->ntpTimestamp(); - sr->log(); - - // TODO For the time being, we will send RR's/REMB's when we get an SR - pushRR(0); - if (mRequestedBitrate > 0) - pushREMB(mRequestedBitrate); - } - return nullptr; + messages.swap(result); } +void RtcpReceivingSession::outgoing([[maybe_unused]] message_vector &messages, + [[maybe_unused]] const message_callback &send) {} + void RtcpReceivingSession::requestBitrate(unsigned int newBitrate) { + PLOG_DEBUG << "Requesting bitrate: " << newBitrate << std::endl; + // TODO: sync mRequestedBitrate = newBitrate; - - PLOG_DEBUG << "[GOOG-REMB] Requesting bitrate: " << newBitrate << std::endl; - pushREMB(newBitrate); + // TODO + // pushREMB(newBitrate); } -void RtcpReceivingSession::pushREMB(unsigned int bitrate) { - message_ptr msg = make_message(RtcpRemb::SizeWithSSRCs(1), Message::Control); - auto remb = reinterpret_cast(msg->data()); +void RtcpReceivingSession::pushREMB(const message_callback &send, unsigned int bitrate) { + auto message = make_message(RtcpRemb::SizeWithSSRCs(1), Message::Control); + auto remb = reinterpret_cast(message->data()); remb->preparePacket(mSsrc, 1, bitrate); remb->setSsrc(0, mSsrc); - - send(msg); + send(message); } -void RtcpReceivingSession::pushRR(unsigned int lastSR_delay) { - auto msg = make_message(RtcpRr::SizeWithReportBlocks(1), Message::Control); - auto rr = reinterpret_cast(msg->data()); +void RtcpReceivingSession::pushRR(const message_callback &send, unsigned int lastSrDelay) { + auto message = make_message(RtcpRr::SizeWithReportBlocks(1), Message::Control); + auto rr = reinterpret_cast(message->data()); rr->preparePacket(mSsrc, 1); rr->getReportBlock(0)->preparePacket(mSsrc, 0, 0, uint16_t(mGreatestSeqNo), 0, 0, mSyncNTPTS, - lastSR_delay); + lastSrDelay); rr->log(); - - send(msg); -} - -bool RtcpReceivingSession::send(message_ptr msg) { - try { - outgoingCallback(std::move(msg)); - return true; - } catch (const std::exception &e) { - LOG_DEBUG << "RTCP tx failed: " << e.what(); - } - return false; + send(message); } bool RtcpReceivingSession::requestKeyframe() { - pushPLI(); + // TODO + // pushPLI(); return true; } -void RtcpReceivingSession::pushPLI() { - auto msg = make_message(RtcpPli::Size(), Message::Control); - auto *pli = reinterpret_cast(msg->data()); +void RtcpReceivingSession::pushPLI(const message_callback &send) { + auto message = make_message(RtcpPli::Size(), Message::Control); + auto *pli = reinterpret_cast(message->data()); pli->preparePacket(mSsrc); - send(msg); + send(message); } } // namespace rtc diff --git a/src/rtcpsrreporter.cpp b/src/rtcpsrreporter.cpp index 6bf8d65fe..2e29f1166 100644 --- a/src/rtcpsrreporter.cpp +++ b/src/rtcpsrreporter.cpp @@ -16,6 +16,7 @@ namespace { +// TODO: move to utils uint64_t ntp_time() { const auto now = std::chrono::system_clock::now(); const double secs = std::chrono::duration(now.time_since_epoch()).count(); @@ -27,22 +28,41 @@ uint64_t ntp_time() { namespace rtc { -ChainedOutgoingProduct RtcpSrReporter::processOutgoingBinaryMessage(ChainedMessagesProduct messages, - message_ptr control) { +RtcpSrReporter::RtcpSrReporter(shared_ptr rtpConfig) + : rtpConfig(rtpConfig) { + mLastReportedTimestamp = rtpConfig->timestamp; +} + +void RtcpSrReporter::setNeedsToReport() { mNeedsToReport = true; } + +uint32_t RtcpSrReporter::lastReportedTimestamp() const { return mLastReportedTimestamp; } + +void RtcpSrReporter::incoming([[maybe_unused]] message_vector &messages, + [[maybe_unused]] const message_callback &send) {} + +void RtcpSrReporter::outgoing(message_vector &messages, const message_callback &send) { + for (const auto &message : messages) { + if (message->type == Message::Control) + continue; + + if (message->size() < sizeof(RtpHeader)) + continue; + + auto rtp = reinterpret_cast(message->data()); + addToReport(rtp, uint32_t(message->size())); + } + if (std::exchange(mNeedsToReport, false)) { auto timestamp = rtpConfig->timestamp; auto sr = getSenderReport(timestamp); - if (control) { - control->insert(control->end(), sr->begin(), sr->end()); - } else { - control = sr; - } + // TODO + // if (control) { + // control->insert(control->end(), sr->begin(), sr->end()); + //} else { + // control = sr; + //} + send(sr); } - for (auto message : *messages) { - auto rtp = reinterpret_cast(message->data()); - addToReport(rtp, uint32_t(message->size())); - } - return {messages, control}; } void RtcpSrReporter::addToReport(RtpHeader *rtp, uint32_t rtpSize) { @@ -51,11 +71,6 @@ void RtcpSrReporter::addToReport(RtpHeader *rtp, uint32_t rtpSize) { mPayloadOctets += rtpSize - uint32_t(rtp->getSize()); } -RtcpSrReporter::RtcpSrReporter(shared_ptr rtpConfig) - : MediaHandlerElement(), rtpConfig(rtpConfig) { - mLastReportedTimestamp = rtpConfig->timestamp; -} - message_ptr RtcpSrReporter::getSenderReport(uint32_t timestamp) { auto srSize = RtcpSr::Size(0); auto msg = make_message(srSize + RtcpSdes::Size({{uint8_t(rtpConfig->cname.size())}}), @@ -79,10 +94,6 @@ message_ptr RtcpSrReporter::getSenderReport(uint32_t timestamp) { return msg; } -void RtcpSrReporter::setNeedsToReport() { mNeedsToReport = true; } - -uint32_t RtcpSrReporter::lastReportedTimestamp() const { return mLastReportedTimestamp; } - } // namespace rtc #endif /* RTC_ENABLE_MEDIA */ diff --git a/src/rtppacketizer.cpp b/src/rtppacketizer.cpp index e4b86b98b..b2a06f525 100644 --- a/src/rtppacketizer.cpp +++ b/src/rtppacketizer.cpp @@ -17,13 +17,13 @@ namespace rtc { RtpPacketizer::RtpPacketizer(shared_ptr rtpConfig) : rtpConfig(rtpConfig) {} -binary_ptr RtpPacketizer::packetize(shared_ptr payload, bool setMark) { +message_ptr RtpPacketizer::packetize(shared_ptr payload, bool mark) { size_t rtpExtHeaderSize = 0; const bool setVideoRotation = (rtpConfig->videoOrientationId != 0) && (rtpConfig->videoOrientationId < 15) && // needs fixing if longer extension headers are supported - setMark && + mark && (rtpConfig->videoOrientation != 0); if (setVideoRotation) { @@ -42,15 +42,14 @@ binary_ptr RtpPacketizer::packetize(shared_ptr payload, bool setMark) { rtpExtHeaderSize += 4; } - auto msg = std::make_shared(rtpHeaderSize + rtpExtHeaderSize + payload->size()); - auto *rtp = (RtpHeader *)msg->data(); + auto message = make_message(RtpHeaderSize + rtpExtHeaderSize + payload->size()); + auto *rtp = (RtpHeader *)message->data(); rtp->setPayloadType(rtpConfig->payloadType); - // increase sequence number - rtp->setSeqNumber(rtpConfig->sequenceNumber++); + rtp->setSeqNumber(rtpConfig->sequenceNumber++); // increase sequence number rtp->setTimestamp(rtpConfig->timestamp); rtp->setSsrc(rtpConfig->ssrc); - if (setMark) { + if (mark) { rtp->setMarker(true); } @@ -90,10 +89,15 @@ binary_ptr RtpPacketizer::packetize(shared_ptr payload, bool setMark) { } rtp->preparePacket(); - std::memcpy(msg->data() + rtpHeaderSize + rtpExtHeaderSize, payload->data(), payload->size()); - return msg; + + std::memcpy(message->data() + RtpHeaderSize + rtpExtHeaderSize, payload->data(), + payload->size()); + + return message; } +void RtpPacketizer::media([[maybe_unused]] const Description::Media &desc) {} + } // namespace rtc #endif /* RTC_ENABLE_MEDIA */ diff --git a/src/track.cpp b/src/track.cpp index 29ab6d24c..251f2667d 100644 --- a/src/track.cpp +++ b/src/track.cpp @@ -44,6 +44,13 @@ void Track::setMediaHandler(shared_ptr handler) { impl()->setMediaHandler(std::move(handler)); } +void Track::chainMediaHandler(shared_ptr handler) { + if(auto first = impl()->getMediaHandler()) + first->addToChain(std::move(handler)); + else + impl()->setMediaHandler(std::move(handler)); +} + bool Track::requestKeyframe() { // only push PLI for video if (description().type() == "video") {