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 "webrtc/system_wrappers/include/clock.h" 12 13#if defined(_WIN32) 14// Windows needs to be included before mmsystem.h 15#include "webrtc/base/win32.h" 16#include <MMSystem.h> 17#elif ((defined WEBRTC_LINUX) || (defined WEBRTC_MAC)) 18#include <sys/time.h> 19#include <time.h> 20#endif 21 22#include "webrtc/base/criticalsection.h" 23#include "webrtc/system_wrappers/include/rw_lock_wrapper.h" 24#include "webrtc/system_wrappers/include/tick_util.h" 25 26namespace webrtc { 27 28const 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 36class RealTimeClock : public Clock { 37 // Return a timestamp in milliseconds relative to some arbitrary source; the 38 // source is fixed for this clock. 39 int64_t TimeInMilliseconds() const override { 40 return TickTime::MillisecondTimestamp(); 41 } 42 43 // Return a timestamp in microseconds relative to some arbitrary source; the 44 // source is fixed for this clock. 45 int64_t TimeInMicroseconds() const override { 46 return TickTime::MicrosecondTimestamp(); 47 } 48 49 // Retrieve an NTP absolute timestamp in seconds and fractions of a second. 50 void CurrentNtp(uint32_t& seconds, uint32_t& fractions) const override { 51 timeval tv = CurrentTimeVal(); 52 double microseconds_in_seconds; 53 Adjust(tv, &seconds, µseconds_in_seconds); 54 fractions = static_cast<uint32_t>( 55 microseconds_in_seconds * kMagicNtpFractionalUnit + 0.5); 56 } 57 58 // Retrieve an NTP absolute timestamp in milliseconds. 59 int64_t CurrentNtpInMilliseconds() const override { 60 timeval tv = CurrentTimeVal(); 61 uint32_t seconds; 62 double microseconds_in_seconds; 63 Adjust(tv, &seconds, µseconds_in_seconds); 64 return 1000 * static_cast<int64_t>(seconds) + 65 static_cast<int64_t>(1000.0 * microseconds_in_seconds + 0.5); 66 } 67 68 protected: 69 virtual timeval CurrentTimeVal() const = 0; 70 71 static void Adjust(const timeval& tv, 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(_WIN32) 87// TODO(pbos): Consider modifying the implementation to synchronize itself 88// against system time (update ref_point_, make it non-const) periodically to 89// prevent clock drift. 90class WindowsRealTimeClock : public RealTimeClock { 91 public: 92 WindowsRealTimeClock() 93 : last_time_ms_(0), 94 num_timer_wraps_(0), 95 ref_point_(GetSystemReferencePoint()) {} 96 97 virtual ~WindowsRealTimeClock() {} 98 99 protected: 100 struct ReferencePoint { 101 FILETIME file_time; 102 LARGE_INTEGER counter_ms; 103 }; 104 105 timeval CurrentTimeVal() const override { 106 const uint64_t FILETIME_1970 = 0x019db1ded53e8000; 107 108 FILETIME StartTime; 109 uint64_t Time; 110 struct timeval tv; 111 112 // We can't use query performance counter since they can change depending on 113 // speed stepping. 114 GetTime(&StartTime); 115 116 Time = (((uint64_t) StartTime.dwHighDateTime) << 32) + 117 (uint64_t) StartTime.dwLowDateTime; 118 119 // Convert the hecto-nano second time to tv format. 120 Time -= FILETIME_1970; 121 122 tv.tv_sec = (uint32_t)(Time / (uint64_t)10000000); 123 tv.tv_usec = (uint32_t)((Time % (uint64_t)10000000) / 10); 124 return tv; 125 } 126 127 void GetTime(FILETIME* current_time) const { 128 DWORD t; 129 LARGE_INTEGER elapsed_ms; 130 { 131 rtc::CritScope lock(&crit_); 132 // time MUST be fetched inside the critical section to avoid non-monotonic 133 // last_time_ms_ values that'll register as incorrect wraparounds due to 134 // concurrent calls to GetTime. 135 t = timeGetTime(); 136 if (t < last_time_ms_) 137 num_timer_wraps_++; 138 last_time_ms_ = t; 139 elapsed_ms.HighPart = num_timer_wraps_; 140 } 141 elapsed_ms.LowPart = t; 142 elapsed_ms.QuadPart = elapsed_ms.QuadPart - ref_point_.counter_ms.QuadPart; 143 144 // Translate to 100-nanoseconds intervals (FILETIME resolution) 145 // and add to reference FILETIME to get current FILETIME. 146 ULARGE_INTEGER filetime_ref_as_ul; 147 filetime_ref_as_ul.HighPart = ref_point_.file_time.dwHighDateTime; 148 filetime_ref_as_ul.LowPart = ref_point_.file_time.dwLowDateTime; 149 filetime_ref_as_ul.QuadPart += 150 static_cast<ULONGLONG>((elapsed_ms.QuadPart) * 1000 * 10); 151 152 // Copy to result 153 current_time->dwHighDateTime = filetime_ref_as_ul.HighPart; 154 current_time->dwLowDateTime = filetime_ref_as_ul.LowPart; 155 } 156 157 static ReferencePoint GetSystemReferencePoint() { 158 ReferencePoint ref = {}; 159 FILETIME ft0 = {}; 160 FILETIME ft1 = {}; 161 // Spin waiting for a change in system time. As soon as this change happens, 162 // get the matching call for timeGetTime() as soon as possible. This is 163 // assumed to be the most accurate offset that we can get between 164 // timeGetTime() and system time. 165 166 // Set timer accuracy to 1 ms. 167 timeBeginPeriod(1); 168 GetSystemTimeAsFileTime(&ft0); 169 do { 170 GetSystemTimeAsFileTime(&ft1); 171 172 ref.counter_ms.QuadPart = timeGetTime(); 173 Sleep(0); 174 } while ((ft0.dwHighDateTime == ft1.dwHighDateTime) && 175 (ft0.dwLowDateTime == ft1.dwLowDateTime)); 176 ref.file_time = ft1; 177 timeEndPeriod(1); 178 return ref; 179 } 180 181 // mutable as time-accessing functions are const. 182 mutable rtc::CriticalSection crit_; 183 mutable DWORD last_time_ms_; 184 mutable LONG num_timer_wraps_; 185 const ReferencePoint ref_point_; 186}; 187 188#elif ((defined WEBRTC_LINUX) || (defined WEBRTC_MAC)) 189class UnixRealTimeClock : public RealTimeClock { 190 public: 191 UnixRealTimeClock() {} 192 193 ~UnixRealTimeClock() override {} 194 195 protected: 196 timeval CurrentTimeVal() const override { 197 struct timeval tv; 198 struct timezone tz; 199 tz.tz_minuteswest = 0; 200 tz.tz_dsttime = 0; 201 gettimeofday(&tv, &tz); 202 return tv; 203 } 204}; 205#endif 206 207#if defined(_WIN32) 208static WindowsRealTimeClock* volatile g_shared_clock = nullptr; 209#endif 210Clock* Clock::GetRealTimeClock() { 211#if defined(_WIN32) 212 // This read relies on volatile read being atomic-load-acquire. This is 213 // true in MSVC since at least 2005: 214 // "A read of a volatile object (volatile read) has Acquire semantics" 215 if (g_shared_clock != nullptr) 216 return g_shared_clock; 217 WindowsRealTimeClock* clock = new WindowsRealTimeClock; 218 if (InterlockedCompareExchangePointer( 219 reinterpret_cast<void* volatile*>(&g_shared_clock), clock, nullptr) != 220 nullptr) { 221 // g_shared_clock was assigned while we constructed/tried to assign our 222 // instance, delete our instance and use the existing one. 223 delete clock; 224 } 225 return g_shared_clock; 226#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) 227 static UnixRealTimeClock clock; 228 return &clock; 229#else 230 return NULL; 231#endif 232} 233 234SimulatedClock::SimulatedClock(int64_t initial_time_us) 235 : time_us_(initial_time_us), lock_(RWLockWrapper::CreateRWLock()) { 236} 237 238SimulatedClock::~SimulatedClock() { 239} 240 241int64_t SimulatedClock::TimeInMilliseconds() const { 242 ReadLockScoped synchronize(*lock_); 243 return (time_us_ + 500) / 1000; 244} 245 246int64_t SimulatedClock::TimeInMicroseconds() const { 247 ReadLockScoped synchronize(*lock_); 248 return time_us_; 249} 250 251void SimulatedClock::CurrentNtp(uint32_t& seconds, uint32_t& fractions) const { 252 int64_t now_ms = TimeInMilliseconds(); 253 seconds = (now_ms / 1000) + kNtpJan1970; 254 fractions = 255 static_cast<uint32_t>((now_ms % 1000) * kMagicNtpFractionalUnit / 1000); 256} 257 258int64_t SimulatedClock::CurrentNtpInMilliseconds() const { 259 return TimeInMilliseconds() + 1000 * static_cast<int64_t>(kNtpJan1970); 260} 261 262void SimulatedClock::AdvanceTimeMilliseconds(int64_t milliseconds) { 263 AdvanceTimeMicroseconds(1000 * milliseconds); 264} 265 266void SimulatedClock::AdvanceTimeMicroseconds(int64_t microseconds) { 267 WriteLockScoped synchronize(*lock_); 268 time_us_ += microseconds; 269} 270 271}; // namespace webrtc 272