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> 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;

View file

@ -145,6 +145,7 @@ class VideoReceiveStreamInterface : public MediaReceiveStreamInterface {
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'.

View file

@ -443,6 +443,9 @@ struct MediaReceiverInfo {
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

View file

@ -3364,6 +3364,20 @@ WebRtcVideoChannel::WebRtcVideoReceiveStream::GetVideoReceiverInfo(
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());

View file

@ -6548,6 +6548,10 @@ TEST_F(WebRtcVideoChannelTest, GetStatsTranslatesDecodeStatsCorrectly) {
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 @@ TEST_F(WebRtcVideoChannelTest, GetStatsTranslatesDecodeStatsCorrectly) {
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,

View file

@ -421,6 +421,14 @@ void SetInboundRTPStreamStatsFromMediaReceiverInfo(
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 =

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_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 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRtpStreamStats_Video) {
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 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRtpStreamStats_Video) {
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(

View file

@ -843,6 +843,20 @@ class RTCStatsReportVerifier {
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);

View file

@ -466,6 +466,8 @@ WEBRTC_RTCSTATS_IMPL(
&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 @@ RTCInboundRtpStreamStats::RTCInboundRtpStreamStats(std::string id,
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"),

View file

@ -566,8 +566,10 @@ VideoReceiveStreamInterface::Stats VideoReceiveStream2::GetStats() const {
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;
}