stats: Implement receive RTX stats
* retransmittedBytesReceived
* retransmittedPacketsReceived
added to the specification in
https://github.com/w3c/webrtc-stats/pull/735
BUG=webrtc:15096
Change-Id: I6770e5d8d09ac1c2693c918fd943b0ab257ec7ba
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/295260
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Philipp Hancke <phancke@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#39959}
diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h
index 4428ab5..15b0158 100644
--- a/api/stats/rtcstats_objects.h
+++ b/api/stats/rtcstats_objects.h
@@ -425,6 +425,10 @@
RTCStatsMember<uint64_t> fec_packets_discarded;
RTCStatsMember<uint64_t> bytes_received;
RTCStatsMember<uint64_t> header_bytes_received;
+ // Inbound RTX stats. Only defined when RTX is used and it is therefore
+ // possible to distinguish retransmissions.
+ RTCStatsMember<uint64_t> retransmitted_packets_received;
+ RTCStatsMember<uint64_t> retransmitted_bytes_received;
RTCStatsMember<double> last_packet_received_timestamp;
RTCStatsMember<double> jitter_buffer_delay;
RTCStatsMember<double> jitter_buffer_target_delay;
diff --git a/call/video_receive_stream.h b/call/video_receive_stream.h
index bde8c8b..4d6b36b 100644
--- a/call/video_receive_stream.h
+++ b/call/video_receive_stream.h
@@ -145,6 +145,7 @@
std::string c_name;
RtpReceiveStats rtp_stats;
RtcpPacketTypeCounter rtcp_packet_type_counts;
+ absl::optional<RtpReceiveStats> rtx_rtp_stats;
// Timing frame info: all important timestamps for a full lifetime of a
// single 'timing frame'.
diff --git a/media/base/media_channel.h b/media/base/media_channel.h
index 378042f..52aedec 100644
--- a/media/base/media_channel.h
+++ b/media/base/media_channel.h
@@ -443,6 +443,9 @@
int64_t header_and_padding_bytes_received = 0;
int packets_received = 0;
int packets_lost = 0;
+
+ absl::optional<uint64_t> retransmitted_bytes_received;
+ absl::optional<uint64_t> retransmitted_packets_received;
absl::optional<uint32_t> nacks_sent;
// Jitter (network-related) latency (cumulative).
// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-jitterbufferdelay
diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc
index 83581bf..af97dfa 100644
--- a/media/engine/webrtc_video_engine.cc
+++ b/media/engine/webrtc_video_engine.cc
@@ -3364,6 +3364,20 @@
info.timing_frame_info = stats.timing_frame_info;
+ if (stats.rtx_rtp_stats.has_value()) {
+ info.retransmitted_packets_received =
+ stats.rtx_rtp_stats->packet_counter.packets;
+ info.retransmitted_bytes_received =
+ stats.rtx_rtp_stats->packet_counter.payload_bytes;
+ // RTX information gets added to primary counters.
+ info.payload_bytes_received +=
+ stats.rtx_rtp_stats->packet_counter.payload_bytes;
+ info.header_and_padding_bytes_received +=
+ stats.rtx_rtp_stats->packet_counter.header_bytes +
+ stats.rtx_rtp_stats->packet_counter.padding_bytes;
+ info.packets_received += stats.rtx_rtp_stats->packet_counter.packets;
+ }
+
if (log_stats)
RTC_LOG(LS_INFO) << stats.ToString(rtc::TimeMillis());
diff --git a/media/engine/webrtc_video_engine_unittest.cc b/media/engine/webrtc_video_engine_unittest.cc
index 99d36b7..bbabddf 100644
--- a/media/engine/webrtc_video_engine_unittest.cc
+++ b/media/engine/webrtc_video_engine_unittest.cc
@@ -6548,6 +6548,10 @@
stats.total_assembly_time = webrtc::TimeDelta::Millis(4);
stats.frames_assembled_from_multiple_packets = 2;
stats.power_efficient_decoder = true;
+ webrtc::RtpReceiveStats rtx_stats;
+ rtx_stats.packet_counter.packets = 5;
+ rtx_stats.packet_counter.payload_bytes = 23;
+ stats.rtx_rtp_stats = rtx_stats;
stream->SetStats(stats);
cricket::VideoMediaSendInfo send_info;
@@ -6586,6 +6590,10 @@
EXPECT_EQ(stats.frames_assembled_from_multiple_packets,
receive_info.receivers[0].frames_assembled_from_multiple_packets);
EXPECT_TRUE(receive_info.receivers[0].power_efficient_decoder);
+ EXPECT_EQ(stats.rtx_rtp_stats->packet_counter.packets,
+ receive_info.receivers[0].retransmitted_packets_received);
+ EXPECT_EQ(stats.rtx_rtp_stats->packet_counter.payload_bytes,
+ receive_info.receivers[0].retransmitted_bytes_received);
}
TEST_F(WebRtcVideoChannelTest,
diff --git a/pc/rtc_stats_collector.cc b/pc/rtc_stats_collector.cc
index 9b9f5ba..4535597 100644
--- a/pc/rtc_stats_collector.cc
+++ b/pc/rtc_stats_collector.cc
@@ -421,6 +421,14 @@
static_cast<uint64_t>(media_receiver_info.payload_bytes_received);
inbound_stats->header_bytes_received = static_cast<uint64_t>(
media_receiver_info.header_and_padding_bytes_received);
+ if (media_receiver_info.retransmitted_bytes_received.has_value()) {
+ inbound_stats->retransmitted_bytes_received =
+ *media_receiver_info.retransmitted_bytes_received;
+ }
+ if (media_receiver_info.retransmitted_packets_received.has_value()) {
+ inbound_stats->retransmitted_packets_received =
+ *media_receiver_info.retransmitted_packets_received;
+ }
inbound_stats->packets_lost =
static_cast<int32_t>(media_receiver_info.packets_lost);
inbound_stats->jitter_buffer_delay =
diff --git a/pc/rtc_stats_collector_unittest.cc b/pc/rtc_stats_collector_unittest.cc
index 9b0466d..9db5b3f 100644
--- a/pc/rtc_stats_collector_unittest.cc
+++ b/pc/rtc_stats_collector_unittest.cc
@@ -2667,7 +2667,6 @@
video_media_info.receivers[0].jitter_buffer_target_delay_seconds = 1.1;
video_media_info.receivers[0].jitter_buffer_minimum_delay_seconds = 0.999;
video_media_info.receivers[0].jitter_buffer_emitted_count = 13;
-
video_media_info.receivers[0].last_packet_received_timestamp_ms =
absl::nullopt;
video_media_info.receivers[0].content_type = VideoContentType::UNSPECIFIED;
@@ -2676,6 +2675,8 @@
video_media_info.receivers[0].decoder_implementation_name = "";
video_media_info.receivers[0].min_playout_delay_ms = 50;
video_media_info.receivers[0].power_efficient_decoder = false;
+ video_media_info.receivers[0].retransmitted_packets_received = 17;
+ video_media_info.receivers[0].retransmitted_bytes_received = 62;
// Note: these two values intentionally differ,
// only the decoded one should show up.
@@ -2741,6 +2742,8 @@
expected_video.min_playout_delay = 0.05;
expected_video.frames_per_second = 5;
expected_video.power_efficient_decoder = false;
+ expected_video.retransmitted_packets_received = 17;
+ expected_video.retransmitted_bytes_received = 62;
ASSERT_TRUE(report->Get(expected_video.id()));
EXPECT_EQ(
diff --git a/pc/rtc_stats_integrationtest.cc b/pc/rtc_stats_integrationtest.cc
index 42a7769..3f67042 100644
--- a/pc/rtc_stats_integrationtest.cc
+++ b/pc/rtc_stats_integrationtest.cc
@@ -843,6 +843,20 @@
inbound_stream.total_samples_duration);
verifier.TestMemberIsUndefined(inbound_stream.frames_received);
}
+
+ // RTX stats are typically only defined for video where RTX is negotiated.
+ if (inbound_stream.kind.is_defined() && *inbound_stream.kind == "video") {
+ verifier.TestMemberIsNonNegative<uint64_t>(
+ inbound_stream.retransmitted_packets_received);
+ verifier.TestMemberIsNonNegative<uint64_t>(
+ inbound_stream.retransmitted_bytes_received);
+ } else {
+ verifier.TestMemberIsUndefined(
+ inbound_stream.retransmitted_packets_received);
+ verifier.TestMemberIsUndefined(
+ inbound_stream.retransmitted_bytes_received);
+ }
+
// Test runtime too short to get an estimate (at least two RTCP sender
// reports need to be received).
verifier.MarkMemberTested(inbound_stream.estimated_playout_timestamp, true);
diff --git a/stats/rtcstats_objects.cc b/stats/rtcstats_objects.cc
index 997764b..5aef7f9 100644
--- a/stats/rtcstats_objects.cc
+++ b/stats/rtcstats_objects.cc
@@ -466,6 +466,8 @@
&fec_packets_discarded,
&bytes_received,
&header_bytes_received,
+ &retransmitted_packets_received,
+ &retransmitted_bytes_received,
&last_packet_received_timestamp,
&jitter_buffer_delay,
&jitter_buffer_target_delay,
@@ -528,6 +530,8 @@
fec_packets_discarded("fecPacketsDiscarded"),
bytes_received("bytesReceived"),
header_bytes_received("headerBytesReceived"),
+ retransmitted_packets_received("retransmittedPacketsReceived"),
+ retransmitted_bytes_received("retransmittedBytesReceived"),
last_packet_received_timestamp("lastPacketReceivedTimestamp"),
jitter_buffer_delay("jitterBufferDelay"),
jitter_buffer_target_delay("jitterBufferTargetDelay"),
diff --git a/video/video_receive_stream2.cc b/video/video_receive_stream2.cc
index 9cc78c7..d4ca5e8 100644
--- a/video/video_receive_stream2.cc
+++ b/video/video_receive_stream2.cc
@@ -566,8 +566,10 @@
if (rtx_ssrc()) {
StreamStatistician* rtx_statistician =
rtp_receive_statistics_->GetStatistician(rtx_ssrc());
- if (rtx_statistician)
+ if (rtx_statistician) {
stats.total_bitrate_bps += rtx_statistician->BitrateReceived();
+ stats.rtx_rtp_stats = rtx_statistician->GetStats();
+ }
}
return stats;
}