1 /*
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 
11 #include "system_wrappers/include/clock.h"
12 
13 #if defined(WEBRTC_WIN)
14 
15 // Windows needs to be included before mmsystem.h
16 #include "rtc_base/win32.h"
17 
18 #include <mmsystem.h>
19 
20 
21 #elif defined(WEBRTC_POSIX)
22 
23 #include <sys/time.h>
24 #include <time.h>
25 
26 #endif  // defined(WEBRTC_POSIX)
27 
28 #include "rtc_base/synchronization/mutex.h"
29 #include "rtc_base/synchronization/rw_lock_wrapper.h"
30 #include "rtc_base/time_utils.h"
31 
32 namespace webrtc {
33 
34 class RealTimeClock : public Clock {
CurrentTime()35   Timestamp CurrentTime() override {
36     return Timestamp::Micros(rtc::TimeMicros());
37   }
38   // Return a timestamp in milliseconds relative to some arbitrary source; the
39   // source is fixed for this clock.
TimeInMilliseconds()40   int64_t TimeInMilliseconds() override { return rtc::TimeMillis(); }
41 
42   // Return a timestamp in microseconds relative to some arbitrary source; the
43   // source is fixed for this clock.
TimeInMicroseconds()44   int64_t TimeInMicroseconds() override { return rtc::TimeMicros(); }
45 
46   // Retrieve an NTP absolute timestamp.
CurrentNtpTime()47   NtpTime CurrentNtpTime() override {
48     timeval tv = CurrentTimeVal();
49     double microseconds_in_seconds;
50     uint32_t seconds;
51     Adjust(tv, &seconds, &microseconds_in_seconds);
52     uint32_t fractions = static_cast<uint32_t>(
53         microseconds_in_seconds * kMagicNtpFractionalUnit + 0.5);
54     return NtpTime(seconds, fractions);
55   }
56 
57   // Retrieve an NTP absolute timestamp in milliseconds.
CurrentNtpInMilliseconds()58   int64_t CurrentNtpInMilliseconds() override {
59     timeval tv = CurrentTimeVal();
60     uint32_t seconds;
61     double microseconds_in_seconds;
62     Adjust(tv, &seconds, &microseconds_in_seconds);
63     return 1000 * static_cast<int64_t>(seconds) +
64            static_cast<int64_t>(1000.0 * microseconds_in_seconds + 0.5);
65   }
66 
67  protected:
68   virtual timeval CurrentTimeVal() = 0;
69 
Adjust(const timeval & tv,uint32_t * adjusted_s,double * adjusted_us_in_s)70   static void Adjust(const timeval& tv,
71                      uint32_t* adjusted_s,
72                      double* adjusted_us_in_s) {
73     *adjusted_s = tv.tv_sec + kNtpJan1970;
74     *adjusted_us_in_s = tv.tv_usec / 1e6;
75 
76     if (*adjusted_us_in_s >= 1) {
77       *adjusted_us_in_s -= 1;
78       ++*adjusted_s;
79     } else if (*adjusted_us_in_s < -1) {
80       *adjusted_us_in_s += 1;
81       --*adjusted_s;
82     }
83   }
84 };
85 
86 #if defined(WINUWP)
87 class WinUwpRealTimeClock final : public RealTimeClock {
88  public:
89   WinUwpRealTimeClock() = default;
~WinUwpRealTimeClock()90   ~WinUwpRealTimeClock() override {}
91 
92  protected:
CurrentTimeVal()93   timeval CurrentTimeVal() override {
94     // The rtc::SystemTimeNanos() method is already time offset from a base
95     // epoch value and might as be synchronized against an NTP time server as
96     // an added bonus.
97     auto nanos = rtc::SystemTimeNanos();
98 
99     struct timeval tv;
100 
101     tv.tv_sec = rtc::dchecked_cast<long>(nanos / 1000000000);
102     tv.tv_usec = rtc::dchecked_cast<long>(nanos / 1000);
103 
104     return tv;
105   }
106 };
107 
108 #elif defined(WEBRTC_WIN)
109 // TODO(pbos): Consider modifying the implementation to synchronize itself
110 // against system time (update ref_point_) periodically to
111 // prevent clock drift.
112 class WindowsRealTimeClock : public RealTimeClock {
113  public:
WindowsRealTimeClock()114   WindowsRealTimeClock()
115       : last_time_ms_(0),
116         num_timer_wraps_(0),
117         ref_point_(GetSystemReferencePoint()) {}
118 
~WindowsRealTimeClock()119   ~WindowsRealTimeClock() override {}
120 
121  protected:
122   struct ReferencePoint {
123     FILETIME file_time;
124     LARGE_INTEGER counter_ms;
125   };
126 
CurrentTimeVal()127   timeval CurrentTimeVal() override {
128     const uint64_t FILETIME_1970 = 0x019db1ded53e8000;
129 
130     FILETIME StartTime;
131     uint64_t Time;
132     struct timeval tv;
133 
134     // We can't use query performance counter since they can change depending on
135     // speed stepping.
136     GetTime(&StartTime);
137 
138     Time = (((uint64_t)StartTime.dwHighDateTime) << 32) +
139            (uint64_t)StartTime.dwLowDateTime;
140 
141     // Convert the hecto-nano second time to tv format.
142     Time -= FILETIME_1970;
143 
144     tv.tv_sec = (uint32_t)(Time / (uint64_t)10000000);
145     tv.tv_usec = (uint32_t)((Time % (uint64_t)10000000) / 10);
146     return tv;
147   }
148 
GetTime(FILETIME * current_time)149   void GetTime(FILETIME* current_time) {
150     DWORD t;
151     LARGE_INTEGER elapsed_ms;
152     {
153       MutexLock lock(&mutex_);
154       // time MUST be fetched inside the critical section to avoid non-monotonic
155       // last_time_ms_ values that'll register as incorrect wraparounds due to
156       // concurrent calls to GetTime.
157       t = timeGetTime();
158       if (t < last_time_ms_)
159         num_timer_wraps_++;
160       last_time_ms_ = t;
161       elapsed_ms.HighPart = num_timer_wraps_;
162     }
163     elapsed_ms.LowPart = t;
164     elapsed_ms.QuadPart = elapsed_ms.QuadPart - ref_point_.counter_ms.QuadPart;
165 
166     // Translate to 100-nanoseconds intervals (FILETIME resolution)
167     // and add to reference FILETIME to get current FILETIME.
168     ULARGE_INTEGER filetime_ref_as_ul;
169     filetime_ref_as_ul.HighPart = ref_point_.file_time.dwHighDateTime;
170     filetime_ref_as_ul.LowPart = ref_point_.file_time.dwLowDateTime;
171     filetime_ref_as_ul.QuadPart +=
172         static_cast<ULONGLONG>((elapsed_ms.QuadPart) * 1000 * 10);
173 
174     // Copy to result
175     current_time->dwHighDateTime = filetime_ref_as_ul.HighPart;
176     current_time->dwLowDateTime = filetime_ref_as_ul.LowPart;
177   }
178 
GetSystemReferencePoint()179   static ReferencePoint GetSystemReferencePoint() {
180     ReferencePoint ref = {};
181     FILETIME ft0 = {};
182     FILETIME ft1 = {};
183     // Spin waiting for a change in system time. As soon as this change happens,
184     // get the matching call for timeGetTime() as soon as possible. This is
185     // assumed to be the most accurate offset that we can get between
186     // timeGetTime() and system time.
187 
188     // Set timer accuracy to 1 ms.
189     timeBeginPeriod(1);
190     GetSystemTimeAsFileTime(&ft0);
191     do {
192       GetSystemTimeAsFileTime(&ft1);
193 
194       ref.counter_ms.QuadPart = timeGetTime();
195       Sleep(0);
196     } while ((ft0.dwHighDateTime == ft1.dwHighDateTime) &&
197              (ft0.dwLowDateTime == ft1.dwLowDateTime));
198     ref.file_time = ft1;
199     timeEndPeriod(1);
200     return ref;
201   }
202 
203   Mutex mutex_;
204   DWORD last_time_ms_;
205   LONG num_timer_wraps_;
206   const ReferencePoint ref_point_;
207 };
208 
209 #elif defined(WEBRTC_POSIX)
210 class UnixRealTimeClock : public RealTimeClock {
211  public:
UnixRealTimeClock()212   UnixRealTimeClock() {}
213 
~UnixRealTimeClock()214   ~UnixRealTimeClock() override {}
215 
216  protected:
CurrentTimeVal()217   timeval CurrentTimeVal() override {
218     struct timeval tv;
219     struct timezone tz;
220     tz.tz_minuteswest = 0;
221     tz.tz_dsttime = 0;
222     gettimeofday(&tv, &tz);
223     return tv;
224   }
225 };
226 #endif  // defined(WEBRTC_POSIX)
227 
GetRealTimeClock()228 Clock* Clock::GetRealTimeClock() {
229 #if defined(WINUWP)
230   static Clock* const clock = new WinUwpRealTimeClock();
231 #elif defined(WEBRTC_WIN)
232   static Clock* const clock = new WindowsRealTimeClock();
233 #elif defined(WEBRTC_POSIX)
234   static Clock* const clock = new UnixRealTimeClock();
235 #else
236   static Clock* const clock = nullptr;
237 #endif
238   return clock;
239 }
240 
SimulatedClock(int64_t initial_time_us)241 SimulatedClock::SimulatedClock(int64_t initial_time_us)
242     : SimulatedClock(Timestamp::Micros(initial_time_us)) {}
243 
SimulatedClock(Timestamp initial_time)244 SimulatedClock::SimulatedClock(Timestamp initial_time)
245     : time_(initial_time), lock_(RWLockWrapper::CreateRWLock()) {}
246 
~SimulatedClock()247 SimulatedClock::~SimulatedClock() {}
248 
CurrentTime()249 Timestamp SimulatedClock::CurrentTime() {
250   ReadLockScoped synchronize(*lock_);
251   return time_;
252 }
253 
CurrentNtpTime()254 NtpTime SimulatedClock::CurrentNtpTime() {
255   int64_t now_ms = TimeInMilliseconds();
256   uint32_t seconds = (now_ms / 1000) + kNtpJan1970;
257   uint32_t fractions =
258       static_cast<uint32_t>((now_ms % 1000) * kMagicNtpFractionalUnit / 1000);
259   return NtpTime(seconds, fractions);
260 }
261 
CurrentNtpInMilliseconds()262 int64_t SimulatedClock::CurrentNtpInMilliseconds() {
263   return TimeInMilliseconds() + 1000 * static_cast<int64_t>(kNtpJan1970);
264 }
265 
AdvanceTimeMilliseconds(int64_t milliseconds)266 void SimulatedClock::AdvanceTimeMilliseconds(int64_t milliseconds) {
267   AdvanceTime(TimeDelta::Millis(milliseconds));
268 }
269 
AdvanceTimeMicroseconds(int64_t microseconds)270 void SimulatedClock::AdvanceTimeMicroseconds(int64_t microseconds) {
271   AdvanceTime(TimeDelta::Micros(microseconds));
272 }
273 
AdvanceTime(TimeDelta delta)274 void SimulatedClock::AdvanceTime(TimeDelta delta) {
275   WriteLockScoped synchronize(*lock_);
276   time_ += delta;
277 }
278 
279 }  // namespace webrtc
280