blob: 2c3981a5a4fe1dbf740122ee73123895a7b25515 [file] [log] [blame]
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +00001/*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "system_wrappers/include/clock.h"
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +000012
Paul Hallak704d6e52021-04-08 14:57:45 +020013#include "system_wrappers/include/field_trial.h"
14
Sergey Ulanov6acefdb2017-12-11 17:38:13 -080015#if defined(WEBRTC_WIN)
Karl Wiberg79eb1d92017-11-08 12:26:07 +010016
pbos@webrtc.orgacaf3a12013-05-27 15:07:45 +000017// Windows needs to be included before mmsystem.h
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/win32.h"
Karl Wiberg79eb1d92017-11-08 12:26:07 +010019
Mirko Bonadei01914412018-03-23 16:30:58 +010020#include <mmsystem.h>
Karl Wiberg79eb1d92017-11-08 12:26:07 +010021
Yves Gerey988cc082018-10-23 12:03:01 +020022
Sergey Ulanov6acefdb2017-12-11 17:38:13 -080023#elif defined(WEBRTC_POSIX)
Karl Wiberg79eb1d92017-11-08 12:26:07 +010024
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +000025#include <sys/time.h>
26#include <time.h>
Karl Wiberg79eb1d92017-11-08 12:26:07 +010027
Sergey Ulanov6acefdb2017-12-11 17:38:13 -080028#endif // defined(WEBRTC_POSIX)
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +000029
Markus Handell85585f42020-07-08 23:04:37 +020030#include "rtc_base/synchronization/mutex.h"
Steve Anton10542f22019-01-11 09:11:00 -080031#include "rtc_base/time_utils.h"
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +000032
33namespace webrtc {
Paul Hallak704d6e52021-04-08 14:57:45 +020034namespace {
35
36int64_t NtpOffsetUsCalledOnce() {
37 constexpr int64_t kNtpJan1970Sec = 2208988800;
38 int64_t clock_time = rtc::TimeMicros();
39 int64_t utc_time = rtc::TimeUTCMicros();
40 return utc_time - clock_time + kNtpJan1970Sec * rtc::kNumMicrosecsPerSec;
41}
42
43NtpTime TimeMicrosToNtp(int64_t time_us) {
44 static int64_t ntp_offset_us = NtpOffsetUsCalledOnce();
45
46 int64_t time_ntp_us = time_us + ntp_offset_us;
47 RTC_DCHECK_GE(time_ntp_us, 0); // Time before year 1900 is unsupported.
48
49 // Convert seconds to uint32 through uint64 for a well-defined cast.
50 // A wrap around, which will happen in 2036, is expected for NTP time.
51 uint32_t ntp_seconds =
52 static_cast<uint64_t>(time_ntp_us / rtc::kNumMicrosecsPerSec);
53
54 // Scale fractions of the second to NTP resolution.
55 constexpr int64_t kNtpFractionsInSecond = 1LL << 32;
56 int64_t us_fractions = time_ntp_us % rtc::kNumMicrosecsPerSec;
57 uint32_t ntp_fractions =
58 us_fractions * kNtpFractionsInSecond / rtc::kNumMicrosecsPerSec;
59
60 return NtpTime(ntp_seconds, ntp_fractions);
61}
62
63void GetSecondsAndFraction(const timeval& time,
64 uint32_t* seconds,
65 double* fraction) {
66 *seconds = time.tv_sec + kNtpJan1970;
67 *fraction = time.tv_usec / 1e6;
68
69 while (*fraction >= 1) {
70 --*fraction;
71 ++*seconds;
72 }
73 while (*fraction < 0) {
74 ++*fraction;
75 --*seconds;
76 }
77}
78
79} // namespace
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +000080
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +000081class RealTimeClock : public Clock {
Paul Hallak704d6e52021-04-08 14:57:45 +020082 public:
83 RealTimeClock()
84 : use_system_independent_ntp_time_(!field_trial::IsEnabled(
85 "WebRTC-SystemIndependentNtpTimeKillSwitch")) {}
86
Danil Chapovalov0c626af2020-02-10 11:16:00 +010087 Timestamp CurrentTime() override {
88 return Timestamp::Micros(rtc::TimeMicros());
89 }
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +000090
Sebastian Jansson2a96ab22019-01-30 20:44:45 +010091 NtpTime CurrentNtpTime() override {
Paul Hallak704d6e52021-04-08 14:57:45 +020092 return use_system_independent_ntp_time_ ? TimeMicrosToNtp(rtc::TimeMicros())
93 : SystemDependentNtpTime();
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +000094 }
95
96 protected:
Sebastian Jansson2a96ab22019-01-30 20:44:45 +010097 virtual timeval CurrentTimeVal() = 0;
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +000098
Paul Hallak704d6e52021-04-08 14:57:45 +020099 private:
100 NtpTime SystemDependentNtpTime() {
101 uint32_t seconds;
102 double fraction;
103 GetSecondsAndFraction(CurrentTimeVal(), &seconds, &fraction);
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000104
Paul Hallak704d6e52021-04-08 14:57:45 +0200105 return NtpTime(seconds, static_cast<uint32_t>(
106 fraction * kMagicNtpFractionalUnit + 0.5));
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000107 }
Paul Hallak704d6e52021-04-08 14:57:45 +0200108
109 bool use_system_independent_ntp_time_;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000110};
111
Robin Raymondce1b1402018-11-22 20:10:11 -0500112#if defined(WINUWP)
113class WinUwpRealTimeClock final : public RealTimeClock {
114 public:
115 WinUwpRealTimeClock() = default;
116 ~WinUwpRealTimeClock() override {}
117
118 protected:
Sebastian Jansson2a96ab22019-01-30 20:44:45 +0100119 timeval CurrentTimeVal() override {
Johannes Kron373bb7b2021-02-23 14:23:47 +0100120 // The rtc::WinUwpSystemTimeNanos() method is already time offset from a
121 // base epoch value and might as be synchronized against an NTP time server
122 // as an added bonus.
123 auto nanos = rtc::WinUwpSystemTimeNanos();
Robin Raymondce1b1402018-11-22 20:10:11 -0500124
125 struct timeval tv;
126
127 tv.tv_sec = rtc::dchecked_cast<long>(nanos / 1000000000);
128 tv.tv_usec = rtc::dchecked_cast<long>(nanos / 1000);
129
130 return tv;
131 }
132};
133
134#elif defined(WEBRTC_WIN)
pbos@webrtc.orgf9389222015-01-21 12:51:13 +0000135// TODO(pbos): Consider modifying the implementation to synchronize itself
Sebastian Jansson2a96ab22019-01-30 20:44:45 +0100136// against system time (update ref_point_) periodically to
pbos@webrtc.orgf9389222015-01-21 12:51:13 +0000137// prevent clock drift.
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000138class WindowsRealTimeClock : public RealTimeClock {
139 public:
pbos@webrtc.orgf9389222015-01-21 12:51:13 +0000140 WindowsRealTimeClock()
141 : last_time_ms_(0),
142 num_timer_wraps_(0),
143 ref_point_(GetSystemReferencePoint()) {}
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000144
Mirko Bonadeic14d9bb2018-07-16 15:44:28 +0200145 ~WindowsRealTimeClock() override {}
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000146
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000147 protected:
pbos@webrtc.orgf9389222015-01-21 12:51:13 +0000148 struct ReferencePoint {
149 FILETIME file_time;
150 LARGE_INTEGER counter_ms;
151 };
152
Sebastian Jansson2a96ab22019-01-30 20:44:45 +0100153 timeval CurrentTimeVal() override {
pbos@webrtc.org046deb92013-04-09 09:06:11 +0000154 const uint64_t FILETIME_1970 = 0x019db1ded53e8000;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000155
156 FILETIME StartTime;
pbos@webrtc.org046deb92013-04-09 09:06:11 +0000157 uint64_t Time;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000158 struct timeval tv;
159
wu@webrtc.org7a9a3b72014-05-29 19:40:28 +0000160 // We can't use query performance counter since they can change depending on
161 // speed stepping.
pbos@webrtc.orgf9389222015-01-21 12:51:13 +0000162 GetTime(&StartTime);
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000163
Karl Wiberg79eb1d92017-11-08 12:26:07 +0100164 Time = (((uint64_t)StartTime.dwHighDateTime) << 32) +
165 (uint64_t)StartTime.dwLowDateTime;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000166
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000167 // Convert the hecto-nano second time to tv format.
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000168 Time -= FILETIME_1970;
169
pbos@webrtc.org046deb92013-04-09 09:06:11 +0000170 tv.tv_sec = (uint32_t)(Time / (uint64_t)10000000);
171 tv.tv_usec = (uint32_t)((Time % (uint64_t)10000000) / 10);
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000172 return tv;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000173 }
wu@webrtc.org7a9a3b72014-05-29 19:40:28 +0000174
Sebastian Jansson2a96ab22019-01-30 20:44:45 +0100175 void GetTime(FILETIME* current_time) {
pbos@webrtc.orgf9389222015-01-21 12:51:13 +0000176 DWORD t;
177 LARGE_INTEGER elapsed_ms;
178 {
Markus Handell85585f42020-07-08 23:04:37 +0200179 MutexLock lock(&mutex_);
pbos@webrtc.orgf9389222015-01-21 12:51:13 +0000180 // time MUST be fetched inside the critical section to avoid non-monotonic
181 // last_time_ms_ values that'll register as incorrect wraparounds due to
182 // concurrent calls to GetTime.
183 t = timeGetTime();
184 if (t < last_time_ms_)
185 num_timer_wraps_++;
186 last_time_ms_ = t;
187 elapsed_ms.HighPart = num_timer_wraps_;
188 }
189 elapsed_ms.LowPart = t;
190 elapsed_ms.QuadPart = elapsed_ms.QuadPart - ref_point_.counter_ms.QuadPart;
191
192 // Translate to 100-nanoseconds intervals (FILETIME resolution)
193 // and add to reference FILETIME to get current FILETIME.
194 ULARGE_INTEGER filetime_ref_as_ul;
195 filetime_ref_as_ul.HighPart = ref_point_.file_time.dwHighDateTime;
196 filetime_ref_as_ul.LowPart = ref_point_.file_time.dwLowDateTime;
197 filetime_ref_as_ul.QuadPart +=
198 static_cast<ULONGLONG>((elapsed_ms.QuadPart) * 1000 * 10);
199
200 // Copy to result
201 current_time->dwHighDateTime = filetime_ref_as_ul.HighPart;
202 current_time->dwLowDateTime = filetime_ref_as_ul.LowPart;
203 }
204
205 static ReferencePoint GetSystemReferencePoint() {
dchenga771bf82015-07-01 17:52:10 -0700206 ReferencePoint ref = {};
207 FILETIME ft0 = {};
208 FILETIME ft1 = {};
pbos@webrtc.orgf9389222015-01-21 12:51:13 +0000209 // Spin waiting for a change in system time. As soon as this change happens,
210 // get the matching call for timeGetTime() as soon as possible. This is
211 // assumed to be the most accurate offset that we can get between
212 // timeGetTime() and system time.
213
214 // Set timer accuracy to 1 ms.
215 timeBeginPeriod(1);
216 GetSystemTimeAsFileTime(&ft0);
217 do {
218 GetSystemTimeAsFileTime(&ft1);
219
220 ref.counter_ms.QuadPart = timeGetTime();
221 Sleep(0);
222 } while ((ft0.dwHighDateTime == ft1.dwHighDateTime) &&
223 (ft0.dwLowDateTime == ft1.dwLowDateTime));
224 ref.file_time = ft1;
225 timeEndPeriod(1);
226 return ref;
227 }
228
Markus Handell85585f42020-07-08 23:04:37 +0200229 Mutex mutex_;
Sebastian Jansson2a96ab22019-01-30 20:44:45 +0100230 DWORD last_time_ms_;
231 LONG num_timer_wraps_;
pbos@webrtc.orgf9389222015-01-21 12:51:13 +0000232 const ReferencePoint ref_point_;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000233};
234
Sergey Ulanov6acefdb2017-12-11 17:38:13 -0800235#elif defined(WEBRTC_POSIX)
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000236class UnixRealTimeClock : public RealTimeClock {
237 public:
238 UnixRealTimeClock() {}
239
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000240 ~UnixRealTimeClock() override {}
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000241
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000242 protected:
Sebastian Jansson2a96ab22019-01-30 20:44:45 +0100243 timeval CurrentTimeVal() override {
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000244 struct timeval tv;
245 struct timezone tz;
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000246 tz.tz_minuteswest = 0;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000247 tz.tz_dsttime = 0;
248 gettimeofday(&tv, &tz);
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000249 return tv;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000250 }
251};
Sergey Ulanov6acefdb2017-12-11 17:38:13 -0800252#endif // defined(WEBRTC_POSIX)
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000253
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000254Clock* Clock::GetRealTimeClock() {
Robin Raymondce1b1402018-11-22 20:10:11 -0500255#if defined(WINUWP)
256 static Clock* const clock = new WinUwpRealTimeClock();
257#elif defined(WEBRTC_WIN)
Mirko Bonadei6c092d22018-09-10 13:27:11 +0200258 static Clock* const clock = new WindowsRealTimeClock();
Sergey Ulanov6acefdb2017-12-11 17:38:13 -0800259#elif defined(WEBRTC_POSIX)
Mirko Bonadei6c092d22018-09-10 13:27:11 +0200260 static Clock* const clock = new UnixRealTimeClock();
261#else
262 static Clock* const clock = nullptr;
263#endif
264 return clock;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000265}
266
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000267SimulatedClock::SimulatedClock(int64_t initial_time_us)
Niels Möller9308b7a2020-11-03 13:55:44 +0100268 : time_us_(initial_time_us) {}
Sebastian Jansson4de31152019-06-11 08:52:11 +0200269
270SimulatedClock::SimulatedClock(Timestamp initial_time)
Niels Möller9308b7a2020-11-03 13:55:44 +0100271 : SimulatedClock(initial_time.us()) {}
henrik.lundin@webrtc.org59336e82014-05-27 09:34:58 +0000272
Karl Wiberg79eb1d92017-11-08 12:26:07 +0100273SimulatedClock::~SimulatedClock() {}
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000274
Sebastian Jansson4de31152019-06-11 08:52:11 +0200275Timestamp SimulatedClock::CurrentTime() {
Niels Möller9308b7a2020-11-03 13:55:44 +0100276 return Timestamp::Micros(time_us_.load(std::memory_order_relaxed));
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000277}
278
Sebastian Jansson2a96ab22019-01-30 20:44:45 +0100279NtpTime SimulatedClock::CurrentNtpTime() {
henrik.lundin@webrtc.org59336e82014-05-27 09:34:58 +0000280 int64_t now_ms = TimeInMilliseconds();
danilchap21dc1892017-03-07 02:51:09 -0800281 uint32_t seconds = (now_ms / 1000) + kNtpJan1970;
282 uint32_t fractions =
henrik.lundin@webrtc.org59336e82014-05-27 09:34:58 +0000283 static_cast<uint32_t>((now_ms % 1000) * kMagicNtpFractionalUnit / 1000);
danilchap21dc1892017-03-07 02:51:09 -0800284 return NtpTime(seconds, fractions);
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000285}
286
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000287void SimulatedClock::AdvanceTimeMilliseconds(int64_t milliseconds) {
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100288 AdvanceTime(TimeDelta::Millis(milliseconds));
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000289}
290
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000291void SimulatedClock::AdvanceTimeMicroseconds(int64_t microseconds) {
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100292 AdvanceTime(TimeDelta::Micros(microseconds));
Sebastian Jansson4de31152019-06-11 08:52:11 +0200293}
294
Niels Möller9308b7a2020-11-03 13:55:44 +0100295// TODO(bugs.webrtc.org(12102): It's desirable to let a single thread own
296// advancement of the clock. We could then replace this read-modify-write
297// operation with just a thread checker. But currently, that breaks a couple of
298// tests, in particular, RepeatingTaskTest.ClockIntegration and
299// CallStatsTest.LastProcessedRtt.
Sebastian Jansson4de31152019-06-11 08:52:11 +0200300void SimulatedClock::AdvanceTime(TimeDelta delta) {
Niels Möller9308b7a2020-11-03 13:55:44 +0100301 time_us_.fetch_add(delta.us(), std::memory_order_relaxed);
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000302}
303
Nico Weber22f99252019-02-20 10:13:16 -0500304} // namespace webrtc