From d3eddff30ca7442f16617f392af6a000c26797e2 Mon Sep 17 00:00:00 2001 From: Danil Chapovalov Date: Wed, 3 May 2023 09:32:01 +0200 Subject: [PATCH] In ReportBlockData expose RTCP report block properties directly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These accessors would allow to deprecated report_block() accessor and then would allow to remove redundant RTCPReportBlock and ReportBlock types converging on single ReportBlockData type to pass that information across WebRTC components helpers like fraction_lost() and jitter() would also allow to unify conversion of the rtp specific format into more common way of represent such information Bug: None Change-Id: I3c97f96affcf83b529095899bd63af007f8b4014 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/303880 Reviewed-by: Henrik Boström Commit-Queue: Danil Chapovalov Cr-Commit-Position: refs/heads/main@{#39975} --- modules/rtp_rtcp/include/report_block_data.cc | 9 +- modules/rtp_rtcp/include/report_block_data.h | 56 +++++++- modules/rtp_rtcp/source/rtcp_receiver.cc | 4 +- .../rtp_rtcp/source/rtcp_receiver_unittest.cc | 127 ++++++++---------- 4 files changed, 114 insertions(+), 82 deletions(-) diff --git a/modules/rtp_rtcp/include/report_block_data.cc b/modules/rtp_rtcp/include/report_block_data.cc index c2a37131db..42a8e75968 100644 --- a/modules/rtp_rtcp/include/report_block_data.cc +++ b/modules/rtp_rtcp/include/report_block_data.cc @@ -10,10 +10,15 @@ #include "modules/rtp_rtcp/include/report_block_data.h" +#include "rtc_base/checks.h" + namespace webrtc { -TimeDelta ReportBlockData::AvgRtt() const { - return num_rtts_ > 0 ? sum_rtt_ / num_rtts_ : TimeDelta::Zero(); +TimeDelta ReportBlockData::jitter(int rtp_clock_rate_hz) const { + RTC_DCHECK_GT(rtp_clock_rate_hz, 0); + // Conversion to TimeDelta and division are swapped to avoid conversion + // to/from floating point types. + return TimeDelta::Seconds(jitter()) / rtp_clock_rate_hz; } void ReportBlockData::SetReportBlock(uint32_t sender_ssrc, diff --git a/modules/rtp_rtcp/include/report_block_data.h b/modules/rtp_rtcp/include/report_block_data.h index fa556cf8e7..48a4d93006 100644 --- a/modules/rtp_rtcp/include/report_block_data.h +++ b/modules/rtp_rtcp/include/report_block_data.h @@ -18,6 +18,9 @@ namespace webrtc { +// Represents fields and derived information received in RTCP report block +// attached to RTCP sender report or RTCP receiver report, as described in +// https://www.rfc-editor.org/rfc/rfc3550#section-6.4.1 class ReportBlockData { public: ReportBlockData() = default; @@ -25,6 +28,50 @@ class ReportBlockData { ReportBlockData(const ReportBlockData&) = default; ReportBlockData& operator=(const ReportBlockData&) = default; + // The SSRC identifier for the originator of this report block, + // i.e. remote receiver of the RTP stream. + uint32_t sender_ssrc() const { return report_block_.sender_ssrc; } + + // The SSRC identifier of the source to which the information in this + // reception report block pertains, i.e. local sender of the RTP stream. + uint32_t source_ssrc() const { return report_block_.source_ssrc; } + + // The fraction of RTP data packets from 'source_ssrc()' lost since the + // previous report block was sent. + // Fraction loss in range [0.0, 1.0]. + float fraction_lost() const { return fraction_lost_raw() / 256.0; } + + // Fraction loss as was written in the raw packet: range is [0, 255] where 0 + // represents no loss, and 255 represents 99.6% loss (255/256 * 100%). + uint8_t fraction_lost_raw() const { return report_block_.fraction_lost; } + + // The total number of RTP data packets from 'source_ssrc()' that have been + // lost since the beginning of reception. This number is defined to be the + // number of packets expected less the number of packets actually received, + // where the number of packets received includes any which are late or + // duplicates. Thus, packets that arrive late are not counted as lost, and the + // loss may be negative if there are duplicates. + int cumulative_lost() const { return report_block_.packets_lost; } + + // The low 16 bits contain the highest sequence number received in an RTP data + // packet from 'source_ssrc()', and the most significant 16 bits extend that + // sequence number with the corresponding count of sequence number cycles. + uint32_t extended_highest_sequence_number() const { + return report_block_.extended_highest_sequence_number; + } + + // An estimate of the statistical variance of the RTP data packet interarrival + // time, measured in RTP timestamp units. The interarrival jitter J is defined + // to be the mean deviation (smoothed absolute value) of the difference D in + // packet spacing at the receiver compared to the sender for a pair of + // packets. + uint32_t jitter() const { return report_block_.jitter; } + + // Jitter converted to common time units. + TimeDelta jitter(int rtp_clock_rate_hz) const; + + // TODO(danilchap): Deprecate in favor of using ReportBlockData accessors + // directly. const RTCPReportBlock& report_block() const { return report_block_; } [[deprecated]] int64_t report_block_timestamp_utc_us() const { @@ -34,11 +81,14 @@ class ReportBlockData { [[deprecated]] int64_t min_rtt_ms() const { return min_rtt_.ms(); } [[deprecated]] int64_t max_rtt_ms() const { return max_rtt_.ms(); } [[deprecated]] int64_t sum_rtt_ms() const { return sum_rtt_.ms(); } - [[deprecated]] double AvgRttMs() const { return AvgRtt().ms(); } + // Time in utc epoch (Jan 1st, 1970) the report block was received. Timestamp report_block_timestamp_utc() const { return report_block_timestamp_utc_; } + + // Round Trip Time measurments for given (sender_ssrc, source_ssrc) pair. + // Min, max, sum, number of measurements are since beginning of the call. TimeDelta last_rtt() const { return last_rtt_; } TimeDelta min_rtt() const { return min_rtt_; } TimeDelta max_rtt() const { return max_rtt_; } @@ -46,11 +96,9 @@ class ReportBlockData { size_t num_rtts() const { return num_rtts_; } bool has_rtt() const { return num_rtts_ != 0; } - TimeDelta AvgRtt() const; - void SetReportBlock(uint32_t sender_ssrc, const rtcp::ReportBlock& report_block, - Timestamp report_block_timestamp_utc_us); + Timestamp report_block_timestamp_utc); void AddRoundTripTimeSample(TimeDelta rtt); private: diff --git a/modules/rtp_rtcp/source/rtcp_receiver.cc b/modules/rtp_rtcp/source/rtcp_receiver.cc index 5f53c5823c..9a0effca12 100644 --- a/modules/rtp_rtcp/source/rtcp_receiver.cc +++ b/modules/rtp_rtcp/source/rtcp_receiver.cc @@ -612,7 +612,7 @@ void RTCPReceiver::HandleReportBlock(const ReportBlock& report_block, ReportBlockData* report_block_data = &received_report_blocks_[report_block.source_ssrc()]; if (report_block.extended_high_seq_num() > - report_block_data->report_block().extended_highest_sequence_number) { + report_block_data->extended_highest_sequence_number()) { // We have successfully delivered new RTP packets to the remote side after // the last RR was sent from the remote side. last_increased_sequence_number_ = last_received_rb_; @@ -806,7 +806,7 @@ bool RTCPReceiver::HandleBye(const CommonHeader& rtcp_block) { // Clear our lists. rtts_.erase(bye.sender_ssrc()); EraseIf(received_report_blocks_, [&](const auto& elem) { - return elem.second.report_block().sender_ssrc == bye.sender_ssrc(); + return elem.second.sender_ssrc() == bye.sender_ssrc(); }); TmmbrInformation* tmmbr_info = GetTmmbrInformation(bye.sender_ssrc()); diff --git a/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc index 979609ab40..b1a5667801 100644 --- a/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc +++ b/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc @@ -441,12 +441,10 @@ TEST(RtcpReceiverTest, InjectRrPacketWithTwoReportBlocks) { receiver.IncomingPacket(rr1.Build()); EXPECT_EQ(now, receiver.LastReceivedReportBlockMs()); - EXPECT_THAT(receiver.GetLatestReportBlockData(), - UnorderedElementsAre( - Property(&ReportBlockData::report_block, - Field(&RTCPReportBlock::fraction_lost, 0)), - Property(&ReportBlockData::report_block, - Field(&RTCPReportBlock::fraction_lost, 10)))); + EXPECT_THAT( + receiver.GetLatestReportBlockData(), + UnorderedElementsAre(Property(&ReportBlockData::fraction_lost_raw, 0), + Property(&ReportBlockData::fraction_lost_raw, 10))); // Insert next receiver report with same ssrc but new values. rtcp::ReportBlock rb3; @@ -478,20 +476,16 @@ TEST(RtcpReceiverTest, InjectRrPacketWithTwoReportBlocks) { EXPECT_THAT( receiver.GetLatestReportBlockData(), UnorderedElementsAre( - Property( - &ReportBlockData::report_block, - AllOf(Field(&RTCPReportBlock::source_ssrc, kReceiverMainSsrc), - Field(&RTCPReportBlock::fraction_lost, kFracLost[0]), - Field(&RTCPReportBlock::packets_lost, kCumLost[0]), - Field(&RTCPReportBlock::extended_highest_sequence_number, - kSequenceNumbers[0]))), - Property( - &ReportBlockData::report_block, - AllOf(Field(&RTCPReportBlock::source_ssrc, kReceiverExtraSsrc), - Field(&RTCPReportBlock::fraction_lost, kFracLost[1]), - Field(&RTCPReportBlock::packets_lost, kCumLost[1]), - Field(&RTCPReportBlock::extended_highest_sequence_number, - kSequenceNumbers[1]))))); + AllOf(Property(&ReportBlockData::source_ssrc, kReceiverMainSsrc), + Property(&ReportBlockData::fraction_lost_raw, kFracLost[0]), + Property(&ReportBlockData::cumulative_lost, kCumLost[0]), + Property(&ReportBlockData::extended_highest_sequence_number, + kSequenceNumbers[0])), + AllOf(Property(&ReportBlockData::source_ssrc, kReceiverExtraSsrc), + Property(&ReportBlockData::fraction_lost_raw, kFracLost[1]), + Property(&ReportBlockData::cumulative_lost, kCumLost[1]), + Property(&ReportBlockData::extended_highest_sequence_number, + kSequenceNumbers[1])))); } TEST(RtcpReceiverTest, @@ -522,16 +516,14 @@ TEST(RtcpReceiverTest, EXPECT_EQ(now, receiver.LastReceivedReportBlockMs()); - EXPECT_THAT( - receiver.GetLatestReportBlockData(), - ElementsAre(Property( - &ReportBlockData::report_block, - AllOf(Field(&RTCPReportBlock::source_ssrc, kReceiverMainSsrc), - Field(&RTCPReportBlock::sender_ssrc, kSenderSsrc), - Field(&RTCPReportBlock::fraction_lost, kFracLost[0]), - Field(&RTCPReportBlock::packets_lost, kCumLost[0]), - Field(&RTCPReportBlock::extended_highest_sequence_number, - kSequenceNumbers[0]))))); + EXPECT_THAT(receiver.GetLatestReportBlockData(), + ElementsAre(AllOf( + Property(&ReportBlockData::source_ssrc, kReceiverMainSsrc), + Property(&ReportBlockData::sender_ssrc, kSenderSsrc), + Property(&ReportBlockData::fraction_lost_raw, kFracLost[0]), + Property(&ReportBlockData::cumulative_lost, kCumLost[0]), + Property(&ReportBlockData::extended_highest_sequence_number, + kSequenceNumbers[0])))); rtcp::ReportBlock rb2; rb2.SetMediaSsrc(kReceiverMainSsrc); @@ -547,16 +539,14 @@ TEST(RtcpReceiverTest, OnReceivedRtcpReceiverReport(SizeIs(1), _, now)); receiver.IncomingPacket(rr2.Build()); - EXPECT_THAT( - receiver.GetLatestReportBlockData(), - UnorderedElementsAre(Property( - &ReportBlockData::report_block, - AllOf(Field(&RTCPReportBlock::source_ssrc, kReceiverMainSsrc), - Field(&RTCPReportBlock::sender_ssrc, kSenderSsrc2), - Field(&RTCPReportBlock::fraction_lost, kFracLost[1]), - Field(&RTCPReportBlock::packets_lost, kCumLost[1]), - Field(&RTCPReportBlock::extended_highest_sequence_number, - kSequenceNumbers[1]))))); + EXPECT_THAT(receiver.GetLatestReportBlockData(), + UnorderedElementsAre(AllOf( + Property(&ReportBlockData::source_ssrc, kReceiverMainSsrc), + Property(&ReportBlockData::sender_ssrc, kSenderSsrc2), + Property(&ReportBlockData::fraction_lost_raw, kFracLost[1]), + Property(&ReportBlockData::cumulative_lost, kCumLost[1]), + Property(&ReportBlockData::extended_highest_sequence_number, + kSequenceNumbers[1])))); } TEST(RtcpReceiverTest, GetRtt) { @@ -1573,19 +1563,18 @@ TEST(RtcpReceiverTest, rtcp_report.SetSenderSsrc(kSenderSsrc); rtcp_report.AddReportBlock(rtcp_block); EXPECT_CALL(observer, OnReportBlockDataUpdated) - .WillOnce([&](ReportBlockData report_block_data) { - const auto& report_block = report_block_data.report_block(); - EXPECT_EQ(rtcp_block.source_ssrc(), report_block.source_ssrc); - EXPECT_EQ(kSenderSsrc, report_block.sender_ssrc); - EXPECT_EQ(rtcp_block.fraction_lost(), report_block.fraction_lost); - EXPECT_EQ(rtcp_block.cumulative_lost(), report_block.packets_lost); + .WillOnce([&](ReportBlockData report_block) { + EXPECT_EQ(rtcp_block.source_ssrc(), report_block.source_ssrc()); + EXPECT_EQ(kSenderSsrc, report_block.sender_ssrc()); + EXPECT_EQ(rtcp_block.fraction_lost(), report_block.fraction_lost_raw()); + EXPECT_EQ(rtcp_block.cumulative_lost(), report_block.cumulative_lost()); EXPECT_EQ(rtcp_block.extended_high_seq_num(), - report_block.extended_highest_sequence_number); - EXPECT_EQ(rtcp_block.jitter(), report_block.jitter); - EXPECT_EQ(report_block_data.report_block_timestamp_utc(), + report_block.extended_highest_sequence_number()); + EXPECT_EQ(rtcp_block.jitter(), report_block.jitter()); + EXPECT_EQ(report_block.report_block_timestamp_utc(), Timestamp::Millis(kNtpNowMs)); // No RTT is calculated in this test. - EXPECT_EQ(0u, report_block_data.num_rtts()); + EXPECT_EQ(0u, report_block.num_rtts()); }); EXPECT_CALL(mocks.rtp_rtcp_impl, OnReceivedRtcpReportBlocks); EXPECT_CALL(mocks.bandwidth_observer, OnReceivedRtcpReceiverReport); @@ -1627,8 +1616,7 @@ TEST(RtcpReceiverTest, VerifyRttObtainedFromReportBlockDataObserver) { InSequence sequence; EXPECT_CALL(observer, OnReportBlockDataUpdated) .WillOnce([&](ReportBlockData report_block_data) { - EXPECT_EQ(kReceiverMainSsrc, - report_block_data.report_block().source_ssrc); + EXPECT_EQ(kReceiverMainSsrc, report_block_data.source_ssrc()); EXPECT_EQ(1u, report_block_data.num_rtts()); EXPECT_EQ(kRtt, report_block_data.min_rtt()); EXPECT_EQ(kRtt, report_block_data.max_rtt()); @@ -1637,8 +1625,7 @@ TEST(RtcpReceiverTest, VerifyRttObtainedFromReportBlockDataObserver) { }); EXPECT_CALL(observer, OnReportBlockDataUpdated) .WillOnce([](ReportBlockData report_block_data) { - EXPECT_EQ(kReceiverExtraSsrc, - report_block_data.report_block().source_ssrc); + EXPECT_EQ(kReceiverExtraSsrc, report_block_data.source_ssrc()); EXPECT_EQ(0u, report_block_data.num_rtts()); }); receiver.IncomingPacket(sr.Build()); @@ -1664,11 +1651,9 @@ TEST(RtcpReceiverTest, GetReportBlockDataAfterOneReportBlock) { auto report_block_datas = receiver.GetLatestReportBlockData(); ASSERT_THAT(report_block_datas, SizeIs(1)); - EXPECT_EQ(kReceiverMainSsrc, - report_block_datas[0].report_block().source_ssrc); - EXPECT_EQ( - kSequenceNumber, - report_block_datas[0].report_block().extended_highest_sequence_number); + EXPECT_EQ(kReceiverMainSsrc, report_block_datas[0].source_ssrc()); + EXPECT_EQ(kSequenceNumber, + report_block_datas[0].extended_highest_sequence_number()); } TEST(RtcpReceiverTest, GetReportBlockDataAfterTwoReportBlocksOfSameSsrc) { @@ -1706,11 +1691,9 @@ TEST(RtcpReceiverTest, GetReportBlockDataAfterTwoReportBlocksOfSameSsrc) { // Only the latest block should be returned. auto report_block_datas = receiver.GetLatestReportBlockData(); ASSERT_THAT(report_block_datas, SizeIs(1)); - EXPECT_EQ(kReceiverMainSsrc, - report_block_datas[0].report_block().source_ssrc); - EXPECT_EQ( - kSequenceNumber2, - report_block_datas[0].report_block().extended_highest_sequence_number); + EXPECT_EQ(kReceiverMainSsrc, report_block_datas[0].source_ssrc()); + EXPECT_EQ(kSequenceNumber2, + report_block_datas[0].extended_highest_sequence_number()); } TEST(RtcpReceiverTest, GetReportBlockDataAfterTwoReportBlocksOfDifferentSsrcs) { @@ -1747,16 +1730,12 @@ TEST(RtcpReceiverTest, GetReportBlockDataAfterTwoReportBlocksOfDifferentSsrcs) { // Both report blocks should be returned. auto report_block_datas = receiver.GetLatestReportBlockData(); ASSERT_THAT(report_block_datas, SizeIs(2)); - EXPECT_EQ(kReceiverMainSsrc, - report_block_datas[0].report_block().source_ssrc); - EXPECT_EQ( - kSequenceNumber1, - report_block_datas[0].report_block().extended_highest_sequence_number); - EXPECT_EQ(kReceiverExtraSsrc, - report_block_datas[1].report_block().source_ssrc); - EXPECT_EQ( - kSequenceNumber2, - report_block_datas[1].report_block().extended_highest_sequence_number); + EXPECT_EQ(kReceiverMainSsrc, report_block_datas[0].source_ssrc()); + EXPECT_EQ(kSequenceNumber1, + report_block_datas[0].extended_highest_sequence_number()); + EXPECT_EQ(kReceiverExtraSsrc, report_block_datas[1].source_ssrc()); + EXPECT_EQ(kSequenceNumber2, + report_block_datas[1].extended_highest_sequence_number()); } TEST(RtcpReceiverTest, ReceivesTransportFeedback) {