blob: 33eb8561f6b5ea2844c3fb66b7510304339453ce [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
11#include "webrtc/system_wrappers/interface/clock.h"
12
13#if defined(_WIN32)
pbos@webrtc.orgacaf3a12013-05-27 15:07:45 +000014// Windows needs to be included before mmsystem.h
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +000015#include <Windows.h>
16#include <WinSock.h>
17#include <MMSystem.h>
18#elif ((defined WEBRTC_LINUX) || (defined WEBRTC_MAC))
19#include <sys/time.h>
20#include <time.h>
21#endif
22
henrik.lundin@webrtc.org59336e82014-05-27 09:34:58 +000023#include "webrtc/system_wrappers/interface/rw_lock_wrapper.h"
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +000024#include "webrtc/system_wrappers/interface/tick_util.h"
25
26namespace webrtc {
27
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +000028const double kNtpFracPerMs = 4.294967296E6;
29
30int64_t Clock::NtpToMs(uint32_t ntp_secs, uint32_t ntp_frac) {
31 const double ntp_frac_ms = static_cast<double>(ntp_frac) / kNtpFracPerMs;
32 return 1000 * static_cast<int64_t>(ntp_secs) +
33 static_cast<int64_t>(ntp_frac_ms + 0.5);
34}
35
wu@webrtc.org7a9a3b72014-05-29 19:40:28 +000036#if defined(_WIN32)
37
38struct reference_point {
39 FILETIME file_time;
40 LARGE_INTEGER counterMS;
41};
42
43struct WindowsHelpTimer {
44 volatile LONG _timeInMs;
45 volatile LONG _numWrapTimeInMs;
46 reference_point _ref_point;
47
48 volatile LONG _sync_flag;
49};
50
51void Synchronize(WindowsHelpTimer* help_timer) {
52 const LONG start_value = 0;
53 const LONG new_value = 1;
54 const LONG synchronized_value = 2;
55
56 LONG compare_flag = new_value;
57 while (help_timer->_sync_flag == start_value) {
58 const LONG new_value = 1;
59 compare_flag = InterlockedCompareExchange(
60 &help_timer->_sync_flag, new_value, start_value);
61 }
62 if (compare_flag != start_value) {
63 // This thread was not the one that incremented the sync flag.
64 // Block until synchronization finishes.
65 while (compare_flag != synchronized_value) {
66 ::Sleep(0);
67 }
68 return;
69 }
70 // Only the synchronizing thread gets here so this part can be
71 // considered single threaded.
72
73 // set timer accuracy to 1 ms
74 timeBeginPeriod(1);
75 FILETIME ft0 = { 0, 0 },
76 ft1 = { 0, 0 };
77 //
78 // Spin waiting for a change in system time. Get the matching
79 // performance counter value for that time.
80 //
81 ::GetSystemTimeAsFileTime(&ft0);
82 do {
83 ::GetSystemTimeAsFileTime(&ft1);
84
85 help_timer->_ref_point.counterMS.QuadPart = ::timeGetTime();
86 ::Sleep(0);
87 } while ((ft0.dwHighDateTime == ft1.dwHighDateTime) &&
88 (ft0.dwLowDateTime == ft1.dwLowDateTime));
89 help_timer->_ref_point.file_time = ft1;
90 timeEndPeriod(1);
91}
92
93void get_time(WindowsHelpTimer* help_timer, FILETIME& current_time) {
94 // we can't use query performance counter due to speed stepping
95 DWORD t = timeGetTime();
96 // NOTE: we have a missmatch in sign between _timeInMs(LONG) and
97 // (DWORD) however we only use it here without +- etc
98 volatile LONG* timeInMsPtr = &help_timer->_timeInMs;
99 // Make sure that we only inc wrapper once.
100 DWORD old = InterlockedExchange(timeInMsPtr, t);
101 if(old > t) {
102 // wrap
103 help_timer->_numWrapTimeInMs++;
104 }
105 LARGE_INTEGER elapsedMS;
106 elapsedMS.HighPart = help_timer->_numWrapTimeInMs;
107 elapsedMS.LowPart = t;
108
109 elapsedMS.QuadPart = elapsedMS.QuadPart -
110 help_timer->_ref_point.counterMS.QuadPart;
111
112 // Translate to 100-nanoseconds intervals (FILETIME resolution)
113 // and add to reference FILETIME to get current FILETIME.
114 ULARGE_INTEGER filetime_ref_as_ul;
115
116 filetime_ref_as_ul.HighPart =
117 help_timer->_ref_point.file_time.dwHighDateTime;
118 filetime_ref_as_ul.LowPart =
119 help_timer->_ref_point.file_time.dwLowDateTime;
120 filetime_ref_as_ul.QuadPart +=
121 (ULONGLONG)((elapsedMS.QuadPart)*1000*10);
122
123 // Copy to result
124 current_time.dwHighDateTime = filetime_ref_as_ul.HighPart;
125 current_time.dwLowDateTime = filetime_ref_as_ul.LowPart;
126}
127#endif
128
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000129class RealTimeClock : public Clock {
130 // Return a timestamp in milliseconds relative to some arbitrary source; the
131 // source is fixed for this clock.
henrik.lundin@webrtc.org190a32f2014-06-09 17:40:49 +0000132 virtual int64_t TimeInMilliseconds() const OVERRIDE {
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000133 return TickTime::MillisecondTimestamp();
134 }
135
136 // Return a timestamp in microseconds relative to some arbitrary source; the
137 // source is fixed for this clock.
henrik.lundin@webrtc.org190a32f2014-06-09 17:40:49 +0000138 virtual int64_t TimeInMicroseconds() const OVERRIDE {
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000139 return TickTime::MicrosecondTimestamp();
140 }
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000141
142 // Retrieve an NTP absolute timestamp in seconds and fractions of a second.
henrik.lundin@webrtc.org190a32f2014-06-09 17:40:49 +0000143 virtual void CurrentNtp(uint32_t& seconds,
144 uint32_t& fractions) const OVERRIDE {
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000145 timeval tv = CurrentTimeVal();
146 double microseconds_in_seconds;
147 Adjust(tv, &seconds, &microseconds_in_seconds);
148 fractions = static_cast<uint32_t>(
149 microseconds_in_seconds * kMagicNtpFractionalUnit + 0.5);
150 }
151
152 // Retrieve an NTP absolute timestamp in milliseconds.
henrik.lundin@webrtc.org190a32f2014-06-09 17:40:49 +0000153 virtual int64_t CurrentNtpInMilliseconds() const OVERRIDE {
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000154 timeval tv = CurrentTimeVal();
155 uint32_t seconds;
156 double microseconds_in_seconds;
157 Adjust(tv, &seconds, &microseconds_in_seconds);
158 return 1000 * static_cast<int64_t>(seconds) +
159 static_cast<int64_t>(1000.0 * microseconds_in_seconds + 0.5);
160 }
161
162 protected:
163 virtual timeval CurrentTimeVal() const = 0;
164
165 static void Adjust(const timeval& tv, uint32_t* adjusted_s,
166 double* adjusted_us_in_s) {
167 *adjusted_s = tv.tv_sec + kNtpJan1970;
168 *adjusted_us_in_s = tv.tv_usec / 1e6;
169
170 if (*adjusted_us_in_s >= 1) {
171 *adjusted_us_in_s -= 1;
172 ++*adjusted_s;
173 } else if (*adjusted_us_in_s < -1) {
174 *adjusted_us_in_s += 1;
175 --*adjusted_s;
176 }
177 }
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000178};
179
180#if defined(_WIN32)
181class WindowsRealTimeClock : public RealTimeClock {
182 public:
wu@webrtc.org7a9a3b72014-05-29 19:40:28 +0000183 WindowsRealTimeClock(WindowsHelpTimer* helpTimer)
184 : _helpTimer(helpTimer) {}
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000185
186 virtual ~WindowsRealTimeClock() {}
187
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000188 protected:
pbos@webrtc.orga2a27182013-08-01 17:26:15 +0000189 virtual timeval CurrentTimeVal() const OVERRIDE {
pbos@webrtc.org046deb92013-04-09 09:06:11 +0000190 const uint64_t FILETIME_1970 = 0x019db1ded53e8000;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000191
192 FILETIME StartTime;
pbos@webrtc.org046deb92013-04-09 09:06:11 +0000193 uint64_t Time;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000194 struct timeval tv;
195
wu@webrtc.org7a9a3b72014-05-29 19:40:28 +0000196 // We can't use query performance counter since they can change depending on
197 // speed stepping.
198 get_time(_helpTimer, StartTime);
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000199
pbos@webrtc.org046deb92013-04-09 09:06:11 +0000200 Time = (((uint64_t) StartTime.dwHighDateTime) << 32) +
201 (uint64_t) StartTime.dwLowDateTime;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000202
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000203 // Convert the hecto-nano second time to tv format.
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000204 Time -= FILETIME_1970;
205
pbos@webrtc.org046deb92013-04-09 09:06:11 +0000206 tv.tv_sec = (uint32_t)(Time / (uint64_t)10000000);
207 tv.tv_usec = (uint32_t)((Time % (uint64_t)10000000) / 10);
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000208 return tv;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000209 }
wu@webrtc.org7a9a3b72014-05-29 19:40:28 +0000210
211 WindowsHelpTimer* _helpTimer;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000212};
213
214#elif ((defined WEBRTC_LINUX) || (defined WEBRTC_MAC))
215class UnixRealTimeClock : public RealTimeClock {
216 public:
217 UnixRealTimeClock() {}
218
219 virtual ~UnixRealTimeClock() {}
220
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000221 protected:
pbos@webrtc.orga2a27182013-08-01 17:26:15 +0000222 virtual timeval CurrentTimeVal() const OVERRIDE {
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000223 struct timeval tv;
224 struct timezone tz;
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000225 tz.tz_minuteswest = 0;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000226 tz.tz_dsttime = 0;
227 gettimeofday(&tv, &tz);
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000228 return tv;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000229 }
230};
231#endif
232
wu@webrtc.org7a9a3b72014-05-29 19:40:28 +0000233
234#if defined(_WIN32)
235// Keeps the global state for the Windows implementation of RtpRtcpClock.
236// Note that this is a POD. Only PODs are allowed to have static storage
237// duration according to the Google Style guide.
238//
239// Note that on Windows, GetSystemTimeAsFileTime has poorer (up to 15 ms)
240// resolution than the media timers, hence the WindowsHelpTimer context
241// object and Synchronize API to sync the two.
242//
243// We only sync up once, which means that on Windows, our realtime clock
244// wont respond to system time/date changes without a program restart.
245// TODO(henrike): We should probably call sync more often to catch
246// drift and time changes for parity with other platforms.
247
248static WindowsHelpTimer *SyncGlobalHelpTimer() {
249 static WindowsHelpTimer global_help_timer = {0, 0, {{ 0, 0}, 0}, 0};
250 Synchronize(&global_help_timer);
251 return &global_help_timer;
252}
253#endif
254
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000255Clock* Clock::GetRealTimeClock() {
256#if defined(_WIN32)
wu@webrtc.org7a9a3b72014-05-29 19:40:28 +0000257 static WindowsRealTimeClock clock(SyncGlobalHelpTimer());
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000258 return &clock;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000259#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000260 static UnixRealTimeClock clock;
261 return &clock;
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000262#else
263 return NULL;
264#endif
265}
266
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000267SimulatedClock::SimulatedClock(int64_t initial_time_us)
henrik.lundin@webrtc.org59336e82014-05-27 09:34:58 +0000268 : time_us_(initial_time_us), lock_(RWLockWrapper::CreateRWLock()) {
269}
270
271SimulatedClock::~SimulatedClock() {
272}
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000273
henrik.lundin@webrtc.org190a32f2014-06-09 17:40:49 +0000274int64_t SimulatedClock::TimeInMilliseconds() const {
henrik.lundin@webrtc.org59336e82014-05-27 09:34:58 +0000275 ReadLockScoped synchronize(*lock_);
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000276 return (time_us_ + 500) / 1000;
277}
278
henrik.lundin@webrtc.org190a32f2014-06-09 17:40:49 +0000279int64_t SimulatedClock::TimeInMicroseconds() const {
henrik.lundin@webrtc.org59336e82014-05-27 09:34:58 +0000280 ReadLockScoped synchronize(*lock_);
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000281 return time_us_;
282}
283
henrik.lundin@webrtc.org190a32f2014-06-09 17:40:49 +0000284void SimulatedClock::CurrentNtp(uint32_t& seconds, uint32_t& fractions) const {
henrik.lundin@webrtc.org59336e82014-05-27 09:34:58 +0000285 int64_t now_ms = TimeInMilliseconds();
286 seconds = (now_ms / 1000) + kNtpJan1970;
287 fractions =
288 static_cast<uint32_t>((now_ms % 1000) * kMagicNtpFractionalUnit / 1000);
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000289}
290
henrik.lundin@webrtc.org190a32f2014-06-09 17:40:49 +0000291int64_t SimulatedClock::CurrentNtpInMilliseconds() const {
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000292 return TimeInMilliseconds() + 1000 * static_cast<int64_t>(kNtpJan1970);
293}
294
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000295void SimulatedClock::AdvanceTimeMilliseconds(int64_t milliseconds) {
296 AdvanceTimeMicroseconds(1000 * milliseconds);
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000297}
298
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000299void SimulatedClock::AdvanceTimeMicroseconds(int64_t microseconds) {
henrik.lundin@webrtc.org59336e82014-05-27 09:34:58 +0000300 WriteLockScoped synchronize(*lock_);
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000301 time_us_ += microseconds;
302}
303
304}; // namespace webrtc