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}
This commit is contained in:
Philipp Hancke 2023-04-25 10:23:47 +02:00 committed by WebRTC LUCI CQ
parent 2b72d84733
commit f78d1f211a
10 changed files with 63 additions and 2 deletions

View file

@ -425,6 +425,10 @@ class RTC_EXPORT RTCInboundRtpStreamStats final
RTCStatsMember<uint64_t> fec_packets_discarded; RTCStatsMember<uint64_t> fec_packets_discarded;
RTCStatsMember<uint64_t> bytes_received; RTCStatsMember<uint64_t> bytes_received;
RTCStatsMember<uint64_t> header_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> last_packet_received_timestamp;
RTCStatsMember<double> jitter_buffer_delay; RTCStatsMember<double> jitter_buffer_delay;
RTCStatsMember<double> jitter_buffer_target_delay; RTCStatsMember<double> jitter_buffer_target_delay;

View file

@ -145,6 +145,7 @@ class VideoReceiveStreamInterface : public MediaReceiveStreamInterface {
std::string c_name; std::string c_name;
RtpReceiveStats rtp_stats; RtpReceiveStats rtp_stats;
RtcpPacketTypeCounter rtcp_packet_type_counts; RtcpPacketTypeCounter rtcp_packet_type_counts;
absl::optional<RtpReceiveStats> rtx_rtp_stats;
// Timing frame info: all important timestamps for a full lifetime of a // Timing frame info: all important timestamps for a full lifetime of a
// single 'timing frame'. // single 'timing frame'.

View file

@ -443,6 +443,9 @@ struct MediaReceiverInfo {
int64_t header_and_padding_bytes_received = 0; int64_t header_and_padding_bytes_received = 0;
int packets_received = 0; int packets_received = 0;
int packets_lost = 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; absl::optional<uint32_t> nacks_sent;
// Jitter (network-related) latency (cumulative). // Jitter (network-related) latency (cumulative).
// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-jitterbufferdelay // https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-jitterbufferdelay

View file

@ -3364,6 +3364,20 @@ WebRtcVideoChannel::WebRtcVideoReceiveStream::GetVideoReceiverInfo(
info.timing_frame_info = stats.timing_frame_info; 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) if (log_stats)
RTC_LOG(LS_INFO) << stats.ToString(rtc::TimeMillis()); RTC_LOG(LS_INFO) << stats.ToString(rtc::TimeMillis());

View file

@ -6548,6 +6548,10 @@ TEST_F(WebRtcVideoChannelTest, GetStatsTranslatesDecodeStatsCorrectly) {
stats.total_assembly_time = webrtc::TimeDelta::Millis(4); stats.total_assembly_time = webrtc::TimeDelta::Millis(4);
stats.frames_assembled_from_multiple_packets = 2; stats.frames_assembled_from_multiple_packets = 2;
stats.power_efficient_decoder = true; 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); stream->SetStats(stats);
cricket::VideoMediaSendInfo send_info; cricket::VideoMediaSendInfo send_info;
@ -6586,6 +6590,10 @@ TEST_F(WebRtcVideoChannelTest, GetStatsTranslatesDecodeStatsCorrectly) {
EXPECT_EQ(stats.frames_assembled_from_multiple_packets, EXPECT_EQ(stats.frames_assembled_from_multiple_packets,
receive_info.receivers[0].frames_assembled_from_multiple_packets); receive_info.receivers[0].frames_assembled_from_multiple_packets);
EXPECT_TRUE(receive_info.receivers[0].power_efficient_decoder); 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, TEST_F(WebRtcVideoChannelTest,

View file

@ -421,6 +421,14 @@ void SetInboundRTPStreamStatsFromMediaReceiverInfo(
static_cast<uint64_t>(media_receiver_info.payload_bytes_received); static_cast<uint64_t>(media_receiver_info.payload_bytes_received);
inbound_stats->header_bytes_received = static_cast<uint64_t>( inbound_stats->header_bytes_received = static_cast<uint64_t>(
media_receiver_info.header_and_padding_bytes_received); 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 = inbound_stats->packets_lost =
static_cast<int32_t>(media_receiver_info.packets_lost); static_cast<int32_t>(media_receiver_info.packets_lost);
inbound_stats->jitter_buffer_delay = inbound_stats->jitter_buffer_delay =

View file

@ -2667,7 +2667,6 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRtpStreamStats_Video) {
video_media_info.receivers[0].jitter_buffer_target_delay_seconds = 1.1; 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_minimum_delay_seconds = 0.999;
video_media_info.receivers[0].jitter_buffer_emitted_count = 13; video_media_info.receivers[0].jitter_buffer_emitted_count = 13;
video_media_info.receivers[0].last_packet_received_timestamp_ms = video_media_info.receivers[0].last_packet_received_timestamp_ms =
absl::nullopt; absl::nullopt;
video_media_info.receivers[0].content_type = VideoContentType::UNSPECIFIED; video_media_info.receivers[0].content_type = VideoContentType::UNSPECIFIED;
@ -2676,6 +2675,8 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRtpStreamStats_Video) {
video_media_info.receivers[0].decoder_implementation_name = ""; video_media_info.receivers[0].decoder_implementation_name = "";
video_media_info.receivers[0].min_playout_delay_ms = 50; video_media_info.receivers[0].min_playout_delay_ms = 50;
video_media_info.receivers[0].power_efficient_decoder = false; 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, // Note: these two values intentionally differ,
// only the decoded one should show up. // only the decoded one should show up.
@ -2741,6 +2742,8 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRtpStreamStats_Video) {
expected_video.min_playout_delay = 0.05; expected_video.min_playout_delay = 0.05;
expected_video.frames_per_second = 5; expected_video.frames_per_second = 5;
expected_video.power_efficient_decoder = false; 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())); ASSERT_TRUE(report->Get(expected_video.id()));
EXPECT_EQ( EXPECT_EQ(

View file

@ -843,6 +843,20 @@ class RTCStatsReportVerifier {
inbound_stream.total_samples_duration); inbound_stream.total_samples_duration);
verifier.TestMemberIsUndefined(inbound_stream.frames_received); 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 // Test runtime too short to get an estimate (at least two RTCP sender
// reports need to be received). // reports need to be received).
verifier.MarkMemberTested(inbound_stream.estimated_playout_timestamp, true); verifier.MarkMemberTested(inbound_stream.estimated_playout_timestamp, true);

View file

@ -466,6 +466,8 @@ WEBRTC_RTCSTATS_IMPL(
&fec_packets_discarded, &fec_packets_discarded,
&bytes_received, &bytes_received,
&header_bytes_received, &header_bytes_received,
&retransmitted_packets_received,
&retransmitted_bytes_received,
&last_packet_received_timestamp, &last_packet_received_timestamp,
&jitter_buffer_delay, &jitter_buffer_delay,
&jitter_buffer_target_delay, &jitter_buffer_target_delay,
@ -528,6 +530,8 @@ RTCInboundRtpStreamStats::RTCInboundRtpStreamStats(std::string id,
fec_packets_discarded("fecPacketsDiscarded"), fec_packets_discarded("fecPacketsDiscarded"),
bytes_received("bytesReceived"), bytes_received("bytesReceived"),
header_bytes_received("headerBytesReceived"), header_bytes_received("headerBytesReceived"),
retransmitted_packets_received("retransmittedPacketsReceived"),
retransmitted_bytes_received("retransmittedBytesReceived"),
last_packet_received_timestamp("lastPacketReceivedTimestamp"), last_packet_received_timestamp("lastPacketReceivedTimestamp"),
jitter_buffer_delay("jitterBufferDelay"), jitter_buffer_delay("jitterBufferDelay"),
jitter_buffer_target_delay("jitterBufferTargetDelay"), jitter_buffer_target_delay("jitterBufferTargetDelay"),

View file

@ -566,8 +566,10 @@ VideoReceiveStreamInterface::Stats VideoReceiveStream2::GetStats() const {
if (rtx_ssrc()) { if (rtx_ssrc()) {
StreamStatistician* rtx_statistician = StreamStatistician* rtx_statistician =
rtp_receive_statistics_->GetStatistician(rtx_ssrc()); rtp_receive_statistics_->GetStatistician(rtx_ssrc());
if (rtx_statistician) if (rtx_statistician) {
stats.total_bitrate_bps += rtx_statistician->BitrateReceived(); stats.total_bitrate_bps += rtx_statistician->BitrateReceived();
stats.rtx_rtp_stats = rtx_statistician->GetStats();
}
} }
return stats; return stats;
} }