浏览代码

Reorganized stuff to make plog private

Paul-Louis Ageneau 4 年之前
父节点
当前提交
4ca78db146

+ 5 - 6
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

+ 1 - 1
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);

+ 8 - 1
examples/streamer/h264fileparser.cpp

@@ -17,9 +17,16 @@
  */
 
 #include "h264fileparser.hpp"
-#include <fstream>
 #include "rtc/rtc.hpp"
 
+#include <fstream>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <arpa/inet.h>
+#endif
+
 using namespace std;
 
 H264FileParser::H264FileParser(string directory, uint32_t fps, bool loop): FileParser(directory, ".h264", fps, loop) { }

+ 3 - 2
examples/streamer/helpers.cpp

@@ -19,9 +19,8 @@
 #include "helpers.hpp"
 #include <ctime>
 
-#if _WIN32
+#ifdef _WIN32
 // taken from https://stackoverflow.com/questions/10905892/equivalent-of-gettimeday-for-windows
-
 #include <Windows.h>
 
 struct timezone {
@@ -55,6 +54,8 @@ int gettimeofday(struct timeval *tv, struct timezone *tz)
     }
     return 0;
 }
+#else
+#include <sys/time.h>
 #endif
 
 using namespace std;

+ 3 - 1
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 <windows.h>
 
@@ -35,6 +35,8 @@ void usleep(__int64 usec)
     WaitForSingleObject(timer, INFINITE);
     CloseHandle(timer);
 }
+#else
+#include <unistd.h>
 #endif
 
 void StreamSource::stop() {

+ 0 - 1
include/rtc/common.hpp

@@ -41,7 +41,6 @@
 
 #include "rtc.h" // for C API defines
 
-#include "log.hpp"
 #include "utils.hpp"
 
 #include <cstddef>

+ 17 - 0
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<void(LogLevel level, string message)> 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();
 

+ 3 - 3
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 */

+ 3 - 3
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 */

+ 0 - 56
include/rtc/log.hpp

@@ -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

+ 3 - 3
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

+ 9 - 9
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 <cassert>
+
 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 */

+ 1 - 1
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

+ 0 - 1
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"

+ 185 - 582
include/rtc/rtp.hpp

@@ -21,23 +21,9 @@
 #ifndef RTC_RTP_HPP
 #define RTC_RTP_HPP
 
-#include "log.hpp"
+#include "common.hpp"
 
-#include <cmath>
-
-#ifdef _WIN32
-#include <winsock2.h>
-#else
-#include <arpa/inet.h>
-#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 <vector>
 
 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;
-
-public:
-	SSRC csrc[16];
-
-	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); }
-
-	inline size_t getSize() const {
-		return reinterpret_cast<const char *>(&csrc) - reinterpret_cast<const char *>(this) +
-		       sizeof(SSRC) * csrcCount();
-	}
-
-	[[nodiscard]] char *getBody() {
-		return reinterpret_cast<char *>(&csrc) + sizeof(SSRC) * csrcCount();
-	}
-
-	[[nodiscard]] const char *getBody() const {
-		return reinterpret_cast<const char *>(&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();
-	}
+	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;
+
+	[[nodiscard]] size_t getSize() const;
+	[[nodiscard]] const char *getBody() const;
+	[[nodiscard]] char *getBody();
+
+	void log() const;
+
+	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);
-
-		// Middle 32 bits of NTP Timestamp
-		//		  this->lastReport = lastSR_NTP >> 16u;
-		setNTPOfSR(uint64_t(lastSR_NTP));
-		setDelaySinceSR(uint32_t(lastSR_DELAY));
-
-		// The delay, expressed in units of 1/65536 seconds
-		// this->delaySinceLastReport = lastSR_DELAY;
-	}
-
-	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();
-	}
+	[[nodiscard]] uint16_t seqNoCycles() const;
+	[[nodiscard]] uint16_t highestSeqNo() const;
+	[[nodiscard]] uint32_t jitter() const;
+	[[nodiscard]] uint32_t delaySinceSR() const;
+
+	[[nodiscard]] SSRC getSSRC() const;
+	[[nodiscard]] uint32_t getNTPOfSR() const;
+	[[nodiscard]] unsigned int getLossPercentage() const;
+	[[nodiscard]] unsigned int getPacketLostCount() const;
+
+	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);
+
+	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; }
-
-	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); }
-
-	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();
-	}
+	[[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;
+
+	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);
+
+	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:
+	SSRC _senderSSRC;
 	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]] inline RTCP_ReportBlock *getReportBlock(int num) { return &_reportBlocks + num; }
-	[[nodiscard]] inline const RTCP_ReportBlock *getReportBlock(int num) const {
-		return &_reportBlocks + num;
-	}
-
-	[[nodiscard]] static unsigned int size(unsigned int reportCount) {
-		return sizeof(RTCP_HEADER) + 24 + reportCount * sizeof(RTCP_ReportBlock);
-	}
-
-	[[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()));
-	}
-
-	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();
-		}
-	}
+	[[nodiscard]] static unsigned int Size(unsigned int reportCount);
+
+	[[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]] 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;
+
+	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);
+
+	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); }
-
-	/// 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<RTCP_SDES_ITEM *>(reinterpret_cast<uint8_t *>(base) + itemSize);
-		}
-		return reinterpret_cast<RTCP_SDES_ITEM *>(base);
-	}
-
-	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<uint8_t> 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;
-		}
-	}
-
-	[[nodiscard]] static unsigned int size(const std::vector<uint8_t> 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 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<uint8_t> textLengths{};
-		unsigned int i = 0;
-		auto item = getItem(i);
-		while (item->type != 0) {
-			textLengths.push_back(item->length());
-			item = getItem(++i);
-		}
-		return size(textLengths);
-	}
-};
+	[[nodiscard]] static unsigned int Size(const std::vector<uint8_t> textLengths);
 
-struct RTCP_SDES {
-	RTCP_HEADER header;
+	[[nodiscard]] SSRC ssrc() const;
 
-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);
-	}
-
-	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;
-		}
-	}
-
-	/// 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;
-	}
-
-	/// 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<RTCP_SDES_CHUNK *>(reinterpret_cast<uint8_t *>(base) + chunkSize);
-		}
-		return reinterpret_cast<RTCP_SDES_CHUNK *>(base);
-	}
-
-	[[nodiscard]] static unsigned int size(const std::vector<std::vector<uint8_t>> lengths) {
-		unsigned int chunks_size = 0;
-		for (auto length : lengths) {
-			chunks_size += RTCP_SDES_CHUNK::size(length);
-		}
-		return 4 + chunks_size;
-	}
-};
+	void setSSRC(SSRC ssrc);
 
-struct RTCP_RR {
-	RTCP_HEADER header;
-	SSRC _senderSSRC;
+	// 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);
 
-private:
-	RTCP_ReportBlock _reportBlocks;
+	// 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;
 
-public:
-	[[nodiscard]] inline RTCP_ReportBlock *getReportBlock(int num) { return &_reportBlocks + num; }
-	[[nodiscard]] inline const RTCP_ReportBlock *getReportBlock(int num) const {
-		return &_reportBlocks + num;
-	}
-
-	inline SSRC senderSSRC() const { return ntohl(_senderSSRC); }
-	inline void setSenderSSRC(SSRC ssrc) { this->_senderSSRC = htonl(ssrc); }
-
-	[[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()));
-	}
+	long safelyCountChunkSize(size_t maxChunkSize) 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);
-	}
+struct RTC_CPP_EXPORT RTCP_SDES {
+	RTCP_HEADER header;
+	RTCP_SDES_CHUNK _chunks;
 
-	inline static size_t sizeWithReportBlocks(uint8_t reportCount) {
-		return sizeof(header) + 4 + size_t(reportCount) * sizeof(RTCP_ReportBlock);
-	}
+	[[nodiscard]] static unsigned int Size(const std::vector<std::vector<uint8_t>> lengths);
 
-	inline bool isSenderReport() { return header.payloadType() == 200; }
+	bool isValid() const;
 
-	inline bool isReceiverReport() { return header.payloadType() == 201; }
+	// Returns number of chunks in this packet
+	// Returns 0 if packet is invalid
+	unsigned int chunksCount() const;
 
-	inline void log() const {
-		header.log();
-		PLOG_VERBOSE << "RTCP RR: "
-		             << " SSRC=" << ntohl(_senderSSRC);
+	// 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);
 
-		for (unsigned i = 0; i < unsigned(header.reportCount()); i++) {
-			getReportBlock(i)->log();
-		}
-	}
+	void preparePacket(uint8_t chunkCount);
 };
 
-struct RTCP_REMB {
-	RTCP_FB_HEADER header;
-
-	/*! \brief Unique identifier ('R' 'E' 'M' 'B') */
-	char id[4];
-
-	/*! \brief Num SSRC, Br Exp, Br Mantissa (bit mask) */
-	uint32_t bitrate;
-
-	SSRC ssrc[1];
-
-	[[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());
-	}
+struct RTC_CPP_EXPORT RTCP_RR {
+	RTCP_HEADER header;
 
-	void preparePacket(SSRC senderSSRC, unsigned int numSSRC, unsigned int in_bitrate) {
+	SSRC _senderSSRC;
+	RTCP_ReportBlock _reportBlocks;
 
-		// Report Count becomes the format here.
-		header.header.prepareHeader(206, 15, 0);
+	[[nodiscard]] static size_t SizeWithReportBlocks(uint8_t reportCount);
 
-		// Always zero.
-		header.setMediaSourceSSRC(0);
+	SSRC senderSSRC() const;
+	bool isSenderReport();
+	bool isReceiverReport();
 
-		header.setPacketSenderSSRC(senderSSRC);
+	[[nodiscard]] RTCP_ReportBlock *getReportBlock(int num);
+	[[nodiscard]] const RTCP_ReportBlock *getReportBlock(int num) const;
+	[[nodiscard]] size_t getSize() const;
 
-		id[0] = 'R';
-		id[1] = 'E';
-		id[2] = 'M';
-		id[3] = 'B';
+	void preparePacket(SSRC senderSSRC, uint8_t reportCount);
+	void setSenderSSRC(SSRC ssrc);
 
-		setBitrate(numSSRC, in_bitrate);
-	}
+	void log() const;
+};
 
-	void setBitrate(unsigned int numSSRC, unsigned int in_bitrate) {
-		unsigned int exp = 0;
-		while (in_bitrate > pow(2, 18) - 1) {
-			exp++;
-			in_bitrate /= 2;
-		}
+struct RTC_CPP_EXPORT RTCP_REMB {
+	RTCP_FB_HEADER header;
 
-		// "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));
+	char _id[4];       // Unique identifier ('R' 'E' 'M' 'B')
+	uint32_t _bitrate; // Num SSRC, Br Exp, Br Mantissa (bit mask)
+	SSRC _ssrc[1];
 
-		this->bitrate = htonl((numSSRC << (32u - 8u)) | (exp << (32u - 8u - 6u)) | in_bitrate);
-	}
+	[[nodiscard]] static size_t SizeWithSSRCs(int count);
 
-	void setSsrc(int iterator, SSRC newSssrc) { ssrc[iterator] = htonl(newSssrc); }
+	[[nodiscard]] unsigned int getSize() const;
 
-	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); }
-
-	void setPID(uint16_t pid) { _pid = htons(pid); }
-	void setBLP(uint16_t blp) { _blp = htons(blp); }
-
-	std::vector<uint16_t> getSequenceNumbers() {
-		std::vector<uint16_t> 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;
-	}
+	uint16_t pid();
+	uint16_t blp();
+
+	void setPid(uint16_t pid);
+	void setBlp(uint16_t blp);
+
+	std::vector<uint16_t> 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<char *>(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)

+ 9 - 57
src/capi.cpp

@@ -17,10 +17,9 @@
  */
 
 #include "rtc.h"
-
 #include "rtc.hpp"
 
-#include "plog/Formatters/FuncMessageFormatter.h"
+#include "impl/internals.hpp"
 
 #include <chrono>
 #include <exception>
@@ -29,11 +28,6 @@
 #include <unordered_map>
 #include <utility>
 
-#ifdef _WIN32
-#include <codecvt>
-#include <locale>
-#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<wchar_t>;
-		std::wstring_convert<convert_type, wchar_t> converter;
-		std::string str = converter.to_bytes(formatted);
-#else
-		std::string str = formatted;
-#endif
-		std::lock_guard lock(callbackMutex);
-		if (callback)
-			callback(static_cast<rtcLogLevel>(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<plogAppender> appender;
-	const auto severity = static_cast<plog::Severity>(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<rtcLogLevel>(level), message.c_str());
+		};
+
+	InitLogger(static_cast<LogLevel>(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<RtcpNackResponder>(maxStoredPacketsCount);
 		auto chainableHandler = getMediaChainableHandler(tr);

+ 2 - 0
src/description.cpp

@@ -19,6 +19,8 @@
 
 #include "description.hpp"
 
+#include "impl/internals.hpp"
+
 #include <algorithm>
 #include <array>
 #include <cctype>

+ 65 - 1
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 <mutex>
+
+#ifdef _WIN32
+#include <codecvt>
+#include <locale>
+#endif
+
 namespace rtc {
 
+struct LogAppender : public plog::IAppender {
+	synchronized_callback<LogLevel, string> 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<wchar_t>;
+		std::wstring_convert<convert_type, wchar_t> converter;
+		std::string str = converter.to_bytes(formatted);
+#else
+		std::string str = formatted;
+#endif
+
+		if (!callback(static_cast<LogLevel>(severity), str))
+			std::cout << plog::severityToString(severity) << " " << str << std::endl;
+	}
+};
+
+void InitLogger(LogLevel level, LogCallback callback) {
+	static unique_ptr<LogAppender> appender;
+	const auto severity = static_cast<plog::Severity>(level);
+	if (appender) {
+		appender->callback = std::move(callback);
+		InitLogger(severity, nullptr); // change the severity
+	} else if (callback) {
+		appender = std::make_unique<LogAppender>();
+		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<plog::TxtFormatter> 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
-

+ 10 - 0
src/h264rtppacketizer.cpp

@@ -20,6 +20,16 @@
 
 #include "h264rtppacketizer.hpp"
 
+#include "impl/internals.hpp"
+
+#include <cassert>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <arpa/inet.h>
+#endif
+
 namespace rtc {
 
 typedef enum {

+ 16 - 0
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

+ 2 - 2
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<RTCP_FB_HEADER *>(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<RTCP_SR *>(header);

+ 1 - 0
src/impl/threadpool.hpp

@@ -21,6 +21,7 @@
 
 #include "common.hpp"
 #include "init.hpp"
+#include "internals.hpp"
 
 #include <chrono>
 #include <condition_variable>

+ 2 - 0
src/impl/tls.cpp

@@ -18,6 +18,8 @@
 
 #include "tls.hpp"
 
+#include "internals.hpp"
+
 #if USE_GNUTLS
 
 namespace rtc::gnutls {

+ 1 - 0
src/impl/transport.hpp

@@ -20,6 +20,7 @@
 #define RTC_IMPL_TRANSPORT_H
 
 #include "common.hpp"
+#include "internals.hpp"
 #include "message.hpp"
 
 #include <atomic>

+ 0 - 47
src/log.cpp

@@ -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 <mutex>
-
-namespace rtc {
-
-void InitLogger(LogLevel level) { InitLogger(static_cast<plog::Severity>(level)); }
-
-void InitLogger(plog::Severity severity, plog::IAppender *appender) {
-	static plog::ColorConsoleAppender<plog::TxtFormatter> 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

+ 4 - 0
src/mediachainablehandler.cpp

@@ -20,6 +20,10 @@
 
 #include "mediachainablehandler.hpp"
 
+#include "impl/internals.hpp"
+
+#include <cassert>
+
 namespace rtc {
 
 MediaChainableHandler::MediaChainableHandler(shared_ptr<MediaHandlerRootElement> root): MediaHandler(), root(root), leaf(root) { }

+ 4 - 0
src/mediahandlerelement.cpp

@@ -20,6 +20,10 @@
 
 #include "mediahandlerelement.hpp"
 
+#include "impl/internals.hpp"
+
+#include <cassert>
+
 namespace rtc {
 
 ChainedMessagesProduct make_chained_messages_product() {

+ 2 - 0
src/opusrtppacketizer.cpp

@@ -20,6 +20,8 @@
 
 #include "opusrtppacketizer.hpp"
 
+#include <cassert>
+
 namespace rtc {
 
 OpusRtpPacketizer::OpusRtpPacketizer(shared_ptr<RtpPacketizationConfig> rtpConfig)

+ 1 - 0
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"

+ 4 - 0
src/rtcpnackresponder.cpp

@@ -20,6 +20,10 @@
 
 #include "rtcpnackresponder.hpp"
 
+#include "impl/internals.hpp"
+
+#include <cassert>
+
 namespace rtc {
 
 RtcpNackResponder::Storage::Element::Element(binary_ptr packet, uint16_t sequenceNumber, shared_ptr<Element> next)

+ 3 - 3
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<RTCP_REMB *>(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<RTCP_RR *>(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<RTCP_PLI *>(msg->data());
 	pli->preparePacket(mSsrc);
 	send(msg);

+ 5 - 2
src/rtcpsrreporter.cpp

@@ -20,6 +20,9 @@
 
 #include "rtcpsrreporter.hpp"
 
+#include <cmath>
+#include <cassert>
+
 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<RTCP_SR *>(msg->data());
 	auto timestamp_s = rtpConfig->timestampToSeconds(timestamp);

+ 600 - 0
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 <cmath>
+#include <cstring>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <arpa/inet.h>
+#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<const char *>(&_csrc) - reinterpret_cast<const char *>(this) +
+	       sizeof(SSRC) * csrcCount();
+}
+
+const char *RTP::getBody() const {
+	return reinterpret_cast<const char *>(&_csrc) + sizeof(SSRC) * csrcCount();
+}
+
+char *RTP::getBody() { return reinterpret_cast<char *>(&_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<uint8_t> 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<const RTCP_SDES_ITEM *>(reinterpret_cast<const uint8_t *>(base) +
+		                                                itemSize);
+	}
+	return reinterpret_cast<const RTCP_SDES_ITEM *>(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<RTCP_SDES_ITEM *>(reinterpret_cast<uint8_t *>(base) + itemSize);
+	}
+	return reinterpret_cast<RTCP_SDES_ITEM *>(base);
+}
+
+unsigned int RTCP_SDES_CHUNK::getSize() const {
+	std::vector<uint8_t> 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<uint8_t> 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<std::vector<uint8_t>> 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<const RTCP_SDES_CHUNK *>(reinterpret_cast<const uint8_t *>(base) +
+		                                                 chunkSize);
+	}
+	return reinterpret_cast<const RTCP_SDES_CHUNK *>(base);
+}
+
+RTCP_SDES_CHUNK *RTCP_SDES::getChunk(int num) {
+	auto base = &_chunks;
+	while (num-- > 0) {
+		auto chunkSize = base->getSize();
+		base = reinterpret_cast<RTCP_SDES_CHUNK *>(reinterpret_cast<uint8_t *>(base) + chunkSize);
+	}
+	return reinterpret_cast<RTCP_SDES_CHUNK *>(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<uint16_t> RTCP_NACK_PART::getSequenceNumbers() {
+	std::vector<uint16_t> 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<const char *>(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

+ 2 - 0
src/rtppacketizationconfig.cpp

@@ -20,6 +20,8 @@
 
 #include "rtppacketizationconfig.hpp"
 
+#include <cassert>
+
 namespace rtc {
 
 RtpPacketizationConfig::RtpPacketizationConfig(SSRC ssrc, string cname, uint8_t payloadType,

+ 3 - 1
src/rtppacketizer.cpp

@@ -20,6 +20,8 @@
 
 #include "rtppacketizer.hpp"
 
+#include <cstring>
+
 namespace rtc {
 
 RtpPacketizer::RtpPacketizer(shared_ptr<RtpPacketizationConfig> rtpConfig)
@@ -37,7 +39,7 @@ binary_ptr RtpPacketizer::packetize(shared_ptr<binary> 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;
 }