From de212a8e758d057a14053448c78161208e420f92 Mon Sep 17 00:00:00 2001 From: dijunkun Date: Wed, 8 Jan 2025 17:30:13 +0800 Subject: [PATCH] [feat] implementation for qos module --- .../rtp_channel}/rtp_audio_receiver.cpp | 0 .../rtp_channel}/rtp_audio_receiver.h | 0 .../rtp_channel}/rtp_audio_sender.cpp | 0 .../rtp_channel}/rtp_audio_sender.h | 0 .../rtp_channel}/rtp_data_receiver.cpp | 0 .../rtp_channel}/rtp_data_receiver.h | 0 .../rtp_channel}/rtp_data_sender.cpp | 0 .../rtp_channel}/rtp_data_sender.h | 0 .../rtp_channel}/rtp_video_receiver.cpp | 25 +++- .../rtp_channel}/rtp_video_receiver.h | 4 +- .../rtp_channel}/rtp_video_sender.cpp | 0 .../rtp_channel}/rtp_video_sender.h | 0 src/common/array_view.h | 14 +- src/common/enc_mark.h | 31 +++++ src/common/mod_ops.h | 130 ++++++++++++++++++ src/common/sequence_number_unwrapper.h | 73 ++++++++++ src/common/sequence_number_util.h | 73 ++++++++++ src/qos/congestion_control_feedback.cpp | 19 ++- src/qos/congestion_control_feedback.h | 24 +--- .../congestion_control_feedback_generator.cpp | 14 +- .../congestion_control_feedback_generator.h | 40 ++---- .../congestion_control_feedback_tracker.cpp | 27 ++-- src/qos/congestion_control_feedback_tracker.h | 4 +- .../receive_side_congestion_controller.cpp | 95 ++----------- src/qos/receive_side_congestion_controller.h | 23 +--- src/rtcp/rtcp_packet/common_header.cpp | 2 +- src/rtcp/rtcp_packet/common_header.h | 8 +- src/rtcp/rtcp_packet/rtcp_packet.h | 4 + src/rtp/rtp_packet/rtp_packet.h | 2 +- src/rtp/rtp_packet/rtp_packet_received.cpp | 2 - src/rtp/rtp_packet/rtp_packet_received.h | 26 +++- xmake.lua | 91 ++++++------ 32 files changed, 482 insertions(+), 249 deletions(-) rename src/{rtp/rtp_endpoint => channel/rtp_channel}/rtp_audio_receiver.cpp (100%) rename src/{rtp/rtp_endpoint => channel/rtp_channel}/rtp_audio_receiver.h (100%) rename src/{rtp/rtp_endpoint => channel/rtp_channel}/rtp_audio_sender.cpp (100%) rename src/{rtp/rtp_endpoint => channel/rtp_channel}/rtp_audio_sender.h (100%) rename src/{rtp/rtp_endpoint => channel/rtp_channel}/rtp_data_receiver.cpp (100%) rename src/{rtp/rtp_endpoint => channel/rtp_channel}/rtp_data_receiver.h (100%) rename src/{rtp/rtp_endpoint => channel/rtp_channel}/rtp_data_sender.cpp (100%) rename src/{rtp/rtp_endpoint => channel/rtp_channel}/rtp_data_sender.h (100%) rename src/{rtp/rtp_endpoint => channel/rtp_channel}/rtp_video_receiver.cpp (92%) rename src/{rtp/rtp_endpoint => channel/rtp_channel}/rtp_video_receiver.h (94%) rename src/{rtp/rtp_endpoint => channel/rtp_channel}/rtp_video_sender.cpp (100%) rename src/{rtp/rtp_endpoint => channel/rtp_channel}/rtp_video_sender.h (100%) create mode 100644 src/common/enc_mark.h create mode 100644 src/common/mod_ops.h create mode 100644 src/common/sequence_number_unwrapper.h create mode 100644 src/common/sequence_number_util.h diff --git a/src/rtp/rtp_endpoint/rtp_audio_receiver.cpp b/src/channel/rtp_channel/rtp_audio_receiver.cpp similarity index 100% rename from src/rtp/rtp_endpoint/rtp_audio_receiver.cpp rename to src/channel/rtp_channel/rtp_audio_receiver.cpp diff --git a/src/rtp/rtp_endpoint/rtp_audio_receiver.h b/src/channel/rtp_channel/rtp_audio_receiver.h similarity index 100% rename from src/rtp/rtp_endpoint/rtp_audio_receiver.h rename to src/channel/rtp_channel/rtp_audio_receiver.h diff --git a/src/rtp/rtp_endpoint/rtp_audio_sender.cpp b/src/channel/rtp_channel/rtp_audio_sender.cpp similarity index 100% rename from src/rtp/rtp_endpoint/rtp_audio_sender.cpp rename to src/channel/rtp_channel/rtp_audio_sender.cpp diff --git a/src/rtp/rtp_endpoint/rtp_audio_sender.h b/src/channel/rtp_channel/rtp_audio_sender.h similarity index 100% rename from src/rtp/rtp_endpoint/rtp_audio_sender.h rename to src/channel/rtp_channel/rtp_audio_sender.h diff --git a/src/rtp/rtp_endpoint/rtp_data_receiver.cpp b/src/channel/rtp_channel/rtp_data_receiver.cpp similarity index 100% rename from src/rtp/rtp_endpoint/rtp_data_receiver.cpp rename to src/channel/rtp_channel/rtp_data_receiver.cpp diff --git a/src/rtp/rtp_endpoint/rtp_data_receiver.h b/src/channel/rtp_channel/rtp_data_receiver.h similarity index 100% rename from src/rtp/rtp_endpoint/rtp_data_receiver.h rename to src/channel/rtp_channel/rtp_data_receiver.h diff --git a/src/rtp/rtp_endpoint/rtp_data_sender.cpp b/src/channel/rtp_channel/rtp_data_sender.cpp similarity index 100% rename from src/rtp/rtp_endpoint/rtp_data_sender.cpp rename to src/channel/rtp_channel/rtp_data_sender.cpp diff --git a/src/rtp/rtp_endpoint/rtp_data_sender.h b/src/channel/rtp_channel/rtp_data_sender.h similarity index 100% rename from src/rtp/rtp_endpoint/rtp_data_sender.h rename to src/channel/rtp_channel/rtp_data_sender.h diff --git a/src/rtp/rtp_endpoint/rtp_video_receiver.cpp b/src/channel/rtp_channel/rtp_video_receiver.cpp similarity index 92% rename from src/rtp/rtp_endpoint/rtp_video_receiver.cpp rename to src/channel/rtp_channel/rtp_video_receiver.cpp index d0eeff7..9979fa1 100644 --- a/src/rtp/rtp_endpoint/rtp_video_receiver.cpp +++ b/src/channel/rtp_channel/rtp_video_receiver.cpp @@ -5,10 +5,18 @@ #define NV12_BUFFER_SIZE (1280 * 720 * 3 / 2) #define RTCP_RR_INTERVAL 1000 -RtpVideoReceiver::RtpVideoReceiver() {} +RtpVideoReceiver::RtpVideoReceiver() + : receive_side_congestion_controller_( + [this](std::vector> packets) { + SendCombinedRtcpPacket(std::move(packets)); + }) {} RtpVideoReceiver::RtpVideoReceiver(std::shared_ptr io_statistics) - : io_statistics_(io_statistics) { + : io_statistics_(io_statistics), + receive_side_congestion_controller_( + [this](std::vector> packets) { + SendCombinedRtcpPacket(std::move(packets)); + }) { rtcp_thread_ = std::thread(&RtpVideoReceiver::RtcpThread, this); } @@ -31,6 +39,16 @@ void RtpVideoReceiver::InsertRtpPacket(RtpPacket& rtp_packet) { rtp_statistics_->Start(); } + RtpPacketReceived* rtp_packet_received; + rtp_packet_received = dynamic_cast(&rtp_packet); + rtp_packet_received->set_arrival_time( + std::chrono::system_clock::now().time_since_epoch().count()); + rtp_packet_received->set_ecn(EcnMarking::kEct0); + rtp_packet_received->set_recovered(false); + rtp_packet_received->set_payload_type_frequency(0); + receive_side_congestion_controller_.OnReceivedPacket( + *rtp_packet_received, ReceiveSideCongestionController::MediaType::VIDEO); + last_recv_bytes_ = (uint32_t)rtp_packet.PayloadSize(); total_rtp_payload_recv_ += (uint32_t)rtp_packet.PayloadSize(); total_rtp_packets_recv_++; @@ -327,6 +345,9 @@ int RtpVideoReceiver::SendRtcpRR(RtcpReceiverReport& rtcp_rr) { return 0; } +void RtpVideoReceiver::SendCombinedRtcpPacket( + std::vector> packets) {} + bool RtpVideoReceiver::CheckIsTimeSendRR() { uint32_t now_ts = static_cast( std::chrono::duration_cast( diff --git a/src/rtp/rtp_endpoint/rtp_video_receiver.h b/src/channel/rtp_channel/rtp_video_receiver.h similarity index 94% rename from src/rtp/rtp_endpoint/rtp_video_receiver.h rename to src/channel/rtp_channel/rtp_video_receiver.h index 4f83668..9144ea3 100644 --- a/src/rtp/rtp_endpoint/rtp_video_receiver.h +++ b/src/channel/rtp_channel/rtp_video_receiver.h @@ -44,6 +44,8 @@ class RtpVideoReceiver : public ThreadBase { bool CheckIsTimeSendRR(); int SendRtcpRR(RtcpReceiverReport& rtcp_rr); + void SendCombinedRtcpPacket(std::vector> packets); + private: bool Process() override; void RtcpThread(); @@ -86,7 +88,7 @@ class RtpVideoReceiver : public ThreadBase { int rtcp_tcc_interval_ms_ = 200; private: - ReceiveSideCongestionController congestion_controller_; + ReceiveSideCongestionController receive_side_congestion_controller_; }; #endif diff --git a/src/rtp/rtp_endpoint/rtp_video_sender.cpp b/src/channel/rtp_channel/rtp_video_sender.cpp similarity index 100% rename from src/rtp/rtp_endpoint/rtp_video_sender.cpp rename to src/channel/rtp_channel/rtp_video_sender.cpp diff --git a/src/rtp/rtp_endpoint/rtp_video_sender.h b/src/channel/rtp_channel/rtp_video_sender.h similarity index 100% rename from src/rtp/rtp_endpoint/rtp_video_sender.h rename to src/channel/rtp_channel/rtp_video_sender.h diff --git a/src/common/array_view.h b/src/common/array_view.h index 4e8a120..a0febdc 100644 --- a/src/common/array_view.h +++ b/src/common/array_view.h @@ -90,10 +90,10 @@ class ArrayView final : public array_view_internal::ArrayViewBase { template ArrayView(U* data, size_t size) : array_view_internal::ArrayViewBase::ArrayViewBase(data, size) { - RTC_DCHECK_EQ(size == 0 ? nullptr : data, this->data()); - RTC_DCHECK_EQ(size, this->size()); - RTC_DCHECK_EQ(!this->data(), - this->size() == 0); // data is null iff size == 0. + // RTC_DCHECK_EQ(size == 0 ? nullptr : data, this->data()); + // RTC_DCHECK_EQ(size, this->size()); + // RTC_DCHECK_EQ(!this->data(), + // this->size() == 0); // data is null iff size == 0. } // Construct an empty ArrayView. Note that fixed-size ArrayViews of size > 0 @@ -105,7 +105,7 @@ class ArrayView final : public array_view_internal::ArrayViewBase { : ArrayView(static_cast(nullptr), size) { static_assert(Size == 0 || Size == array_view_internal::kArrayViewVarSize, ""); - RTC_DCHECK_EQ(0, size); + // RTC_DCHECK_EQ(0, size); } // Construct an ArrayView from a C-style array. @@ -182,8 +182,8 @@ class ArrayView final : public array_view_internal::ArrayViewBase { // const, because the ArrayView doesn't own the array. (To prevent mutation, // use a const element type.) T& operator[](size_t idx) const { - RTC_DCHECK_LT(idx, this->size()); - RTC_DCHECK(this->data()); + // RTC_DCHECK_LT(idx, this->size()); + // RTC_DCHECK(this->data()); return this->data()[idx]; } T* begin() const { return this->data(); } diff --git a/src/common/enc_mark.h b/src/common/enc_mark.h new file mode 100644 index 0000000..ffcd995 --- /dev/null +++ b/src/common/enc_mark.h @@ -0,0 +1,31 @@ +/* + * @Author: DI JUNKUN + * @Date: 2025-01-08 + * Copyright (c) 2025 by DI JUNKUN, All Rights Reserved. + */ + +#ifndef _ENC_MARK_H_ +#define _ENC_MARK_H_ + +// L4S Explicit Congestion Notification (ECN) . +// https://www.rfc-editor.org/rfc/rfc9331.html ECT stands for ECN-Capable +// Transport and CE stands for Congestion Experienced. + +// RFC-3168, Section 5 +// +-----+-----+ +// | ECN FIELD | +// +-----+-----+ +// ECT CE [Obsolete] RFC 2481 names for the ECN bits. +// 0 0 Not-ECT +// 0 1 ECT(1) +// 1 0 ECT(0) +// 1 1 CE + +enum class EcnMarking { + kNotEct = 0, // Not ECN-Capable Transport + kEct1 = 1, // ECN-Capable Transport + kEct0 = 2, // Not used by L4s (or webrtc.) + kCe = 3, // Congestion experienced +}; + +#endif \ No newline at end of file diff --git a/src/common/mod_ops.h b/src/common/mod_ops.h new file mode 100644 index 0000000..cdb943c --- /dev/null +++ b/src/common/mod_ops.h @@ -0,0 +1,130 @@ +/* + * @Author: DI JUNKUN + * @Date: 2025-01-08 + * Copyright (c) 2025 by DI JUNKUN, All Rights Reserved. + */ + +#ifndef _MOD_OPS_H_ +#define _MOD_OPS_H_ + +#include +#include + +template // NOLINT +inline unsigned long Add(unsigned long a, unsigned long b) { // NOLINT + // RTC_DCHECK_LT(a, M); + unsigned long t = M - b % M; // NOLINT + unsigned long res = a - t; // NOLINT + if (t > a) return res + M; + return res; +} + +template // NOLINT +inline unsigned long Subtract(unsigned long a, unsigned long b) { // NOLINT + // RTC_DCHECK_LT(a, M); + unsigned long sub = b % M; // NOLINT + if (a < sub) return M - (sub - a); + return a - sub; +} + +// Calculates the forward difference between two wrapping numbers. +// +// Example: +// uint8_t x = 253; +// uint8_t y = 2; +// +// ForwardDiff(x, y) == 5 +// +// 252 253 254 255 0 1 2 3 +// ################################################# +// | | x | | | | | y | | +// ################################################# +// |----->----->----->----->-----> +// +// ForwardDiff(y, x) == 251 +// +// 252 253 254 255 0 1 2 3 +// ################################################# +// | | x | | | | | y | | +// ################################################# +// -->-----> |----->--- +// +// If M > 0 then wrapping occurs at M, if M == 0 then wrapping occurs at the +// largest value representable by T. +template +inline typename std::enable_if<(M > 0), T>::type ForwardDiff(T a, T b) { + static_assert(std::is_unsigned::value, + "Type must be an unsigned integer."); + // RTC_DCHECK_LT(a, M); + // RTC_DCHECK_LT(b, M); + return a <= b ? b - a : M - (a - b); +} + +template +inline typename std::enable_if<(M == 0), T>::type ForwardDiff(T a, T b) { + static_assert(std::is_unsigned::value, + "Type must be an unsigned integer."); + return b - a; +} + +template +inline T ForwardDiff(T a, T b) { + return ForwardDiff(a, b); +} + +// Calculates the reverse difference between two wrapping numbers. +// +// Example: +// uint8_t x = 253; +// uint8_t y = 2; +// +// ReverseDiff(y, x) == 5 +// +// 252 253 254 255 0 1 2 3 +// ################################################# +// | | x | | | | | y | | +// ################################################# +// <-----<-----<-----<-----<-----| +// +// ReverseDiff(x, y) == 251 +// +// 252 253 254 255 0 1 2 3 +// ################################################# +// | | x | | | | | y | | +// ################################################# +// ---<-----| |<-----<-- +// +// If M > 0 then wrapping occurs at M, if M == 0 then wrapping occurs at the +// largest value representable by T. +template +inline typename std::enable_if<(M > 0), T>::type ReverseDiff(T a, T b) { + static_assert(std::is_unsigned::value, + "Type must be an unsigned integer."); + // RTC_DCHECK_LT(a, M); + // RTC_DCHECK_LT(b, M); + return b <= a ? a - b : M - (b - a); +} + +template +inline typename std::enable_if<(M == 0), T>::type ReverseDiff(T a, T b) { + static_assert(std::is_unsigned::value, + "Type must be an unsigned integer."); + return a - b; +} + +template +inline T ReverseDiff(T a, T b) { + return ReverseDiff(a, b); +} + +// Calculates the minimum distance between to wrapping numbers. +// +// The minimum distance is defined as min(ForwardDiff(a, b), ReverseDiff(a, b)) +template +inline T MinDiff(T a, T b) { + static_assert(std::is_unsigned::value, + "Type must be an unsigned integer."); + return (std::min)(ForwardDiff(a, b), ReverseDiff(a, b)); +} + +#endif \ No newline at end of file diff --git a/src/common/sequence_number_unwrapper.h b/src/common/sequence_number_unwrapper.h new file mode 100644 index 0000000..043a160 --- /dev/null +++ b/src/common/sequence_number_unwrapper.h @@ -0,0 +1,73 @@ +/* + * @Author: DI JUNKUN + * @Date: 2025-01-08 + * Copyright (c) 2025 by DI JUNKUN, All Rights Reserved. + */ + +#ifndef _SEQUENCE_NUMBER_UNWRAPPER_H_ +#define _SEQUENCE_NUMBER_UNWRAPPER_H_ + +#include + +#include +#include +#include + +#include "sequence_number_util.h" + +// A sequence number unwrapper where the first unwrapped value equals the +// first value being unwrapped. +template +class SeqNumUnwrapper { + static_assert( + std::is_unsigned::value && + std::numeric_limits::max() < std::numeric_limits::max(), + "Type unwrapped must be an unsigned integer smaller than int64_t."); + + public: + // Unwraps `value` and updates the internal state of the unwrapper. + int64_t Unwrap(T value) { + if (!last_value_) { + last_unwrapped_ = {value}; + } else { + last_unwrapped_ += Delta(*last_value_, value); + } + + last_value_ = value; + return last_unwrapped_; + } + + // Returns the `value` without updating the internal state of the unwrapper. + int64_t PeekUnwrap(T value) const { + if (!last_value_) { + return value; + } + return last_unwrapped_ + Delta(*last_value_, value); + } + + // Resets the unwrapper to its initial state. Unwrapped sequence numbers will + // being at 0 after resetting. + void Reset() { + last_unwrapped_ = 0; + last_value_.reset(); + } + + private: + static int64_t Delta(T last_value, T new_value) { + constexpr int64_t kBackwardAdjustment = + M == 0 ? int64_t{std::numeric_limits::max()} + 1 : M; + int64_t result = ForwardDiff(last_value, new_value); + if (!AheadOrAt(new_value, last_value)) { + result -= kBackwardAdjustment; + } + return result; + } + + int64_t last_unwrapped_ = 0; + std::optional last_value_; +}; + +using RtpTimestampUnwrapper = SeqNumUnwrapper; +using RtpSequenceNumberUnwrapper = SeqNumUnwrapper; + +#endif \ No newline at end of file diff --git a/src/common/sequence_number_util.h b/src/common/sequence_number_util.h new file mode 100644 index 0000000..607938b --- /dev/null +++ b/src/common/sequence_number_util.h @@ -0,0 +1,73 @@ +/* + * @Author: DI JUNKUN + * @Date: 2025-01-08 + * Copyright (c) 2025 by DI JUNKUN, All Rights Reserved. + */ + +#ifndef _SEQUENCE_NUMBER_UTIL_H_ +#define _SEQUENCE_NUMBER_UTIL_H_ + +#include +#include + +#include "mod_ops.h" + +// Test if the sequence number `a` is ahead or at sequence number `b`. +// +// If `M` is an even number and the two sequence numbers are at max distance +// from each other, then the sequence number with the highest value is +// considered to be ahead. +template +inline typename std::enable_if<(M > 0), bool>::type AheadOrAt(T a, T b) { + static_assert(std::is_unsigned::value, + "Type must be an unsigned integer."); + const T maxDist = M / 2; + if (!(M & 1) && MinDiff(a, b) == maxDist) return b < a; + return ForwardDiff(b, a) <= maxDist; +} + +template +inline typename std::enable_if<(M == 0), bool>::type AheadOrAt(T a, T b) { + static_assert(std::is_unsigned::value, + "Type must be an unsigned integer."); + const T maxDist = std::numeric_limits::max() / 2 + T(1); + if (a - b == maxDist) return b < a; + return ForwardDiff(b, a) < maxDist; +} + +template +inline bool AheadOrAt(T a, T b) { + return AheadOrAt(a, b); +} + +// Test if the sequence number `a` is ahead of sequence number `b`. +// +// If `M` is an even number and the two sequence numbers are at max distance +// from each other, then the sequence number with the highest value is +// considered to be ahead. +template +inline bool AheadOf(T a, T b) { + static_assert(std::is_unsigned::value, + "Type must be an unsigned integer."); + return a != b && AheadOrAt(a, b); +} + +// Comparator used to compare sequence numbers in a continuous fashion. +// +// WARNING! If used to sort sequence numbers of length M then the interval +// covered by the sequence numbers may not be larger than floor(M/2). +template +struct AscendingSeqNumComp { + bool operator()(T a, T b) const { return AheadOf(a, b); } +}; + +// Comparator used to compare sequence numbers in a continuous fashion. +// +// WARNING! If used to sort sequence numbers of length M then the interval +// covered by the sequence numbers may not be larger than floor(M/2). +template +struct DescendingSeqNumComp { + bool operator()(T a, T b) const { return AheadOf(b, a); } +}; + +#endif \ No newline at end of file diff --git a/src/qos/congestion_control_feedback.cpp b/src/qos/congestion_control_feedback.cpp index 44e8454..c7e95d3 100644 --- a/src/qos/congestion_control_feedback.cpp +++ b/src/qos/congestion_control_feedback.cpp @@ -96,6 +96,10 @@ uint16_t To2BitEcn(EcnMarking ecn_marking) { return kEcnEct0 << 13; case EcnMarking::kCe: return kEcnCe << 13; + default: { + LOG_FATAL("Unexpected ecn marking: {}", static_cast(ecn_marking)); + return 0; + } } } @@ -193,6 +197,8 @@ bool CongestionControlFeedback::Create(uint8_t* buffer, size_t* position, ByteWriter::WriteBigEndian(&buffer[*position], 0); *position += 2; } + + return true; }; ArrayView remaining(packets_); @@ -255,7 +261,7 @@ size_t CongestionControlFeedback::BlockLength() const { return total_size; } -bool CongestionControlFeedback::Parse(const rtcp::CommonHeader& packet) { +bool CongestionControlFeedback::Parse(const RtcpCommonHeader& packet) { const uint8_t* payload = packet.payload(); const uint8_t* payload_end = packet.payload() + packet.payload_size_bytes(); @@ -291,12 +297,11 @@ bool CongestionControlFeedback::Parse(const rtcp::CommonHeader& packet) { uint16_t seq_no = base_seqno + i; bool received = (packet_info & 0x8000); - packets_.push_back( - {.ssrc = ssrc, - .sequence_number = seq_no, - .arrival_time_offset = received ? AtoToTimeDelta(packet_info) - : TimeDelta::MinusInfinity(), - .ecn = ToEcnMarking(packet_info)}); + packets_.push_back(PacketInfo{ssrc, seq_no, + received + ? AtoToTimeDelta(packet_info) + : std::numeric_limits::min(), + ToEcnMarking(packet_info)}); } if (num_reports % 2) { // 2 bytes padding diff --git a/src/qos/congestion_control_feedback.h b/src/qos/congestion_control_feedback.h index 9a20bd3..502fb33 100644 --- a/src/qos/congestion_control_feedback.h +++ b/src/qos/congestion_control_feedback.h @@ -13,29 +13,9 @@ #include #include "array_view.h" +#include "enc_mark.h" #include "rtp_feedback.h" -// L4S Explicit Congestion Notification (ECN) . -// https://www.rfc-editor.org/rfc/rfc9331.html ECT stands for ECN-Capable -// Transport and CE stands for Congestion Experienced. - -// RFC-3168, Section 5 -// +-----+-----+ -// | ECN FIELD | -// +-----+-----+ -// ECT CE [Obsolete] RFC 2481 names for the ECN bits. -// 0 0 Not-ECT -// 0 1 ECT(1) -// 1 0 ECT(0) -// 1 1 CE - -enum class EcnMarking { - kNotEct = 0, // Not ECN-Capable Transport - kEct1 = 1, // ECN-Capable Transport - kEct0 = 2, // Not used by L4s (or webrtc.) - kCe = 3, // Congestion experienced -}; - // Congestion control feedback message as specified in // https://www.rfc-editor.org/rfc/rfc8888.html class CongestionControlFeedback : public RtpFeedback { @@ -58,7 +38,7 @@ class CongestionControlFeedback : public RtpFeedback { uint32_t report_timestamp_compact_ntp); CongestionControlFeedback() = default; - bool Parse(const CommonHeader& packet); + bool Parse(const RtcpCommonHeader& packet); ArrayView packets() const { return packets_; } diff --git a/src/qos/congestion_control_feedback_generator.cpp b/src/qos/congestion_control_feedback_generator.cpp index 7781776..4c2047f 100644 --- a/src/qos/congestion_control_feedback_generator.cpp +++ b/src/qos/congestion_control_feedback_generator.cpp @@ -21,7 +21,7 @@ CongestionControlFeedbackGenerator::CongestionControlFeedbackGenerator( : rtcp_sender_(std::move(rtcp_sender)) {} void CongestionControlFeedbackGenerator::OnReceivedPacket( - const RtpPacketReceived& packet) { + RtpPacketReceived& packet) { marker_bit_seen_ |= packet.Marker(); if (!first_arrival_time_since_feedback_) { first_arrival_time_since_feedback_ = packet.arrival_time(); @@ -63,19 +63,19 @@ int64_t CongestionControlFeedbackGenerator::Process(int64_t now_ms) { } void CongestionControlFeedbackGenerator::OnSendBandwidthEstimateChanged( - DataRate estimate) { + int64_t estimate) { // Feedback reports should max occupy 5% of total bandwidth. max_feedback_rate_ = estimate * 0.05; } void CongestionControlFeedbackGenerator::SetTransportOverhead( - DataSize overhead_per_packet) { + int64_t overhead_per_packet) { packet_overhead_ = overhead_per_packet; } void CongestionControlFeedbackGenerator::SendFeedback(int64_t now_ms) { uint32_t compact_ntp = ConvertToCompactNtp(now_ms); - std::vector rtcp_packet_info; + std::vector rtcp_packet_info; for (auto& [unused, tracker] : feedback_trackers_) { tracker.AddPacketsToFeedback(now_ms, rtcp_packet_info); } @@ -83,18 +83,18 @@ void CongestionControlFeedbackGenerator::SendFeedback(int64_t now_ms) { marker_bit_seen_ = false; first_arrival_time_since_feedback_ = std::nullopt; - auto feedback = std::make_unique( + auto feedback = std::make_unique( std::move(rtcp_packet_info), compact_ntp); CalculateNextPossibleSendTime(feedback->BlockLength(), now_ms); - std::vector> rtcp_packets; + std::vector> rtcp_packets; rtcp_packets.push_back(std::move(feedback)); rtcp_sender_(std::move(rtcp_packets)); } void CongestionControlFeedbackGenerator::CalculateNextPossibleSendTime( int64_t feedback_size, int64_t now_ms) { - int64_t time_since_last_sent = now - last_feedback_sent_time_; + int64_t time_since_last_sent = now_ms - last_feedback_sent_time_; size_t debt_payed = time_since_last_sent * max_feedback_rate_; send_rate_debt_ = debt_payed > send_rate_debt_ ? 0 : send_rate_debt_ - debt_payed; diff --git a/src/qos/congestion_control_feedback_generator.h b/src/qos/congestion_control_feedback_generator.h index 7953601..af43ae6 100644 --- a/src/qos/congestion_control_feedback_generator.h +++ b/src/qos/congestion_control_feedback_generator.h @@ -10,43 +10,22 @@ #include #include +#include "congestion_control_feedback_tracker.h" #include "rtcp_packet.h" #include "rtp_packet_received.h" -class RtpTransportFeedbackGenerator { +class CongestionControlFeedbackGenerator { public: - // Function intented to be used for sending RTCP messages generated by an - // implementation of this class. - using RtcpSender = - std::function> packets)>; - virtual ~RtpTransportFeedbackGenerator() = default; - - virtual void OnReceivedPacket(const RtpPacketReceived& packet) = 0; - - // Sends periodic feedback if it is time to send it. - // Returns time until next call to Process should be made. - virtual int64_t Process(int64_t now) = 0; - - virtual void OnSendBandwidthEstimateChanged(int64_t estimate) = 0; - - // Overhead from transport layers below RTP. Ie, IP, SRTP. - virtual void SetTransportOverhead(DataSize overhead_per_packet) = 0; -}; - -class CongestionControlFeedbackGenerator - : public RtpTransportFeedbackGenerator { - public: - CongestionControlFeedbackGenerator( - RtpTransportFeedbackGenerator::RtcpSender feedback_sender); + CongestionControlFeedbackGenerator(RtcpSender feedback_sender); ~CongestionControlFeedbackGenerator() = default; - void OnReceivedPacket(const RtpPacketReceived& packet) override; + void OnReceivedPacket(RtpPacketReceived& packet); - void OnSendBandwidthEstimateChanged(int64_t estimate) override; + void OnSendBandwidthEstimateChanged(int64_t estimate); - int64_t Process(int64_t now_ms) override; + int64_t Process(int64_t now_ms); - void SetTransportOverhead(DataSize overhead_per_packet) override; + void SetTransportOverhead(int64_t overhead_per_packet); private: int64_t NextFeedbackTime() const; @@ -55,6 +34,8 @@ class CongestionControlFeedbackGenerator void CalculateNextPossibleSendTime(int64_t feedback_size, int64_t now_ms); + const RtcpSender rtcp_sender_; + private: // Feedback should not use more than 5% of the configured send bandwidth // estimate. Min and max duration between feedback is configurable using field @@ -73,6 +54,9 @@ class CongestionControlFeedbackGenerator int64_t packet_overhead_ = 0; int64_t send_rate_debt_ = 0; + std::map + feedback_trackers_; + std::optional first_arrival_time_since_feedback_; int64_t next_possible_feedback_send_time_ = 0; int64_t last_feedback_sent_time_ = 0; diff --git a/src/qos/congestion_control_feedback_tracker.cpp b/src/qos/congestion_control_feedback_tracker.cpp index 473d4a7..5f33271 100644 --- a/src/qos/congestion_control_feedback_tracker.cpp +++ b/src/qos/congestion_control_feedback_tracker.cpp @@ -1,5 +1,6 @@ #include "congestion_control_feedback_tracker.h" +#include #include #include #include @@ -7,7 +8,7 @@ #include "log.h" void CongestionControlFeedbackTracker::ReceivedPacket( - const RtpPacketReceived& packet) { + RtpPacketReceived& packet) { int64_t unwrapped_sequence_number = unwrapper_.Unwrap(packet.SequenceNumber()); if (last_sequence_number_in_feedback_ && @@ -25,10 +26,8 @@ void CongestionControlFeedbackTracker::ReceivedPacket( // received. last_sequence_number_in_feedback_ = unwrapped_sequence_number - 1; } - packets_.push_back({.ssrc = packet.Ssrc(), - .unwrapped_sequence_number = unwrapped_sequence_number, - .arrival_time = packet.arrival_time(), - .ecn = packet.ecn()}); + packets_.push_back({packet.Ssrc(), unwrapped_sequence_number, + packet.arrival_time(), packet.ecn()}); } void CongestionControlFeedbackTracker::AddPacketsToFeedback( @@ -37,10 +36,11 @@ void CongestionControlFeedbackTracker::AddPacketsToFeedback( if (packets_.empty()) { return; } - absl::c_sort(packets_, [](const PacketInfo& a, const PacketInfo& b) { - return std::tie(a.unwrapped_sequence_number, a.arrival_time) < - std::tie(b.unwrapped_sequence_number, b.arrival_time); - }); + std::sort(packets_.begin(), packets_.end(), + [](const PacketInfo& a, const PacketInfo& b) { + return std::tie(a.unwrapped_sequence_number, a.arrival_time) < + std::tie(b.unwrapped_sequence_number, b.arrival_time); + }); if (!last_sequence_number_in_feedback_) { last_sequence_number_in_feedback_ = packets_.front().unwrapped_sequence_number - 1; @@ -61,7 +61,7 @@ void CongestionControlFeedbackTracker::AddPacketsToFeedback( } EcnMarking ecn = EcnMarking::kNotEct; - TimeDelta arrival_time_offset = TimeDelta::MinusInfinity(); + int64_t arrival_time_offset = std::numeric_limits::min(); if (sequence_number == packet_it->unwrapped_sequence_number) { arrival_time_offset = feedback_time - packet_it->arrival_time; @@ -83,11 +83,8 @@ void CongestionControlFeedbackTracker::AddPacketsToFeedback( ++packet_it; } } // else - the packet has not been received yet. - packet_feedback.push_back( - {.ssrc = ssrc, - .sequence_number = static_cast(sequence_number), - .arrival_time_offset = arrival_time_offset, - .ecn = ecn}); + packet_feedback.push_back({ssrc, static_cast(sequence_number), + arrival_time_offset, ecn}); } last_sequence_number_in_feedback_ = packets_.back().unwrapped_sequence_number; packets_.clear(); diff --git a/src/qos/congestion_control_feedback_tracker.h b/src/qos/congestion_control_feedback_tracker.h index 6f96404..760e066 100644 --- a/src/qos/congestion_control_feedback_tracker.h +++ b/src/qos/congestion_control_feedback_tracker.h @@ -11,13 +11,15 @@ #include #include "congestion_control_feedback.h" +#include "enc_mark.h" #include "rtp_packet_received.h" +#include "sequence_number_unwrapper.h" class CongestionControlFeedbackTracker { public: CongestionControlFeedbackTracker() = default; - void ReceivedPacket(const RtpPacketReceived& packet); + void ReceivedPacket(RtpPacketReceived& packet); // Adds received packets to `packet_feedback` // RTP sequence numbers are continous from the last created feedback unless diff --git a/src/qos/receive_side_congestion_controller.cpp b/src/qos/receive_side_congestion_controller.cpp index 7de3985..644abb5 100644 --- a/src/qos/receive_side_congestion_controller.cpp +++ b/src/qos/receive_side_congestion_controller.cpp @@ -11,6 +11,7 @@ #include "receive_side_congestion_controller.h" #include +#include #include #include @@ -18,99 +19,33 @@ namespace { static const uint32_t kTimeOffsetSwitchThreshold = 30; } // namespace -void ReceiveSideCongestionController::OnRttUpdate(int64_t avg_rtt_ms, - int64_t max_rtt_ms) { - std::lock_guard guard(mutex_); - rbe_->OnRttUpdate(avg_rtt_ms, max_rtt_ms); -} - -void ReceiveSideCongestionController::RemoveStream(uint32_t ssrc) { - std::lock_guard guard(mutex_); - rbe_->RemoveStream(ssrc); -} - -int64_t ReceiveSideCongestionController::LatestReceiveSideEstimate() const { - std::lock_guard guard(mutex_); - return rbe_->LatestEstimate(); -} - -void ReceiveSideCongestionController::PickEstimator( - bool has_absolute_send_time) { - if (has_absolute_send_time) { - // If we see AST in header, switch RBE strategy immediately. - if (!using_absolute_send_time_) { - RTC_LOG(LS_INFO) - << "WrappingBitrateEstimator: Switching to absolute send time RBE."; - using_absolute_send_time_ = true; - // rbe_ = std::make_unique( - // env_, &remb_throttler_); - } - packets_since_absolute_send_time_ = 0; - } else { - // When we don't see AST, wait for a few packets before going back to TOF. - if (using_absolute_send_time_) { - ++packets_since_absolute_send_time_; - if (packets_since_absolute_send_time_ >= kTimeOffsetSwitchThreshold) { - RTC_LOG(LS_INFO) - << "WrappingBitrateEstimator: Switching to transmission " - "time offset RBE."; - using_absolute_send_time_ = false; - // rbe_ = std::make_unique( - // env_, &remb_throttler_); - } - } - } -} - ReceiveSideCongestionController::ReceiveSideCongestionController( - const Environment& env, - TransportSequenceNumberFeedbackGenenerator::RtcpSender feedback_sender, - RembThrottler::RembSender remb_sender, - absl::Nullable network_state_estimator) - : env_(env), - // remb_throttler_(std::move(remb_sender), &env_.clock()),, - congestion_control_feedback_generator_(env, feedback_sender), - // rbe_(std::make_unique( - // env_, &remb_throttler_)), + RtcpSender feedback_sender) + : congestion_control_feedback_generator_(feedback_sender), using_absolute_send_time_(false), - packets_since_absolute_send_time_(0) { - FieldTrialParameter force_send_rfc8888_feedback("force_send", false); - ParseFieldTrial( - {&force_send_rfc8888_feedback}, - env.field_trials().Lookup("WebRTC-RFC8888CongestionControlFeedback")); - if (force_send_rfc8888_feedback) { - EnablSendCongestionControlFeedbackAccordingToRfc8888(); - } -} - -void ReceiveSideCongestionController:: - EnablSendCongestionControlFeedbackAccordingToRfc8888() { - // RTC_DCHECK_RUN_ON(&sequence_checker_); - send_rfc8888_congestion_feedback_ = true; -} + packets_since_absolute_send_time_(0) {} void ReceiveSideCongestionController::OnReceivedPacket( - const RtpPacketReceived& packet, MediaType media_type) { - if (send_rfc8888_congestion_feedback_) { - // RTC_DCHECK_RUN_ON(&sequence_checker_); - congestion_control_feedback_generator_.OnReceivedPacket(packet); - return; - } + RtpPacketReceived& packet, MediaType media_type) { + // RTC_DCHECK_RUN_ON(&sequence_checker_); + congestion_control_feedback_generator_.OnReceivedPacket(packet); + return; } void ReceiveSideCongestionController::OnBitrateChanged(int bitrate_bps) { // RTC_DCHECK_RUN_ON(&sequence_checker_); - int64_t send_bandwidth_estimate = int64_t::BitsPerSec(bitrate_bps); + int64_t send_bandwidth_estimate = bitrate_bps; congestion_control_feedback_generator_.OnSendBandwidthEstimateChanged( send_bandwidth_estimate); } int64_t ReceiveSideCongestionController::MaybeProcess() { - int64_t now = env_.clock().CurrentTime(); - if (send_rfc8888_congestion_feedback_) { - // RTC_DCHECK_RUN_ON(&sequence_checker_); - return congestion_control_feedback_generator_.Process(now); - } + auto now = std::chrono::system_clock::now(); + int64_t now_ms = std::chrono::duration_cast( + now.time_since_epoch()) + .count(); + // RTC_DCHECK_RUN_ON(&sequence_checker_); + return congestion_control_feedback_generator_.Process(now_ms); } void ReceiveSideCongestionController::SetMaxDesiredReceiveBitrate( diff --git a/src/qos/receive_side_congestion_controller.h b/src/qos/receive_side_congestion_controller.h index 1c93124..b242c01 100644 --- a/src/qos/receive_side_congestion_controller.h +++ b/src/qos/receive_side_congestion_controller.h @@ -17,14 +17,11 @@ class ReceiveSideCongestionController { enum MediaType { VIDEO, AUDIO, DATA }; public: - ReceiveSideCongestionController(); - ~ReceiveSideCongestionController() override = default; + ReceiveSideCongestionController(RtcpSender feedback_sender); + ~ReceiveSideCongestionController() = default; public: - void OnReceivedPacket(const RtpPacketReceived& packet, MediaType media_type); - - // Implements CallStatsObserver. - void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) override; + void OnReceivedPacket(RtpPacketReceived& packet, MediaType media_type); // This is send bitrate, used to control the rate of feedback messages. void OnBitrateChanged(int bitrate_bps); @@ -35,21 +32,11 @@ class ReceiveSideCongestionController { void SetTransportOverhead(int64_t overhead_per_packet); - // Returns latest receive side bandwidth estimation. - // Returns zero if receive side bandwidth estimation is unavailable. - int64_t LatestReceiveSideEstimate() const; - - // Removes stream from receive side bandwidth estimation. - // Noop if receive side bwe is not used or stream doesn't participate in it. - void RemoveStream(uint32_t ssrc); - // Runs periodic tasks if it is time to run them, returns time until next // call to `MaybeProcess` should be non idle. int64_t MaybeProcess(); private: - void PickEstimator(bool has_absolute_send_time); - // RembThrottler remb_throttler_; // TODO: bugs.webrtc.org/42224904 - Use sequence checker for all usage of @@ -58,13 +45,11 @@ class ReceiveSideCongestionController { // arbitrary thread by external projects. // SequenceChecker sequence_checker_; - bool send_rfc8888_congestion_feedback_ = false; CongestionControlFeedbackGenerator congestion_control_feedback_generator_; std::mutex mutex_; - std::unique_ptr rbe_; bool using_absolute_send_time_; - uint32_t packets_since_absolute_send_time_ RTC_GUARDED_BY(mutex_); + uint32_t packets_since_absolute_send_time_; }; #endif \ No newline at end of file diff --git a/src/rtcp/rtcp_packet/common_header.cpp b/src/rtcp/rtcp_packet/common_header.cpp index ea6f2b6..9290443 100644 --- a/src/rtcp/rtcp_packet/common_header.cpp +++ b/src/rtcp/rtcp_packet/common_header.cpp @@ -24,7 +24,7 @@ // --------------------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // // Common header for all RTCP packets, 4 octets. -bool CommonHeader::Parse(const uint8_t* buffer, size_t size_bytes) { +bool RtcpCommonHeader::Parse(const uint8_t* buffer, size_t size_bytes) { const uint8_t kVersion = 2; if (size_bytes < kHeaderSizeBytes) { diff --git a/src/rtcp/rtcp_packet/common_header.h b/src/rtcp/rtcp_packet/common_header.h index 6e76e2c..ed382d4 100644 --- a/src/rtcp/rtcp_packet/common_header.h +++ b/src/rtcp/rtcp_packet/common_header.h @@ -13,13 +13,13 @@ #include #include -class CommonHeader { +class RtcpCommonHeader { public: static constexpr size_t kHeaderSizeBytes = 4; - CommonHeader() {} - CommonHeader(const CommonHeader&) = default; - CommonHeader& operator=(const CommonHeader&) = default; + RtcpCommonHeader() {} + RtcpCommonHeader(const RtcpCommonHeader&) = default; + RtcpCommonHeader& operator=(const RtcpCommonHeader&) = default; bool Parse(const uint8_t* buffer, size_t size_bytes); diff --git a/src/rtcp/rtcp_packet/rtcp_packet.h b/src/rtcp/rtcp_packet/rtcp_packet.h index 4e055cd..470fa05 100644 --- a/src/rtcp/rtcp_packet/rtcp_packet.h +++ b/src/rtcp/rtcp_packet/rtcp_packet.h @@ -11,6 +11,7 @@ #include #include +#include #include class RtcpPacket { @@ -59,4 +60,7 @@ class RtcpPacket { uint32_t sender_ssrc_ = 0; }; +using RtcpSender = + std::function> packets)>; + #endif \ No newline at end of file diff --git a/src/rtp/rtp_packet/rtp_packet.h b/src/rtp/rtp_packet/rtp_packet.h index fa66d8b..9c78f40 100644 --- a/src/rtp/rtp_packet/rtp_packet.h +++ b/src/rtp/rtp_packet/rtp_packet.h @@ -190,7 +190,7 @@ class RtpPacket { RtpPacket &operator=(const RtpPacket &rtp_packet); RtpPacket &operator=(RtpPacket &&rtp_packet); - ~RtpPacket(); + virtual ~RtpPacket(); public: // Set Header diff --git a/src/rtp/rtp_packet/rtp_packet_received.cpp b/src/rtp/rtp_packet/rtp_packet_received.cpp index 9101460..3201fbc 100644 --- a/src/rtp/rtp_packet/rtp_packet_received.cpp +++ b/src/rtp/rtp_packet/rtp_packet_received.cpp @@ -1,8 +1,6 @@ #include "rtp_packet_received.h" RtpPacketReceived::RtpPacketReceived() = default; -RtpPacketReceived::RtpPacketReceived(int64_t arrival_time) - : arrival_time_(arrival_time) {} RtpPacketReceived::RtpPacketReceived(const RtpPacketReceived& packet) = default; RtpPacketReceived::RtpPacketReceived(RtpPacketReceived&& packet) = default; diff --git a/src/rtp/rtp_packet/rtp_packet_received.h b/src/rtp/rtp_packet/rtp_packet_received.h index 2a60383..ab4e984 100644 --- a/src/rtp/rtp_packet/rtp_packet_received.h +++ b/src/rtp/rtp_packet/rtp_packet_received.h @@ -9,13 +9,12 @@ #include +#include "enc_mark.h" #include "rtp_packet.h" class RtpPacketReceived : public RtpPacket { public: RtpPacketReceived(); - explicit RtpPacketReceived( - int64_t arrival_time = (std::numeric_limits::min)()); RtpPacketReceived(const RtpPacketReceived& packet); RtpPacketReceived(RtpPacketReceived&& packet); @@ -24,8 +23,29 @@ class RtpPacketReceived : public RtpPacket { ~RtpPacketReceived(); + public: + int64_t arrival_time() const { return arrival_time_; } + void set_arrival_time(int64_t time) { arrival_time_ = time; } + + // Explicit Congestion Notification (ECN), RFC-3168, Section 5. + // Used by L4S: https://www.rfc-editor.org/rfc/rfc9331.html + EcnMarking ecn() const { return ecn_; } + void set_ecn(EcnMarking ecn) { ecn_ = ecn; } + + // Flag if packet was recovered via RTX or FEC. + bool recovered() const { return recovered_; } + void set_recovered(bool value) { recovered_ = value; } + + int payload_type_frequency() const { return payload_type_frequency_; } + void set_payload_type_frequency(int value) { + payload_type_frequency_ = value; + } + private: - int64_t arrival_time_ = (std::numeric_limits::min)(); + int64_t arrival_time_ = std::numeric_limits::min(); + EcnMarking ecn_ = EcnMarking::kNotEct; + int payload_type_frequency_ = 0; + bool recovered_ = false; }; #endif \ No newline at end of file diff --git a/xmake.lua b/xmake.lua index bae2b48..3e77c30 100644 --- a/xmake.lua +++ b/xmake.lua @@ -10,7 +10,8 @@ set_installdir("$(projectdir)/out") add_defines("ASIO_STANDALONE", "ASIO_HAS_STD_TYPE_TRAITS", "ASIO_HAS_STD_SHARED_PTR", "ASIO_HAS_STD_ADDRESSOF", "ASIO_HAS_STD_ATOMIC", "ASIO_HAS_STD_CHRONO", - "ASIO_HAS_CSTDINT", "ASIO_HAS_STD_ARRAY", "ASIO_HAS_STD_SYSTEM_ERROR") + "ASIO_HAS_CSTDINT", "ASIO_HAS_STD_ARRAY", "ASIO_HAS_STD_SYSTEM_ERROR", + "NOMINMAX") add_requires("asio 1.24.0", "nlohmann_json 3.11.3", "spdlog 1.14.1", "openfec 1.4.2", "libopus 1.5.1", "openh264 2.4.1", "dav1d 1.4.3", "libyuv 2024.5.21", "aom 3.9.0", {system = false}, {configs = {shared = false}}) add_packages("asio", "nlohmann_json", "spdlog", "openfec", "libopus", "openh264", "dav1d", "libyuv", "aom") @@ -76,27 +77,6 @@ target("statistics") add_files("src/statistics/*.cpp") add_includedirs("src/statistics", {public = true}) -target("rtcp") - set_kind("object") - add_deps("log", "common") - add_files("src/rtcp/*.cpp", - "src/rtcp/rtcp_packet/*.cpp", - "src/rtcp/rtp_feedback/*.cpp") - add_includedirs("src/rtcp", - "src/rtcp/rtcp_packet", - "src/rtcp/rtp_feedback", {public = true}) - -target("rtp", "qos") - set_kind("object") - add_deps("log", "frame", "ringbuffer", "thread", "rtcp", "fec", "statistics") - add_files("src/rtp/*.cpp", - "src/rtp/rtp_endpoint/*.cpp", - "src/rtp/rtp_packet/*.cpp") - add_includedirs("src/rtp", - "src/rtp/rtp_endpoint", - "src/rtp/rtp_packet", - "src/qos", {public = true}) - target("ice") set_kind("object") add_deps("log", "common", "ws") @@ -115,7 +95,44 @@ target("ws") set_kind("object") add_deps("log") add_files("src/ws/*.cpp") - add_includedirs("thirdparty/websocketpp/include", {public = true}) + add_includedirs("src/ws", + "thirdparty/websocketpp/include", {public = true}) + +target("rtp") + set_kind("object") + add_deps("log", "frame", "ringbuffer", "thread", "rtcp", "fec", "statistics") + add_files("src/rtp/*.cpp", + "src/rtp/rtp_packet/*.cpp") + add_includedirs("src/rtp", + "src/rtp/rtp_packet", {public = true}) + +target("rtcp") + set_kind("object") + add_deps("log", "common") + add_files("src/rtcp/*.cpp", + "src/rtcp/rtcp_packet/*.cpp", + "src/rtcp/rtp_feedback/*.cpp") + add_includedirs("src/rtcp", + "src/rtcp/rtcp_packet", + "src/rtcp/rtp_feedback", {public = true}) + +target("qos") + set_kind("object") + add_deps("log", "rtp") + add_files("src/qos/*.cpp") + add_includedirs("src/qos", {public = true}) + +target("channel") + set_kind("object") + add_deps("log", "rtp", "rtcp", "ice", "qos") + add_files("src/channel/*.cpp", "src/channel/rtp_channel/*.cpp") + add_includedirs("src/channel", "src/channel/rtp_channel", {public = true}) + +target("transport") + set_kind("object") + add_deps("log", "ws", "ice", "channel", "rtp", "rtcp", "statistics", "media") + add_files("src/transport/*.cpp") + add_includedirs("src/transport", {public = true}) target("media") set_kind("object") @@ -187,41 +204,17 @@ target("media") add_includedirs("src/media/audio/encode", "src/media/audio/decode", "src/interface", {public = true}) -target("qos") - set_kind("object") - add_deps("log", "rtp") - add_files("src/qos/*.cpp") - add_includedirs("src/qos", {public = true}) - --- target("transport") --- set_kind("object") --- add_deps("log", "ws", "ice", "qos", "rtp", "rtcp", "statistics", "media") --- add_files("src/transport/*.cpp") --- add_includedirs("src/ws", "src/ice", "src/qos", {public = true}) - -target("transport") - set_kind("object") - add_deps("log", "ws", "ice", "channel", "rtp", "rtcp", "statistics", "media") - add_files("src/transport/*.cpp") - add_includedirs("src/ws", "src/ice", "src/channel", {public = true}) - -target("channel") - set_kind("object") - add_deps("log", "rtp", "rtcp", "ice") - add_files("src/channel/*.cpp") - add_includedirs("src/rtp", "src/rtcp", {public = true}) - target("pc") set_kind("object") add_deps("log", "ws", "ice", "transport", "inih", "common") add_files("src/pc/*.cpp") - add_includedirs("src/transport", "src/interface", {public = true}) + add_includedirs("src/pc", "src/interface", {public = true}) target("projectx") set_kind("static") add_deps("log", "pc") add_files("src/rtc/*.cpp") - add_includedirs("src/rtc", "src/pc", "src/interface") + add_includedirs("src/rtc", "src/interface") if is_os("windows") then add_linkdirs("thirdparty/nvcodec/lib/x64")