Consolidate the different NTP clocks into one.
WebRTC code has two ways of querying for the NTP time:
- rtc::TimeMillis() + NtpOffsetMs()
- Clock::CurrentNtpTime
`Clock::CurrentNtpTime` is not monotonic and is platform dependent.
This CL changes its implementation return `rtc::TimeMillis() +
NtpOffsetMs()`
More info is available in the attached bug.
Bug: webrtc:11327
Change-Id: I34fe4cc2d321c2b63275c93be21122c9de1ab403
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/213425
Commit-Queue: Paul Hallak <phallak@google.com>
Reviewed-by: Minyue Li <minyue@webrtc.org>
Reviewed-by: Henrik Andreassson <henrika@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33655}
diff --git a/system_wrappers/include/clock.h b/system_wrappers/include/clock.h
index f70a2f4..bcb7fea 100644
--- a/system_wrappers/include/clock.h
+++ b/system_wrappers/include/clock.h
@@ -32,18 +32,24 @@
class RTC_EXPORT Clock {
public:
virtual ~Clock() {}
+
// Return a timestamp relative to an unspecified epoch.
+ // TODO(bugs.webrtc.org/11327): Make this a pure virtual function.
virtual Timestamp CurrentTime() {
return Timestamp::Micros(TimeInMicroseconds());
}
+
+ // TODO(bugs.webrtc.org/11327): Make the following two methods non-virtual
+ // or completely remove them.
virtual int64_t TimeInMilliseconds() { return CurrentTime().ms(); }
virtual int64_t TimeInMicroseconds() { return CurrentTime().us(); }
- // Retrieve an NTP absolute timestamp.
+ // Retrieve an NTP absolute timestamp (with an epoch of Jan 1, 1900).
virtual NtpTime CurrentNtpTime() = 0;
- // Retrieve an NTP absolute timestamp in milliseconds.
- virtual int64_t CurrentNtpInMilliseconds() = 0;
+ // TODO(bugs.webrtc.org/11327): Make the following method non-virtual
+ // or completely remove it.
+ virtual int64_t CurrentNtpInMilliseconds() { return CurrentNtpTime().ToMs(); }
// Returns an instance of the real-time system clock implementation.
static Clock* GetRealTimeClock();
@@ -51,21 +57,16 @@
class SimulatedClock : public Clock {
public:
+ // The constructors assume an epoch of Jan 1, 1970.
explicit SimulatedClock(int64_t initial_time_us);
explicit SimulatedClock(Timestamp initial_time);
-
~SimulatedClock() override;
- // Return a timestamp relative to some arbitrary source; the source is fixed
- // for this clock.
+ // Return a timestamp with an epoch of Jan 1, 1970.
Timestamp CurrentTime() override;
- // Retrieve an NTP absolute timestamp.
NtpTime CurrentNtpTime() override;
- // Converts an NTP timestamp to a millisecond timestamp.
- int64_t CurrentNtpInMilliseconds() override;
-
// Advance the simulated clock with a given number of milliseconds or
// microseconds.
void AdvanceTimeMilliseconds(int64_t milliseconds);
diff --git a/system_wrappers/source/clock.cc b/system_wrappers/source/clock.cc
index 8edffa6..2c3981a 100644
--- a/system_wrappers/source/clock.cc
+++ b/system_wrappers/source/clock.cc
@@ -10,6 +10,8 @@
#include "system_wrappers/include/clock.h"
+#include "system_wrappers/include/field_trial.h"
+
#if defined(WEBRTC_WIN)
// Windows needs to be included before mmsystem.h
@@ -29,57 +31,82 @@
#include "rtc_base/time_utils.h"
namespace webrtc {
+namespace {
+
+int64_t NtpOffsetUsCalledOnce() {
+ constexpr int64_t kNtpJan1970Sec = 2208988800;
+ int64_t clock_time = rtc::TimeMicros();
+ int64_t utc_time = rtc::TimeUTCMicros();
+ return utc_time - clock_time + kNtpJan1970Sec * rtc::kNumMicrosecsPerSec;
+}
+
+NtpTime TimeMicrosToNtp(int64_t time_us) {
+ static int64_t ntp_offset_us = NtpOffsetUsCalledOnce();
+
+ int64_t time_ntp_us = time_us + ntp_offset_us;
+ RTC_DCHECK_GE(time_ntp_us, 0); // Time before year 1900 is unsupported.
+
+ // Convert seconds to uint32 through uint64 for a well-defined cast.
+ // A wrap around, which will happen in 2036, is expected for NTP time.
+ uint32_t ntp_seconds =
+ static_cast<uint64_t>(time_ntp_us / rtc::kNumMicrosecsPerSec);
+
+ // Scale fractions of the second to NTP resolution.
+ constexpr int64_t kNtpFractionsInSecond = 1LL << 32;
+ int64_t us_fractions = time_ntp_us % rtc::kNumMicrosecsPerSec;
+ uint32_t ntp_fractions =
+ us_fractions * kNtpFractionsInSecond / rtc::kNumMicrosecsPerSec;
+
+ return NtpTime(ntp_seconds, ntp_fractions);
+}
+
+void GetSecondsAndFraction(const timeval& time,
+ uint32_t* seconds,
+ double* fraction) {
+ *seconds = time.tv_sec + kNtpJan1970;
+ *fraction = time.tv_usec / 1e6;
+
+ while (*fraction >= 1) {
+ --*fraction;
+ ++*seconds;
+ }
+ while (*fraction < 0) {
+ ++*fraction;
+ --*seconds;
+ }
+}
+
+} // namespace
class RealTimeClock : public Clock {
+ public:
+ RealTimeClock()
+ : use_system_independent_ntp_time_(!field_trial::IsEnabled(
+ "WebRTC-SystemIndependentNtpTimeKillSwitch")) {}
+
Timestamp CurrentTime() override {
return Timestamp::Micros(rtc::TimeMicros());
}
- // Return a timestamp in milliseconds relative to some arbitrary source; the
- // source is fixed for this clock.
- int64_t TimeInMilliseconds() override { return rtc::TimeMillis(); }
- // Return a timestamp in microseconds relative to some arbitrary source; the
- // source is fixed for this clock.
- int64_t TimeInMicroseconds() override { return rtc::TimeMicros(); }
-
- // Retrieve an NTP absolute timestamp.
NtpTime CurrentNtpTime() override {
- timeval tv = CurrentTimeVal();
- double microseconds_in_seconds;
- uint32_t seconds;
- Adjust(tv, &seconds, µseconds_in_seconds);
- uint32_t fractions = static_cast<uint32_t>(
- microseconds_in_seconds * kMagicNtpFractionalUnit + 0.5);
- return NtpTime(seconds, fractions);
- }
-
- // Retrieve an NTP absolute timestamp in milliseconds.
- int64_t CurrentNtpInMilliseconds() override {
- timeval tv = CurrentTimeVal();
- uint32_t seconds;
- double microseconds_in_seconds;
- Adjust(tv, &seconds, µseconds_in_seconds);
- return 1000 * static_cast<int64_t>(seconds) +
- static_cast<int64_t>(1000.0 * microseconds_in_seconds + 0.5);
+ return use_system_independent_ntp_time_ ? TimeMicrosToNtp(rtc::TimeMicros())
+ : SystemDependentNtpTime();
}
protected:
virtual timeval CurrentTimeVal() = 0;
- static void Adjust(const timeval& tv,
- uint32_t* adjusted_s,
- double* adjusted_us_in_s) {
- *adjusted_s = tv.tv_sec + kNtpJan1970;
- *adjusted_us_in_s = tv.tv_usec / 1e6;
+ private:
+ NtpTime SystemDependentNtpTime() {
+ uint32_t seconds;
+ double fraction;
+ GetSecondsAndFraction(CurrentTimeVal(), &seconds, &fraction);
- if (*adjusted_us_in_s >= 1) {
- *adjusted_us_in_s -= 1;
- ++*adjusted_s;
- } else if (*adjusted_us_in_s < -1) {
- *adjusted_us_in_s += 1;
- --*adjusted_s;
- }
+ return NtpTime(seconds, static_cast<uint32_t>(
+ fraction * kMagicNtpFractionalUnit + 0.5));
}
+
+ bool use_system_independent_ntp_time_;
};
#if defined(WINUWP)
@@ -257,10 +284,6 @@
return NtpTime(seconds, fractions);
}
-int64_t SimulatedClock::CurrentNtpInMilliseconds() {
- return TimeInMilliseconds() + 1000 * static_cast<int64_t>(kNtpJan1970);
-}
-
void SimulatedClock::AdvanceTimeMilliseconds(int64_t milliseconds) {
AdvanceTime(TimeDelta::Millis(milliseconds));
}