In ReportBlockData expose RTCP report block properties directly
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 <hbos@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39975}
diff --git a/modules/rtp_rtcp/include/report_block_data.cc b/modules/rtp_rtcp/include/report_block_data.cc
index c2a3713..42a8e75 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 fa556cf..48a4d93 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 @@
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 @@
[[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<double>(); }
+ // 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 @@
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 5f53c58..9a0effc 100644
--- a/modules/rtp_rtcp/source/rtcp_receiver.cc
+++ b/modules/rtp_rtcp/source/rtcp_receiver.cc
@@ -612,7 +612,7 @@
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 @@
// 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 979609a..b1a5667 100644
--- a/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
+++ b/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
@@ -441,12 +441,10 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
});
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 @@
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 @@
// 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 @@
// 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) {