Add histograms for Abs-Capture-Timestamp
Bug: webrtc:380712819
Change-Id: I5f56caffe33a257432551321f7c097c852b134dd
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/368903
Reviewed-by: Johannes Kron <kron@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#43458}
diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn
index 1342dba..3bbddc7 100644
--- a/modules/rtp_rtcp/BUILD.gn
+++ b/modules/rtp_rtcp/BUILD.gn
@@ -731,6 +731,7 @@
"../../rtc_base:timeutils",
"../../rtc_base/network:ecn_marking",
"../../system_wrappers",
+ "../../system_wrappers:metrics",
"../../test:explicit_key_value_config",
"../../test:mock_transport",
"../../test:rtp_test_utils",
diff --git a/modules/rtp_rtcp/source/absolute_capture_time_interpolator.cc b/modules/rtp_rtcp/source/absolute_capture_time_interpolator.cc
index fdbd31b..481dc35 100644
--- a/modules/rtp_rtcp/source/absolute_capture_time_interpolator.cc
+++ b/modules/rtp_rtcp/source/absolute_capture_time_interpolator.cc
@@ -10,9 +10,18 @@
#include "modules/rtp_rtcp/source/absolute_capture_time_interpolator.h"
-#include <limits>
+#include <cstdint>
+#include <optional>
+#include "api/array_view.h"
+#include "api/rtp_headers.h"
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
#include "rtc_base/checks.h"
+#include "rtc_base/synchronization/mutex.h"
+#include "system_wrappers/include/clock.h"
+#include "system_wrappers/include/metrics.h"
+#include "system_wrappers/include/ntp_time.h"
namespace webrtc {
@@ -36,6 +45,9 @@
int rtp_clock_frequency_hz,
const std::optional<AbsoluteCaptureTime>& received_extension) {
const Timestamp receive_time = clock_->CurrentTime();
+ if (!first_packet_time_) {
+ first_packet_time_ = receive_time;
+ }
MutexLock lock(&mutex_);
@@ -60,7 +72,40 @@
last_received_extension_ = *received_extension;
last_receive_time_ = receive_time;
-
+ // Record statistics on the abs-capture-time extension
+ if (!first_extension_time_) {
+ RTC_HISTOGRAM_COUNTS_1M("WebRTC.Call.AbsCapture.ExtensionWait",
+ (receive_time - *first_packet_time_).ms());
+ first_extension_time_ = receive_time;
+ }
+ Timestamp capture_as_timestamp = Timestamp::Micros(
+ UQ32x32ToInt64Us(received_extension->absolute_capture_timestamp));
+ TimeDelta capture_delta = receive_time - capture_as_timestamp;
+ RTC_HISTOGRAM_COUNTS_1G("WebRTC.Call.AbsCapture.Delta",
+ abs(capture_delta.us()));
+ if (previous_capture_delta_) {
+ RTC_HISTOGRAM_COUNTS_1G(
+ "WebRTC.Call.AbsCapture.DeltaDeviation",
+ abs((capture_delta - *previous_capture_delta_).us()));
+ }
+ previous_capture_delta_ = capture_delta;
+ if (received_extension->estimated_capture_clock_offset) {
+ if (!first_offset_time_) {
+ RTC_HISTOGRAM_COUNTS_1M("WebRTC.Call.AbsCapture.OffsetWait",
+ (receive_time - *first_packet_time_).ms());
+ first_offset_time_ = receive_time;
+ }
+ TimeDelta offset_as_delta = TimeDelta::Micros(UQ32x32ToInt64Us(
+ *received_extension->estimated_capture_clock_offset));
+ RTC_HISTOGRAM_COUNTS_1G("WebRTC.Call.AbsCapture.Offset",
+ abs(offset_as_delta.us()));
+ if (previous_offset_as_delta_) {
+ RTC_HISTOGRAM_COUNTS_1G(
+ "WebRTC.Call.AbsCapture.OffsetDeviation",
+ abs((offset_as_delta - *previous_offset_as_delta_).us()));
+ }
+ previous_offset_as_delta_ = offset_as_delta;
+ }
return received_extension;
}
}
diff --git a/modules/rtp_rtcp/source/absolute_capture_time_interpolator.h b/modules/rtp_rtcp/source/absolute_capture_time_interpolator.h
index 59ddead..5b9f817 100644
--- a/modules/rtp_rtcp/source/absolute_capture_time_interpolator.h
+++ b/modules/rtp_rtcp/source/absolute_capture_time_interpolator.h
@@ -11,6 +11,9 @@
#ifndef MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_INTERPOLATOR_H_
#define MODULES_RTP_RTCP_SOURCE_ABSOLUTE_CAPTURE_TIME_INTERPOLATOR_H_
+#include <cstdint>
+#include <optional>
+
#include "api/array_view.h"
#include "api/rtp_headers.h"
#include "api/units/time_delta.h"
@@ -80,6 +83,12 @@
uint32_t last_rtp_timestamp_ RTC_GUARDED_BY(mutex_);
int last_rtp_clock_frequency_hz_ RTC_GUARDED_BY(mutex_);
AbsoluteCaptureTime last_received_extension_ RTC_GUARDED_BY(mutex_);
+ // Variables used for statistics generation
+ std::optional<Timestamp> first_packet_time_;
+ std::optional<Timestamp> first_offset_time_;
+ std::optional<Timestamp> first_extension_time_;
+ std::optional<TimeDelta> previous_capture_delta_;
+ std::optional<TimeDelta> previous_offset_as_delta_;
};
} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/absolute_capture_time_interpolator_unittest.cc b/modules/rtp_rtcp/source/absolute_capture_time_interpolator_unittest.cc
index 7471496..140db51 100644
--- a/modules/rtp_rtcp/source/absolute_capture_time_interpolator_unittest.cc
+++ b/modules/rtp_rtcp/source/absolute_capture_time_interpolator_unittest.cc
@@ -10,8 +10,14 @@
#include "modules/rtp_rtcp/source/absolute_capture_time_interpolator.h"
+#include <cstdint>
+#include <optional>
+
+#include "api/rtp_headers.h"
+#include "api/units/time_delta.h"
+#include "system_wrappers/include/clock.h"
+#include "system_wrappers/include/metrics.h"
#include "system_wrappers/include/ntp_time.h"
-#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
@@ -342,4 +348,36 @@
std::nullopt);
}
+TEST(AbsoluteCaptureTimeInterpolatorTest, MetricsAreUpdated) {
+ constexpr uint32_t kRtpTimestamp0 = 102030000;
+ constexpr uint32_t kSource = 1234;
+ constexpr uint32_t kFrequency = 1000;
+ SimulatedClock clock(0);
+ AbsoluteCaptureTimeInterpolator interpolator(&clock);
+
+ metrics::Reset();
+ // First packet has no extension.
+ interpolator.OnReceivePacket(kSource, kRtpTimestamp0, kFrequency,
+ std::nullopt);
+ EXPECT_METRIC_EQ(metrics::NumSamples("WebRTC.Call.AbsCapture.ExtensionWait"),
+ 0);
+
+ // Second packet has extension, but no offset.
+ clock.AdvanceTimeMilliseconds(10);
+ interpolator.OnReceivePacket(
+ kSource, kRtpTimestamp0 + 10, kFrequency,
+ AbsoluteCaptureTime{Int64MsToUQ32x32(5000), std::nullopt});
+ EXPECT_METRIC_EQ(metrics::NumSamples("WebRTC.Call.AbsCapture.ExtensionWait"),
+ 1);
+
+ // Third packet has extension with offset, value zero.
+ clock.AdvanceTimeMilliseconds(10);
+ interpolator.OnReceivePacket(
+ kSource, kRtpTimestamp0 + 20, kFrequency,
+ AbsoluteCaptureTime{Int64MsToUQ32x32(20), Int64MsToUQ32x32(0)});
+ EXPECT_METRIC_EQ(metrics::NumSamples("WebRTC.Call.AbsCapture.Delta"), 2);
+ EXPECT_METRIC_EQ(metrics::NumSamples("WebRTC.Call.AbsCapture.DeltaDeviation"),
+ 1);
+}
+
} // namespace webrtc
diff --git a/system_wrappers/include/metrics.h b/system_wrappers/include/metrics.h
index 6e2da1b..61365dd 100644
--- a/system_wrappers/include/metrics.h
+++ b/system_wrappers/include/metrics.h
@@ -125,6 +125,12 @@
#define RTC_HISTOGRAM_COUNTS_100000(name, sample) \
RTC_HISTOGRAM_COUNTS(name, sample, 1, 100000, 50)
+#define RTC_HISTOGRAM_COUNTS_1M(name, sample) \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 1'000'000, 50)
+
+#define RTC_HISTOGRAM_COUNTS_1G(name, sample) \
+ RTC_HISTOGRAM_COUNTS(name, sample, 1, 1'000'000'000, 50)
+
#define RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count) \
RTC_HISTOGRAM_COMMON_BLOCK(name, sample, \
webrtc::metrics::HistogramFactoryGetCounts( \
@@ -300,6 +306,12 @@
#define RTC_HISTOGRAM_COUNTS_100000(name, sample) \
webrtc::metrics_impl::NoOp(name, sample)
+#define RTC_HISTOGRAM_COUNTS_1M(name, sample) \
+ webrtc::metrics_impl::NoOp(name, sample)
+
+#define RTC_HISTOGRAM_COUNTS_1G(name, sample) \
+ webrtc::metrics_impl::NoOp(name, sample)
+
#define RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count) \
webrtc::metrics_impl::NoOp(name, sample, min, max, bucket_count)
diff --git a/system_wrappers/include/ntp_time.h b/system_wrappers/include/ntp_time.h
index b912bc8..2edfd4a 100644
--- a/system_wrappers/include/ntp_time.h
+++ b/system_wrappers/include/ntp_time.h
@@ -120,5 +120,11 @@
std::round(q32x32 * (1000.0 / NtpTime::kFractionsPerSecond)));
}
+// Converts UQ32.32-formatted fixed-point seconds to `int64_t` microseconds.
+inline int64_t UQ32x32ToInt64Us(uint64_t q32x32) {
+ return rtc::dchecked_cast<int64_t>(
+ std::round(q32x32 * (1'000'000.0 / NtpTime::kFractionsPerSecond)));
+}
+
} // namespace webrtc
#endif // SYSTEM_WRAPPERS_INCLUDE_NTP_TIME_H_