blob: 7784246fa428f9c1a146a03f98bf17dcf3c6b97a [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
Paul Hallakb59e9042021-05-20 17:21:49 +020096 NtpTime ConvertTimestampToNtpTime(Timestamp timestamp) override {
Artem Titovf0671922021-07-27 12:40:17 +020097 // This method does not check `use_system_independent_ntp_time_` because
98 // all callers never used the old behavior of `CurrentNtpTime`.
Paul Hallakb59e9042021-05-20 17:21:49 +020099 return TimeMicrosToNtp(timestamp.us());
100 }
101
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000102 protected:
Sebastian Jansson2a96ab22019-01-30 20:44:45 +0100103 virtual timeval CurrentTimeVal() = 0;
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000104
Paul Hallak704d6e52021-04-08 14:57:45 +0200105 private:
106 NtpTime SystemDependentNtpTime() {
107 uint32_t seconds;
108 double fraction;
109 GetSecondsAndFraction(CurrentTimeVal(), &seconds, &fraction);
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000110
Paul Hallak704d6e52021-04-08 14:57:45 +0200111 return NtpTime(seconds, static_cast<uint32_t>(
112 fraction * kMagicNtpFractionalUnit + 0.5));
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000113 }
Paul Hallak704d6e52021-04-08 14:57:45 +0200114
115 bool use_system_independent_ntp_time_;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000116};
117
Robin Raymondce1b1402018-11-22 20:10:11 -0500118#if defined(WINUWP)
119class WinUwpRealTimeClock final : public RealTimeClock {
120 public:
121 WinUwpRealTimeClock() = default;
122 ~WinUwpRealTimeClock() override {}
123
124 protected:
Sebastian Jansson2a96ab22019-01-30 20:44:45 +0100125 timeval CurrentTimeVal() override {
Johannes Kron373bb7b2021-02-23 14:23:47 +0100126 // The rtc::WinUwpSystemTimeNanos() method is already time offset from a
127 // base epoch value and might as be synchronized against an NTP time server
128 // as an added bonus.
129 auto nanos = rtc::WinUwpSystemTimeNanos();
Robin Raymondce1b1402018-11-22 20:10:11 -0500130
131 struct timeval tv;
132
133 tv.tv_sec = rtc::dchecked_cast<long>(nanos / 1000000000);
134 tv.tv_usec = rtc::dchecked_cast<long>(nanos / 1000);
135
136 return tv;
137 }
138};
139
140#elif defined(WEBRTC_WIN)
pbos@webrtc.orgf9389222015-01-21 12:51:13 +0000141// TODO(pbos): Consider modifying the implementation to synchronize itself
Sebastian Jansson2a96ab22019-01-30 20:44:45 +0100142// against system time (update ref_point_) periodically to
pbos@webrtc.orgf9389222015-01-21 12:51:13 +0000143// prevent clock drift.
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000144class WindowsRealTimeClock : public RealTimeClock {
145 public:
pbos@webrtc.orgf9389222015-01-21 12:51:13 +0000146 WindowsRealTimeClock()
147 : last_time_ms_(0),
148 num_timer_wraps_(0),
149 ref_point_(GetSystemReferencePoint()) {}
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000150
Mirko Bonadeic14d9bb2018-07-16 15:44:28 +0200151 ~WindowsRealTimeClock() override {}
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000152
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000153 protected:
pbos@webrtc.orgf9389222015-01-21 12:51:13 +0000154 struct ReferencePoint {
155 FILETIME file_time;
156 LARGE_INTEGER counter_ms;
157 };
158
Sebastian Jansson2a96ab22019-01-30 20:44:45 +0100159 timeval CurrentTimeVal() override {
pbos@webrtc.org046deb92013-04-09 09:06:11 +0000160 const uint64_t FILETIME_1970 = 0x019db1ded53e8000;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000161
162 FILETIME StartTime;
pbos@webrtc.org046deb92013-04-09 09:06:11 +0000163 uint64_t Time;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000164 struct timeval tv;
165
wu@webrtc.org7a9a3b72014-05-29 19:40:28 +0000166 // We can't use query performance counter since they can change depending on
167 // speed stepping.
pbos@webrtc.orgf9389222015-01-21 12:51:13 +0000168 GetTime(&StartTime);
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000169
Karl Wiberg79eb1d92017-11-08 12:26:07 +0100170 Time = (((uint64_t)StartTime.dwHighDateTime) << 32) +
171 (uint64_t)StartTime.dwLowDateTime;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000172
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000173 // Convert the hecto-nano second time to tv format.
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000174 Time -= FILETIME_1970;
175
pbos@webrtc.org046deb92013-04-09 09:06:11 +0000176 tv.tv_sec = (uint32_t)(Time / (uint64_t)10000000);
177 tv.tv_usec = (uint32_t)((Time % (uint64_t)10000000) / 10);
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000178 return tv;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000179 }
wu@webrtc.org7a9a3b72014-05-29 19:40:28 +0000180
Sebastian Jansson2a96ab22019-01-30 20:44:45 +0100181 void GetTime(FILETIME* current_time) {
pbos@webrtc.orgf9389222015-01-21 12:51:13 +0000182 DWORD t;
183 LARGE_INTEGER elapsed_ms;
184 {
Markus Handell85585f42020-07-08 23:04:37 +0200185 MutexLock lock(&mutex_);
pbos@webrtc.orgf9389222015-01-21 12:51:13 +0000186 // time MUST be fetched inside the critical section to avoid non-monotonic
187 // last_time_ms_ values that'll register as incorrect wraparounds due to
188 // concurrent calls to GetTime.
189 t = timeGetTime();
190 if (t < last_time_ms_)
191 num_timer_wraps_++;
192 last_time_ms_ = t;
193 elapsed_ms.HighPart = num_timer_wraps_;
194 }
195 elapsed_ms.LowPart = t;
196 elapsed_ms.QuadPart = elapsed_ms.QuadPart - ref_point_.counter_ms.QuadPart;
197
198 // Translate to 100-nanoseconds intervals (FILETIME resolution)
199 // and add to reference FILETIME to get current FILETIME.
200 ULARGE_INTEGER filetime_ref_as_ul;
201 filetime_ref_as_ul.HighPart = ref_point_.file_time.dwHighDateTime;
202 filetime_ref_as_ul.LowPart = ref_point_.file_time.dwLowDateTime;
203 filetime_ref_as_ul.QuadPart +=
204 static_cast<ULONGLONG>((elapsed_ms.QuadPart) * 1000 * 10);
205
206 // Copy to result
207 current_time->dwHighDateTime = filetime_ref_as_ul.HighPart;
208 current_time->dwLowDateTime = filetime_ref_as_ul.LowPart;
209 }
210
211 static ReferencePoint GetSystemReferencePoint() {
dchenga771bf82015-07-01 17:52:10 -0700212 ReferencePoint ref = {};
213 FILETIME ft0 = {};
214 FILETIME ft1 = {};
pbos@webrtc.orgf9389222015-01-21 12:51:13 +0000215 // Spin waiting for a change in system time. As soon as this change happens,
216 // get the matching call for timeGetTime() as soon as possible. This is
217 // assumed to be the most accurate offset that we can get between
218 // timeGetTime() and system time.
219
220 // Set timer accuracy to 1 ms.
221 timeBeginPeriod(1);
222 GetSystemTimeAsFileTime(&ft0);
223 do {
224 GetSystemTimeAsFileTime(&ft1);
225
226 ref.counter_ms.QuadPart = timeGetTime();
227 Sleep(0);
228 } while ((ft0.dwHighDateTime == ft1.dwHighDateTime) &&
229 (ft0.dwLowDateTime == ft1.dwLowDateTime));
230 ref.file_time = ft1;
231 timeEndPeriod(1);
232 return ref;
233 }
234
Markus Handell85585f42020-07-08 23:04:37 +0200235 Mutex mutex_;
Sebastian Jansson2a96ab22019-01-30 20:44:45 +0100236 DWORD last_time_ms_;
237 LONG num_timer_wraps_;
pbos@webrtc.orgf9389222015-01-21 12:51:13 +0000238 const ReferencePoint ref_point_;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000239};
240
Sergey Ulanov6acefdb2017-12-11 17:38:13 -0800241#elif defined(WEBRTC_POSIX)
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000242class UnixRealTimeClock : public RealTimeClock {
243 public:
244 UnixRealTimeClock() {}
245
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000246 ~UnixRealTimeClock() override {}
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000247
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000248 protected:
Sebastian Jansson2a96ab22019-01-30 20:44:45 +0100249 timeval CurrentTimeVal() override {
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000250 struct timeval tv;
John Elliott59aba462021-10-29 11:57:15 -0700251 gettimeofday(&tv, nullptr);
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000252 return tv;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000253 }
254};
Sergey Ulanov6acefdb2017-12-11 17:38:13 -0800255#endif // defined(WEBRTC_POSIX)
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000256
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000257Clock* Clock::GetRealTimeClock() {
Robin Raymondce1b1402018-11-22 20:10:11 -0500258#if defined(WINUWP)
259 static Clock* const clock = new WinUwpRealTimeClock();
260#elif defined(WEBRTC_WIN)
Mirko Bonadei6c092d22018-09-10 13:27:11 +0200261 static Clock* const clock = new WindowsRealTimeClock();
Sergey Ulanov6acefdb2017-12-11 17:38:13 -0800262#elif defined(WEBRTC_POSIX)
Mirko Bonadei6c092d22018-09-10 13:27:11 +0200263 static Clock* const clock = new UnixRealTimeClock();
264#else
265 static Clock* const clock = nullptr;
266#endif
267 return clock;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000268}
269
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000270SimulatedClock::SimulatedClock(int64_t initial_time_us)
Niels Möller9308b7a2020-11-03 13:55:44 +0100271 : time_us_(initial_time_us) {}
Sebastian Jansson4de31152019-06-11 08:52:11 +0200272
273SimulatedClock::SimulatedClock(Timestamp initial_time)
Niels Möller9308b7a2020-11-03 13:55:44 +0100274 : SimulatedClock(initial_time.us()) {}
henrik.lundin@webrtc.org59336e82014-05-27 09:34:58 +0000275
Karl Wiberg79eb1d92017-11-08 12:26:07 +0100276SimulatedClock::~SimulatedClock() {}
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000277
Sebastian Jansson4de31152019-06-11 08:52:11 +0200278Timestamp SimulatedClock::CurrentTime() {
Niels Möller9308b7a2020-11-03 13:55:44 +0100279 return Timestamp::Micros(time_us_.load(std::memory_order_relaxed));
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000280}
281
Paul Hallakb59e9042021-05-20 17:21:49 +0200282NtpTime SimulatedClock::ConvertTimestampToNtpTime(Timestamp timestamp) {
283 int64_t now_us = timestamp.us();
284 uint32_t seconds = (now_us / 1'000'000) + kNtpJan1970;
285 uint32_t fractions = static_cast<uint32_t>(
286 (now_us % 1'000'000) * kMagicNtpFractionalUnit / 1'000'000);
danilchap21dc1892017-03-07 02:51:09 -0800287 return NtpTime(seconds, fractions);
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000288}
289
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000290void SimulatedClock::AdvanceTimeMilliseconds(int64_t milliseconds) {
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100291 AdvanceTime(TimeDelta::Millis(milliseconds));
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000292}
293
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000294void SimulatedClock::AdvanceTimeMicroseconds(int64_t microseconds) {
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100295 AdvanceTime(TimeDelta::Micros(microseconds));
Sebastian Jansson4de31152019-06-11 08:52:11 +0200296}
297
Niels Möller9308b7a2020-11-03 13:55:44 +0100298// TODO(bugs.webrtc.org(12102): It's desirable to let a single thread own
299// advancement of the clock. We could then replace this read-modify-write
300// operation with just a thread checker. But currently, that breaks a couple of
301// tests, in particular, RepeatingTaskTest.ClockIntegration and
302// CallStatsTest.LastProcessedRtt.
Sebastian Jansson4de31152019-06-11 08:52:11 +0200303void SimulatedClock::AdvanceTime(TimeDelta delta) {
Niels Möller9308b7a2020-11-03 13:55:44 +0100304 time_us_.fetch_add(delta.us(), std::memory_order_relaxed);
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000305}
306
Nico Weber22f99252019-02-20 10:13:16 -0500307} // namespace webrtc