diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3339e83..7cfb5be 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -64,6 +64,14 @@ set(LIBDATACHANNEL_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/track.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/processor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/capi.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/rtppacketizationconfig.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpsenderreportable.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/rtppacketizer.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/opusrtppacketizer.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/opuspacketizationhandler.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/h264rtppacketizer.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/nalunit.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/h264packetizationhandler.cpp
)
set(LIBDATACHANNEL_WEBSOCKET_SOURCES
@@ -95,6 +103,14 @@ set(LIBDATACHANNEL_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rtp.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/track.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/websocket.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rtppacketizationconfig.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rtcpsenderreportable.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/rtppacketizer.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/opusrtppacketizer.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/opuspacketizationhandler.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h264rtppacketizer.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/nalunit.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/rtc/h264packetizationhandler.hpp
)
set(TESTS_SOURCES
diff --git a/include/rtc/h264packetizationhandler.hpp b/include/rtc/h264packetizationhandler.hpp
new file mode 100644
index 0000000..ba49df5
--- /dev/null
+++ b/include/rtc/h264packetizationhandler.hpp
@@ -0,0 +1,72 @@
+/*
+ * libdatachannel client example
+ * Copyright (c) 2020 Filip Klembara (in2core)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see .
+ */
+
+#ifndef H264PacketizationHandler_hpp
+#define H264PacketizationHandler_hpp
+
+#include "rtcp.hpp"
+#include "h264rtppacketizer.hpp"
+#include "rtcpsenderreportable.hpp"
+#include "nalunit.hpp"
+
+#if RTC_ENABLE_MEDIA
+
+namespace rtc {
+
+/// Handler for H264 packetization
+class H264PacketizationHandler: public RtcpHandler, public RTCPSenderReportable {
+ /// RTP packetizer for H264
+ const std::shared_ptr packetizer;
+
+ const uint16_t maximumFragmentSize;
+
+ std::shared_ptr splitMessage(message_ptr message);
+public:
+ /// Nalunit separator
+ enum class Separator {
+ LongStartSequence, // 0x00, 0x00, 0x00, 0x01
+ ShortStartSequence, // 0x00, 0x00, 0x01
+ StartSequence, // LongStartSequence or ShortStartSequence
+ Length // first 4 bytes is nal unit length
+ };
+
+ /// Construct handler for H264 packetization.
+ /// @param separator Nal units separator
+ /// @param packetizer RTP packetizer for h264
+ H264PacketizationHandler(Separator separator, std::shared_ptr packetizer, uint16_t maximumFragmentSize = NalUnits::defaultMaximumFragmentSize);
+
+ /// Returns message unchanged
+ /// @param ptr message
+ message_ptr incoming(message_ptr ptr) override;
+
+ /// Returns packetized message if message type is binary
+ /// @note NAL units in `ptr` message must be separated by `separator` given in constructor
+ /// @note If message generates multiple rtp packets, all but last are send using `outgoingCallback`. It is your responsibility to send last packet.
+ /// @param ptr message containing all NAL units for current timestamp (one sample)
+ /// @return last packet
+ message_ptr outgoing(message_ptr ptr) override;
+private:
+ /// Separator
+ const Separator separator;
+};
+
+} // namespace
+
+#endif /* RTC_ENABLE_MEDIA */
+
+#endif /* H264PacketizationHandler_hpp */
diff --git a/include/rtc/h264rtppacketizer.hpp b/include/rtc/h264rtppacketizer.hpp
new file mode 100644
index 0000000..6227b8b
--- /dev/null
+++ b/include/rtc/h264rtppacketizer.hpp
@@ -0,0 +1,45 @@
+/*
+ * libdatachannel streamer example
+ * Copyright (c) 2020 Filip Klembara (in2core)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see .
+ */
+
+#ifndef H264RTPPacketizer_hpp
+#define H264RTPPacketizer_hpp
+
+#include "rtppacketizer.hpp"
+
+#if RTC_ENABLE_MEDIA
+
+namespace rtc {
+
+/// RTP packetization of h264 payload
+class H264RTPPacketizer: public rtc::RTPPacketizer {
+
+public:
+ /// Default clock rate for H264 in RTP
+ static const auto defaultClockRate = 90 * 1000;
+
+ /// Constructs h264 payload packetizer with given RTP configuration.
+ /// @note RTP configuration is used in packetization process which may change some configuration properties such as sequence number.
+ /// @param rtpConfig RTP configuration
+ H264RTPPacketizer(std::shared_ptr rtpConfig);
+};
+
+} // namespace
+
+#endif /* RTC_ENABLE_MEDIA */
+
+#endif /* H264RTPPacketizer_hpp */
diff --git a/include/rtc/nalunit.hpp b/include/rtc/nalunit.hpp
new file mode 100644
index 0000000..76a21b6
--- /dev/null
+++ b/include/rtc/nalunit.hpp
@@ -0,0 +1,155 @@
+/*
+ * libdatachannel streamer example
+ * Copyright (c) 2020 Filip Klembara (in2core)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see .
+ */
+
+#ifndef NalUnit_hpp
+#define NalUnit_hpp
+
+#include "include.hpp"
+
+#if RTC_ENABLE_MEDIA
+
+namespace rtc {
+
+#pragma pack(push, 1)
+
+/// Nalu header
+struct NalUnitHeader {
+ bool forbiddenBit() { return _first >> 7; }
+ uint8_t nri() { return _first >> 5 & 0x03; }
+ uint8_t unitType() { return _first & 0x1F; }
+
+ 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 NalUnitFragmentHeader {
+ bool isStart() { return _first >> 7; }
+ bool reservedBit6() { return (_first >> 6) & 0x01; }
+ bool isEnd() { return (_first >> 5) & 0x01; }
+ uint8_t unitType() { return _first & 0x1F; }
+
+ void setStart(bool isSet) { _first = (_first & 0x7F) | (isSet << 7); }
+ 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)
+
+/// Nal unit
+struct NalUnit: rtc::binary {
+ NalUnit(const NalUnit &unit) = default;
+ NalUnit(size_t size, bool includingHeader = true): rtc::binary(size + (includingHeader ? 0 : 1)) { }
+
+ template
+ NalUnit(Iterator begin_, Iterator end_): rtc::binary(begin_, end_) { }
+
+ NalUnit(rtc::binary &&data) : rtc::binary(std::move(data)) { }
+
+ bool forbiddenBit() { return header()->forbiddenBit(); }
+ uint8_t nri() { return header()->nri(); }
+ uint8_t unitType() { return header()->unitType(); }
+ rtc::binary payload() {
+ assert(size() >= 1);
+ return {begin() + 1, end()};
+ }
+
+ void setForbiddenBit(bool isSet) { header()->setForbiddenBit(isSet); }
+ void setNRI(uint8_t nri) { header()->setNRI(nri); }
+ void setUnitType(uint8_t type) { header()->setUnitType(type); }
+ void setPayload(rtc::binary payload) {
+ assert(size() >= 1);
+ erase(begin() + 1, end());
+ insert(end(), payload.begin(), payload.end());
+ }
+
+protected:
+ NalUnitHeader * header() {
+ assert(size() >= 1);
+ return (NalUnitHeader *) data();
+ }
+};
+
+/// Nal unit fragment A
+struct NalUnitFragmentA: NalUnit {
+ enum class FragmentType {
+ Start,
+ Middle,
+ End
+ };
+
+ NalUnitFragmentA(FragmentType type, bool forbiddenBit, uint8_t nri, uint8_t unitType, rtc::binary data);
+
+ static std::vector fragmentsFrom(NalUnit nalu, uint16_t maximumFragmentSize);
+
+ uint8_t unitType() { return fragmentHeader()->unitType(); }
+
+ rtc::binary payload() {
+ assert(size() >= 2);
+ return {begin() + 2, end()};
+ }
+
+ FragmentType type() {
+ if(fragmentHeader()->isStart()) {
+ return FragmentType::Start;
+ } else if(fragmentHeader()->isEnd()) {
+ return FragmentType::End;
+ } else {
+ return FragmentType::Middle;
+ }
+ }
+
+ void setUnitType(uint8_t type) { fragmentHeader()->setUnitType(type); }
+
+ void setPayload(rtc::binary payload) {
+ assert(size() >= 2);
+ erase(begin() + 2, end());
+ insert(end(), payload.begin(), payload.end());
+ }
+
+ void setFragmentType(FragmentType type);
+
+protected:
+ NalUnitHeader * fragmentIndicator() {
+ return (NalUnitHeader *) data();
+ }
+
+ NalUnitFragmentHeader * fragmentHeader() {
+ return (NalUnitFragmentHeader *) fragmentIndicator() + 1;
+ }
+
+ const uint8_t nal_type_fu_A = 28;
+};
+
+class NalUnits: public std::vector {
+public:
+ static const uint16_t defaultMaximumFragmentSize = 1100;
+ std::vector generateFragments(uint16_t maximumFragmentSize = NalUnits::defaultMaximumFragmentSize);
+};
+
+} // namespace
+
+#endif /* RTC_ENABLE_MEDIA */
+
+#endif /* NalUnit_hpp */
diff --git a/include/rtc/opuspacketizationhandler.hpp b/include/rtc/opuspacketizationhandler.hpp
new file mode 100644
index 0000000..4f1d5d5
--- /dev/null
+++ b/include/rtc/opuspacketizationhandler.hpp
@@ -0,0 +1,52 @@
+/*
+ * libdatachannel client example
+ * Copyright (c) 2020 Filip Klembara (in2core)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see .
+ */
+
+#ifndef OpusPacketizationHandler_hpp
+#define OpusPacketizationHandler_hpp
+
+#include "rtcpsenderreportable.hpp"
+#include "opusrtppacketizer.hpp"
+#include "rtcp.hpp"
+
+#if RTC_ENABLE_MEDIA
+
+namespace rtc {
+
+/// Handler for opus packetization
+class OpusPacketizationHandler: public RtcpHandler, public RTCPSenderReportable {
+ /// RTP packetizer for opus
+ const std::shared_ptr packetizer;
+
+public:
+ /// Construct handler for opus packetization.
+ /// @param packetizer RTP packetizer for opus
+ OpusPacketizationHandler(std::shared_ptr packetizer);
+
+ /// Returns message unchanged
+ /// @param ptr message
+ message_ptr incoming(message_ptr ptr) override;
+ /// Returns packetized message if message type is binary
+ /// @param ptr message
+ message_ptr outgoing(message_ptr ptr) override;
+};
+
+} // namespace
+
+#endif /* RTC_ENABLE_MEDIA */
+
+#endif /* OpusPacketizationHandler_hpp */
diff --git a/include/rtc/opusrtppacketizer.hpp b/include/rtc/opusrtppacketizer.hpp
new file mode 100644
index 0000000..bfefb8d
--- /dev/null
+++ b/include/rtc/opusrtppacketizer.hpp
@@ -0,0 +1,51 @@
+/*
+ * libdatachannel streamer example
+ * Copyright (c) 2020 Filip Klembara (in2core)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see .
+ */
+
+#ifndef OpusRTPPacketizer_hpp
+#define OpusRTPPacketizer_hpp
+
+#include "rtppacketizer.hpp"
+
+#if RTC_ENABLE_MEDIA
+
+namespace rtc {
+
+/// RTP packetizer for opus
+class OpusRTPPacketizer: public rtc::RTPPacketizer {
+
+public:
+ /// default clock rate used in opus RTP communication
+ static const uint32_t defaultClockRate = 48 * 1000;
+
+ /// Constructs opus packetizer with given RTP configuration.
+ /// @note RTP configuration is used in packetization process which may change some configuration properties such as sequence number.
+ /// @param rtpConfig RTP configuration
+ OpusRTPPacketizer(std::shared_ptr rtpConfig);
+
+ /// Creates RTP packet for given payload based on `rtpConfig`.
+ /// @note This function increase sequence number after packetization.
+ /// @param payload RTP payload
+ /// @param setMark This needs to be `false` for all RTP packets with opus payload
+ rtc::message_ptr packetize(rtc::binary payload, bool setMark) override;
+};
+
+} // namespace
+
+#endif /* RTC_ENABLE_MEDIA */
+
+#endif /* OpusRTPPacketizer_hpp */
diff --git a/include/rtc/rtc.hpp b/include/rtc/rtc.hpp
index 261e4db..7ad4e01 100644
--- a/include/rtc/rtc.hpp
+++ b/include/rtc/rtc.hpp
@@ -25,5 +25,13 @@
#include "peerconnection.hpp"
#include "websocket.hpp"
+#if RTC_ENABLE_MEDIA
+
+// opus/h264 streaming
+#include "opuspacketizationhandler.hpp"
+#include "h264packetizationhandler.hpp"
+
+#endif /* RTC_ENABLE_MEDIA */
+
// C API
#include "rtc.h"
diff --git a/include/rtc/rtcpsenderreportable.hpp b/include/rtc/rtcpsenderreportable.hpp
new file mode 100644
index 0000000..69c243c
--- /dev/null
+++ b/include/rtc/rtcpsenderreportable.hpp
@@ -0,0 +1,87 @@
+/*
+ * libdatachannel streamer example
+ * Copyright (c) 2020 Filip Klembara (in2core)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see .
+ */
+
+#ifndef RTCPSenderReporter_hpp
+#define RTCPSenderReporter_hpp
+
+#include "message.hpp"
+#include "rtppacketizationconfig.hpp"
+
+#if RTC_ENABLE_MEDIA
+
+namespace rtc {
+
+/// Class for sending RTCP SR
+class RTCPSenderReportable {
+ bool needsToReport = false;
+
+ uint32_t packetCount = 0;
+ uint32_t payloadOctets = 0;
+ double timeOffset = 0;
+
+ uint32_t _previousReportedTimestamp = 0;
+
+ void addToReport(RTP * rtp, uint32_t rtpSize);
+ message_ptr getSenderReport(uint32_t timestamp);
+protected:
+ /// Outgoing callback for sender reports
+ synchronized_callback senderReportOutgoingCallback;
+public:
+ static uint64_t secondsToNTP(double seconds);
+
+ /// Timestamp of previous sender report
+ const uint32_t & previousReportedTimestamp = _previousReportedTimestamp;
+
+ /// RTP configuration
+ const std::shared_ptr rtpConfig;
+
+ RTCPSenderReportable(std::shared_ptr rtpConfig);
+
+ /// Set `needsToReport` flag. Sender report will be sent before next RTP packet with same timestamp.
+ void setNeedsToReport();
+
+ /// Set offset to compute NTS for RTCP SR packets. Offset represents relation between real start time and timestamp of the stream in RTP packets
+ /// @note `time_offset = rtpConfig->startTime_s - rtpConfig->timestampToSeconds(rtpConfig->timestamp)`
+ void startRecording();
+
+ /// Send RTCP SR with given timestamp
+ /// @param timestamp timestamp of the RTCP SR
+ void sendReport(uint32_t timestamp);
+
+protected:
+ /// Calls given block with function for statistics. Sends RTCP SR packet with current timestamp before `block` call if `needs_to_report` flag is true.
+ /// @param block Block of code to run. This block has function for rtp stats recording.
+ template
+ T withStatsRecording(std::function)> block) {
+ if (needsToReport) {
+ sendReport(rtpConfig->timestamp);
+ needsToReport = false;
+ }
+ auto result = block([this](message_ptr _rtp) {
+ auto rtp = reinterpret_cast(_rtp->data());
+ this->addToReport(rtp, _rtp->size());
+ });
+ return result;
+ }
+};
+
+} // namespace
+
+#endif /* RTC_ENABLE_MEDIA */
+
+#endif /* RTCPSenderReporter_hpp */
diff --git a/include/rtc/rtppacketizationconfig.hpp b/include/rtc/rtppacketizationconfig.hpp
new file mode 100644
index 0000000..89ab128
--- /dev/null
+++ b/include/rtc/rtppacketizationconfig.hpp
@@ -0,0 +1,91 @@
+/*
+ * libdatachannel streamer example
+ * Copyright (c) 2020 Filip Klembara (in2core)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see .
+ */
+
+#ifndef RTPPacketizationConfig_hpp
+#define RTPPacketizationConfig_hpp
+
+#include "rtp.hpp"
+
+#if RTC_ENABLE_MEDIA
+
+namespace rtc {
+
+/// RTP configuration used in packetization process
+struct RTPPacketizationConfig {
+private:
+ uint32_t _startTimestamp = 0;
+ double _startTime_s = 0;
+ RTPPacketizationConfig(const RTPPacketizationConfig&) = delete;
+public:
+ const SSRC ssrc;
+ const std::string cname;
+ const uint8_t payloadType;
+ const uint32_t clockRate;
+ const double & startTime_s = _startTime_s;
+ const uint32_t & startTimestamp = _startTimestamp;
+
+ /// current sequence number
+ uint16_t sequenceNumber;
+ /// current timestamp
+ uint32_t timestamp;
+
+ enum class EpochStart: unsigned long long {
+ T1970 = 2208988800, // number of seconds between 1970 and 1900
+ T1900 = 0
+ };
+
+ /// Creates relation between time and timestamp mapping given start time and start timestamp
+ /// @param startTime_s Start time of the stream
+ /// @param epochStart Type of used epoch
+ /// @param startTimestamp Corresponding timestamp for given start time (current timestamp will be used if value is nullopt)
+ void setStartTime(double startTime_s, EpochStart epochStart, std::optional startTimestamp = std::nullopt);
+
+
+ /// Construct RTP configuration used in packetization process
+ /// @param ssrc SSRC of source
+ /// @param cname CNAME of source
+ /// @param payloadType Payload type of source
+ /// @param clockRate Clock rate of source used in timestamps
+ /// @param sequenceNumber Initial sequence number of RTP packets (random number is choosed if nullopt)
+ /// @param timestamp Initial timastamp of RTP packets (random number is choosed if nullopt)
+ RTPPacketizationConfig(SSRC ssrc, std::string cname, uint8_t payloadType, uint32_t clockRate, std::optional sequenceNumber = std::nullopt, std::optional timestamp = std::nullopt);
+
+ /// Convert timestamp to seconds
+ /// @param timestamp Timestamp
+ /// @param clockRate Clock rate for timestamp calculation
+ static double getSecondsFromTimestamp(uint32_t timestamp, uint32_t clockRate);
+
+ /// Convert timestamp to seconds
+ /// @param timestamp Timestamp
+ double timestampToSeconds(uint32_t timestamp);
+
+ /// Convert seconds to timestamp
+ /// @param seconds Number of seconds
+ /// @param clockRate Clock rate for timestamp calculation
+ static uint32_t getTimestampFromSeconds(double seconds, uint32_t clockRate);
+
+ /// Convert seconds to timestamp
+ /// @param seconds Number of seconds
+ uint32_t secondsToTimestamp(double seconds);
+};
+
+} // namespace
+
+#endif /* RTC_ENABLE_MEDIA */
+
+#endif /* RTPPacketizationConfig_hpp */
diff --git a/include/rtc/rtppacketizer.hpp b/include/rtc/rtppacketizer.hpp
new file mode 100644
index 0000000..154a562
--- /dev/null
+++ b/include/rtc/rtppacketizer.hpp
@@ -0,0 +1,52 @@
+/*
+ * libdatachannel streamer example
+ * Copyright (c) 2020 Filip Klembara (in2core)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see .
+ */
+
+#ifndef RTPPacketizer_hpp
+#define RTPPacketizer_hpp
+
+#include "rtppacketizationconfig.hpp"
+#include "message.hpp"
+
+#if RTC_ENABLE_MEDIA
+
+namespace rtc {
+
+/// Class responsizble for rtp packetization
+class RTPPacketizer {
+ static const auto rtpHeaderSize = 12;
+public:
+ // rtp configuration
+ const std::shared_ptr rtpConfig;
+
+ /// Constructs packetizer with given RTP configuration.
+ /// @note RTP configuration is used in packetization process which may change some configuration properties such as sequence number.
+ /// @param rtpConfig RTP configuration
+ RTPPacketizer(std::shared_ptr rtpConfig);
+
+ /// Creates RTP packet for given payload based on `rtpConfig`.
+ /// @note This function increase sequence number after packetization.
+ /// @param payload RTP payload
+ /// @param setMark Set marker flag in RTP packet if true
+ virtual message_ptr packetize(binary payload, bool setMark);
+};
+
+} // namespace
+
+#endif /* RTC_ENABLE_MEDIA */
+
+#endif /* RTPPacketizer_hpp */
diff --git a/src/h264packetizationhandler.cpp b/src/h264packetizationhandler.cpp
new file mode 100644
index 0000000..9351d69
--- /dev/null
+++ b/src/h264packetizationhandler.cpp
@@ -0,0 +1,164 @@
+/*
+ * libdatachannel client example
+ * Copyright (c) 2020 Filip Klembara (in2core)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see .
+ */
+
+#include "h264packetizationhandler.hpp"
+
+#if RTC_ENABLE_MEDIA
+
+using namespace rtc;
+using namespace std;
+
+typedef enum {
+ NUSM_noMatch,
+ NUSM_firstZero,
+ NUSM_secondZero,
+ NUSM_thirdZero,
+ NUSM_shortMatch,
+ NUSM_longMatch
+} NalUnitStartSequenceMatch;
+
+NalUnitStartSequenceMatch StartSequenceMatchSucc(NalUnitStartSequenceMatch match, byte _byte, H264PacketizationHandler::Separator separator) {
+ assert(separator != H264PacketizationHandler::Separator::Length);
+ auto byte = (uint8_t) _byte;
+ auto detectShort = separator == H264PacketizationHandler::Separator::ShortStartSequence || separator == H264PacketizationHandler::Separator::StartSequence;
+ auto detectLong = separator == H264PacketizationHandler::Separator::LongStartSequence || separator == H264PacketizationHandler::Separator::StartSequence;
+ switch (match) {
+ case NUSM_noMatch:
+ if (byte == 0x00) {
+ return NUSM_firstZero;
+ }
+ break;
+ case NUSM_firstZero:
+ if (byte == 0x00) {
+ return NUSM_secondZero;
+ }
+ break;
+ case NUSM_secondZero:
+ if (byte == 0x00 && detectLong) {
+ return NUSM_thirdZero;
+ } else if (byte == 0x01 && detectShort) {
+ return NUSM_shortMatch;
+ }
+ break;
+ case NUSM_thirdZero:
+ if (byte == 0x01 && detectLong) {
+ return NUSM_longMatch;
+ }
+ break;
+ case NUSM_shortMatch:
+ return NUSM_shortMatch;
+ case NUSM_longMatch:
+ return NUSM_longMatch;
+ }
+ return NUSM_noMatch;
+}
+
+message_ptr H264PacketizationHandler::incoming(message_ptr ptr) {
+ return ptr;
+}
+
+shared_ptr H264PacketizationHandler::splitMessage(rtc::message_ptr message) {
+ auto nalus = make_shared();
+ if (separator == Separator::Length) {
+ unsigned long long index = 0;
+ while (index < message->size()) {
+ assert(index + 4 < message->size());
+ if (index + 4 >= message->size()) {
+ LOG_WARNING << "Invalid NAL Unit data (incomplete length), ignoring!";
+ break;
+ }
+ auto lengthPtr = (uint32_t *) (message->data() + index);
+ uint32_t length = ntohl(*lengthPtr);
+ auto naluStartIndex = index + 4;
+ auto naluEndIndex = naluStartIndex + length;
+
+ assert(naluEndIndex <= message->size());
+ if (naluEndIndex > message->size()) {
+ LOG_WARNING << "Invalid NAL Unit data (incomplete unit), ignoring!";
+ break;
+ }
+ nalus->push_back(NalUnit(message->begin() + naluStartIndex, message->begin() + naluEndIndex));
+ index = naluEndIndex;
+ }
+ } else {
+ NalUnitStartSequenceMatch match = NUSM_noMatch;
+ unsigned long long index = 0;
+ while (index < message->size()) {
+ match = StartSequenceMatchSucc(match, (*message)[index++], separator);
+ if (match == NUSM_longMatch || match == NUSM_shortMatch) {
+ match = NUSM_noMatch;
+ break;
+ }
+ }
+ index++;
+ unsigned long long naluStartIndex = index;
+
+ while (index < message->size()) {
+ match = StartSequenceMatchSucc(match, (*message)[index], separator);
+ if (match == NUSM_longMatch || match == NUSM_shortMatch) {
+ auto sequenceLength = match == NUSM_longMatch ? 4 : 3;
+ unsigned long long naluEndIndex = index - sequenceLength;
+ match = NUSM_noMatch;
+ nalus->push_back(NalUnit(message->begin() + naluStartIndex, message->begin() + naluEndIndex + 1));
+ naluStartIndex = index + 1;
+ }
+ index++;
+ }
+ nalus->push_back(NalUnit(message->begin() + naluStartIndex, message->end()));
+ }
+ return nalus;
+}
+
+message_ptr H264PacketizationHandler::outgoing(message_ptr ptr) {
+ if (ptr->type == Message::Binary) {
+ auto nalus = splitMessage(ptr);
+ auto fragments = nalus->generateFragments(maximumFragmentSize);
+
+ auto lastPacket = withStatsRecording([fragments, this](function addToReport) {
+ for(unsigned long long index = 0; index < fragments.size() - 1; index++) {
+ auto packet = packetizer->packetize(fragments[index], false);
+
+ addToReport(packet);
+
+ outgoingCallback(std::move(packet));
+ }
+ // packet is last, marker must be set
+ auto lastPacket = packetizer->packetize(fragments[fragments.size() - 1], true);
+ addToReport(lastPacket);
+ return lastPacket;
+ });
+ return lastPacket;
+ }
+ return ptr;
+}
+
+H264PacketizationHandler::H264PacketizationHandler(Separator separator,
+ std::shared_ptr packetizer,
+ uint16_t maximumFragmentSize):
+ RtcpHandler(),
+ rtc::RTCPSenderReportable(packetizer->rtpConfig),
+ packetizer(packetizer),
+ maximumFragmentSize(maximumFragmentSize),
+ separator(separator) {
+
+ senderReportOutgoingCallback = [this](message_ptr msg) {
+ outgoingCallback(msg);
+ };
+}
+
+#endif /* RTC_ENABLE_MEDIA */
diff --git a/src/h264rtppacketizer.cpp b/src/h264rtppacketizer.cpp
new file mode 100644
index 0000000..2d3f7f3
--- /dev/null
+++ b/src/h264rtppacketizer.cpp
@@ -0,0 +1,28 @@
+/*
+ * libdatachannel streamer example
+ * Copyright (c) 2020 Filip Klembara (in2core)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see .
+ */
+
+#include "h264rtppacketizer.hpp"
+
+#if RTC_ENABLE_MEDIA
+
+using namespace std;
+using namespace rtc;
+
+H264RTPPacketizer::H264RTPPacketizer(std::shared_ptr rtpConfig): RTPPacketizer(rtpConfig) { }
+
+#endif /* RTC_ENABLE_MEDIA */
diff --git a/src/nalunit.cpp b/src/nalunit.cpp
new file mode 100644
index 0000000..9430f9a
--- /dev/null
+++ b/src/nalunit.cpp
@@ -0,0 +1,103 @@
+/*
+ * libdatachannel streamer example
+ * Copyright (c) 2020 Filip Klembara (in2core)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see .
+ */
+
+#include "nalunit.hpp"
+
+#if RTC_ENABLE_MEDIA
+
+using namespace std;
+using namespace rtc;
+
+NalUnitFragmentA::NalUnitFragmentA(FragmentType type, bool forbiddenBit, uint8_t nri, uint8_t unitType, binary data): NalUnit(data.size() + 2) {
+ setForbiddenBit(forbiddenBit);
+ setNRI(nri);
+ fragmentIndicator()->setUnitType(NalUnitFragmentA::nal_type_fu_A);
+ setFragmentType(type);
+ setUnitType(unitType);
+ copy(data.begin(), data.end(), begin() + 2);
+}
+
+vector NalUnitFragmentA::fragmentsFrom(NalUnit nalu, uint16_t maximumFragmentSize) {
+ assert(nalu.size() > maximumFragmentSize);
+ if (nalu.size() <= maximumFragmentSize) {
+ // we need to change `maximum_fragment_size` to have at least two fragments
+ maximumFragmentSize = nalu.size() / 2;
+ }
+ auto fragments_count = ceil(double(nalu.size()) / maximumFragmentSize);
+ maximumFragmentSize = ceil(nalu.size() / fragments_count);
+
+ // 2 bytes for FU indicator and FU header
+ maximumFragmentSize -= 2;
+ auto f = nalu.forbiddenBit();
+ uint8_t nri = nalu.nri() & 0x03;
+ uint8_t naluType = nalu.unitType() & 0x1F;
+ auto payload = nalu.payload();
+ vector result{};
+ uint64_t offset = 0;
+ while (offset < payload.size()) {
+ vector fragmentData;
+ FragmentType fragmentType;
+ if (offset == 0) {
+ fragmentType = FragmentType::Start;
+ } else if (offset + maximumFragmentSize < payload.size()) {
+ fragmentType = FragmentType::Middle;
+ } else {
+ if (offset + maximumFragmentSize > payload.size()) {
+ maximumFragmentSize = payload.size() - offset;
+ }
+ fragmentType = FragmentType::End;
+ }
+ fragmentData = {payload.begin() + offset, payload.begin() + offset + maximumFragmentSize};
+ NalUnitFragmentA fragment{fragmentType, f, nri, naluType, fragmentData};
+ result.push_back(fragment);
+ offset += maximumFragmentSize;
+ }
+ return result;
+}
+
+void NalUnitFragmentA::setFragmentType(FragmentType type) {
+ fragmentHeader()->setReservedBit6(false);
+ switch (type) {
+ case FragmentType::Start:
+ fragmentHeader()->setStart(true);
+ fragmentHeader()->setEnd(false);
+ break;
+ case FragmentType::End:
+ fragmentHeader()->setStart(false);
+ fragmentHeader()->setEnd(true);
+ break;
+ default:
+ fragmentHeader()->setStart(false);
+ fragmentHeader()->setEnd(false);
+ }
+}
+
+vector NalUnits::generateFragments(uint16_t maximumFragmentSize) {
+ vector result{};
+ for (auto nalu: *this) {
+ if (nalu.size() > maximumFragmentSize) {
+ std::vector fragments = NalUnitFragmentA::fragmentsFrom(nalu, maximumFragmentSize);
+ result.insert(result.end(), fragments.begin(), fragments.end());
+ } else {
+ result.push_back(nalu);
+ }
+ }
+ return result;
+}
+
+#endif /* RTC_ENABLE_MEDIA */
diff --git a/src/opuspacketizationhandler.cpp b/src/opuspacketizationhandler.cpp
new file mode 100644
index 0000000..362c210
--- /dev/null
+++ b/src/opuspacketizationhandler.cpp
@@ -0,0 +1,46 @@
+/*
+ * libdatachannel client example
+ * Copyright (c) 2020 Filip Klembara (in2core)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see .
+ */
+
+#include "opuspacketizationhandler.hpp"
+
+#if RTC_ENABLE_MEDIA
+
+using namespace rtc;
+
+OpusPacketizationHandler::OpusPacketizationHandler(std::shared_ptr packetizer): RtcpHandler(), RTCPSenderReportable(packetizer->rtpConfig), packetizer(packetizer) {
+ senderReportOutgoingCallback = [this](message_ptr msg) {
+ outgoingCallback(msg);
+ };
+}
+
+message_ptr OpusPacketizationHandler::incoming(message_ptr ptr) {
+ return ptr;
+}
+
+message_ptr OpusPacketizationHandler::outgoing(message_ptr ptr) {
+ if (ptr->type == Message::Binary) {
+ return withStatsRecording([this, ptr](std::function addToReport) {
+ auto rtp = packetizer->packetize(*ptr, false);
+ addToReport(rtp);
+ return rtp;
+ });
+ }
+ return ptr;
+}
+
+#endif /* RTC_ENABLE_MEDIA */
diff --git a/src/opusrtppacketizer.cpp b/src/opusrtppacketizer.cpp
new file mode 100644
index 0000000..c7207ec
--- /dev/null
+++ b/src/opusrtppacketizer.cpp
@@ -0,0 +1,33 @@
+/*
+ * libdatachannel streamer example
+ * Copyright (c) 2020 Filip Klembara (in2core)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see .
+ */
+
+#include "opusrtppacketizer.hpp"
+
+#if RTC_ENABLE_MEDIA
+
+using namespace std;
+using namespace rtc;
+
+OpusRTPPacketizer::OpusRTPPacketizer(std::shared_ptr rtpConfig): RTPPacketizer(rtpConfig) { }
+
+message_ptr OpusRTPPacketizer::packetize(binary payload, bool setMark) {
+ assert(!setMark);
+ return RTPPacketizer::packetize(payload, false);
+}
+
+#endif /* RTC_ENABLE_MEDIA */
diff --git a/src/rtcpsenderreportable.cpp b/src/rtcpsenderreportable.cpp
new file mode 100644
index 0000000..7e382fe
--- /dev/null
+++ b/src/rtcpsenderreportable.cpp
@@ -0,0 +1,74 @@
+/*
+ * libdatachannel streamer example
+ * Copyright (c) 2020 Filip Klembara (in2core)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see .
+ */
+
+#include "rtcpsenderreportable.hpp"
+
+#if RTC_ENABLE_MEDIA
+
+using namespace rtc;
+using namespace std;
+
+void RTCPSenderReportable::startRecording() {
+ _previousReportedTimestamp = rtpConfig->timestamp;
+ timeOffset = rtpConfig->startTime_s - rtpConfig->timestampToSeconds(rtpConfig->timestamp);
+}
+
+void RTCPSenderReportable::sendReport(uint32_t timestamp) {
+ auto sr = getSenderReport(timestamp);
+ _previousReportedTimestamp = timestamp;
+ senderReportOutgoingCallback(move(sr));
+}
+
+void RTCPSenderReportable::addToReport(RTP * rtp, uint32_t rtpSize) {
+ packetCount += 1;
+ assert(!rtp->padding());
+ payloadOctets += rtpSize - rtp->getSize();
+}
+
+RTCPSenderReportable::RTCPSenderReportable(std::shared_ptr rtpConfig): rtpConfig(rtpConfig) { }
+
+uint64_t RTCPSenderReportable::secondsToNTP(double seconds) {
+ return std::round(seconds * double(uint64_t(1) << 32));
+}
+
+void RTCPSenderReportable::setNeedsToReport() {
+ needsToReport = true;
+}
+
+message_ptr RTCPSenderReportable::getSenderReport(uint32_t timestamp) {
+ 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);
+ auto currentTime = timeOffset + timestamp_s;
+ sr->setNtpTimestamp(secondsToNTP(currentTime));
+ sr->setRtpTimestamp(timestamp);
+ sr->setPacketCount(packetCount);
+ sr->setOctetCount(payloadOctets);
+ sr->preparePacket(rtpConfig->ssrc, 0);
+
+ auto sdes = reinterpret_cast(msg->data() + srSize);
+ auto chunk = sdes->getChunk(0);
+ chunk->setSSRC(rtpConfig->ssrc);
+ chunk->type = 1;
+ chunk->setText(rtpConfig->cname);
+ sdes->preparePacket(1);
+ return msg;
+}
+
+#endif /* RTC_ENABLE_MEDIA */
diff --git a/src/rtppacketizationconfig.cpp b/src/rtppacketizationconfig.cpp
new file mode 100644
index 0000000..5b59332
--- /dev/null
+++ b/src/rtppacketizationconfig.cpp
@@ -0,0 +1,73 @@
+/*
+ * libdatachannel streamer example
+ * Copyright (c) 2020 Filip Klembara (in2core)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see .
+ */
+
+#include "rtppacketizationconfig.hpp"
+
+#if RTC_ENABLE_MEDIA
+
+using namespace rtc;
+using namespace std;
+
+RTPPacketizationConfig::RTPPacketizationConfig(SSRC ssrc,
+ string cname,
+ uint8_t payloadType,
+ uint32_t clockRate,
+ optional sequenceNumber,
+ optional timestamp): ssrc(ssrc), cname(cname), payloadType(payloadType), clockRate(clockRate) {
+ assert(clockRate > 0);
+ srand((unsigned)time(NULL));
+ if (sequenceNumber.has_value()) {
+ this->sequenceNumber = sequenceNumber.value();
+ } else {
+ this->sequenceNumber = rand();
+ }
+ if (timestamp.has_value()) {
+ this->timestamp = timestamp.value();
+ } else {
+ this->timestamp = rand();
+ }
+ this->_startTimestamp = this->timestamp;
+}
+
+void RTPPacketizationConfig::setStartTime(double startTime_s, EpochStart epochStart, std::optional startTimestamp) {
+ this->_startTime_s = startTime_s + static_cast(epochStart);
+ if (startTimestamp.has_value()) {
+ this->_startTimestamp = startTimestamp.value();
+ timestamp = this->startTimestamp;
+ } else {
+ this->_startTimestamp = timestamp;
+ }
+}
+
+double RTPPacketizationConfig::getSecondsFromTimestamp(uint32_t timestamp, uint32_t clockRate) {
+ return double(timestamp) / double(clockRate);
+}
+
+double RTPPacketizationConfig::timestampToSeconds(uint32_t timestamp) {
+ return RTPPacketizationConfig::getSecondsFromTimestamp(timestamp, clockRate);
+}
+
+uint32_t RTPPacketizationConfig::getTimestampFromSeconds(double seconds, uint32_t clockRate) {
+ return uint32_t(seconds * clockRate);
+}
+
+uint32_t RTPPacketizationConfig::secondsToTimestamp(double seconds) {
+ return RTPPacketizationConfig::getTimestampFromSeconds(seconds, clockRate);
+}
+
+#endif /* RTC_ENABLE_MEDIA */
diff --git a/src/rtppacketizer.cpp b/src/rtppacketizer.cpp
new file mode 100644
index 0000000..3e55ff2
--- /dev/null
+++ b/src/rtppacketizer.cpp
@@ -0,0 +1,44 @@
+/*
+ * libdatachannel streamer example
+ * Copyright (c) 2020 Filip Klembara (in2core)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; If not, see .
+ */
+
+#include "rtppacketizer.hpp"
+
+#if RTC_ENABLE_MEDIA
+
+using namespace std;
+using namespace rtc;
+
+RTPPacketizer::RTPPacketizer(shared_ptr rtpConfig): rtpConfig(rtpConfig) { }
+
+message_ptr RTPPacketizer::packetize(binary payload, bool setMark) {
+ auto msg = make_message(rtpHeaderSize + payload.size());
+ auto * rtp = (RTP *)msg->data();
+ rtp->setPayloadType(rtpConfig->payloadType);
+ // increase sequence number
+ rtp->setSeqNumber(rtpConfig->sequenceNumber++);
+ rtp->setTimestamp(rtpConfig->timestamp);
+ rtp->setSsrc(rtpConfig->ssrc);
+ if (setMark) {
+ rtp->setMarker(true);
+ }
+ rtp->preparePacket();
+ copy(payload.begin(), payload.end(), msg->begin() + rtpHeaderSize);
+ return msg;
+}
+
+#endif /* RTC_ENABLE_MEDIA */