diff --git a/src/channel/rtcp_channel/rtcp_receiver.cpp b/src/channel/rtcp_channel/rtcp_receiver.cpp new file mode 100644 index 0000000..165abac --- /dev/null +++ b/src/channel/rtcp_channel/rtcp_receiver.cpp @@ -0,0 +1,5 @@ +#include "rtcp_receiver.h" + +RtcpReceiver::RtcpReceiver() {} + +RtcpReceiver::~RtcpReceiver() {} \ No newline at end of file diff --git a/src/channel/rtcp_channel/rtcp_receiver.h b/src/channel/rtcp_channel/rtcp_receiver.h new file mode 100644 index 0000000..0e62a9a --- /dev/null +++ b/src/channel/rtcp_channel/rtcp_receiver.h @@ -0,0 +1,19 @@ +/* + * @Author: DI JUNKUN + * @Date: 2025-02-17 + * Copyright (c) 2025 by DI JUNKUN, All Rights Reserved. + */ + +#ifndef _RTCP_RECEIVER_H_ +#define _RTCP_RECEIVER_H_ + +class RtcpReceiver { + public: + RtcpReceiver(); + ~RtcpReceiver(); + + public: + private: +} + +#endif \ No newline at end of file diff --git a/src/channel/rtcp_channel/rtcp_sender.cpp b/src/channel/rtcp_channel/rtcp_sender.cpp new file mode 100644 index 0000000..71140e4 --- /dev/null +++ b/src/channel/rtcp_channel/rtcp_sender.cpp @@ -0,0 +1,43 @@ +#include "rtcp_sender.h" + +RtcpSender::RtcpSender(std::shared_ptr clock, uint32_t ssrc) + : clock_(clock), ssrc_(ssrc) {} + +RtcpSender::~RtcpSender() {} + +void RtcpSender::BuildSR(const RtcpContext& ctx, PacketSender& sender) { + // The timestamp of this RTCP packet should be estimated as the timestamp of + // the frame being captured at this moment. We are calculating that + // timestamp as the last frame's timestamp + the time since the last frame + // was captured. + int rtp_rate = rtp_clock_rates_khz_[last_payload_type_]; + if (rtp_rate <= 0) { + rtp_rate = + (audio_ ? kBogusRtpRateForAudioRtcp : kVideoPayloadTypeFrequency) / + 1000; + } + // Round now_us_ to the closest millisecond, because Ntp time is rounded + // when converted to milliseconds, + uint32_t rtp_timestamp = + timestamp_offset_ + last_rtp_timestamp_ + + ((ctx.now_.us() + 500) / 1000 - last_frame_capture_time_->ms()) * + rtp_rate; + + rtcp::SenderReport report; + report.SetSenderSsrc(ssrc_); + report.SetNtp(env_.clock().ConvertTimestampToNtpTime(ctx.now_)); + report.SetRtpTimestamp(rtp_timestamp); + report.SetPacketCount(ctx.feedback_state_.packets_sent); + report.SetOctetCount(ctx.feedback_state_.media_bytes_sent); + report.SetReportBlocks(CreateReportBlocks(ctx.feedback_state_)); + sender.AppendPacket(report); +} + +void RtcpSender::BuildRR(const RtcpContext& ctx, PacketSender& sender) { + rtcp::ReceiverReport report; + report.SetSenderSsrc(ssrc_); + report.SetReportBlocks(CreateReportBlocks(ctx.feedback_state_)); + if (method_ == RtcpMode::kCompound || !report.report_blocks().empty()) { + sender.AppendPacket(report); + } +} \ No newline at end of file diff --git a/src/channel/rtcp_channel/rtcp_sender.h b/src/channel/rtcp_channel/rtcp_sender.h new file mode 100644 index 0000000..f8e4b2f --- /dev/null +++ b/src/channel/rtcp_channel/rtcp_sender.h @@ -0,0 +1,26 @@ +/* + * @Author: DI JUNKUN + * @Date: 2025-02-17 + * Copyright (c) 2025 by DI JUNKUN, All Rights Reserved. + */ + +#ifndef _RTCP_SENDER_H_ +#define _RTCP_SENDER_H_ + +#include + +#include "api/clock/clock.h" +#include "rtcp/rtcp_packet/rtcp_packet.h" + +class RtcpSender { + public: + RtcpSender(std::shared_ptr clock, uint32_t ssrc); + ~RtcpSender(); + + public: + private: + std::shared_ptr clock_; + uint32_t ssrc_; +} + +#endif \ No newline at end of file diff --git a/src/rtcp/congestion_control_feedback.cpp b/src/rtcp/congestion_control_feedback.cpp index 1784215..b6b6b56 100644 --- a/src/rtcp/congestion_control_feedback.cpp +++ b/src/rtcp/congestion_control_feedback.cpp @@ -261,7 +261,7 @@ size_t CongestionControlFeedback::BlockLength() const { return total_size; } -bool CongestionControlFeedback::Parse(const rtcp::CommonHeader& packet) { +bool CongestionControlFeedback::Parse(const CommonHeader& packet) { const uint8_t* payload = packet.payload(); const uint8_t* payload_end = packet.payload() + packet.payload_size_bytes(); diff --git a/src/rtcp/rtcp_packet/common_header.cpp b/src/rtcp/rtcp_packet/common_header.cpp index 6908cce..a9f480d 100644 --- a/src/rtcp/rtcp_packet/common_header.cpp +++ b/src/rtcp/rtcp_packet/common_header.cpp @@ -13,8 +13,6 @@ #include "byte_io.h" #include "log.h" -namespace webrtc { -namespace rtcp { // 0 1 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -83,5 +81,3 @@ bool CommonHeader::Parse(const uint8_t* buffer, size_t size_bytes) { } return true; } -} // namespace rtcp -} // namespace webrtc diff --git a/src/rtcp/rtcp_packet/common_header.h b/src/rtcp/rtcp_packet/common_header.h index 5416406..984015a 100644 --- a/src/rtcp/rtcp_packet/common_header.h +++ b/src/rtcp/rtcp_packet/common_header.h @@ -13,8 +13,6 @@ #include #include -namespace webrtc { -namespace rtcp { class CommonHeader { public: static constexpr size_t kHeaderSizeBytes = 4; @@ -47,6 +45,5 @@ class CommonHeader { uint32_t payload_size_ = 0; const uint8_t* payload_ = nullptr; }; -} // namespace rtcp -} // namespace webrtc + #endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_COMMON_HEADER_H_ diff --git a/src/rtcp/rtcp_packet/receiver_report.cpp b/src/rtcp/rtcp_packet/receiver_report.cpp new file mode 100644 index 0000000..cc31221 --- /dev/null +++ b/src/rtcp/rtcp_packet/receiver_report.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "receiver_report.h" + +#include + +#include "byte_io.h" +#include "common_header.h" +#include "log.h" + +// RTCP receiver report (RFC 3550). +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| RC | PT=RR=201 | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC of packet sender | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// | report block(s) | +// | .... | + +ReceiverReport::ReceiverReport() = default; + +ReceiverReport::ReceiverReport(const ReceiverReport& rhs) = default; + +ReceiverReport::~ReceiverReport() = default; + +bool ReceiverReport::Parse(const CommonHeader& packet) { + const uint8_t report_blocks_count = packet.count(); + + if (packet.payload_size_bytes() < + kRrBaseLength + report_blocks_count * ReportBlock::kLength) { + LOG_WARN("Packet is too small to contain all the data."); + return false; + } + + SetSenderSsrc(ByteReader::ReadBigEndian(packet.payload())); + + const uint8_t* next_report_block = packet.payload() + kRrBaseLength; + + report_blocks_.resize(report_blocks_count); + for (ReportBlock& block : report_blocks_) { + block.Parse(next_report_block, ReportBlock::kLength); + next_report_block += ReportBlock::kLength; + } + + return true; +} + +size_t ReceiverReport::BlockLength() const { + return kHeaderLength + kRrBaseLength + + report_blocks_.size() * ReportBlock::kLength; +} + +bool ReceiverReport::Create(uint8_t* packet, size_t* index, size_t max_length, + PacketReadyCallback callback) const { + while (*index + BlockLength() > max_length) { + if (!OnBufferFull(packet, index, callback)) return false; + } + CreateHeader(report_blocks_.size(), kPacketType, HeaderLength(), packet, + index); + ByteWriter::WriteBigEndian(packet + *index, sender_ssrc()); + *index += kRrBaseLength; + for (const ReportBlock& block : report_blocks_) { + block.Create(packet + *index); + *index += ReportBlock::kLength; + } + return true; +} + +bool ReceiverReport::AddReportBlock(const ReportBlock& block) { + if (report_blocks_.size() >= kMaxNumberOfReportBlocks) { + LOG_WARN("Max report blocks reached."); + return false; + } + report_blocks_.push_back(block); + return true; +} + +bool ReceiverReport::SetReportBlocks(std::vector blocks) { + if (blocks.size() > kMaxNumberOfReportBlocks) { + LOG_WARN("Too many report blocks ({}) for receiver report.", blocks.size()); + return false; + } + report_blocks_ = std::move(blocks); + return true; +} diff --git a/src/rtcp/rtcp_packet/receiver_report.h b/src/rtcp/rtcp_packet/receiver_report.h new file mode 100644 index 0000000..330dac3 --- /dev/null +++ b/src/rtcp/rtcp_packet/receiver_report.h @@ -0,0 +1,50 @@ +/* + * @Author: DI JUNKUN + * @Date: 2025-02-17 + * Copyright (c) 2025 by DI JUNKUN, All Rights Reserved. + */ + +#ifndef _RECEIVER_REPORT_H_ +#define _RECEIVER_REPORT_H_ + +#include +#include + +#include + +#include "report_block.h" +#include "rtcp_packet.h" + +class CommonHeader; + +class ReceiverReport : public RtcpPacket { + public: + static constexpr uint8_t kPacketType = 201; + static constexpr size_t kMaxNumberOfReportBlocks = 0x1f; + + ReceiverReport(); + ReceiverReport(const ReceiverReport&); + ~ReceiverReport() override; + + // Parse assumes header is already parsed and validated. + bool Parse(const CommonHeader& packet); + + bool AddReportBlock(const ReportBlock& block); + bool SetReportBlocks(std::vector blocks); + + const std::vector& report_blocks() const { + return report_blocks_; + } + + size_t BlockLength() const override; + + bool Create(uint8_t* packet, size_t* index, size_t max_length, + PacketReadyCallback callback) const override; + + private: + static constexpr size_t kRrBaseLength = 4; + + std::vector report_blocks_; +}; + +#endif \ No newline at end of file diff --git a/src/rtcp/rtcp_packet/report_block.cpp b/src/rtcp/rtcp_packet/report_block.cpp new file mode 100644 index 0000000..87b2d3e --- /dev/null +++ b/src/rtcp/rtcp_packet/report_block.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "report_block.h" + +#include "byte_io.h" +#include "log.h" + +// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications. +// +// RTCP report block (RFC 3550). +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// 0 | SSRC_1 (SSRC of first source) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 4 | fraction lost | cumulative number of packets lost | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 8 | extended highest sequence number received | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 12 | interarrival jitter | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 16 | last SR (LSR) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 20 | delay since last SR (DLSR) | +// 24 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +ReportBlock::ReportBlock() + : source_ssrc_(0), + fraction_lost_(0), + cumulative_lost_(0), + extended_high_seq_num_(0), + jitter_(0), + last_sr_(0), + delay_since_last_sr_(0) {} + +bool ReportBlock::Parse(const uint8_t* buffer, size_t length) { + if (length < ReportBlock::kLength) { + LOG_ERROR("Report Block should be 24 bytes long"); + return false; + } + + source_ssrc_ = ByteReader::ReadBigEndian(&buffer[0]); + fraction_lost_ = buffer[4]; + cumulative_lost_ = ByteReader::ReadBigEndian(&buffer[5]); + extended_high_seq_num_ = ByteReader::ReadBigEndian(&buffer[8]); + jitter_ = ByteReader::ReadBigEndian(&buffer[12]); + last_sr_ = ByteReader::ReadBigEndian(&buffer[16]); + delay_since_last_sr_ = ByteReader::ReadBigEndian(&buffer[20]); + + return true; +} + +void ReportBlock::Create(uint8_t* buffer) const { + ByteWriter::WriteBigEndian(&buffer[0], source_ssrc()); + ByteWriter::WriteBigEndian(&buffer[4], fraction_lost()); + ByteWriter::WriteBigEndian(&buffer[5], cumulative_lost()); + ByteWriter::WriteBigEndian(&buffer[8], extended_high_seq_num()); + ByteWriter::WriteBigEndian(&buffer[12], jitter()); + ByteWriter::WriteBigEndian(&buffer[16], last_sr()); + ByteWriter::WriteBigEndian(&buffer[20], delay_since_last_sr()); +} + +bool ReportBlock::SetCumulativeLost(int32_t cumulative_lost) { + // We have only 3 bytes to store it, and it's a signed value. + if (cumulative_lost >= (1 << 23) || cumulative_lost < -(1 << 23)) { + LOG_WARN("Cumulative lost is too big to fit into Report Block"); + return false; + } + cumulative_lost_ = cumulative_lost; + return true; +} diff --git a/src/rtcp/rtcp_packet/report_block.h b/src/rtcp/rtcp_packet/report_block.h new file mode 100644 index 0000000..7b774f1 --- /dev/null +++ b/src/rtcp/rtcp_packet/report_block.h @@ -0,0 +1,60 @@ +/* + * @Author: DI JUNKUN + * @Date: 2025-02-17 + * Copyright (c) 2025 by DI JUNKUN, All Rights Reserved. + */ + +#ifndef _REPORT_BLOCK_H_ +#define _REPORT_BLOCK_H_ + +#include +#include + +// A ReportBlock represents the Sender Report packet from +// RFC 3550 section 6.4.1. +class ReportBlock { + public: + static constexpr size_t kLength = 24; + + ReportBlock(); + ~ReportBlock() {} + + bool Parse(const uint8_t* buffer, size_t length); + + // Fills buffer with the ReportBlock. + // Consumes ReportBlock::kLength bytes. + void Create(uint8_t* buffer) const; + + void SetMediaSsrc(uint32_t ssrc) { source_ssrc_ = ssrc; } + void SetFractionLost(uint8_t fraction_lost) { + fraction_lost_ = fraction_lost; + } + bool SetCumulativeLost(int32_t cumulative_lost); + void SetExtHighestSeqNum(uint32_t ext_highest_seq_num) { + extended_high_seq_num_ = ext_highest_seq_num; + } + void SetJitter(uint32_t jitter) { jitter_ = jitter; } + void SetLastSr(uint32_t last_sr) { last_sr_ = last_sr; } + void SetDelayLastSr(uint32_t delay_last_sr) { + delay_since_last_sr_ = delay_last_sr; + } + + uint32_t source_ssrc() const { return source_ssrc_; } + uint8_t fraction_lost() const { return fraction_lost_; } + int32_t cumulative_lost() const { return cumulative_lost_; } + uint32_t extended_high_seq_num() const { return extended_high_seq_num_; } + uint32_t jitter() const { return jitter_; } + uint32_t last_sr() const { return last_sr_; } + uint32_t delay_since_last_sr() const { return delay_since_last_sr_; } + + private: + uint32_t source_ssrc_; // 32 bits + uint8_t fraction_lost_; // 8 bits representing a fixed point value 0..1 + int32_t cumulative_lost_; // Signed 24-bit value + uint32_t extended_high_seq_num_; // 32 bits + uint32_t jitter_; // 32 bits + uint32_t last_sr_; // 32 bits + uint32_t delay_since_last_sr_; // 32 bits, units of 1/65536 seconds +}; + +#endif \ No newline at end of file diff --git a/src/rtcp/rtcp_packet/sender_report.cpp b/src/rtcp/rtcp_packet/sender_report.cpp new file mode 100644 index 0000000..0e26b90 --- /dev/null +++ b/src/rtcp/rtcp_packet/sender_report.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "sender_report.h" + +#include + +#include "byte_io.h" +#include "common_header.h" +#include "log.h" + +// Sender report (SR) (RFC 3550). +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| RC | PT=SR=200 | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 0 | SSRC of sender | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// 4 | NTP timestamp, most significant word | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 8 | NTP timestamp, least significant word | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 12 | RTP timestamp | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 16 | sender's packet count | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 20 | sender's octet count | +// 24 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + +SenderReport::SenderReport() + : rtp_timestamp_(0), sender_packet_count_(0), sender_octet_count_(0) {} + +SenderReport::SenderReport(const SenderReport&) = default; +SenderReport::SenderReport(SenderReport&&) = default; +SenderReport& SenderReport::operator=(const SenderReport&) = default; +SenderReport& SenderReport::operator=(SenderReport&&) = default; +SenderReport::~SenderReport() = default; + +bool SenderReport::Parse(const CommonHeader& packet) { + const uint8_t report_block_count = packet.count(); + if (packet.payload_size_bytes() < + kSenderBaseLength + report_block_count * ReportBlock::kLength) { + LOG_WARN("Packet is too small to contain all the data."); + return false; + } + // Read SenderReport header. + const uint8_t* const payload = packet.payload(); + SetSenderSsrc(ByteReader::ReadBigEndian(&payload[0])); + uint32_t secs = ByteReader::ReadBigEndian(&payload[4]); + uint32_t frac = ByteReader::ReadBigEndian(&payload[8]); + ntp_.Set(secs, frac); + rtp_timestamp_ = ByteReader::ReadBigEndian(&payload[12]); + sender_packet_count_ = ByteReader::ReadBigEndian(&payload[16]); + sender_octet_count_ = ByteReader::ReadBigEndian(&payload[20]); + report_blocks_.resize(report_block_count); + const uint8_t* next_block = payload + kSenderBaseLength; + for (ReportBlock& block : report_blocks_) { + bool block_parsed = block.Parse(next_block, ReportBlock::kLength); + next_block += ReportBlock::kLength; + } + return true; +} + +size_t SenderReport::BlockLength() const { + return kHeaderLength + kSenderBaseLength + + report_blocks_.size() * ReportBlock::kLength; +} + +bool SenderReport::Create(uint8_t* packet, size_t* index, size_t max_length, + PacketReadyCallback callback) const { + while (*index + BlockLength() > max_length) { + if (!OnBufferFull(packet, index, callback)) return false; + } + const size_t index_end = *index + BlockLength(); + + CreateHeader(report_blocks_.size(), kPacketType, HeaderLength(), packet, + index); + // Write SenderReport header. + ByteWriter::WriteBigEndian(&packet[*index + 0], sender_ssrc()); + ByteWriter::WriteBigEndian(&packet[*index + 4], ntp_.seconds()); + ByteWriter::WriteBigEndian(&packet[*index + 8], ntp_.fractions()); + ByteWriter::WriteBigEndian(&packet[*index + 12], rtp_timestamp_); + ByteWriter::WriteBigEndian(&packet[*index + 16], + sender_packet_count_); + ByteWriter::WriteBigEndian(&packet[*index + 20], + sender_octet_count_); + *index += kSenderBaseLength; + // Write report blocks. + for (const ReportBlock& block : report_blocks_) { + block.Create(packet + *index); + *index += ReportBlock::kLength; + } + return true; +} + +bool SenderReport::AddReportBlock(const ReportBlock& block) { + if (report_blocks_.size() >= kMaxNumberOfReportBlocks) { + LOG_WARN("Max report blocks reached."); + return false; + } + report_blocks_.push_back(block); + return true; +} + +bool SenderReport::SetReportBlocks(std::vector blocks) { + if (blocks.size() > kMaxNumberOfReportBlocks) { + LOG_WARN("Too many report blocks ({}) for sender report.", blocks.size()); + return false; + } + report_blocks_ = std::move(blocks); + return true; +} diff --git a/src/rtcp/rtcp_packet/sender_report.h b/src/rtcp/rtcp_packet/sender_report.h new file mode 100644 index 0000000..a1a49ed --- /dev/null +++ b/src/rtcp/rtcp_packet/sender_report.h @@ -0,0 +1,71 @@ +/* + * @Author: DI JUNKUN + * @Date: 2025-02-17 + * Copyright (c) 2025 by DI JUNKUN, All Rights Reserved. + */ + +#ifndef _SENDER_REPORT_H_ +#define _SENDER_REPORT_H_ + +#include + +#include "api/ntp/ntp_time.h" +#include "report_block.h" +#include "rtcp_packet.h" + +class CommonHeader; + +class SenderReport : public RtcpPacket { + public: + static constexpr uint8_t kPacketType = 200; + static constexpr size_t kMaxNumberOfReportBlocks = 0x1f; + + SenderReport(); + SenderReport(const SenderReport&); + SenderReport(SenderReport&&); + SenderReport& operator=(const SenderReport&); + SenderReport& operator=(SenderReport&&); + ~SenderReport() override; + + // Parse assumes header is already parsed and validated. + bool Parse(const CommonHeader& packet); + + void SetNtp(webrtc::NtpTime ntp) { ntp_ = ntp; } + void SetRtpTimestamp(uint32_t rtp_timestamp) { + rtp_timestamp_ = rtp_timestamp; + } + void SetPacketCount(uint32_t packet_count) { + sender_packet_count_ = packet_count; + } + void SetOctetCount(uint32_t octet_count) { + sender_octet_count_ = octet_count; + } + bool AddReportBlock(const ReportBlock& block); + bool SetReportBlocks(std::vector blocks); + void ClearReportBlocks() { report_blocks_.clear(); } + + webrtc::NtpTime ntp() const { return ntp_; } + uint32_t rtp_timestamp() const { return rtp_timestamp_; } + uint32_t sender_packet_count() const { return sender_packet_count_; } + uint32_t sender_octet_count() const { return sender_octet_count_; } + + const std::vector& report_blocks() const { + return report_blocks_; + } + + size_t BlockLength() const override; + + bool Create(uint8_t* packet, size_t* index, size_t max_length, + PacketReadyCallback callback) const override; + + private: + static constexpr size_t kSenderBaseLength = 24; + + webrtc::NtpTime ntp_; + uint32_t rtp_timestamp_; + uint32_t sender_packet_count_; + uint32_t sender_octet_count_; + std::vector report_blocks_; +}; + +#endif \ No newline at end of file diff --git a/src/transport/ice_transport.cpp b/src/transport/ice_transport.cpp index 8d8f1d6..59161c8 100644 --- a/src/transport/ice_transport.cpp +++ b/src/transport/ice_transport.cpp @@ -207,7 +207,7 @@ void IceTransport::OnReceiveBuffer(NiceAgent *agent, guint stream_id, bool IceTransport::ParseRtcpPacket(const uint8_t *buffer, size_t size, RtcpPacketInfo *rtcp_packet_info) { - webrtc::rtcp::CommonHeader rtcp_block; + CommonHeader rtcp_block; // If a sender report is received but no DLRR, we need to reset the // roundTripTime stat according to the standard, see // https://www.w3.org/TR/webrtc-stats/#dom-rtcremoteoutboundrtpstreamstats-roundtriptime @@ -300,8 +300,7 @@ bool IceTransport::ParseRtcpPacket(const uint8_t *buffer, size_t size, } bool IceTransport::HandleCongestionControlFeedback( - const webrtc::rtcp::CommonHeader &rtcp_block, - RtcpPacketInfo *rtcp_packet_info) { + const CommonHeader &rtcp_block, RtcpPacketInfo *rtcp_packet_info) { webrtc::rtcp::CongestionControlFeedback feedback; if (!feedback.Parse(rtcp_block) || feedback.packets().empty()) { return false; @@ -318,7 +317,7 @@ bool IceTransport::HandleCongestionControlFeedback( return true; } -bool IceTransport::HandleNack(const webrtc::rtcp::CommonHeader &rtcp_block, +bool IceTransport::HandleNack(const CommonHeader &rtcp_block, RtcpPacketInfo *rtcp_packet_info) { webrtc::rtcp::Nack nack; if (!nack.Parse(rtcp_block)) { diff --git a/src/transport/ice_transport.h b/src/transport/ice_transport.h index d0e8016..5b85d21 100644 --- a/src/transport/ice_transport.h +++ b/src/transport/ice_transport.h @@ -128,11 +128,10 @@ class IceTransport { bool ParseRtcpPacket(const uint8_t *buffer, size_t size, RtcpPacketInfo *rtcp_packet_info); - bool HandleCongestionControlFeedback( - const webrtc::rtcp::CommonHeader &rtcp_block, - RtcpPacketInfo *rtcp_packet_info); + bool HandleCongestionControlFeedback(const CommonHeader &rtcp_block, + RtcpPacketInfo *rtcp_packet_info); - bool HandleNack(const webrtc::rtcp::CommonHeader &rtcp_block, + bool HandleNack(const CommonHeader &rtcp_block, RtcpPacketInfo *rtcp_packet_info); private: