From 4ca78db146a27e79f5083f51584545aa9c98d76c Mon Sep 17 00:00:00 2001 From: Paul-Louis Ageneau Date: Tue, 13 Apr 2021 21:55:09 +0200 Subject: [PATCH] Reorganized stuff to make plog private --- CMakeLists.txt | 11 +- examples/client-benchmark/main.cpp | 2 +- examples/streamer/h264fileparser.cpp | 9 +- examples/streamer/helpers.cpp | 5 +- examples/streamer/stream.cpp | 4 +- include/rtc/common.hpp | 1 - include/rtc/global.hpp | 17 + include/rtc/h264packetizationhandler.hpp | 6 +- include/rtc/h264rtppacketizer.hpp | 6 +- include/rtc/log.hpp | 56 -- include/rtc/mediahandlerrootelement.hpp | 6 +- include/rtc/nalunit.hpp | 18 +- include/rtc/rtc.h | 2 +- include/rtc/rtc.hpp | 1 - include/rtc/rtp.hpp | 725 +++++------------------ src/capi.cpp | 66 +-- src/description.cpp | 2 + src/global.cpp | 66 ++- src/h264rtppacketizer.cpp | 10 + src/impl/internals.hpp | 16 + src/impl/peerconnection.cpp | 4 +- src/impl/threadpool.hpp | 1 + src/impl/tls.cpp | 2 + src/impl/transport.hpp | 1 + src/log.cpp | 47 -- src/mediachainablehandler.cpp | 4 + src/mediahandlerelement.cpp | 4 + src/opusrtppacketizer.cpp | 2 + src/peerconnection.cpp | 1 + src/rtcpnackresponder.cpp | 4 + src/rtcpreceivingsession.cpp | 6 +- src/rtcpsrreporter.cpp | 7 +- src/rtp.cpp | 600 +++++++++++++++++++ src/rtppacketizationconfig.cpp | 2 + src/rtppacketizer.cpp | 4 +- 35 files changed, 956 insertions(+), 762 deletions(-) delete mode 100644 include/rtc/log.hpp delete mode 100644 src/log.cpp create mode 100644 src/rtp.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 70a28e9..3609946 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,7 +44,6 @@ set(LIBDATACHANNEL_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/datachannel.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/description.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/global.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/log.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/message.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/peerconnection.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpreceivingsession.cpp @@ -62,6 +61,7 @@ set(LIBDATACHANNEL_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/mediahandlerelement.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/mediahandlerrootelement.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpnackresponder.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/rtp.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/capi.cpp ) @@ -76,7 +76,6 @@ set(LIBDATACHANNEL_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rtcpreceivingsession.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/common.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/global.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/log.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/message.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/peerconnection.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/reliability.hpp @@ -219,14 +218,14 @@ set_target_properties(datachannel-static PROPERTIES target_include_directories(datachannel PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) target_include_directories(datachannel PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc) target_include_directories(datachannel PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) -target_link_libraries(datachannel PUBLIC Threads::Threads plog::plog) -target_link_libraries(datachannel PRIVATE Usrsctp::Usrsctp) +target_link_libraries(datachannel PUBLIC Threads::Threads) +target_link_libraries(datachannel PRIVATE Usrsctp::Usrsctp plog::plog) target_include_directories(datachannel-static PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) target_include_directories(datachannel-static PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc) target_include_directories(datachannel-static PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) -target_link_libraries(datachannel-static PUBLIC Threads::Threads plog::plog) -target_link_libraries(datachannel-static PRIVATE Usrsctp::Usrsctp) +target_link_libraries(datachannel-static PUBLIC Threads::Threads) +target_link_libraries(datachannel-static PRIVATE Usrsctp::Usrsctp plog::plog) if(WIN32) target_link_libraries(datachannel PUBLIC ws2_32) # winsock2 diff --git a/examples/client-benchmark/main.cpp b/examples/client-benchmark/main.cpp index 56201da..0274965 100644 --- a/examples/client-benchmark/main.cpp +++ b/examples/client-benchmark/main.cpp @@ -71,7 +71,7 @@ bool enableThroughputSet; int throughtputSetAsKB; int bufferSize; const float STEP_COUNT_FOR_1_SEC = 100.0; -const int stepDurationInMs = 1000 / STEP_COUNT_FOR_1_SEC; +const int stepDurationInMs = int(1000 / STEP_COUNT_FOR_1_SEC); int main(int argc, char **argv) try { Cmdline params(argc, argv); diff --git a/examples/streamer/h264fileparser.cpp b/examples/streamer/h264fileparser.cpp index d44c414..13ac00e 100644 --- a/examples/streamer/h264fileparser.cpp +++ b/examples/streamer/h264fileparser.cpp @@ -17,9 +17,16 @@ */ #include "h264fileparser.hpp" -#include #include "rtc/rtc.hpp" +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + using namespace std; H264FileParser::H264FileParser(string directory, uint32_t fps, bool loop): FileParser(directory, ".h264", fps, loop) { } diff --git a/examples/streamer/helpers.cpp b/examples/streamer/helpers.cpp index b9413b6..2563968 100644 --- a/examples/streamer/helpers.cpp +++ b/examples/streamer/helpers.cpp @@ -19,9 +19,8 @@ #include "helpers.hpp" #include -#if _WIN32 +#ifdef _WIN32 // taken from https://stackoverflow.com/questions/10905892/equivalent-of-gettimeday-for-windows - #include struct timezone { @@ -55,6 +54,8 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) } return 0; } +#else +#include #endif using namespace std; diff --git a/examples/streamer/stream.cpp b/examples/streamer/stream.cpp index e7a5e06..1ee7d57 100644 --- a/examples/streamer/stream.cpp +++ b/examples/streamer/stream.cpp @@ -19,7 +19,7 @@ #include "stream.hpp" #include "helpers.hpp" -#if _WIN32 +#ifdef _WIN32 // taken from https://stackoverflow.com/questions/5801813/c-usleep-is-obsolete-workarounds-for-windows-mingw #include @@ -35,6 +35,8 @@ void usleep(__int64 usec) WaitForSingleObject(timer, INFINITE); CloseHandle(timer); } +#else +#include #endif void StreamSource::stop() { diff --git a/include/rtc/common.hpp b/include/rtc/common.hpp index 0876c4b..9966841 100644 --- a/include/rtc/common.hpp +++ b/include/rtc/common.hpp @@ -41,7 +41,6 @@ #include "rtc.h" // for C API defines -#include "log.hpp" #include "utils.hpp" #include diff --git a/include/rtc/global.hpp b/include/rtc/global.hpp index da4cd68..7dfc9de 100644 --- a/include/rtc/global.hpp +++ b/include/rtc/global.hpp @@ -25,6 +25,23 @@ namespace rtc { +enum class LogLevel { // Don't change, it must match plog severity + None = 0, + Fatal = 1, + Error = 2, + Warning = 3, + Info = 4, + Debug = 5, + Verbose = 6 +}; + +typedef std::function LogCallback; + +RTC_CPP_EXPORT void InitLogger(LogLevel level, LogCallback callback = nullptr); +#ifdef PLOG +RTC_CPP_EXPORT void InitLogger(plog::Severity severity, plog::IAppender *appender = nullptr); +#endif + RTC_EXPORT void Preload(); RTC_EXPORT void Cleanup(); diff --git a/include/rtc/h264packetizationhandler.hpp b/include/rtc/h264packetizationhandler.hpp index ec4779f..be33d43 100644 --- a/include/rtc/h264packetizationhandler.hpp +++ b/include/rtc/h264packetizationhandler.hpp @@ -16,8 +16,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef H264_PACKETIZATION_HANDLER_H -#define H264_PACKETIZATION_HANDLER_H +#ifndef RTC_H264_PACKETIZATION_HANDLER_H +#define RTC_H264_PACKETIZATION_HANDLER_H #if RTC_ENABLE_MEDIA @@ -39,4 +39,4 @@ public: #endif /* RTC_ENABLE_MEDIA */ -#endif /* H264_PACKETIZATION_HANDLER_H */ +#endif /* RTC_H264_PACKETIZATION_HANDLER_H */ diff --git a/include/rtc/h264rtppacketizer.hpp b/include/rtc/h264rtppacketizer.hpp index a3ed74e..7d8cf21 100644 --- a/include/rtc/h264rtppacketizer.hpp +++ b/include/rtc/h264rtppacketizer.hpp @@ -16,8 +16,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef H264_RTP_PACKETIZER_H -#define H264_RTP_PACKETIZER_H +#ifndef RTC_H264_RTP_PACKETIZER_H +#define RTC_H264_RTP_PACKETIZER_H #if RTC_ENABLE_MEDIA @@ -64,4 +64,4 @@ private: #endif /* RTC_ENABLE_MEDIA */ -#endif /* H264_RTP_PACKETIZER_H */ +#endif /* RTC_H264_RTP_PACKETIZER_H */ diff --git a/include/rtc/log.hpp b/include/rtc/log.hpp deleted file mode 100644 index e8b851f..0000000 --- a/include/rtc/log.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (c) 2019 Paul-Louis Ageneau - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef RTC_LOG_H -#define RTC_LOG_H - -// Disable warnings before including plog -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wall" -#elif defined(_MSC_VER) -#pragma warning(push, 0) -#endif - -#include "plog/Log.h" - -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic pop -#elif defined(_MSC_VER) -#pragma warning(pop) -#endif - -#include "common.hpp" - -namespace rtc { - -enum class LogLevel { // Don't change, it must match plog severity - None = 0, - Fatal = 1, - Error = 2, - Warning = 3, - Info = 4, - Debug = 5, - Verbose = 6 -}; - -RTC_CPP_EXPORT void InitLogger(LogLevel level); -RTC_CPP_EXPORT void InitLogger(plog::Severity severity, plog::IAppender *appender = nullptr); -} // namespace rtc - -#endif diff --git a/include/rtc/mediahandlerrootelement.hpp b/include/rtc/mediahandlerrootelement.hpp index 474765b..231622f 100644 --- a/include/rtc/mediahandlerrootelement.hpp +++ b/include/rtc/mediahandlerrootelement.hpp @@ -16,8 +16,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef RTCP_MEDIA_HANDLER_ROOT_ELEMENT_H -#define RTCP_MEDIA_HANDLER_ROOT_ELEMENT_H +#ifndef RTC_MEDIA_HANDLER_ROOT_ELEMENT_H +#define RTC_MEDIA_HANDLER_ROOT_ELEMENT_H #if RTC_ENABLE_MEDIA @@ -43,4 +43,4 @@ public: #endif // RTC_ENABLE_MEDIA -#endif // RTCP_MEDIA_HANDLER_ROOT_ELEMENT_H +#endif // RTC_MEDIA_HANDLER_ROOT_ELEMENT_H diff --git a/include/rtc/nalunit.hpp b/include/rtc/nalunit.hpp index c3fc93e..393a537 100644 --- a/include/rtc/nalunit.hpp +++ b/include/rtc/nalunit.hpp @@ -16,19 +16,23 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef NAL_UNIT_H -#define NAL_UNIT_H +#ifndef RTC_NAL_UNIT_H +#define RTC_NAL_UNIT_H #if RTC_ENABLE_MEDIA #include "common.hpp" +#include + namespace rtc { #pragma pack(push, 1) /// Nalu header struct RTC_CPP_EXPORT NalUnitHeader { + uint8_t _first = 0; + bool forbiddenBit() { return _first >> 7; } uint8_t nri() { return _first >> 5 & 0x03; } uint8_t unitType() { return _first & 0x1F; } @@ -36,13 +40,12 @@ struct RTC_CPP_EXPORT NalUnitHeader { void setForbiddenBit(bool isSet) { _first = (_first & 0x7F) | (isSet << 7); } void setNRI(uint8_t nri) { _first = (_first & 0x9F) | ((nri & 0x03) << 5); } void setUnitType(uint8_t type) { _first = (_first & 0xE0) | (type & 0x1F); } - -private: - uint8_t _first = 0; }; /// Nalu fragment header struct RTC_CPP_EXPORT NalUnitFragmentHeader { + uint8_t _first = 0; + bool isStart() { return _first >> 7; } bool reservedBit6() { return (_first >> 6) & 0x01; } bool isEnd() { return (_first >> 5) & 0x01; } @@ -52,9 +55,6 @@ struct RTC_CPP_EXPORT NalUnitFragmentHeader { void setEnd(bool isSet) { _first = (_first & 0xDF) | (isSet << 6); } void setReservedBit6(bool isSet) { _first = (_first & 0xBF) | (isSet << 5); } void setUnitType(uint8_t type) { _first = (_first & 0xE0) | (type & 0x1F); } - -private: - uint8_t _first = 0; }; #pragma pack(pop) @@ -152,4 +152,4 @@ public: #endif /* RTC_ENABLE_MEDIA */ -#endif /* NAL_UNIT_H */ +#endif /* RTC_NAL_UNIT_H */ diff --git a/include/rtc/rtc.h b/include/rtc/rtc.h index 71b9dd5..2d08fbc 100644 --- a/include/rtc/rtc.h +++ b/include/rtc/rtc.h @@ -284,7 +284,7 @@ int rtcChainRtcpSrReporter(int tr); /// Chain RtcpNackResponder to handler chain for given track /// @param tr Track id /// @param maxStoredPacketsCount Maximum stored packet count -int rtcChainRtcpNackResponder(int tr, unsigned maxStoredPacketsCount); +int rtcChainRtcpNackResponder(int tr, unsigned int maxStoredPacketsCount); /// Set start time for RTP stream /// @param startTime_s Start time in seconds diff --git a/include/rtc/rtc.hpp b/include/rtc/rtc.hpp index fe6709b..524e238 100644 --- a/include/rtc/rtc.hpp +++ b/include/rtc/rtc.hpp @@ -22,7 +22,6 @@ // C++ API #include "common.hpp" #include "global.hpp" -#include "log.hpp" // #include "datachannel.hpp" #include "peerconnection.hpp" diff --git a/include/rtc/rtp.hpp b/include/rtc/rtp.hpp index 88a9099..8708abd 100644 --- a/include/rtc/rtp.hpp +++ b/include/rtc/rtp.hpp @@ -21,23 +21,9 @@ #ifndef RTC_RTP_HPP #define RTC_RTP_HPP -#include "log.hpp" +#include "common.hpp" -#include - -#ifdef _WIN32 -#include -#else -#include -#endif - -#ifndef htonll -#define htonll(x) \ - ((uint64_t)(((uint64_t)htonl((uint32_t)(x))) << 32) | (uint64_t)htonl((uint32_t)((x) >> 32))) -#endif -#ifndef ntohll -#define ntohll(x) htonll(x) -#endif +#include namespace rtc { @@ -45,63 +31,40 @@ typedef uint32_t SSRC; #pragma pack(push, 1) -struct RTP { -private: +struct RTC_CPP_EXPORT RTP { uint8_t _first; uint8_t _payloadType; uint16_t _seqNumber; uint32_t _timestamp; SSRC _ssrc; + SSRC _csrc[16]; -public: - SSRC csrc[16]; + [[nodiscard]] uint8_t version() const; + [[nodiscard]] bool padding() const; + [[nodiscard]] bool extension() const; + [[nodiscard]] uint8_t csrcCount() const; + [[nodiscard]] uint8_t marker() const; + [[nodiscard]] uint8_t payloadType() const; + [[nodiscard]] uint16_t seqNumber() const; + [[nodiscard]] uint32_t timestamp() const; + [[nodiscard]] uint32_t ssrc() const; - inline uint8_t version() const { return _first >> 6; } - inline bool padding() const { return (_first >> 5) & 0x01; } - inline bool extension() const { return (_first >> 4) & 0x01; } - inline uint8_t csrcCount() const { return _first & 0x0F; } - inline uint8_t marker() const { return _payloadType & 0b10000000; } - inline uint8_t payloadType() const { return _payloadType & 0b01111111; } - inline uint16_t seqNumber() const { return ntohs(_seqNumber); } - inline uint32_t timestamp() const { return ntohl(_timestamp); } - inline uint32_t ssrc() const { return ntohl(_ssrc); } + [[nodiscard]] size_t getSize() const; + [[nodiscard]] const char *getBody() const; + [[nodiscard]] char *getBody(); - inline size_t getSize() const { - return reinterpret_cast(&csrc) - reinterpret_cast(this) + - sizeof(SSRC) * csrcCount(); - } + void log() const; - [[nodiscard]] char *getBody() { - return reinterpret_cast(&csrc) + sizeof(SSRC) * csrcCount(); - } - - [[nodiscard]] const char *getBody() const { - return reinterpret_cast(&csrc) + sizeof(SSRC) * csrcCount(); - } - - inline void preparePacket() { _first |= (1 << 7); } - - inline void setSeqNumber(uint16_t newSeqNo) { _seqNumber = htons(newSeqNo); } - inline void setPayloadType(uint8_t newPayloadType) { - _payloadType = (_payloadType & 0b10000000u) | (0b01111111u & newPayloadType); - } - inline void setSsrc(uint32_t in_ssrc) { _ssrc = htonl(in_ssrc); } - inline void setMarker(bool marker) { _payloadType = (_payloadType & 0x7F) | (marker << 7); }; - - void setTimestamp(uint32_t i) { _timestamp = htonl(i); } - - void log() { - PLOG_VERBOSE << "RTP V: " << (int)version() << " P: " << (padding() ? "P" : " ") - << " X: " << (extension() ? "X" : " ") << " CC: " << (int)csrcCount() - << " M: " << (marker() ? "M" : " ") << " PT: " << (int)payloadType() - << " SEQNO: " << seqNumber() << " TS: " << timestamp(); - } + void preparePacket(); + void setSeqNumber(uint16_t newSeqNo); + void setPayloadType(uint8_t newPayloadType); + void setSsrc(uint32_t in_ssrc); + void setMarker(bool marker); + void setTimestamp(uint32_t i); }; -struct RTCP_ReportBlock { - SSRC ssrc; - -private: +struct RTC_CPP_EXPORT RTCP_ReportBlock { + SSRC _ssrc; uint32_t _fractionLostAndPacketsLost; // fraction lost is 8-bit, packets lost is 24-bit uint16_t _seqNoCycles; uint16_t _highestSeqNo; @@ -109,136 +72,68 @@ private: uint32_t _lastReport; uint32_t _delaySinceLastReport; -public: - inline void preparePacket(SSRC in_ssrc, [[maybe_unused]] unsigned int packetsLost, - [[maybe_unused]] unsigned int totalPackets, uint16_t highestSeqNo, - uint16_t seqNoCycles, uint32_t jitter, uint64_t lastSR_NTP, - uint64_t lastSR_DELAY) { - setSeqNo(highestSeqNo, seqNoCycles); - setJitter(jitter); - setSSRC(in_ssrc); + [[nodiscard]] uint16_t seqNoCycles() const; + [[nodiscard]] uint16_t highestSeqNo() const; + [[nodiscard]] uint32_t jitter() const; + [[nodiscard]] uint32_t delaySinceSR() const; - // Middle 32 bits of NTP Timestamp - // this->lastReport = lastSR_NTP >> 16u; - setNTPOfSR(uint64_t(lastSR_NTP)); - setDelaySinceSR(uint32_t(lastSR_DELAY)); + [[nodiscard]] SSRC getSSRC() const; + [[nodiscard]] uint32_t getNTPOfSR() const; + [[nodiscard]] unsigned int getLossPercentage() const; + [[nodiscard]] unsigned int getPacketLostCount() const; - // The delay, expressed in units of 1/65536 seconds - // this->delaySinceLastReport = lastSR_DELAY; - } + void preparePacket(SSRC in_ssrc, unsigned int packetsLost, unsigned int totalPackets, + uint16_t highestSeqNo, uint16_t seqNoCycles, uint32_t jitter, + uint64_t lastSR_NTP, uint64_t lastSR_DELAY); + void setSSRC(SSRC in_ssrc); + void setPacketsLost(unsigned int packetsLost, unsigned int totalPackets); + void setSeqNo(uint16_t highestSeqNo, uint16_t seqNoCycles); + void setJitter(uint32_t jitter); + void setNTPOfSR(uint64_t ntp); + void setDelaySinceSR(uint32_t sr); - inline void setSSRC(SSRC in_ssrc) { this->ssrc = htonl(in_ssrc); } - [[nodiscard]] inline SSRC getSSRC() const { return ntohl(ssrc); } - - inline void setPacketsLost([[maybe_unused]] unsigned int packetsLost, - [[maybe_unused]] unsigned int totalPackets) { - // TODO Implement loss percentages. - _fractionLostAndPacketsLost = 0; - } - - [[nodiscard]] inline unsigned int getLossPercentage() const { - // TODO Implement loss percentages. - return 0; - } - [[nodiscard]] inline unsigned int getPacketLostCount() const { - // TODO Implement total packets lost. - return 0; - } - - inline uint16_t seqNoCycles() const { return ntohs(_seqNoCycles); } - inline uint16_t highestSeqNo() const { return ntohs(_highestSeqNo); } - inline uint32_t jitter() const { return ntohl(_jitter); } - - inline void setSeqNo(uint16_t highestSeqNo, uint16_t seqNoCycles) { - _highestSeqNo = htons(highestSeqNo); - _seqNoCycles = htons(seqNoCycles); - } - - inline void setJitter(uint32_t jitter) { _jitter = htonl(jitter); } - - inline void setNTPOfSR(uint64_t ntp) { _lastReport = htonll(ntp >> 16u); } - [[nodiscard]] inline uint32_t getNTPOfSR() const { return ntohl(_lastReport) << 16u; } - - inline void setDelaySinceSR(uint32_t sr) { - // The delay, expressed in units of 1/65536 seconds - _delaySinceLastReport = htonl(sr); - } - [[nodiscard]] inline uint32_t getDelaySinceSR() const { return ntohl(_delaySinceLastReport); } - - inline void log() const { - PLOG_VERBOSE << "RTCP report block: " - << "ssrc=" - << ntohl(ssrc) - // TODO: Implement these reports - // << ", fractionLost=" << fractionLost - // << ", packetsLost=" << packetsLost - << ", highestSeqNo=" << highestSeqNo() << ", seqNoCycles=" << seqNoCycles() - << ", jitter=" << jitter() << ", lastSR=" << getNTPOfSR() - << ", lastSRDelay=" << getDelaySinceSR(); - } + void log() const; }; -struct RTCP_HEADER { -private: +struct RTC_CPP_EXPORT RTCP_HEADER { uint8_t _first; uint8_t _payloadType; uint16_t _length; -public: - inline uint8_t version() const { return _first >> 6; } - inline bool padding() const { return (_first >> 5) & 0x01; } - inline uint8_t reportCount() const { return _first & 0x0F; } - inline uint8_t payloadType() const { return _payloadType; } - inline uint16_t length() const { return ntohs(_length); } - inline size_t lengthInBytes() const { return (1 + length()) * 4; } + [[nodiscard]] uint8_t version() const; + [[nodiscard]] bool padding() const; + [[nodiscard]] uint8_t reportCount() const; + [[nodiscard]] uint8_t payloadType() const; + [[nodiscard]] uint16_t length() const; + [[nodiscard]] size_t lengthInBytes() const; - inline void setPayloadType(uint8_t type) { _payloadType = type; } - inline void setReportCount(uint8_t count) { - _first = (_first & 0b11100000u) | (count & 0b00011111u); - } - inline void setLength(uint16_t length) { _length = htons(length); } + void prepareHeader(uint8_t payloadType, uint8_t reportCount, uint16_t length); + void setPayloadType(uint8_t type); + void setReportCount(uint8_t count); + void setLength(uint16_t length); - inline void prepareHeader(uint8_t payloadType, uint8_t reportCount, uint16_t length) { - _first = 0b10000000; // version 2, no padding - setReportCount(reportCount); - setPayloadType(payloadType); - setLength(length); - } - - inline void log() const { - PLOG_VERBOSE << "RTCP header: " - << "version=" << unsigned(version()) << ", padding=" << padding() - << ", reportCount=" << unsigned(reportCount()) - << ", payloadType=" << unsigned(payloadType()) << ", length=" << length(); - } + void log() const; }; -struct RTCP_FB_HEADER { +struct RTC_CPP_EXPORT RTCP_FB_HEADER { RTCP_HEADER header; - SSRC packetSender; - SSRC mediaSource; - [[nodiscard]] SSRC getPacketSenderSSRC() const { return ntohl(packetSender); } + SSRC _packetSender; + SSRC _mediaSource; - [[nodiscard]] SSRC getMediaSourceSSRC() const { return ntohl(mediaSource); } + [[nodiscard]] SSRC packetSenderSSRC() const; + [[nodiscard]] SSRC mediaSourceSSRC() const; - void setPacketSenderSSRC(SSRC ssrc) { this->packetSender = htonl(ssrc); } + void setPacketSenderSSRC(SSRC ssrc); + void setMediaSourceSSRC(SSRC ssrc); - void setMediaSourceSSRC(SSRC ssrc) { this->mediaSource = htonl(ssrc); } - - void log() { - header.log(); - PLOG_VERBOSE << "FB: " - << " packet sender: " << getPacketSenderSSRC() - << " media source: " << getMediaSourceSSRC(); - } + void log() const; }; -struct RTCP_SR { +struct RTC_CPP_EXPORT RTCP_SR { RTCP_HEADER header; + SSRC _senderSSRC; - -private: uint64_t _ntpTimestamp; uint32_t _rtpTimestamp; uint32_t _packetCount; @@ -246,418 +141,175 @@ private: RTCP_ReportBlock _reportBlocks; -public: - inline void preparePacket(SSRC senderSSRC, uint8_t reportCount) { - unsigned int length = - ((sizeof(header) + 24 + reportCount * sizeof(RTCP_ReportBlock)) / 4) - 1; - header.prepareHeader(200, reportCount, uint16_t(length)); - this->_senderSSRC = htonl(senderSSRC); - } + [[nodiscard]] static unsigned int Size(unsigned int reportCount); - [[nodiscard]] inline RTCP_ReportBlock *getReportBlock(int num) { return &_reportBlocks + num; } - [[nodiscard]] inline const RTCP_ReportBlock *getReportBlock(int num) const { - return &_reportBlocks + num; - } + [[nodiscard]] uint64_t ntpTimestamp() const; + [[nodiscard]] uint32_t rtpTimestamp() const; + [[nodiscard]] uint32_t packetCount() const; + [[nodiscard]] uint32_t octetCount() const; + [[nodiscard]] uint32_t senderSSRC() const; - [[nodiscard]] static unsigned int size(unsigned int reportCount) { - return sizeof(RTCP_HEADER) + 24 + reportCount * sizeof(RTCP_ReportBlock); - } + [[nodiscard]] const RTCP_ReportBlock *getReportBlock(int num) const; + [[nodiscard]] RTCP_ReportBlock *getReportBlock(int num); + [[nodiscard]] unsigned int size(unsigned int reportCount); + [[nodiscard]] size_t getSize() const; - [[nodiscard]] inline size_t getSize() const { - // "length" in packet is one less than the number of 32 bit words in the packet. - return sizeof(uint32_t) * (1 + size_t(header.length())); - } + void preparePacket(SSRC senderSSRC, uint8_t reportCount); + void setNtpTimestamp(uint64_t ts); + void setRtpTimestamp(uint32_t ts); + void setOctetCount(uint32_t ts); + void setPacketCount(uint32_t ts); - inline uint64_t ntpTimestamp() const { return ntohll(_ntpTimestamp); } - inline uint32_t rtpTimestamp() const { return ntohl(_rtpTimestamp); } - inline uint32_t packetCount() const { return ntohl(_packetCount); } - inline uint32_t octetCount() const { return ntohl(_octetCount); } - inline uint32_t senderSSRC() const { return ntohl(_senderSSRC); } - - inline void setNtpTimestamp(uint64_t ts) { _ntpTimestamp = htonll(ts); } - inline void setRtpTimestamp(uint32_t ts) { _rtpTimestamp = htonl(ts); } - inline void setOctetCount(uint32_t ts) { _octetCount = htonl(ts); } - inline void setPacketCount(uint32_t ts) { _packetCount = htonl(ts); } - - inline void log() const { - header.log(); - PLOG_VERBOSE << "RTCP SR: " - << " SSRC=" << senderSSRC() << ", NTP_TS=" << ntpTimestamp() - << ", RTP_TS=" << rtpTimestamp() << ", packetCount=" << packetCount() - << ", octetCount=" << octetCount(); - - for (unsigned i = 0; i < unsigned(header.reportCount()); i++) { - getReportBlock(i)->log(); - } - } + void log() const; }; -struct RTCP_SDES_ITEM { -public: +struct RTC_CPP_EXPORT RTCP_SDES_ITEM { uint8_t type; -private: uint8_t _length; char _text[1]; -public: - inline std::string text() const { return std::string(_text, _length); } - inline void setText(std::string text) { - if(text.size() > 0xFF) - throw std::invalid_argument("text is too long"); + [[nodiscard]] static unsigned int Size(uint8_t textLength); - _length = uint8_t(text.size()); - memcpy(_text, text.data(), text.size()); - } + [[nodiscard]] string text() const; + [[nodiscard]] uint8_t length() const; - inline uint8_t length() { return _length; } - - [[nodiscard]] static unsigned int size(uint8_t textLength) { return textLength + 2; } + void setText(string text); }; struct RTCP_SDES_CHUNK { -private: SSRC _ssrc; RTCP_SDES_ITEM _items; -public: - inline SSRC ssrc() const { return ntohl(_ssrc); } - inline void setSSRC(SSRC ssrc) { _ssrc = htonl(ssrc); } + [[nodiscard]] static unsigned int Size(const std::vector textLengths); - /// Get item at given index - /// @note All items with index < `num` must be valid, otherwise this function has undefined - /// behaviour (use `safelyCountChunkSize` to check if chunk is valid) - /// @param num Index of item to return - inline RTCP_SDES_ITEM *getItem(int num) { - auto base = &_items; - while (num-- > 0) { - auto itemSize = RTCP_SDES_ITEM::size(base->length()); - base = reinterpret_cast(reinterpret_cast(base) + itemSize); - } - return reinterpret_cast(base); - } + [[nodiscard]] SSRC ssrc() const; - long safelyCountChunkSize(size_t maxChunkSize) { - if (maxChunkSize < RTCP_SDES_CHUNK::size({})) { - // chunk is truncated - return -1; - } else { - size_t size = sizeof(SSRC); - unsigned int i = 0; - // We can always access first 4 bytes of first item (in case of no items there will be 4 - // null bytes) - auto item = getItem(i); - std::vector textsLength{}; - while (item->type != 0) { - if (size + RTCP_SDES_ITEM::size(0) > maxChunkSize) { - // item is too short - return -1; - } - auto itemLength = item->length(); - if (size + RTCP_SDES_ITEM::size(itemLength) >= maxChunkSize) { - // item is too large (it can't be equal to chunk size because after item there - // must be 1-4 null bytes as padding) - return -1; - } - textsLength.push_back(itemLength); - // safely to access next item - item = getItem(++i); - } - auto realSize = RTCP_SDES_CHUNK::size(textsLength); - if (realSize > maxChunkSize) { - // Chunk is too large - return -1; - } - return realSize; - } - } + void setSSRC(SSRC ssrc); - [[nodiscard]] static unsigned int size(const std::vector textLengths) { - unsigned int itemsSize = 0; - for (auto length : textLengths) { - itemsSize += RTCP_SDES_ITEM::size(length); - } - auto nullTerminatedItemsSize = itemsSize + 1; - auto words = uint8_t(std::ceil(double(nullTerminatedItemsSize) / 4)) + 1; - return words * 4; - } + // Get item at given index + // All items with index < num must be valid, otherwise this function has undefined behaviour + // (use safelyCountChunkSize() to check if chunk is valid). + [[nodiscard]] const RTCP_SDES_ITEM *getItem(int num) const; + [[nodiscard]] RTCP_SDES_ITEM *getItem(int num); - /// Get size of chunk - /// @note All items must be valid, otherwise this function has undefined behaviour (use - /// `safelyCountChunkSize` to check if chunk is valid) - [[nodiscard]] unsigned int getSize() { - std::vector textLengths{}; - unsigned int i = 0; - auto item = getItem(i); - while (item->type != 0) { - textLengths.push_back(item->length()); - item = getItem(++i); - } - return size(textLengths); - } + // Get size of chunk + // All items must be valid, otherwise this function has undefined behaviour (use + // safelyCountChunkSize() to check if chunk is valid) + [[nodiscard]] unsigned int getSize() const; + + long safelyCountChunkSize(size_t maxChunkSize) const; }; -struct RTCP_SDES { +struct RTC_CPP_EXPORT RTCP_SDES { RTCP_HEADER header; - -private: RTCP_SDES_CHUNK _chunks; -public: - inline void preparePacket(uint8_t chunkCount) { - unsigned int chunkSize = 0; - for (uint8_t i = 0; i < chunkCount; i++) { - auto chunk = getChunk(i); - chunkSize += chunk->getSize(); - } - uint16_t length = uint16_t((sizeof(header) + chunkSize) / 4 - 1); - header.prepareHeader(202, chunkCount, length); - } + [[nodiscard]] static unsigned int Size(const std::vector> lengths); - bool isValid() { - auto chunksSize = header.lengthInBytes() - sizeof(header); - if (chunksSize == 0) { - return true; - } else { - // there is at least one chunk - unsigned int i = 0; - unsigned int size = 0; - while (size < chunksSize) { - if (chunksSize < size + RTCP_SDES_CHUNK::size({})) { - // chunk is truncated - return false; - } - auto chunk = getChunk(i++); - auto chunkSize = chunk->safelyCountChunkSize(chunksSize - size); - if (chunkSize < 0) { - // chunk is invalid - return false; - } - size += chunkSize; - } - return size == chunksSize; - } - } + bool isValid() const; - /// Returns number of chunks in this packet - /// @note Returns 0 if packet is invalid - inline unsigned int chunksCount() { - if (!isValid()) { - return 0; - } - uint16_t chunksSize = 4 * (header.length() + 1) - sizeof(header); - unsigned int size = 0; - unsigned int i = 0; - while (size < chunksSize) { - size += getChunk(i++)->getSize(); - } - return i; - } + // Returns number of chunks in this packet + // Returns 0 if packet is invalid + unsigned int chunksCount() const; - /// Get chunk at given index - /// @note All chunks (and their items) with index < `num` must be valid, otherwise this function - /// has undefined behaviour (use `isValid` to check if chunk is valid) - /// @param num Index of chunk to return - inline RTCP_SDES_CHUNK *getChunk(int num) { - auto base = &_chunks; - while (num-- > 0) { - auto chunkSize = base->getSize(); - base = - reinterpret_cast(reinterpret_cast(base) + chunkSize); - } - return reinterpret_cast(base); - } + // Get chunk at given index + // All chunks (and their items) with index < `num` must be valid, otherwise this function has + // undefined behaviour (use `isValid` to check if chunk is valid). + const RTCP_SDES_CHUNK *getChunk(int num) const; + RTCP_SDES_CHUNK *getChunk(int num); - [[nodiscard]] static unsigned int size(const std::vector> lengths) { - unsigned int chunks_size = 0; - for (auto length : lengths) { - chunks_size += RTCP_SDES_CHUNK::size(length); - } - return 4 + chunks_size; - } + void preparePacket(uint8_t chunkCount); }; -struct RTCP_RR { +struct RTC_CPP_EXPORT RTCP_RR { RTCP_HEADER header; - SSRC _senderSSRC; -private: + SSRC _senderSSRC; RTCP_ReportBlock _reportBlocks; -public: - [[nodiscard]] inline RTCP_ReportBlock *getReportBlock(int num) { return &_reportBlocks + num; } - [[nodiscard]] inline const RTCP_ReportBlock *getReportBlock(int num) const { - return &_reportBlocks + num; - } + [[nodiscard]] static size_t SizeWithReportBlocks(uint8_t reportCount); - inline SSRC senderSSRC() const { return ntohl(_senderSSRC); } - inline void setSenderSSRC(SSRC ssrc) { this->_senderSSRC = htonl(ssrc); } + SSRC senderSSRC() const; + bool isSenderReport(); + bool isReceiverReport(); - [[nodiscard]] inline size_t getSize() const { - // "length" in packet is one less than the number of 32 bit words in the packet. - return sizeof(uint32_t) * (1 + size_t(header.length())); - } + [[nodiscard]] RTCP_ReportBlock *getReportBlock(int num); + [[nodiscard]] const RTCP_ReportBlock *getReportBlock(int num) const; + [[nodiscard]] size_t getSize() const; - inline void preparePacket(SSRC senderSSRC, uint8_t reportCount) { - // "length" in packet is one less than the number of 32 bit words in the packet. - size_t length = (sizeWithReportBlocks(reportCount) / 4) - 1; - header.prepareHeader(201, reportCount, uint16_t(length)); - this->_senderSSRC = htonl(senderSSRC); - } + void preparePacket(SSRC senderSSRC, uint8_t reportCount); + void setSenderSSRC(SSRC ssrc); - inline static size_t sizeWithReportBlocks(uint8_t reportCount) { - return sizeof(header) + 4 + size_t(reportCount) * sizeof(RTCP_ReportBlock); - } - - inline bool isSenderReport() { return header.payloadType() == 200; } - - inline bool isReceiverReport() { return header.payloadType() == 201; } - - inline void log() const { - header.log(); - PLOG_VERBOSE << "RTCP RR: " - << " SSRC=" << ntohl(_senderSSRC); - - for (unsigned i = 0; i < unsigned(header.reportCount()); i++) { - getReportBlock(i)->log(); - } - } + void log() const; }; -struct RTCP_REMB { +struct RTC_CPP_EXPORT RTCP_REMB { RTCP_FB_HEADER header; - /*! \brief Unique identifier ('R' 'E' 'M' 'B') */ - char id[4]; + char _id[4]; // Unique identifier ('R' 'E' 'M' 'B') + uint32_t _bitrate; // Num SSRC, Br Exp, Br Mantissa (bit mask) + SSRC _ssrc[1]; - /*! \brief Num SSRC, Br Exp, Br Mantissa (bit mask) */ - uint32_t bitrate; + [[nodiscard]] static size_t SizeWithSSRCs(int count); - SSRC ssrc[1]; + [[nodiscard]] unsigned int getSize() const; - [[nodiscard]] unsigned int getSize() const { - // "length" in packet is one less than the number of 32 bit words in the packet. - return sizeof(uint32_t) * (1 + header.header.length()); - } - - void preparePacket(SSRC senderSSRC, unsigned int numSSRC, unsigned int in_bitrate) { - - // Report Count becomes the format here. - header.header.prepareHeader(206, 15, 0); - - // Always zero. - header.setMediaSourceSSRC(0); - - header.setPacketSenderSSRC(senderSSRC); - - id[0] = 'R'; - id[1] = 'E'; - id[2] = 'M'; - id[3] = 'B'; - - setBitrate(numSSRC, in_bitrate); - } - - void setBitrate(unsigned int numSSRC, unsigned int in_bitrate) { - unsigned int exp = 0; - while (in_bitrate > pow(2, 18) - 1) { - exp++; - in_bitrate /= 2; - } - - // "length" in packet is one less than the number of 32 bit words in the packet. - header.header.setLength( - uint16_t((offsetof(RTCP_REMB, ssrc) / sizeof(uint32_t)) - 1 + numSSRC)); - - this->bitrate = htonl((numSSRC << (32u - 8u)) | (exp << (32u - 8u - 6u)) | in_bitrate); - } - - void setSsrc(int iterator, SSRC newSssrc) { ssrc[iterator] = htonl(newSssrc); } - - size_t static inline sizeWithSSRCs(int count) { - return sizeof(RTCP_REMB) + (count - 1) * sizeof(SSRC); - } + void preparePacket(SSRC senderSSRC, unsigned int numSSRC, unsigned int in_bitrate); + void setBitrate(unsigned int numSSRC, unsigned int in_bitrate); + void setSsrc(int iterator, SSRC newSssrc); }; -struct RTCP_PLI { +struct RTC_CPP_EXPORT RTCP_PLI { RTCP_FB_HEADER header; - void preparePacket(SSRC messageSSRC) { - header.header.prepareHeader(206, 1, 2); - header.setPacketSenderSSRC(messageSSRC); - header.setMediaSourceSSRC(messageSSRC); - } + [[nodiscard]] static unsigned int Size(); - void print() { header.log(); } + void preparePacket(SSRC messageSSRC); - [[nodiscard]] static unsigned int size() { return sizeof(RTCP_FB_HEADER); } + void log() const; }; -struct RTCP_FIR_PART { +struct RTC_CPP_EXPORT RTCP_FIR_PART { uint32_t ssrc; uint8_t seqNo; uint8_t dummy1; uint16_t dummy2; }; -struct RTCP_FIR { +struct RTC_CPP_EXPORT RTCP_FIR { RTCP_FB_HEADER header; RTCP_FIR_PART parts[1]; - void preparePacket(SSRC messageSSRC, uint8_t seqNo) { - header.header.prepareHeader(206, 4, 2 + 2 * 1); - header.setPacketSenderSSRC(messageSSRC); - header.setMediaSourceSSRC(messageSSRC); - parts[0].ssrc = htonl(messageSSRC); - parts[0].seqNo = seqNo; - } + static unsigned int Size(); - void print() { header.log(); } + void preparePacket(SSRC messageSSRC, uint8_t seqNo); - [[nodiscard]] static unsigned int size() { - return sizeof(RTCP_FB_HEADER) + sizeof(RTCP_FIR_PART); - } + void log() const; }; -struct RTCP_NACK_PART { +struct RTC_CPP_EXPORT RTCP_NACK_PART { uint16_t _pid; uint16_t _blp; - uint16_t getPID() { return ntohs(_pid); } - uint16_t getBLP() { return ntohs(_blp); } + uint16_t pid(); + uint16_t blp(); - void setPID(uint16_t pid) { _pid = htons(pid); } - void setBLP(uint16_t blp) { _blp = htons(blp); } + void setPid(uint16_t pid); + void setBlp(uint16_t blp); - std::vector getSequenceNumbers() { - std::vector result{}; - result.reserve(17); - uint16_t pid = getPID(); - result.push_back(pid); - uint16_t bitmask = getBLP(); - uint16_t i = pid + 1; - while (bitmask > 0) { - if (bitmask & 0x1) { - result.push_back(i); - } - i += 1; - bitmask >>= 1; - } - return result; - } + std::vector getSequenceNumbers(); }; -class RTCP_NACK { -public: +struct RTC_CPP_EXPORT RTCP_NACK { RTCP_FB_HEADER header; RTCP_NACK_PART parts[1]; -public: - void preparePacket(SSRC ssrc, unsigned int discreteSeqNoCount) { - header.header.prepareHeader(205, 1, 2 + uint16_t(discreteSeqNoCount)); - header.setMediaSourceSSRC(ssrc); - header.setPacketSenderSSRC(ssrc); - } + [[nodiscard]] static unsigned int Size(unsigned int discreteSeqNoCount); + + [[nodiscard]] unsigned int getSeqNoCount(); + + void preparePacket(SSRC ssrc, unsigned int discreteSeqNoCount); /** * Add a packet to the list of missing packets. @@ -668,71 +320,22 @@ public: * @param missingPacket The seq no of the missing packet. This will be added to the queue. * @return true if the packet has grown, false otherwise. */ - bool addMissingPacket(unsigned int *fciCount, uint16_t *fciPID, uint16_t missingPacket) { - if (*fciCount == 0 || missingPacket < *fciPID || missingPacket > (*fciPID + 16)) { - parts[*fciCount].setPID(missingPacket); - parts[*fciCount].setBLP(0); - *fciPID = missingPacket; - (*fciCount)++; - return true; - } else { - // TODO SPEED! - uint16_t blp = parts[(*fciCount) - 1].getBLP(); - uint16_t newBit = uint16_t(1u << (missingPacket - (1 + *fciPID))); - parts[(*fciCount) - 1].setBLP(blp | newBit); - return false; - } - } - - [[nodiscard]] static unsigned int getSize(unsigned int discreteSeqNoCount) { - return offsetof(RTCP_NACK, parts) + sizeof(RTCP_NACK_PART) * discreteSeqNoCount; - } - - [[nodiscard]] unsigned int getSeqNoCount() { return header.header.length() - 2; } + bool addMissingPacket(unsigned int *fciCount, uint16_t *fciPID, uint16_t missingPacket); }; -class RTP_RTX { -private: +struct RTC_CPP_EXPORT RTP_RTX { RTP header; -public: - size_t copyTo(RTP *dest, size_t totalSize, uint8_t originalPayloadType) { - memmove((char *)dest, (char *)this, header.getSize()); - dest->setSeqNumber(getOriginalSeqNo()); - dest->setPayloadType(originalPayloadType); - memmove(dest->getBody(), getBody(), getBodySize(totalSize)); - return totalSize; - } + [[nodiscard]] const char *getBody() const; + [[nodiscard]] char *getBody(); + [[nodiscard]] size_t getBodySize(size_t totalSize) const; + [[nodiscard]] size_t getSize() const; + [[nodiscard]] uint16_t getOriginalSeqNo() const; - [[nodiscard]] uint16_t getOriginalSeqNo() const { - return ntohs(*(uint16_t *)(header.getBody())); - } + // Returns the new size of the packet + size_t normalizePacket(size_t totalSize, SSRC originalSSRC, uint8_t originalPayloadType); - [[nodiscard]] char *getBody() { return header.getBody() + sizeof(uint16_t); } - - [[nodiscard]] const char *getBody() const { return header.getBody() + sizeof(uint16_t); } - - [[nodiscard]] size_t getBodySize(size_t totalSize) { - return totalSize - (getBody() - reinterpret_cast(this)); - } - - [[nodiscard]] size_t getSize() const{ - return header.getSize() + sizeof(uint16_t); - } - - [[nodiscard]] RTP &getHeader() { return header; } - - /* - * Returns the new size of the packet - */ - size_t normalizePacket(size_t totalSize, SSRC originalSSRC, uint8_t originalPayloadType) { - header.setSeqNumber(getOriginalSeqNo()); - header.setSsrc(originalSSRC); - header.setPayloadType(originalPayloadType); - // TODO, the -12 is the size of the header (which is variable!) - memmove(header.getBody(), getBody(), totalSize - getSize()); - return totalSize - 2; - } + size_t copyTo(RTP *dest, size_t totalSize, uint8_t originalPayloadType); }; #pragma pack(pop) diff --git a/src/capi.cpp b/src/capi.cpp index 9ccafb3..518d599 100644 --- a/src/capi.cpp +++ b/src/capi.cpp @@ -17,10 +17,9 @@ */ #include "rtc.h" - #include "rtc.hpp" -#include "plog/Formatters/FuncMessageFormatter.h" +#include "impl/internals.hpp" #include #include @@ -29,11 +28,6 @@ #include #include -#ifdef _WIN32 -#include -#include -#endif - using namespace rtc; using std::chrono::milliseconds; @@ -287,58 +281,16 @@ int copyAndReturn(binary b, char *buffer, int size) { return int(b.size()); } -class plogAppender : public plog::IAppender { -public: - plogAppender(rtcLogCallbackFunc cb = nullptr) { setCallback(cb); } - - plogAppender(plogAppender &&appender) : callback(nullptr) { - std::lock_guard lock(appender.callbackMutex); - std::swap(appender.callback, callback); - } - - void setCallback(rtcLogCallbackFunc cb) { - std::lock_guard lock(callbackMutex); - callback = cb; - } - - void write(const plog::Record &record) override { - plog::Severity severity = record.getSeverity(); - auto formatted = plog::FuncMessageFormatter::format(record); - formatted.pop_back(); // remove newline -#ifdef _WIN32 - using convert_type = std::codecvt_utf8; - std::wstring_convert converter; - std::string str = converter.to_bytes(formatted); -#else - std::string str = formatted; -#endif - std::lock_guard lock(callbackMutex); - if (callback) - callback(static_cast(record.getSeverity()), str.c_str()); - else - std::cout << plog::severityToString(severity) << " " << str << std::endl; - } - -private: - rtcLogCallbackFunc callback; - std::mutex callbackMutex; -}; - } // namespace void rtcInitLogger(rtcLogLevel level, rtcLogCallbackFunc cb) { - static optional appender; - const auto severity = static_cast(level); - std::lock_guard lock(mutex); - if (appender) { - appender->setCallback(cb); - InitLogger(severity, nullptr); // change the severity - } else if (cb) { - appender.emplace(plogAppender(cb)); - InitLogger(severity, &appender.value()); - } else { - InitLogger(severity, nullptr); // log to stdout - } + LogCallback callback = nullptr; + if (cb) + callback = [cb](LogLevel level, string message) { + cb(static_cast(level), message.c_str()); + }; + + InitLogger(static_cast(level), callback); } void rtcSetUserPointer(int i, void *ptr) { setUserPointer(i, ptr); } @@ -590,7 +542,7 @@ int rtcChainRtcpSrReporter(int tr) { }); } -int rtcChainRtcpNackResponder(int tr, unsigned maxStoredPacketsCount) { +int rtcChainRtcpNackResponder(int tr, unsigned int maxStoredPacketsCount) { return wrap([tr, maxStoredPacketsCount] { auto responder = std::make_shared(maxStoredPacketsCount); auto chainableHandler = getMediaChainableHandler(tr); diff --git a/src/description.cpp b/src/description.cpp index 874ce06..52f87d4 100644 --- a/src/description.cpp +++ b/src/description.cpp @@ -19,6 +19,8 @@ #include "description.hpp" +#include "impl/internals.hpp" + #include #include #include diff --git a/src/global.cpp b/src/global.cpp index feff8a6..fd313b5 100644 --- a/src/global.cpp +++ b/src/global.cpp @@ -16,16 +16,80 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "plog/Appenders/ColorConsoleAppender.h" +#include "plog/Formatters/FuncMessageFormatter.h" +#include "plog/Formatters/TxtFormatter.h" +#include "plog/Init.h" +#include "plog/Log.h" +#include "plog/Logger.h" +// #include "global.hpp" #include "impl/init.hpp" +#include + +#ifdef _WIN32 +#include +#include +#endif + namespace rtc { +struct LogAppender : public plog::IAppender { + synchronized_callback callback; + + void write(const plog::Record &record) override { + const auto severity = record.getSeverity(); + auto formatted = plog::FuncMessageFormatter::format(record); + formatted.pop_back(); // remove newline + +#ifdef _WIN32 + using convert_type = std::codecvt_utf8; + std::wstring_convert converter; + std::string str = converter.to_bytes(formatted); +#else + std::string str = formatted; +#endif + + if (!callback(static_cast(severity), str)) + std::cout << plog::severityToString(severity) << " " << str << std::endl; + } +}; + +void InitLogger(LogLevel level, LogCallback callback) { + static unique_ptr appender; + const auto severity = static_cast(level); + if (appender) { + appender->callback = std::move(callback); + InitLogger(severity, nullptr); // change the severity + } else if (callback) { + appender = std::make_unique(); + appender->callback = std::move(callback); + InitLogger(severity, appender.get()); + } else { + InitLogger(severity, nullptr); // log to cout + } +} + +void InitLogger(plog::Severity severity, plog::IAppender *appender) { + static plog::ColorConsoleAppender consoleAppender; + static plog::Logger<0> *logger = nullptr; + static std::mutex mutex; + std::lock_guard lock(mutex); + if (!logger) { + logger = &plog::init(severity, appender ? appender : &consoleAppender); + PLOG_DEBUG << "Logger initialized"; + } else { + logger->setMaxSeverity(severity); + if (appender) + logger->addAppender(appender); + } +} + void Preload() { Init::Preload(); } void Cleanup() { Init::Cleanup(); } void SetSctpSettings(SctpSettings s) { Init::SetSctpSettings(std::move(s)); } } // namespace rtc - diff --git a/src/h264rtppacketizer.cpp b/src/h264rtppacketizer.cpp index 4ee5143..ee7f0c2 100644 --- a/src/h264rtppacketizer.cpp +++ b/src/h264rtppacketizer.cpp @@ -20,6 +20,16 @@ #include "h264rtppacketizer.hpp" +#include "impl/internals.hpp" + +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + namespace rtc { typedef enum { diff --git a/src/impl/internals.hpp b/src/impl/internals.hpp index 95bfc11..dab9a78 100644 --- a/src/impl/internals.hpp +++ b/src/impl/internals.hpp @@ -21,6 +21,22 @@ #include "common.hpp" +// Disable warnings before including plog +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wall" +#elif defined(_MSC_VER) +#pragma warning(push, 0) +#endif + +#include "plog/Log.h" + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#elif defined(_MSC_VER) +#pragma warning(pop) +#endif + namespace rtc { const size_t MAX_NUMERICNODE_LEN = 48; // Max IPv6 string representation length diff --git a/src/impl/peerconnection.cpp b/src/impl/peerconnection.cpp index ab5b12b..0fbc25e 100644 --- a/src/impl/peerconnection.cpp +++ b/src/impl/peerconnection.cpp @@ -440,8 +440,8 @@ void PeerConnection::forwardMedia(message_ptr message) { offset += header->lengthInBytes(); if (header->payloadType() == 205 || header->payloadType() == 206) { auto rtcpfb = reinterpret_cast(header); - ssrcs.insert(rtcpfb->getPacketSenderSSRC()); - ssrcs.insert(rtcpfb->getMediaSourceSSRC()); + ssrcs.insert(rtcpfb->packetSenderSSRC()); + ssrcs.insert(rtcpfb->mediaSourceSSRC()); } else if (header->payloadType() == 200 || header->payloadType() == 201) { auto rtcpsr = reinterpret_cast(header); diff --git a/src/impl/threadpool.hpp b/src/impl/threadpool.hpp index 26fb328..4626058 100644 --- a/src/impl/threadpool.hpp +++ b/src/impl/threadpool.hpp @@ -21,6 +21,7 @@ #include "common.hpp" #include "init.hpp" +#include "internals.hpp" #include #include diff --git a/src/impl/tls.cpp b/src/impl/tls.cpp index d91383f..e4b3206 100644 --- a/src/impl/tls.cpp +++ b/src/impl/tls.cpp @@ -18,6 +18,8 @@ #include "tls.hpp" +#include "internals.hpp" + #if USE_GNUTLS namespace rtc::gnutls { diff --git a/src/impl/transport.hpp b/src/impl/transport.hpp index a57b9a8..0e81cc2 100644 --- a/src/impl/transport.hpp +++ b/src/impl/transport.hpp @@ -20,6 +20,7 @@ #define RTC_IMPL_TRANSPORT_H #include "common.hpp" +#include "internals.hpp" #include "message.hpp" #include diff --git a/src/log.cpp b/src/log.cpp deleted file mode 100644 index ba783e6..0000000 --- a/src/log.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) 2019-2020 Paul-Louis Ageneau - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "log.hpp" - -#include "plog/Appenders/ColorConsoleAppender.h" -#include "plog/Formatters/TxtFormatter.h" -#include "plog/Init.h" -#include "plog/Log.h" -#include "plog/Logger.h" - -#include - -namespace rtc { - -void InitLogger(LogLevel level) { InitLogger(static_cast(level)); } - -void InitLogger(plog::Severity severity, plog::IAppender *appender) { - static plog::ColorConsoleAppender consoleAppender; - static plog::Logger<0> *logger = nullptr; - static std::mutex mutex; - std::lock_guard lock(mutex); - if (!logger) { - logger = &plog::init(severity, appender ? appender : &consoleAppender); - PLOG_DEBUG << "Logger initialized"; - } else { - logger->setMaxSeverity(severity); - if (appender) - logger->addAppender(appender); - } -} -} // namespace rtc diff --git a/src/mediachainablehandler.cpp b/src/mediachainablehandler.cpp index 844a9c1..d75858f 100644 --- a/src/mediachainablehandler.cpp +++ b/src/mediachainablehandler.cpp @@ -20,6 +20,10 @@ #include "mediachainablehandler.hpp" +#include "impl/internals.hpp" + +#include + namespace rtc { MediaChainableHandler::MediaChainableHandler(shared_ptr root): MediaHandler(), root(root), leaf(root) { } diff --git a/src/mediahandlerelement.cpp b/src/mediahandlerelement.cpp index 7c28c49..7cb176c 100644 --- a/src/mediahandlerelement.cpp +++ b/src/mediahandlerelement.cpp @@ -20,6 +20,10 @@ #include "mediahandlerelement.hpp" +#include "impl/internals.hpp" + +#include + namespace rtc { ChainedMessagesProduct make_chained_messages_product() { diff --git a/src/opusrtppacketizer.cpp b/src/opusrtppacketizer.cpp index afb249f..004186c 100644 --- a/src/opusrtppacketizer.cpp +++ b/src/opusrtppacketizer.cpp @@ -20,6 +20,8 @@ #include "opusrtppacketizer.hpp" +#include + namespace rtc { OpusRtpPacketizer::OpusRtpPacketizer(shared_ptr rtpConfig) diff --git a/src/peerconnection.cpp b/src/peerconnection.cpp index 3405498..bd84853 100644 --- a/src/peerconnection.cpp +++ b/src/peerconnection.cpp @@ -24,6 +24,7 @@ #include "impl/certificate.hpp" #include "impl/dtlstransport.hpp" #include "impl/icetransport.hpp" +#include "impl/internals.hpp" #include "impl/peerconnection.hpp" #include "impl/processor.hpp" #include "impl/sctptransport.hpp" diff --git a/src/rtcpnackresponder.cpp b/src/rtcpnackresponder.cpp index 66638f8..de08ac6 100644 --- a/src/rtcpnackresponder.cpp +++ b/src/rtcpnackresponder.cpp @@ -20,6 +20,10 @@ #include "rtcpnackresponder.hpp" +#include "impl/internals.hpp" + +#include + namespace rtc { RtcpNackResponder::Storage::Element::Element(binary_ptr packet, uint16_t sequenceNumber, shared_ptr next) diff --git a/src/rtcpreceivingsession.cpp b/src/rtcpreceivingsession.cpp index c187c67..3ae0d98 100644 --- a/src/rtcpreceivingsession.cpp +++ b/src/rtcpreceivingsession.cpp @@ -97,7 +97,7 @@ void RtcpReceivingSession::requestBitrate(unsigned int newBitrate) { } void RtcpReceivingSession::pushREMB(unsigned int bitrate) { - message_ptr msg = make_message(RTCP_REMB::sizeWithSSRCs(1), Message::Type::Control); + message_ptr msg = make_message(RTCP_REMB::SizeWithSSRCs(1), Message::Type::Control); auto remb = reinterpret_cast(msg->data()); remb->preparePacket(mSsrc, 1, bitrate); remb->setSsrc(0, mSsrc); @@ -106,7 +106,7 @@ void RtcpReceivingSession::pushREMB(unsigned int bitrate) { } void RtcpReceivingSession::pushRR(unsigned int lastSR_delay) { - auto msg = make_message(RTCP_RR::sizeWithReportBlocks(1), Message::Type::Control); + auto msg = make_message(RTCP_RR::SizeWithReportBlocks(1), Message::Type::Control); auto rr = reinterpret_cast(msg->data()); rr->preparePacket(mSsrc, 1); rr->getReportBlock(0)->preparePacket(mSsrc, 0, 0, uint16_t(mGreatestSeqNo), 0, 0, mSyncNTPTS, @@ -132,7 +132,7 @@ bool RtcpReceivingSession::requestKeyframe() { } void RtcpReceivingSession::pushPLI() { - auto msg = make_message(RTCP_PLI::size(), Message::Type::Control); + auto msg = make_message(RTCP_PLI::Size(), Message::Type::Control); auto *pli = reinterpret_cast(msg->data()); pli->preparePacket(mSsrc); send(msg); diff --git a/src/rtcpsrreporter.cpp b/src/rtcpsrreporter.cpp index 75f7f1f..a0ee771 100644 --- a/src/rtcpsrreporter.cpp +++ b/src/rtcpsrreporter.cpp @@ -20,6 +20,9 @@ #include "rtcpsrreporter.hpp" +#include +#include + namespace rtc { ChainedOutgoingProduct RtcpSrReporter::processOutgoingBinaryMessage(ChainedMessagesProduct messages, message_ptr control) { @@ -61,8 +64,8 @@ uint64_t RtcpSrReporter::secondsToNTP(double seconds) { void RtcpSrReporter::setNeedsToReport() { needsToReport = true; } message_ptr RtcpSrReporter::getSenderReport(uint32_t timestamp) { - auto srSize = RTCP_SR::size(0); - auto msg = make_message(srSize + RTCP_SDES::size({{uint8_t(rtpConfig->cname.size())}}), + auto srSize = RTCP_SR::Size(0); + auto msg = make_message(srSize + RTCP_SDES::Size({{uint8_t(rtpConfig->cname.size())}}), Message::Type::Control); auto sr = reinterpret_cast(msg->data()); auto timestamp_s = rtpConfig->timestampToSeconds(timestamp); diff --git a/src/rtp.cpp b/src/rtp.cpp new file mode 100644 index 0000000..5039a58 --- /dev/null +++ b/src/rtp.cpp @@ -0,0 +1,600 @@ +/** + * Copyright (c) 2020 Staz Modrzynski + * Copyright (c) 2020 Paul-Louis Ageneau + * Copyright (c) 2020 Filip Klembara (in2core) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "rtp.hpp" + +#include "impl/internals.hpp" + +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +#ifndef htonll +#define htonll(x) \ + ((uint64_t)(((uint64_t)htonl((uint32_t)(x))) << 32) | (uint64_t)htonl((uint32_t)((x) >> 32))) +#endif +#ifndef ntohll +#define ntohll(x) htonll(x) +#endif + +namespace rtc { + +uint8_t RTP::version() const { return _first >> 6; } +bool RTP::padding() const { return (_first >> 5) & 0x01; } +bool RTP::extension() const { return (_first >> 4) & 0x01; } +uint8_t RTP::csrcCount() const { return _first & 0x0F; } +uint8_t RTP::marker() const { return _payloadType & 0b10000000; } +uint8_t RTP::payloadType() const { return _payloadType & 0b01111111; } +uint16_t RTP::seqNumber() const { return ntohs(_seqNumber); } +uint32_t RTP::timestamp() const { return ntohl(_timestamp); } +uint32_t RTP::ssrc() const { return ntohl(_ssrc); } + +size_t RTP::getSize() const { + return reinterpret_cast(&_csrc) - reinterpret_cast(this) + + sizeof(SSRC) * csrcCount(); +} + +const char *RTP::getBody() const { + return reinterpret_cast(&_csrc) + sizeof(SSRC) * csrcCount(); +} + +char *RTP::getBody() { return reinterpret_cast(&_csrc) + sizeof(SSRC) * csrcCount(); } + +void RTP::preparePacket() { _first |= (1 << 7); } + +void RTP::setSeqNumber(uint16_t newSeqNo) { _seqNumber = htons(newSeqNo); } + +void RTP::setPayloadType(uint8_t newPayloadType) { + _payloadType = (_payloadType & 0b10000000u) | (0b01111111u & newPayloadType); +} + +void RTP::setSsrc(uint32_t in_ssrc) { _ssrc = htonl(in_ssrc); } + +void RTP::setMarker(bool marker) { _payloadType = (_payloadType & 0x7F) | (marker << 7); }; + +void RTP::setTimestamp(uint32_t i) { _timestamp = htonl(i); } + +void RTP::log() const { + PLOG_VERBOSE << "RTP V: " << (int)version() << " P: " << (padding() ? "P" : " ") + << " X: " << (extension() ? "X" : " ") << " CC: " << (int)csrcCount() + << " M: " << (marker() ? "M" : " ") << " PT: " << (int)payloadType() + << " SEQNO: " << seqNumber() << " TS: " << timestamp(); +} + +SSRC RTCP_ReportBlock::getSSRC() const { return ntohl(_ssrc); } + +void RTCP_ReportBlock::preparePacket(SSRC in_ssrc, [[maybe_unused]] unsigned int packetsLost, + [[maybe_unused]] unsigned int totalPackets, + uint16_t highestSeqNo, uint16_t seqNoCycles, uint32_t jitter, + uint64_t lastSR_NTP, uint64_t lastSR_DELAY) { + setSeqNo(highestSeqNo, seqNoCycles); + setJitter(jitter); + setSSRC(in_ssrc); + + // Middle 32 bits of NTP Timestamp + // _lastReport = lastSR_NTP >> 16u; + setNTPOfSR(uint64_t(lastSR_NTP)); + setDelaySinceSR(uint32_t(lastSR_DELAY)); + + // The delay, expressed in units of 1/65536 seconds + // _delaySinceLastReport = lastSR_DELAY; +} + +void RTCP_ReportBlock::setSSRC(SSRC in_ssrc) { _ssrc = htonl(in_ssrc); } + +void RTCP_ReportBlock::setPacketsLost([[maybe_unused]] unsigned int packetsLost, + [[maybe_unused]] unsigned int totalPackets) { + // TODO Implement loss percentages. + _fractionLostAndPacketsLost = 0; +} + +unsigned int RTCP_ReportBlock::getLossPercentage() const { + // TODO Implement loss percentages. + return 0; +} + +unsigned int RTCP_ReportBlock::getPacketLostCount() const { + // TODO Implement total packets lost. + return 0; +} + +uint16_t RTCP_ReportBlock::seqNoCycles() const { return ntohs(_seqNoCycles); } + +uint16_t RTCP_ReportBlock::highestSeqNo() const { return ntohs(_highestSeqNo); } + +uint32_t RTCP_ReportBlock::jitter() const { return ntohl(_jitter); } + +uint32_t RTCP_ReportBlock::delaySinceSR() const { return ntohl(_delaySinceLastReport); } + +void RTCP_ReportBlock::setSeqNo(uint16_t highestSeqNo, uint16_t seqNoCycles) { + _highestSeqNo = htons(highestSeqNo); + _seqNoCycles = htons(seqNoCycles); +} + +void RTCP_ReportBlock::setJitter(uint32_t jitter) { _jitter = htonl(jitter); } + +void RTCP_ReportBlock::setNTPOfSR(uint64_t ntp) { _lastReport = htonll(ntp >> 16u); } + +uint32_t RTCP_ReportBlock::getNTPOfSR() const { return ntohl(_lastReport) << 16u; } + +void RTCP_ReportBlock::setDelaySinceSR(uint32_t sr) { + // The delay, expressed in units of 1/65536 seconds + _delaySinceLastReport = htonl(sr); +} + +void RTCP_ReportBlock::log() const { + PLOG_VERBOSE << "RTCP report block: " + << "ssrc=" + << ntohl(_ssrc) + // TODO: Implement these reports + // << ", fractionLost=" << fractionLost + // << ", packetsLost=" << packetsLost + << ", highestSeqNo=" << highestSeqNo() << ", seqNoCycles=" << seqNoCycles() + << ", jitter=" << jitter() << ", lastSR=" << getNTPOfSR() + << ", lastSRDelay=" << delaySinceSR(); +} + +uint8_t RTCP_HEADER::version() const { return _first >> 6; } + +bool RTCP_HEADER::padding() const { return (_first >> 5) & 0x01; } + +uint8_t RTCP_HEADER::reportCount() const { return _first & 0x0F; } + +uint8_t RTCP_HEADER::payloadType() const { return _payloadType; } + +uint16_t RTCP_HEADER::length() const { return ntohs(_length); } + +size_t RTCP_HEADER::lengthInBytes() const { return (1 + length()) * 4; } + +void RTCP_HEADER::setPayloadType(uint8_t type) { _payloadType = type; } + +void RTCP_HEADER::setReportCount(uint8_t count) { + _first = (_first & 0b11100000u) | (count & 0b00011111u); +} + +void RTCP_HEADER::setLength(uint16_t length) { _length = htons(length); } + +void RTCP_HEADER::prepareHeader(uint8_t payloadType, uint8_t reportCount, uint16_t length) { + _first = 0b10000000; // version 2, no padding + setReportCount(reportCount); + setPayloadType(payloadType); + setLength(length); +} + +void RTCP_HEADER::log() const { + PLOG_VERBOSE << "RTCP header: " + << "version=" << unsigned(version()) << ", padding=" << padding() + << ", reportCount=" << unsigned(reportCount()) + << ", payloadType=" << unsigned(payloadType()) << ", length=" << length(); +} + +SSRC RTCP_FB_HEADER::packetSenderSSRC() const { return ntohl(_packetSender); } + +SSRC RTCP_FB_HEADER::mediaSourceSSRC() const { return ntohl(_mediaSource); } + +void RTCP_FB_HEADER::setPacketSenderSSRC(SSRC ssrc) { _packetSender = htonl(ssrc); } + +void RTCP_FB_HEADER::setMediaSourceSSRC(SSRC ssrc) { _mediaSource = htonl(ssrc); } + +void RTCP_FB_HEADER::log() const { + header.log(); + PLOG_VERBOSE << "FB: " + << " packet sender: " << packetSenderSSRC() + << " media source: " << mediaSourceSSRC(); +} + +unsigned int RTCP_SR::Size(unsigned int reportCount) { + return sizeof(RTCP_HEADER) + 24 + reportCount * sizeof(RTCP_ReportBlock); +} + +void RTCP_SR::preparePacket(SSRC senderSSRC, uint8_t reportCount) { + unsigned int length = ((sizeof(header) + 24 + reportCount * sizeof(RTCP_ReportBlock)) / 4) - 1; + header.prepareHeader(200, reportCount, uint16_t(length)); + this->_senderSSRC = htonl(senderSSRC); +} + +const RTCP_ReportBlock *RTCP_SR::getReportBlock(int num) const { return &_reportBlocks + num; } + +RTCP_ReportBlock *RTCP_SR::getReportBlock(int num) { return &_reportBlocks + num; } + +size_t RTCP_SR::getSize() const { + // "length" in packet is one less than the number of 32 bit words in the packet. + return sizeof(uint32_t) * (1 + size_t(header.length())); +} + +uint64_t RTCP_SR::ntpTimestamp() const { return ntohll(_ntpTimestamp); } +uint32_t RTCP_SR::rtpTimestamp() const { return ntohl(_rtpTimestamp); } +uint32_t RTCP_SR::packetCount() const { return ntohl(_packetCount); } +uint32_t RTCP_SR::octetCount() const { return ntohl(_octetCount); } +uint32_t RTCP_SR::senderSSRC() const { return ntohl(_senderSSRC); } + +void RTCP_SR::setNtpTimestamp(uint64_t ts) { _ntpTimestamp = htonll(ts); } +void RTCP_SR::setRtpTimestamp(uint32_t ts) { _rtpTimestamp = htonl(ts); } +void RTCP_SR::setOctetCount(uint32_t ts) { _octetCount = htonl(ts); } +void RTCP_SR::setPacketCount(uint32_t ts) { _packetCount = htonl(ts); } + +void RTCP_SR::log() const { + header.log(); + PLOG_VERBOSE << "RTCP SR: " + << " SSRC=" << senderSSRC() << ", NTP_TS=" << ntpTimestamp() + << ", RTP_TS=" << rtpTimestamp() << ", packetCount=" << packetCount() + << ", octetCount=" << octetCount(); + + for (unsigned i = 0; i < unsigned(header.reportCount()); i++) { + getReportBlock(i)->log(); + } +} + +unsigned int RTCP_SDES_ITEM::Size(uint8_t textLength) { return textLength + 2; } + +std::string RTCP_SDES_ITEM::text() const { return std::string(_text, _length); } + +void RTCP_SDES_ITEM::setText(std::string text) { + if (text.size() > 0xFF) + throw std::invalid_argument("text is too long"); + + _length = uint8_t(text.size()); + memcpy(_text, text.data(), text.size()); +} + +uint8_t RTCP_SDES_ITEM::length() const { return _length; } + +unsigned int RTCP_SDES_CHUNK::Size(const std::vector textLengths) { + unsigned int itemsSize = 0; + for (auto length : textLengths) { + itemsSize += RTCP_SDES_ITEM::Size(length); + } + auto nullTerminatedItemsSize = itemsSize + 1; + auto words = uint8_t(std::ceil(double(nullTerminatedItemsSize) / 4)) + 1; + return words * 4; +} + +SSRC RTCP_SDES_CHUNK::ssrc() const { return ntohl(_ssrc); } + +void RTCP_SDES_CHUNK::setSSRC(SSRC ssrc) { _ssrc = htonl(ssrc); } + +const RTCP_SDES_ITEM *RTCP_SDES_CHUNK::getItem(int num) const { + auto base = &_items; + while (num-- > 0) { + auto itemSize = RTCP_SDES_ITEM::Size(base->length()); + base = reinterpret_cast(reinterpret_cast(base) + + itemSize); + } + return reinterpret_cast(base); +} + +RTCP_SDES_ITEM *RTCP_SDES_CHUNK::getItem(int num) { + auto base = &_items; + while (num-- > 0) { + auto itemSize = RTCP_SDES_ITEM::Size(base->length()); + base = reinterpret_cast(reinterpret_cast(base) + itemSize); + } + return reinterpret_cast(base); +} + +unsigned int RTCP_SDES_CHUNK::getSize() const { + std::vector textLengths{}; + unsigned int i = 0; + auto item = getItem(i); + while (item->type != 0) { + textLengths.push_back(item->length()); + item = getItem(++i); + } + return Size(textLengths); +} + +long RTCP_SDES_CHUNK::safelyCountChunkSize(size_t maxChunkSize) const { + if (maxChunkSize < RTCP_SDES_CHUNK::Size({})) { + // chunk is truncated + return -1; + } + + size_t size = sizeof(SSRC); + unsigned int i = 0; + // We can always access first 4 bytes of first item (in case of no items there will be 4 + // null bytes) + auto item = getItem(i); + std::vector textsLength{}; + while (item->type != 0) { + if (size + RTCP_SDES_ITEM::Size(0) > maxChunkSize) { + // item is too short + return -1; + } + auto itemLength = item->length(); + if (size + RTCP_SDES_ITEM::Size(itemLength) >= maxChunkSize) { + // item is too large (it can't be equal to chunk size because after item there + // must be 1-4 null bytes as padding) + return -1; + } + textsLength.push_back(itemLength); + // safely to access next item + item = getItem(++i); + } + auto realSize = RTCP_SDES_CHUNK::Size(textsLength); + if (realSize > maxChunkSize) { + // Chunk is too large + return -1; + } + return realSize; +} + +unsigned int RTCP_SDES::Size(const std::vector> lengths) { + unsigned int chunks_size = 0; + for (auto length : lengths) + chunks_size += RTCP_SDES_CHUNK::Size(length); + + return 4 + chunks_size; +} + +bool RTCP_SDES::isValid() const { + auto chunksSize = header.lengthInBytes() - sizeof(header); + if (chunksSize == 0) { + return true; + } + // there is at least one chunk + unsigned int i = 0; + unsigned int size = 0; + while (size < chunksSize) { + if (chunksSize < size + RTCP_SDES_CHUNK::Size({})) { + // chunk is truncated + return false; + } + auto chunk = getChunk(i++); + auto chunkSize = chunk->safelyCountChunkSize(chunksSize - size); + if (chunkSize < 0) { + // chunk is invalid + return false; + } + size += chunkSize; + } + return size == chunksSize; +} + +unsigned int RTCP_SDES::chunksCount() const { + if (!isValid()) { + return 0; + } + uint16_t chunksSize = 4 * (header.length() + 1) - sizeof(header); + unsigned int size = 0; + unsigned int i = 0; + while (size < chunksSize) { + size += getChunk(i++)->getSize(); + } + return i; +} + +const RTCP_SDES_CHUNK *RTCP_SDES::getChunk(int num) const { + auto base = &_chunks; + while (num-- > 0) { + auto chunkSize = base->getSize(); + base = reinterpret_cast(reinterpret_cast(base) + + chunkSize); + } + return reinterpret_cast(base); +} + +RTCP_SDES_CHUNK *RTCP_SDES::getChunk(int num) { + auto base = &_chunks; + while (num-- > 0) { + auto chunkSize = base->getSize(); + base = reinterpret_cast(reinterpret_cast(base) + chunkSize); + } + return reinterpret_cast(base); +} + +void RTCP_SDES::preparePacket(uint8_t chunkCount) { + unsigned int chunkSize = 0; + for (uint8_t i = 0; i < chunkCount; i++) { + auto chunk = getChunk(i); + chunkSize += chunk->getSize(); + } + uint16_t length = uint16_t((sizeof(header) + chunkSize) / 4 - 1); + header.prepareHeader(202, chunkCount, length); +} + +const RTCP_ReportBlock *RTCP_RR::getReportBlock(int num) const { return &_reportBlocks + num; } + +RTCP_ReportBlock *RTCP_RR::getReportBlock(int num) { return &_reportBlocks + num; } + +size_t RTCP_RR::SizeWithReportBlocks(uint8_t reportCount) { + return sizeof(header) + 4 + size_t(reportCount) * sizeof(RTCP_ReportBlock); +} + +SSRC RTCP_RR::senderSSRC() const { return ntohl(_senderSSRC); } + +bool RTCP_RR::isSenderReport() { return header.payloadType() == 200; } + +bool RTCP_RR::isReceiverReport() { return header.payloadType() == 201; } + +size_t RTCP_RR::getSize() const { + // "length" in packet is one less than the number of 32 bit words in the packet. + return sizeof(uint32_t) * (1 + size_t(header.length())); +} + +void RTCP_RR::preparePacket(SSRC senderSSRC, uint8_t reportCount) { + // "length" in packet is one less than the number of 32 bit words in the packet. + size_t length = (SizeWithReportBlocks(reportCount) / 4) - 1; + header.prepareHeader(201, reportCount, uint16_t(length)); + this->_senderSSRC = htonl(senderSSRC); +} + +void RTCP_RR::setSenderSSRC(SSRC ssrc) { this->_senderSSRC = htonl(ssrc); } + +void RTCP_RR::log() const { + header.log(); + PLOG_VERBOSE << "RTCP RR: " + << " SSRC=" << ntohl(_senderSSRC); + + for (unsigned i = 0; i < unsigned(header.reportCount()); i++) { + getReportBlock(i)->log(); + } +} + +size_t RTCP_REMB::SizeWithSSRCs(int count) { + return sizeof(RTCP_REMB) + (count - 1) * sizeof(SSRC); +} + +unsigned int RTCP_REMB::getSize() const { + // "length" in packet is one less than the number of 32 bit words in the packet. + return sizeof(uint32_t) * (1 + header.header.length()); +} + +void RTCP_REMB::preparePacket(SSRC senderSSRC, unsigned int numSSRC, unsigned int in_bitrate) { + + // Report Count becomes the format here. + header.header.prepareHeader(206, 15, 0); + + // Always zero. + header.setMediaSourceSSRC(0); + + header.setPacketSenderSSRC(senderSSRC); + + _id[0] = 'R'; + _id[1] = 'E'; + _id[2] = 'M'; + _id[3] = 'B'; + + setBitrate(numSSRC, in_bitrate); +} + +void RTCP_REMB::setBitrate(unsigned int numSSRC, unsigned int in_bitrate) { + unsigned int exp = 0; + while (in_bitrate > pow(2, 18) - 1) { + exp++; + in_bitrate /= 2; + } + + // "length" in packet is one less than the number of 32 bit words in the packet. + header.header.setLength( + uint16_t((offsetof(RTCP_REMB, _ssrc) / sizeof(uint32_t)) - 1 + numSSRC)); + + _bitrate = htonl((numSSRC << (32u - 8u)) | (exp << (32u - 8u - 6u)) | in_bitrate); +} + +void RTCP_REMB::setSsrc(int iterator, SSRC newSssrc) { _ssrc[iterator] = htonl(newSssrc); } + +unsigned int RTCP_PLI::Size() { return sizeof(RTCP_FB_HEADER); } + +void RTCP_PLI::preparePacket(SSRC messageSSRC) { + header.header.prepareHeader(206, 1, 2); + header.setPacketSenderSSRC(messageSSRC); + header.setMediaSourceSSRC(messageSSRC); +} + +void RTCP_PLI::log() const { header.log(); } + +unsigned int RTCP_FIR::Size() { return sizeof(RTCP_FB_HEADER) + sizeof(RTCP_FIR_PART); } + +void RTCP_FIR::preparePacket(SSRC messageSSRC, uint8_t seqNo) { + header.header.prepareHeader(206, 4, 2 + 2 * 1); + header.setPacketSenderSSRC(messageSSRC); + header.setMediaSourceSSRC(messageSSRC); + parts[0].ssrc = htonl(messageSSRC); + parts[0].seqNo = seqNo; +} + +void RTCP_FIR::log() const { header.log(); } + +uint16_t RTCP_NACK_PART::pid() { return ntohs(_pid); } +uint16_t RTCP_NACK_PART::blp() { return ntohs(_blp); } + +void RTCP_NACK_PART::setPid(uint16_t pid) { _pid = htons(pid); } +void RTCP_NACK_PART::setBlp(uint16_t blp) { _blp = htons(blp); } + +std::vector RTCP_NACK_PART::getSequenceNumbers() { + std::vector result{}; + result.reserve(17); + uint16_t p = pid(); + result.push_back(p); + uint16_t bitmask = blp(); + uint16_t i = p + 1; + while (bitmask > 0) { + if (bitmask & 0x1) { + result.push_back(i); + } + i += 1; + bitmask >>= 1; + } + return result; +} + +unsigned int RTCP_NACK::Size(unsigned int discreteSeqNoCount) { + return offsetof(RTCP_NACK, parts) + sizeof(RTCP_NACK_PART) * discreteSeqNoCount; +} + +unsigned int RTCP_NACK::getSeqNoCount() { return header.header.length() - 2; } + +void RTCP_NACK::preparePacket(SSRC ssrc, unsigned int discreteSeqNoCount) { + header.header.prepareHeader(205, 1, 2 + uint16_t(discreteSeqNoCount)); + header.setMediaSourceSSRC(ssrc); + header.setPacketSenderSSRC(ssrc); +} + +bool RTCP_NACK::addMissingPacket(unsigned int *fciCount, uint16_t *fciPID, uint16_t missingPacket) { + if (*fciCount == 0 || missingPacket < *fciPID || missingPacket > (*fciPID + 16)) { + parts[*fciCount].setPid(missingPacket); + parts[*fciCount].setBlp(0); + *fciPID = missingPacket; + (*fciCount)++; + return true; + } else { + // TODO SPEED! + uint16_t blp = parts[(*fciCount) - 1].blp(); + uint16_t newBit = uint16_t(1u << (missingPacket - (1 + *fciPID))); + parts[(*fciCount) - 1].setBlp(blp | newBit); + return false; + } +} + +uint16_t RTP_RTX::getOriginalSeqNo() const { return ntohs(*(uint16_t *)(header.getBody())); } + +const char *RTP_RTX::getBody() const { return header.getBody() + sizeof(uint16_t); } + +char *RTP_RTX::getBody() { return header.getBody() + sizeof(uint16_t); } + +size_t RTP_RTX::getBodySize(size_t totalSize) const { + return totalSize - (getBody() - reinterpret_cast(this)); +} + +size_t RTP_RTX::getSize() const { return header.getSize() + sizeof(uint16_t); } + +size_t RTP_RTX::normalizePacket(size_t totalSize, SSRC originalSSRC, uint8_t originalPayloadType) { + header.setSeqNumber(getOriginalSeqNo()); + header.setSsrc(originalSSRC); + header.setPayloadType(originalPayloadType); + // TODO, the -12 is the size of the header (which is variable!) + memmove(header.getBody(), getBody(), totalSize - getSize()); + return totalSize - 2; +} + +size_t RTP_RTX::copyTo(RTP *dest, size_t totalSize, uint8_t originalPayloadType) { + memmove((char *)dest, (char *)this, header.getSize()); + dest->setSeqNumber(getOriginalSeqNo()); + dest->setPayloadType(originalPayloadType); + memmove(dest->getBody(), getBody(), getBodySize(totalSize)); + return totalSize; +} + +}; // namespace rtc diff --git a/src/rtppacketizationconfig.cpp b/src/rtppacketizationconfig.cpp index d9ec465..b8cd2b0 100644 --- a/src/rtppacketizationconfig.cpp +++ b/src/rtppacketizationconfig.cpp @@ -20,6 +20,8 @@ #include "rtppacketizationconfig.hpp" +#include + namespace rtc { RtpPacketizationConfig::RtpPacketizationConfig(SSRC ssrc, string cname, uint8_t payloadType, diff --git a/src/rtppacketizer.cpp b/src/rtppacketizer.cpp index da91cae..5a2f167 100644 --- a/src/rtppacketizer.cpp +++ b/src/rtppacketizer.cpp @@ -20,6 +20,8 @@ #include "rtppacketizer.hpp" +#include + namespace rtc { RtpPacketizer::RtpPacketizer(shared_ptr rtpConfig) @@ -37,7 +39,7 @@ binary_ptr RtpPacketizer::packetize(shared_ptr payload, bool setMark) { rtp->setMarker(true); } rtp->preparePacket(); - memcpy(msg->data() + rtpHeaderSize, payload->data(), payload->size()); + std::memcpy(msg->data() + rtpHeaderSize, payload->data(), payload->size()); return msg; }