Wire up RTCInboundRtpStreamStats.lastPacketReceivedTimestamp.
This collects this metric for both audio and video streams.
https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-lastpacketreceivedtimestamp
This is a follow-up to https://webrtc-review.googlesource.com/c/src/+/130479
which calculated this metric. This CL is purely plumbing from
"StreamDataCounters::last_packet_received_timestamp_ms" to
RTCInboundRtpStreamStats.
Bug: webrtc:10449
Change-Id: I757ad19b5b8e84553da5edd4a75efa3e1fe30b56
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/131397
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Åsa Persson <asapersson@webrtc.org>
Reviewed-by: Fredrik Solenberg <solenberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27628}
diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h
index 8a1fe56..81ec084 100644
--- a/api/stats/rtcstats_objects.h
+++ b/api/stats/rtcstats_objects.h
@@ -397,6 +397,7 @@
RTCStatsMember<uint32_t> packets_received;
RTCStatsMember<uint64_t> bytes_received;
RTCStatsMember<int32_t> packets_lost; // Signed per RFC 3550
+ RTCStatsMember<double> last_packet_received_timestamp;
// TODO(hbos): Collect and populate this value for both "audio" and "video",
// currently not collected for "video". https://bugs.webrtc.org/7065
RTCStatsMember<double> jitter;
diff --git a/audio/audio_receive_stream.cc b/audio/audio_receive_stream.cc
index e13e880..b4948ee 100644
--- a/audio/audio_receive_stream.cc
+++ b/audio/audio_receive_stream.cc
@@ -190,6 +190,8 @@
stats.packets_lost = call_stats.cumulativeLost;
stats.fraction_lost = Q8ToFloat(call_stats.fractionLost);
stats.capture_start_ntp_time_ms = call_stats.capture_start_ntp_time_ms_;
+ stats.last_packet_received_timestamp_ms =
+ call_stats.last_packet_received_timestamp_ms;
stats.codec_name = receive_codec->second.name;
stats.codec_payload_type = receive_codec->first;
stats.ext_seqnum = call_stats.extendedMax;
diff --git a/audio/channel_receive.cc b/audio/channel_receive.cc
index 4f00d9f..f65d125 100644
--- a/audio/channel_receive.cc
+++ b/audio/channel_receive.cc
@@ -757,17 +757,23 @@
stats.rttMs = GetRTT();
// --- Data counters
-
- size_t bytesReceived(0);
- uint32_t packetsReceived(0);
-
if (statistician) {
- statistician->GetDataCounters(&bytesReceived, &packetsReceived);
+ StreamDataCounters data_counters;
+ statistician->GetReceiveStreamDataCounters(&data_counters);
+ // TODO(http://crbug.com/webrtc/10525): Bytes received should only include
+ // payload bytes, not header and padding bytes.
+ stats.bytesReceived = data_counters.transmitted.payload_bytes +
+ data_counters.transmitted.header_bytes +
+ data_counters.transmitted.padding_bytes;
+ stats.packetsReceived = data_counters.transmitted.packets;
+ stats.last_packet_received_timestamp_ms =
+ data_counters.last_packet_received_timestamp_ms;
+ } else {
+ stats.bytesReceived = 0;
+ stats.packetsReceived = 0;
+ stats.last_packet_received_timestamp_ms = absl::nullopt;
}
- stats.bytesReceived = bytesReceived;
- stats.packetsReceived = packetsReceived;
-
// --- Timestamps
{
rtc::CritScope lock(&ts_stats_lock_);
diff --git a/audio/channel_receive.h b/audio/channel_receive.h
index a67b0db..1f78874 100644
--- a/audio/channel_receive.h
+++ b/audio/channel_receive.h
@@ -59,6 +59,10 @@
// The capture ntp time (in local timebase) of the first played out audio
// frame.
int64_t capture_start_ntp_time_ms_;
+ // The timestamp at which the last packet was received, i.e. the time of the
+ // local clock when it was received - not the RTP timestamp of that packet.
+ // https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-lastpacketreceivedtimestamp
+ absl::optional<int64_t> last_packet_received_timestamp_ms;
};
namespace voe {
diff --git a/call/audio_receive_stream.h b/call/audio_receive_stream.h
index 3f1a5ad..257042b 100644
--- a/call/audio_receive_stream.h
+++ b/call/audio_receive_stream.h
@@ -73,6 +73,10 @@
int32_t decoding_plc_cng = 0;
int32_t decoding_muted_output = 0;
int64_t capture_start_ntp_time_ms = 0;
+ // The timestamp at which the last packet was received, i.e. the time of the
+ // local clock when it was received - not the RTP timestamp of that packet.
+ // https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-lastpacketreceivedtimestamp
+ absl::optional<int64_t> last_packet_received_timestamp_ms;
uint64_t jitter_buffer_flushes = 0;
double relative_packet_arrival_delay_seconds = 0.0;
};
diff --git a/media/base/media_channel.h b/media/base/media_channel.h
index b64803b..c21f89e 100644
--- a/media/base/media_channel.h
+++ b/media/base/media_channel.h
@@ -435,6 +435,10 @@
int packets_rcvd = 0;
int packets_lost = 0;
float fraction_lost = 0.0f;
+ // The timestamp at which the last packet was received, i.e. the time of the
+ // local clock when it was received - not the RTP timestamp of that packet.
+ // https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-lastpacketreceivedtimestamp
+ absl::optional<int64_t> last_packet_received_timestamp_ms;
std::string codec_name;
absl::optional<int> codec_payload_type;
std::vector<SsrcReceiverInfo> local_stats;
diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc
index 762f033..57ff372 100644
--- a/media/engine/webrtc_video_engine.cc
+++ b/media/engine/webrtc_video_engine.cc
@@ -2697,6 +2697,8 @@
info.frames_decoded = stats.frames_decoded;
info.frames_rendered = stats.frames_rendered;
info.qp_sum = stats.qp_sum;
+ info.last_packet_received_timestamp_ms =
+ stats.rtp_stats.last_packet_received_timestamp_ms;
info.first_frame_received_to_decoded_ms =
stats.first_frame_received_to_decoded_ms;
info.interframe_delay_max_ms = stats.interframe_delay_max_ms;
diff --git a/media/engine/webrtc_voice_engine.cc b/media/engine/webrtc_voice_engine.cc
index b35090d..0765427 100644
--- a/media/engine/webrtc_voice_engine.cc
+++ b/media/engine/webrtc_voice_engine.cc
@@ -2267,6 +2267,8 @@
rinfo.decoding_plc_cng = stats.decoding_plc_cng;
rinfo.decoding_muted_output = stats.decoding_muted_output;
rinfo.capture_start_ntp_time_ms = stats.capture_start_ntp_time_ms;
+ rinfo.last_packet_received_timestamp_ms =
+ stats.last_packet_received_timestamp_ms;
rinfo.jitter_buffer_flushes = stats.jitter_buffer_flushes;
rinfo.relative_packet_arrival_delay_seconds =
stats.relative_packet_arrival_delay_seconds;
diff --git a/pc/rtc_stats_collector.cc b/pc/rtc_stats_collector.cc
index 7427356..3bf8566 100644
--- a/pc/rtc_stats_collector.cc
+++ b/pc/rtc_stats_collector.cc
@@ -244,6 +244,12 @@
rtc::kNumMillisecsPerSec;
// |fir_count|, |pli_count| and |sli_count| are only valid for video and are
// purposefully left undefined for audio.
+ if (voice_receiver_info.last_packet_received_timestamp_ms) {
+ inbound_audio->last_packet_received_timestamp =
+ static_cast<double>(
+ *voice_receiver_info.last_packet_received_timestamp_ms) /
+ rtc::kNumMillisecsPerSec;
+ }
}
void SetInboundRTPStreamStatsFromVideoReceiverInfo(
@@ -267,6 +273,12 @@
inbound_video->frames_decoded = video_receiver_info.frames_decoded;
if (video_receiver_info.qp_sum)
inbound_video->qp_sum = *video_receiver_info.qp_sum;
+ if (video_receiver_info.last_packet_received_timestamp_ms) {
+ inbound_video->last_packet_received_timestamp =
+ static_cast<double>(
+ *video_receiver_info.last_packet_received_timestamp_ms) /
+ rtc::kNumMillisecsPerSec;
+ }
// TODO(https://crbug.com/webrtc/10529): When info's |content_info| is
// optional, support the "unspecified" value.
if (video_receiver_info.content_type == VideoContentType::SCREENSHARE)
diff --git a/pc/rtc_stats_collector_unittest.cc b/pc/rtc_stats_collector_unittest.cc
index 7e843a6..82cd241 100644
--- a/pc/rtc_stats_collector_unittest.cc
+++ b/pc/rtc_stats_collector_unittest.cc
@@ -1625,6 +1625,8 @@
voice_media_info.receivers[0].codec_payload_type = 42;
voice_media_info.receivers[0].jitter_ms = 4500;
voice_media_info.receivers[0].fraction_lost = 5.5f;
+ voice_media_info.receivers[0].last_packet_received_timestamp_ms =
+ absl::nullopt;
RtpCodecParameters codec_parameters;
codec_parameters.payload_type = 42;
@@ -1656,12 +1658,25 @@
expected_audio.packets_received = 2;
expected_audio.bytes_received = 3;
expected_audio.packets_lost = -1;
+ // |expected_audio.last_packet_received_timestamp| should be undefined.
expected_audio.jitter = 4.5;
expected_audio.fraction_lost = 5.5;
ASSERT_TRUE(report->Get(expected_audio.id()));
EXPECT_EQ(
report->Get(expected_audio.id())->cast_to<RTCInboundRTPStreamStats>(),
expected_audio);
+
+ // Set previously undefined values and "GetStats" again.
+ voice_media_info.receivers[0].last_packet_received_timestamp_ms = 3000;
+ expected_audio.last_packet_received_timestamp = 3.0;
+ voice_media_channel->SetStats(voice_media_info);
+
+ report = stats_->GetFreshStatsReport();
+
+ ASSERT_TRUE(report->Get(expected_audio.id()));
+ EXPECT_EQ(
+ report->Get(expected_audio.id())->cast_to<RTCInboundRTPStreamStats>(),
+ expected_audio);
EXPECT_TRUE(report->Get(*expected_audio.track_id));
EXPECT_TRUE(report->Get(*expected_audio.transport_id));
EXPECT_TRUE(report->Get(*expected_audio.codec_id));
@@ -1684,6 +1699,8 @@
video_media_info.receivers[0].nacks_sent = 7;
video_media_info.receivers[0].frames_decoded = 8;
video_media_info.receivers[0].qp_sum = absl::nullopt;
+ video_media_info.receivers[0].last_packet_received_timestamp_ms =
+ absl::nullopt;
video_media_info.receivers[0].content_type = VideoContentType::UNSPECIFIED;
RtpCodecParameters codec_parameters;
@@ -1719,6 +1736,7 @@
expected_video.fraction_lost = 4.5;
expected_video.frames_decoded = 8;
// |expected_video.qp_sum| should be undefined.
+ // |expected_video.last_packet_received_timestamp| should be undefined.
// |expected_video.content_type| should be undefined.
ASSERT_TRUE(report->Get(expected_video.id()));
@@ -1728,7 +1746,9 @@
// Set previously undefined values and "GetStats" again.
video_media_info.receivers[0].qp_sum = 9;
+ video_media_info.receivers[0].last_packet_received_timestamp_ms = 1000;
expected_video.qp_sum = 9;
+ expected_video.last_packet_received_timestamp = 1.0;
video_media_info.receivers[0].content_type = VideoContentType::SCREENSHARE;
expected_video.content_type = "screenshare";
video_media_channel->SetStats(video_media_info);
diff --git a/pc/rtc_stats_integrationtest.cc b/pc/rtc_stats_integrationtest.cc
index 6935769..9b1b6d0 100644
--- a/pc/rtc_stats_integrationtest.cc
+++ b/pc/rtc_stats_integrationtest.cc
@@ -719,6 +719,7 @@
// packets_lost is defined as signed, but this should never happen in
// this test. See RFC 3550.
verifier.TestMemberIsNonNegative<int32_t>(inbound_stream.packets_lost);
+ verifier.TestMemberIsDefined(inbound_stream.last_packet_received_timestamp);
if (inbound_stream.media_type.is_defined() &&
*inbound_stream.media_type == "video") {
verifier.TestMemberIsUndefined(inbound_stream.jitter);
diff --git a/stats/rtcstats_objects.cc b/stats/rtcstats_objects.cc
index 7c023d1..4bf3e68 100644
--- a/stats/rtcstats_objects.cc
+++ b/stats/rtcstats_objects.cc
@@ -578,6 +578,7 @@
&packets_received,
&bytes_received,
&packets_lost,
+ &last_packet_received_timestamp,
&jitter,
&fraction_lost,
&round_trip_time,
@@ -605,6 +606,7 @@
packets_received("packetsReceived"),
bytes_received("bytesReceived"),
packets_lost("packetsLost"),
+ last_packet_received_timestamp("lastPacketReceivedTimestamp"),
jitter("jitter"),
fraction_lost("fractionLost"),
round_trip_time("roundTripTime"),
@@ -627,6 +629,7 @@
packets_received(other.packets_received),
bytes_received(other.bytes_received),
packets_lost(other.packets_lost),
+ last_packet_received_timestamp(other.last_packet_received_timestamp),
jitter(other.jitter),
fraction_lost(other.fraction_lost),
round_trip_time(other.round_trip_time),