diff --git a/system_wrappers/include/clock.h b/system_wrappers/include/clock.h index f70a2f4e85..bcb7feaa7d 100644 --- a/system_wrappers/include/clock.h +++ b/system_wrappers/include/clock.h @@ -32,18 +32,24 @@ const double kMagicNtpFractionalUnit = 4.294967296E+9; 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 RTC_EXPORT Clock { 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 8edffa6a05..2c3981a5a4 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(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( - 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(seconds) + - static_cast(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( + fraction * kMagicNtpFractionalUnit + 0.5)); } + + bool use_system_independent_ntp_time_; }; #if defined(WINUWP) @@ -257,10 +284,6 @@ NtpTime SimulatedClock::CurrentNtpTime() { return NtpTime(seconds, fractions); } -int64_t SimulatedClock::CurrentNtpInMilliseconds() { - return TimeInMilliseconds() + 1000 * static_cast(kNtpJan1970); -} - void SimulatedClock::AdvanceTimeMilliseconds(int64_t milliseconds) { AdvanceTime(TimeDelta::Millis(milliseconds)); }