From b7a5066c6b08c30c33a921e22d6d3508a6ed48d3 Mon Sep 17 00:00:00 2001 From: dijunkun Date: Wed, 26 Feb 2025 17:30:24 +0800 Subject: [PATCH] [fix] fix rtcp common header --- src/channel/audio_channel_receive.h | 21 ++++ src/channel/audio_channel_send.h | 8 ++ src/channel/data_channel_receive.h | 21 ++++ src/channel/data_channel_send.h | 8 ++ src/channel/rtp_channel/rtp_audio_receiver.h | 10 ++ src/channel/rtp_channel/rtp_data_receiver.h | 9 ++ .../rtp_channel/rtp_video_receiver.cpp | 29 +++++ src/channel/rtp_channel/rtp_video_receiver.h | 9 +- src/channel/rtp_channel/rtp_video_sender.cpp | 13 +- src/channel/video_channel_receive.cpp | 2 +- src/channel/video_channel_receive.h | 20 +++ src/channel/video_channel_send.h | 7 ++ src/rtcp/congestion_control_feedback.cpp | 4 +- src/rtcp/congestion_control_feedback.h | 4 +- src/rtcp/nack.cpp | 4 +- src/rtcp/nack.h | 4 +- src/rtcp/rtcp_packet/common_header.cpp | 83 ------------ src/rtcp/rtcp_packet/common_header.h | 49 -------- src/rtcp/rtcp_packet/receiver_report.cpp | 10 +- src/rtcp/rtcp_packet/receiver_report.h | 4 +- src/rtcp/rtcp_packet/rtcp_common_header.cpp | 118 ++++++++++++------ src/rtcp/rtcp_packet/rtcp_common_header.h | 83 +++++------- src/rtcp/rtcp_packet/sender_report.cpp | 8 +- src/rtcp/rtcp_packet/sender_report.h | 14 ++- src/rtcp/rtp_feedback/rtp_feedback.h | 2 +- src/transport/ice_transport.cpp | 21 +++- src/transport/ice_transport.h | 7 +- src/transport/ice_transport_controller.cpp | 20 ++- src/transport/ice_transport_controller.h | 1 + 29 files changed, 334 insertions(+), 259 deletions(-) delete mode 100644 src/rtcp/rtcp_packet/common_header.cpp delete mode 100644 src/rtcp/rtcp_packet/common_header.h diff --git a/src/channel/audio_channel_receive.h b/src/channel/audio_channel_receive.h index 074ba45..e11dbe8 100644 --- a/src/channel/audio_channel_receive.h +++ b/src/channel/audio_channel_receive.h @@ -22,8 +22,29 @@ class AudioChannelReceive { public: void Initialize(rtp::PAYLOAD_TYPE payload_type); void Destroy(); + + uint32_t GetSsrc() { + if (rtp_audio_receiver_) { + return rtp_audio_receiver_->GetSsrc(); + } + return 0; + } + + uint32_t GetRemoteSsrc() { + if (rtp_audio_receiver_) { + return rtp_audio_receiver_->GetRemoteSsrc(); + } + return 0; + } + int OnReceiveRtpPacket(const char *data, size_t size); + void OnSenderReport(int64_t now_time, uint64_t ntp_time) { + if (rtp_audio_receiver_) { + rtp_audio_receiver_->OnSenderReport(now_time, ntp_time); + } + } + private: std::shared_ptr ice_agent_ = nullptr; std::shared_ptr ice_io_statistics_ = nullptr; diff --git a/src/channel/audio_channel_send.h b/src/channel/audio_channel_send.h index 6bb3477..db05d4e 100644 --- a/src/channel/audio_channel_send.h +++ b/src/channel/audio_channel_send.h @@ -21,6 +21,14 @@ class AudioChannelSend { public: void Initialize(rtp::PAYLOAD_TYPE payload_type); void Destroy(); + + uint32_t GetSsrc() { + if (rtp_audio_sender_) { + return rtp_audio_sender_->GetSsrc(); + } + return 0; + } + int SendAudio(char *data, size_t size); private: diff --git a/src/channel/data_channel_receive.h b/src/channel/data_channel_receive.h index a887ec2..a78af9b 100644 --- a/src/channel/data_channel_receive.h +++ b/src/channel/data_channel_receive.h @@ -21,8 +21,29 @@ class DataChannelReceive { public: void Initialize(rtp::PAYLOAD_TYPE payload_type); void Destroy(); + + uint32_t GetSsrc() { + if (rtp_data_receiver_) { + return rtp_data_receiver_->GetSsrc(); + } + return 0; + } + + uint32_t GetRemoteSsrc() { + if (rtp_data_receiver_) { + return rtp_data_receiver_->GetRemoteSsrc(); + } + return 0; + } + int OnReceiveRtpPacket(const char *data, size_t size); + void OnSenderReport(int64_t now_time, uint64_t ntp_time) { + if (rtp_data_receiver_) { + rtp_data_receiver_->OnSenderReport(now_time, ntp_time); + } + } + private: std::shared_ptr ice_agent_ = nullptr; std::shared_ptr ice_io_statistics_ = nullptr; diff --git a/src/channel/data_channel_send.h b/src/channel/data_channel_send.h index 9022037..4fe3b0f 100644 --- a/src/channel/data_channel_send.h +++ b/src/channel/data_channel_send.h @@ -21,6 +21,14 @@ class DataChannelSend { public: void Initialize(rtp::PAYLOAD_TYPE payload_type); void Destroy(); + + uint32_t GetSsrc() { + if (rtp_data_sender_) { + return rtp_data_sender_->GetSsrc(); + } + return 0; + } + int SendData(const char *data, size_t size); private: diff --git a/src/channel/rtp_channel/rtp_audio_receiver.h b/src/channel/rtp_channel/rtp_audio_receiver.h index 6df1514..f9ec65f 100644 --- a/src/channel/rtp_channel/rtp_audio_receiver.h +++ b/src/channel/rtp_channel/rtp_audio_receiver.h @@ -29,6 +29,10 @@ class RtpAudioReceiver { std::function on_receive_data) { on_receive_data_ = on_receive_data; } + uint32_t GetSsrc() { return ssrc_; } + uint32_t GetRemoteSsrc() { return remote_ssrc_; } + + void OnSenderReport(int64_t now_time, uint64_t ntp_time) {} private: bool CheckIsTimeSendRR(); @@ -46,6 +50,12 @@ class RtpAudioReceiver { uint32_t total_rtp_packets_recv_ = 0; uint32_t last_send_rtcp_rr_packet_ts_ = 0; std::function data_send_func_ = nullptr; + + uint32_t ssrc_ = 0; + uint32_t remote_ssrc_ = 0; + + uint32_t last_sr_ = 0; + uint32_t last_delay_ = 0; }; #endif \ No newline at end of file diff --git a/src/channel/rtp_channel/rtp_data_receiver.h b/src/channel/rtp_channel/rtp_data_receiver.h index b868ed8..ea47891 100644 --- a/src/channel/rtp_channel/rtp_data_receiver.h +++ b/src/channel/rtp_channel/rtp_data_receiver.h @@ -24,6 +24,10 @@ class RtpDataReceiver { on_receive_data_ = on_receive_data; } + uint32_t GetSsrc() { return ssrc_; } + uint32_t GetRemoteSsrc() { return remote_ssrc_; } + void OnSenderReport(int64_t now_time, uint64_t ntp_time) {} + private: bool CheckIsTimeSendRR(); int SendRtcpRR(ReceiverReport& rtcp_rr); @@ -39,8 +43,13 @@ class RtpDataReceiver { uint32_t total_rtp_payload_recv_ = 0; uint32_t total_rtp_packets_recv_ = 0; + uint32_t ssrc_ = 0; + uint32_t remote_ssrc_ = 0; uint32_t last_send_rtcp_rr_packet_ts_ = 0; std::function data_send_func_ = nullptr; + + uint32_t last_sr_ = 0; + uint32_t last_delay_ = 0; }; #endif \ No newline at end of file diff --git a/src/channel/rtp_channel/rtp_video_receiver.cpp b/src/channel/rtp_channel/rtp_video_receiver.cpp index 2d958cb..a196337 100644 --- a/src/channel/rtp_channel/rtp_video_receiver.cpp +++ b/src/channel/rtp_channel/rtp_video_receiver.cpp @@ -545,3 +545,32 @@ void RtpVideoReceiver::SendLossNotification(uint16_t last_decoded_seq_num, uint16_t last_received_seq_num, bool decodability_flag, bool buffering_allowed) {} + +inline uint32_t DivideRoundToNearest(int64_t dividend, int64_t divisor) { + if (dividend < 0) { + int64_t half_of_divisor = divisor / 2; + int64_t quotient = dividend / divisor; + int64_t remainder = dividend % divisor; + if (-remainder > half_of_divisor) { + --quotient; + } + return quotient; + } + + int64_t half_of_divisor = (divisor - 1) / 2; + int64_t quotient = dividend / divisor; + int64_t remainder = dividend % divisor; + if (remainder > half_of_divisor) { + ++quotient; + } + return quotient; +} + +void RtpVideoReceiver::OnSenderReport(int64_t now_time, uint64_t ntp_time) { + last_sr_ = ((uint32_t)(ntp_time / 0x100000000) << 16) | + ((uint32_t)(ntp_time % 0x100000000) >> 16); + last_delay_ = DivideRoundToNearest( + (clock_->CurrentTime().us() - now_time) * 0x10000, 1000000); + + LOG_WARN("OnSenderReport [{}][{}]", last_sr_, last_delay_); +} \ No newline at end of file diff --git a/src/channel/rtp_channel/rtp_video_receiver.h b/src/channel/rtp_channel/rtp_video_receiver.h index 5cb7e00..48af306 100644 --- a/src/channel/rtp_channel/rtp_video_receiver.h +++ b/src/channel/rtp_channel/rtp_video_receiver.h @@ -43,6 +43,9 @@ class RtpVideoReceiver : public ThreadBase, std::function on_receive_complete_frame) { on_receive_complete_frame_ = on_receive_complete_frame; } + uint32_t GetSsrc() { return ssrc_; } + uint32_t GetRemoteSsrc() { return remote_ssrc_; } + void OnSenderReport(int64_t now_time, uint64_t ntp_time); private: void ProcessAv1RtpPacket(RtpPacketAv1& rtp_packet_av1); @@ -114,15 +117,19 @@ class RtpVideoReceiver : public ThreadBase, int rtcp_tcc_interval_ms_ = 200; private: + uint32_t ssrc_ = 0; + uint32_t remote_ssrc_ = 0; std::shared_ptr clock_; ReceiveSideCongestionController receive_side_congestion_controller_; RtcpFeedbackSenderInterface* active_remb_module_; uint32_t feedback_ssrc_ = 0; - uint32_t remote_ssrc_ = 0; std::unique_ptr rtcp_sender_; std::unique_ptr nack_; + uint32_t last_sr_ = 0; + uint32_t last_delay_ = 0; + private: FILE* file_rtp_recv_ = nullptr; }; diff --git a/src/channel/rtp_channel/rtp_video_sender.cpp b/src/channel/rtp_channel/rtp_video_sender.cpp index 67d8152..65d8949 100644 --- a/src/channel/rtp_channel/rtp_video_sender.cpp +++ b/src/channel/rtp_channel/rtp_video_sender.cpp @@ -118,18 +118,7 @@ int RtpVideoSender::SendRtpPacket( rtcp_sr.SetSenderPacketCount(total_rtp_packets_sent_); rtcp_sr.SetSenderOctetCount(total_rtp_payload_sent_); - RtcpReportBlock report; - report.SetMediaSsrc(ssrc_); - report.SetFractionLost(0); - report.SetCumulativeLost(0); - report.SetJitter(0); - report.SetLastSr(0); - report.SetExtHighestSeqNum(0); - report.SetDelayLastSr(0); - - rtcp_sr.SetReportBlock(report); - rtcp_sr.Create(); - + rtcp_sr.Build(); SendRtcpSR(rtcp_sr); } diff --git a/src/channel/video_channel_receive.cpp b/src/channel/video_channel_receive.cpp index 4394e2e..d7b1f47 100644 --- a/src/channel/video_channel_receive.cpp +++ b/src/channel/video_channel_receive.cpp @@ -64,4 +64,4 @@ int VideoChannelReceive::OnReceiveRtpPacket(const char *data, size_t size) { } return 0; -} \ No newline at end of file +} diff --git a/src/channel/video_channel_receive.h b/src/channel/video_channel_receive.h index 98a7731..8a71dd1 100644 --- a/src/channel/video_channel_receive.h +++ b/src/channel/video_channel_receive.h @@ -25,8 +25,28 @@ class VideoChannelReceive { void Initialize(rtp::PAYLOAD_TYPE payload_type); void Destroy(); + uint32_t GetSsrc() { + if (rtp_video_receiver_) { + return rtp_video_receiver_->GetSsrc(); + } + return 0; + } + + uint32_t GetRemoteSsrc() { + if (rtp_video_receiver_) { + return rtp_video_receiver_->GetRemoteSsrc(); + } + return 0; + } + int OnReceiveRtpPacket(const char *data, size_t size); + void OnSenderReport(int64_t now_time, uint64_t ntp_time) { + if (rtp_video_receiver_) { + rtp_video_receiver_->OnSenderReport(now_time, ntp_time); + } + } + private: std::shared_ptr ice_agent_ = nullptr; std::shared_ptr ice_io_statistics_ = nullptr; diff --git a/src/channel/video_channel_send.h b/src/channel/video_channel_send.h index e8a659e..62a6991 100644 --- a/src/channel/video_channel_send.h +++ b/src/channel/video_channel_send.h @@ -32,6 +32,13 @@ class VideoChannelSend { void Initialize(rtp::PAYLOAD_TYPE payload_type); void Destroy(); + uint32_t GetSsrc() { + if (rtp_video_sender_) { + return rtp_video_sender_->GetSsrc(); + } + return 0; + } + int SendVideo(std::shared_ptr encoded_frame); void OnCongestionControlFeedback( diff --git a/src/rtcp/congestion_control_feedback.cpp b/src/rtcp/congestion_control_feedback.cpp index b6b6b56..4242e59 100644 --- a/src/rtcp/congestion_control_feedback.cpp +++ b/src/rtcp/congestion_control_feedback.cpp @@ -21,8 +21,8 @@ #include "api/units/time_delta.h" #include "api/units/timestamp.h" #include "byte_io.h" -#include "common_header.h" #include "log.h" +#include "rtcp_common_header.h" namespace webrtc { namespace rtcp { @@ -261,7 +261,7 @@ size_t CongestionControlFeedback::BlockLength() const { return total_size; } -bool CongestionControlFeedback::Parse(const 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(); diff --git a/src/rtcp/congestion_control_feedback.h b/src/rtcp/congestion_control_feedback.h index 20b316d..07da5ec 100644 --- a/src/rtcp/congestion_control_feedback.h +++ b/src/rtcp/congestion_control_feedback.h @@ -17,7 +17,7 @@ #include "api/array_view.h" #include "api/transport/ecn_marking.h" #include "api/units/time_delta.h" -#include "common_header.h" +#include "rtcp_common_header.h" #include "rtp_feedback.h" namespace webrtc { @@ -45,7 +45,7 @@ class CongestionControlFeedback : public RtpFeedback { uint32_t report_timestamp_compact_ntp); CongestionControlFeedback() = default; - bool Parse(const CommonHeader& packet); + bool Parse(const RtcpCommonHeader& packet); rtc::ArrayView packets() const { return packets_; } diff --git a/src/rtcp/nack.cpp b/src/rtcp/nack.cpp index 027788f..8f3bb42 100644 --- a/src/rtcp/nack.cpp +++ b/src/rtcp/nack.cpp @@ -15,8 +15,8 @@ #include #include "byte_io.h" -#include "common_header.h" #include "log.h" +#include "rtcp_common_header.h" namespace webrtc { namespace rtcp { @@ -48,7 +48,7 @@ Nack::Nack() = default; Nack::Nack(const Nack& rhs) = default; Nack::~Nack() = default; -bool Nack::Parse(const CommonHeader& packet) { +bool Nack::Parse(const RtcpCommonHeader& packet) { if (packet.payload_size_bytes() < kCommonFeedbackLength + kNackItemLength) { LOG_WARN("Payload length {} is too small for a Nack.", packet.payload_size_bytes()); diff --git a/src/rtcp/nack.h b/src/rtcp/nack.h index 3f08c25..c171d5d 100644 --- a/src/rtcp/nack.h +++ b/src/rtcp/nack.h @@ -13,7 +13,7 @@ #include -#include "common_header.h" +#include "rtcp_common_header.h" #include "rtp_feedback.h" namespace webrtc { @@ -26,7 +26,7 @@ class Nack : public RtpFeedback { ~Nack() override; // Parse assumes header is already parsed and validated. - bool Parse(const CommonHeader& packet); + bool Parse(const RtcpCommonHeader& packet); void SetPacketIds(const uint16_t* nack_list, size_t length); void SetPacketIds(std::vector nack_list); diff --git a/src/rtcp/rtcp_packet/common_header.cpp b/src/rtcp/rtcp_packet/common_header.cpp deleted file mode 100644 index a9f480d..0000000 --- a/src/rtcp/rtcp_packet/common_header.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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 "common_header.h" - -#include "byte_io.h" -#include "log.h" - -// 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 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// 0 |V=2|P| C/F | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// 1 | Packet Type | -// ----------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// 2 | length | -// --------------------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// -// Common header for all RTCP packets, 4 octets. -bool CommonHeader::Parse(const uint8_t* buffer, size_t size_bytes) { - const uint8_t kVersion = 2; - - if (size_bytes < kHeaderSizeBytes) { - LOG_WARN( - "Too little data ({} byte{}) remaining in buffer to parse RTCP header " - "(4 bytes).", - size_bytes, (size_bytes != 1 ? "s" : "")); - return false; - } - - uint8_t version = buffer[0] >> 6; - if (version != kVersion) { - LOG_WARN("Invalid RTCP header: Version must be {} but was {}", - static_cast(kVersion), static_cast(version)); - return false; - } - - bool has_padding = (buffer[0] & 0x20) != 0; - count_or_format_ = buffer[0] & 0x1F; - packet_type_ = buffer[1]; - payload_size_ = ByteReader::ReadBigEndian(&buffer[2]) * 4; - payload_ = buffer + kHeaderSizeBytes; - padding_size_ = 0; - - if (size_bytes < kHeaderSizeBytes + payload_size_) { - LOG_WARN( - "Buffer too small ({} bytes) to fit an RtcpPacket with a header and {} " - "bytes.", - size_bytes, payload_size_); - return false; - } - - if (has_padding) { - if (payload_size_ == 0) { - LOG_WARN( - "Invalid RTCP header: Padding bit set but 0 payload size specified."); - return false; - } - - padding_size_ = payload_[payload_size_ - 1]; - if (padding_size_ == 0) { - LOG_WARN( - "Invalid RTCP header: Padding bit set but 0 padding size specified."); - return false; - } - if (padding_size_ > payload_size_) { - LOG_WARN( - "Invalid RTCP header: Too many padding bytes ({}) for a packet " - "payload size of {} bytes.", - padding_size_, payload_size_); - return false; - } - payload_size_ -= padding_size_; - } - return true; -} diff --git a/src/rtcp/rtcp_packet/common_header.h b/src/rtcp/rtcp_packet/common_header.h deleted file mode 100644 index 984015a..0000000 --- a/src/rtcp/rtcp_packet/common_header.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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. - */ -#ifndef MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_COMMON_HEADER_H_ -#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_COMMON_HEADER_H_ - -#include -#include - -class CommonHeader { - public: - static constexpr size_t kHeaderSizeBytes = 4; - - CommonHeader() {} - CommonHeader(const CommonHeader&) = default; - CommonHeader& operator=(const CommonHeader&) = default; - - bool Parse(const uint8_t* buffer, size_t size_bytes); - - uint8_t type() const { return packet_type_; } - // Depending on packet type same header field can be used either as count or - // as feedback message type (fmt). Caller expected to know how it is used. - uint8_t fmt() const { return count_or_format_; } - uint8_t count() const { return count_or_format_; } - size_t payload_size_bytes() const { return payload_size_; } - const uint8_t* payload() const { return payload_; } - size_t packet_size() const { - return kHeaderSizeBytes + payload_size_ + padding_size_; - } - // Returns pointer to the next RTCP packet in compound packet. - const uint8_t* NextPacket() const { - return payload_ + payload_size_ + padding_size_; - } - - private: - uint8_t packet_type_ = 0; - uint8_t count_or_format_ = 0; - uint8_t padding_size_ = 0; - uint32_t payload_size_ = 0; - const uint8_t* payload_ = nullptr; -}; - -#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 index a3f6497..0ddbc7d 100644 --- a/src/rtcp/rtcp_packet/receiver_report.cpp +++ b/src/rtcp/rtcp_packet/receiver_report.cpp @@ -19,7 +19,7 @@ void ReceiverReport::SetReportBlocks( reports_ = std::move(rtcp_report_blocks); } -const uint8_t *ReceiverReport::Create() { +const uint8_t *ReceiverReport::Build() { size_t buffer_size = DEFAULT_SR_SIZE + reports_.size() * RtcpReportBlock::kLength; if (!buffer_ || buffer_size != size_) { @@ -41,13 +41,13 @@ const uint8_t *ReceiverReport::Create() { return buffer_; } -size_t ReceiverReport::Parse(const uint8_t *buffer) { +size_t ReceiverReport::Parse(const RtcpCommonHeader &packet) { reports_.clear(); - size_t pos = rtcp_common_header_.Parse(buffer); + size_t pos = packet.payload_size_bytes(); - for (int i = 0; i < rtcp_common_header_.CountOrFormat(); i++) { + for (int i = 0; i < rtcp_common_header_.fmt(); i++) { RtcpReportBlock report; - pos += report.Parse(buffer + pos); + pos += report.Parse(buffer_ + pos); reports_.emplace_back(std::move(report)); } diff --git a/src/rtcp/rtcp_packet/receiver_report.h b/src/rtcp/rtcp_packet/receiver_report.h index e64e231..e415f6f 100644 --- a/src/rtcp/rtcp_packet/receiver_report.h +++ b/src/rtcp/rtcp_packet/receiver_report.h @@ -48,8 +48,8 @@ class ReceiverReport { void SetReportBlock(RtcpReportBlock &rtcp_report_block); void SetReportBlocks(std::vector &rtcp_report_blocks); - const uint8_t *Create(); - size_t Parse(const uint8_t *buffer); + const uint8_t *Build(); + size_t Parse(const RtcpCommonHeader &packet); const uint8_t *Buffer() const { return buffer_; } size_t Size() const { return size_; } diff --git a/src/rtcp/rtcp_packet/rtcp_common_header.cpp b/src/rtcp/rtcp_packet/rtcp_common_header.cpp index d4ecbe4..24238b1 100644 --- a/src/rtcp/rtcp_packet/rtcp_common_header.cpp +++ b/src/rtcp/rtcp_packet/rtcp_common_header.cpp @@ -1,51 +1,99 @@ +/* + * 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 "rtcp_common_header.h" +#include "byte_io.h" #include "log.h" -RtcpCommonHeader::RtcpCommonHeader() - : version_(0), - padding_(0), - count_or_format_(0), - payload_type_(PAYLOAD_TYPE::UNKNOWN), - length_(0) {} +// 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 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 0 |V=2|P| C/F | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 1 | Packet Type | +// ----------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 2 | length | +// --------------------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Common header for all RTCP packets, 4 octets. -RtcpCommonHeader::RtcpCommonHeader(const uint8_t* buffer, uint32_t size) { - if (size < 4) { - version_ = 2; - padding_ = 0; - count_or_format_ = 0; - payload_type_ = PAYLOAD_TYPE::UNKNOWN; - length_ = 0; - } else { - version_ = buffer[0] >> 6; - padding_ = buffer[0] >> 5 & 0x01; - count_or_format_ = buffer[0] & 0x1F; - payload_type_ = PAYLOAD_TYPE(buffer[1]); - length_ = (buffer[2] << 8) + buffer[3]; - } -} - -RtcpCommonHeader::~RtcpCommonHeader() {} - -int RtcpCommonHeader::Create(uint8_t version, uint8_t padding, +int RtcpCommonHeader::Create(uint8_t version, uint8_t has_padding, uint8_t count_or_format, uint8_t payload_type, uint16_t length, uint8_t* buffer) { if (!buffer) { return 0; } - buffer[0] = (version << 6) | (padding << 5) | (count_or_format << 4); + uint16_t payload_size = length - kHeaderSizeBytes; + buffer[0] = (version << 6) | (has_padding << 5) | (count_or_format << 4); buffer[1] = payload_type; - buffer[2] = length >> 8 & 0xFF; - buffer[3] = length & 0xFF; + buffer[2] = payload_size >> 8 & 0xFF; + buffer[3] = payload_size & 0xFF; return 4; } -size_t RtcpCommonHeader::Parse(const uint8_t* buffer) { - version_ = buffer[0] >> 6; - padding_ = buffer[0] >> 5 & 0x01; +bool RtcpCommonHeader::Parse(const uint8_t* buffer, size_t size_bytes) { + const uint8_t kVersion = 2; + + if (size_bytes < kHeaderSizeBytes) { + LOG_WARN( + "Too little data ({} byte{}) remaining in buffer to parse RTCP header " + "(4 bytes).", + size_bytes, (size_bytes != 1 ? "s" : "")); + return false; + } + + uint8_t version = buffer[0] >> 6; + if (version != kVersion) { + LOG_WARN("Invalid RTCP header: Version must be {} but was {}", + static_cast(kVersion), static_cast(version)); + return false; + } + + bool has_padding = (buffer[0] & 0x20) != 0; count_or_format_ = buffer[0] & 0x1F; - payload_type_ = PAYLOAD_TYPE(buffer[1]); - length_ = (buffer[2] << 8) + buffer[3]; - return 4; -} \ No newline at end of file + packet_type_ = buffer[1]; + payload_size_ = buffer[2] << 8 | buffer[3]; + payload_ = buffer + kHeaderSizeBytes; + padding_size_ = 0; + + if (size_bytes < kHeaderSizeBytes + payload_size_) { + LOG_WARN( + "Buffer too small ({} bytes) to fit an RtcpPacket with a header and {} " + "bytes.", + size_bytes, payload_size_); + return false; + } + + if (has_padding) { + if (payload_size_ == 0) { + LOG_WARN( + "Invalid RTCP header: Padding bit set but 0 payload size specified."); + return false; + } + + padding_size_ = payload_[payload_size_ - 1]; + if (padding_size_ == 0) { + LOG_WARN( + "Invalid RTCP header: Padding bit set but 0 padding size specified."); + return false; + } + if (padding_size_ > payload_size_) { + LOG_WARN( + "Invalid RTCP header: Too many padding bytes ({}) for a packet " + "payload size of {} bytes.", + padding_size_, payload_size_); + return false; + } + payload_size_ -= padding_size_; + } + return true; +} diff --git a/src/rtcp/rtcp_packet/rtcp_common_header.h b/src/rtcp/rtcp_packet/rtcp_common_header.h index 7aad3a8..f428142 100644 --- a/src/rtcp/rtcp_packet/rtcp_common_header.h +++ b/src/rtcp/rtcp_packet/rtcp_common_header.h @@ -1,65 +1,50 @@ -#ifndef _RTCP_HEADER_H_ -#define _RTCP_HEADER_H_ +/* + * @Author: DI JUNKUN + * @Date: 2025-02-26 + * Copyright (c) 2025 by DI JUNKUN, All Rights Reserved. + */ -#include -#include +#ifndef _RTCP_COMMON_HEADER_H_ +#define _RTCP_COMMON_HEADER_H_ -// RTCP header -// 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 | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +#include +#include #include "rtcp_typedef.h" class RtcpCommonHeader { public: - typedef enum { - UNKNOWN = 0, - SR = 200, - RR = 201, - SDES = 202, - BYE = 203, - APP = 204 - } PAYLOAD_TYPE; + static constexpr size_t kHeaderSizeBytes = 4; - public: - RtcpCommonHeader(); - RtcpCommonHeader(const uint8_t* buffer, uint32_t size); - ~RtcpCommonHeader(); + RtcpCommonHeader() {} + RtcpCommonHeader(const RtcpCommonHeader&) = default; + RtcpCommonHeader& operator=(const RtcpCommonHeader&) = default; - public: - void SetVerion(uint8_t version) { version_ = version; } - void SetPadding(uint8_t padding) { padding_ = padding; } - void SetCountOrFormat(uint8_t count_or_format) { - count_or_format_ = count_or_format; - } - void SetPayloadType(PAYLOAD_TYPE payload_type) { - payload_type_ = payload_type; - } - void SetLength(uint16_t length) { length_ = length; } - - public: - uint8_t Verion() const { return version_; } - uint8_t Padding() const { return padding_; } - uint8_t CountOrFormat() const { return count_or_format_; } - PAYLOAD_TYPE PayloadType() const { - return PAYLOAD_TYPE((uint8_t)payload_type_); - } - uint16_t Length() const { return length_; } - - int Create(uint8_t version, uint8_t padding, uint8_t count_or_format, + int Create(uint8_t version, uint8_t has_padding, uint8_t count_or_format, uint8_t payload_type, uint16_t length, uint8_t* buffer); + bool Parse(const uint8_t* buffer, size_t size_bytes); - size_t Parse(const uint8_t* buffer); + uint8_t type() const { return packet_type_; } + // Depending on packet type same header field can be used either as count or + // as feedback message type (fmt). Caller expected to know how it is used. + uint8_t fmt() const { return count_or_format_; } + uint8_t count() const { return count_or_format_; } + size_t payload_size_bytes() const { return payload_size_; } + const uint8_t* payload() const { return payload_; } + size_t packet_size() const { + return kHeaderSizeBytes + payload_size_ + padding_size_; + } + // Returns pointer to the next RTCP packet in compound packet. + const uint8_t* NextPacket() const { + return payload_ + payload_size_ + padding_size_; + } private: - uint8_t version_ : 2; - uint8_t padding_ : 1; - uint8_t count_or_format_ : 5; - PAYLOAD_TYPE payload_type_ : 8; - uint16_t length_ : 16; + uint8_t packet_type_ = 0; + uint8_t count_or_format_ = 0; + uint8_t padding_size_ = 0; + uint32_t payload_size_ = 0; + const uint8_t* payload_ = nullptr; }; #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 index 0cb4ced..179f3c8 100644 --- a/src/rtcp/rtcp_packet/sender_report.cpp +++ b/src/rtcp/rtcp_packet/sender_report.cpp @@ -20,7 +20,7 @@ void SenderReport::SetReportBlocks( reports_ = std::move(rtcp_report_blocks); } -const uint8_t *SenderReport::Create() { +const uint8_t *SenderReport::Build() { size_t buffer_size = DEFAULT_SR_SIZE + reports_.size() * RtcpReportBlock::kLength; if (!buffer_ || buffer_size != size_) { @@ -71,9 +71,9 @@ const uint8_t *SenderReport::Create() { return buffer_; } -size_t SenderReport::Parse() { +size_t SenderReport::Parse(const RtcpCommonHeader &packet) { reports_.clear(); - size_t pos = rtcp_common_header_.Parse(buffer_); + size_t pos = packet.payload_size_bytes(); sender_info_.sender_ssrc = (buffer_[pos] << 24) + (buffer_[pos + 1] << 16) + (buffer_[pos + 2] << 8) + buffer_[pos + 3]; @@ -96,7 +96,7 @@ size_t SenderReport::Parse() { (buffer_[pos + 2] << 8) + buffer_[pos + 3]; pos += 4; - for (int i = 0; i < rtcp_common_header_.CountOrFormat(); i++) { + for (int i = 0; i < rtcp_common_header_.fmt(); i++) { RtcpReportBlock report; pos += report.Parse(buffer_ + pos); reports_.emplace_back(std::move(report)); diff --git a/src/rtcp/rtcp_packet/sender_report.h b/src/rtcp/rtcp_packet/sender_report.h index 4823a7b..dd1758b 100644 --- a/src/rtcp/rtcp_packet/sender_report.h +++ b/src/rtcp/rtcp_packet/sender_report.h @@ -78,9 +78,19 @@ class SenderReport { void SetReportBlock(RtcpReportBlock &rtcp_report_block); void SetReportBlocks(std::vector &rtcp_report_blocks); + uint32_t SenderSsrc() const { return sender_info_.sender_ssrc; } + uint64_t NtpTimestamp() const { + return (sender_info_.ntp_ts_msw << 32) | sender_info_.ntp_ts_lsw; + } + uint32_t Timestamp() const { return sender_info_.rtp_ts; } + uint32_t SenderPacketCount() const { + return sender_info_.sender_packet_count; + } + uint32_t SenderOctetCount() const { return sender_info_.sender_octet_count; } + public: - const uint8_t *Create(); - size_t Parse(); + const uint8_t *Build(); + size_t Parse(const RtcpCommonHeader &packet); // Entire RTP buffer const uint8_t *Buffer() const { return buffer_; } diff --git a/src/rtcp/rtp_feedback/rtp_feedback.h b/src/rtcp/rtp_feedback/rtp_feedback.h index 3f23798..c111ee7 100644 --- a/src/rtcp/rtp_feedback/rtp_feedback.h +++ b/src/rtcp/rtp_feedback/rtp_feedback.h @@ -10,7 +10,7 @@ #include #include -#include "common_header.h" +#include "rtcp_common_header.h" #include "rtcp_packet.h" // RTPFB: Transport layer feedback message. diff --git a/src/transport/ice_transport.cpp b/src/transport/ice_transport.cpp index 7bc9ae5..be882a7 100644 --- a/src/transport/ice_transport.cpp +++ b/src/transport/ice_transport.cpp @@ -209,7 +209,7 @@ void IceTransport::OnReceiveBuffer(NiceAgent *agent, guint stream_id, bool IceTransport::ParseRtcpPacket(const uint8_t *buffer, size_t size, RtcpPacketInfo *rtcp_packet_info) { - CommonHeader rtcp_block; + RtcpCommonHeader 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 @@ -227,7 +227,7 @@ bool IceTransport::ParseRtcpPacket(const uint8_t *buffer, size_t size, switch (rtcp_block.type()) { case RtcpPacket::RtcpPayloadType::SR: LOG_INFO("Sender report"); - // valid = HandleSenderReport(rtcp_block, rtcp_packet_info); + valid = HandleSenderReport(rtcp_block, rtcp_packet_info); // received_blocks[rtcp_packet_info->remote_ssrc].sender_report = true; break; case RtcpPacket::RtcpPayloadType::RR: @@ -301,8 +301,21 @@ bool IceTransport::ParseRtcpPacket(const uint8_t *buffer, size_t size, return true; } +bool IceTransport::HandleSenderReport(const RtcpCommonHeader &rtcp_block, + RtcpPacketInfo *rtcp_packet_info) { + SenderReport sender_report; + if (!sender_report.Parse(rtcp_block)) { + return false; + } + + if (ice_transport_controller_) { + ice_transport_controller_->OnSenderReport(sender_report); + } + return true; +} + bool IceTransport::HandleCongestionControlFeedback( - const CommonHeader &rtcp_block, RtcpPacketInfo *rtcp_packet_info) { + const RtcpCommonHeader &rtcp_block, RtcpPacketInfo *rtcp_packet_info) { webrtc::rtcp::CongestionControlFeedback feedback; if (!feedback.Parse(rtcp_block) || feedback.packets().empty()) { return false; @@ -319,7 +332,7 @@ bool IceTransport::HandleCongestionControlFeedback( return true; } -bool IceTransport::HandleNack(const CommonHeader &rtcp_block, +bool IceTransport::HandleNack(const RtcpCommonHeader &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 e04de4e..1d5ab01 100644 --- a/src/transport/ice_transport.h +++ b/src/transport/ice_transport.h @@ -130,10 +130,13 @@ class IceTransport { bool ParseRtcpPacket(const uint8_t *buffer, size_t size, RtcpPacketInfo *rtcp_packet_info); - bool HandleCongestionControlFeedback(const CommonHeader &rtcp_block, + bool HandleSenderReport(const RtcpCommonHeader &rtcp_block, + RtcpPacketInfo *rtcp_packet_info); + + bool HandleCongestionControlFeedback(const RtcpCommonHeader &rtcp_block, RtcpPacketInfo *rtcp_packet_info); - bool HandleNack(const CommonHeader &rtcp_block, + bool HandleNack(const RtcpCommonHeader &rtcp_block, RtcpPacketInfo *rtcp_packet_info); private: diff --git a/src/transport/ice_transport_controller.cpp b/src/transport/ice_transport_controller.cpp index f14d970..d1fd4f2 100644 --- a/src/transport/ice_transport_controller.cpp +++ b/src/transport/ice_transport_controller.cpp @@ -332,6 +332,24 @@ int IceTransportController::CreateAudioCodec() { return 0; } +void IceTransportController::OnSenderReport(const SenderReport& sender_report) { + if (video_channel_receive_ && + sender_report.SenderSsrc() == video_channel_receive_->GetRemoteSsrc()) { + video_channel_receive_->OnSenderReport(clock_->CurrentTimeUs(), + sender_report.NtpTimestamp()); + } else if (audio_channel_receive_ && + sender_report.SenderSsrc() == + audio_channel_receive_->GetRemoteSsrc()) { + audio_channel_receive_->OnSenderReport(clock_->CurrentTimeUs(), + sender_report.NtpTimestamp()); + } else if (data_channel_receive_ && + sender_report.SenderSsrc() == + data_channel_receive_->GetRemoteSsrc()) { + data_channel_receive_->OnSenderReport(clock_->CurrentTimeUs(), + sender_report.NtpTimestamp()); + } +} + void IceTransportController::OnCongestionControlFeedback( const webrtc::rtcp::CongestionControlFeedback& feedback) { std::optional feedback_msg = @@ -376,7 +394,7 @@ void IceTransportController::PostUpdates(webrtc::NetworkControlUpdate update) { target_bitrate_ = update.target_rate.has_value() ? update.target_rate->target_rate.bps() : 0; - LOG_WARN("Target bitrate [{}]bps", target_bitrate_); + // LOG_WARN("Target bitrate [{}]bps", target_bitrate_); video_encoder_->SetTargetBitrate(target_bitrate_); } diff --git a/src/transport/ice_transport_controller.h b/src/transport/ice_transport_controller.h index 887a113..bbf8afe 100644 --- a/src/transport/ice_transport_controller.h +++ b/src/transport/ice_transport_controller.h @@ -61,6 +61,7 @@ class IceTransportController void OnReceiveCompleteData(const char *data, size_t size); public: + void OnSenderReport(const SenderReport &sender_report); void OnCongestionControlFeedback( const webrtc::rtcp::CongestionControlFeedback &feedback);