OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2004 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 <stdint.h> | |
12 | |
13 #if defined(WEBRTC_POSIX) | |
14 #include <sys/time.h> | |
15 #if defined(WEBRTC_MAC) | |
16 #include <mach/mach_time.h> | |
17 #endif | |
18 #endif | |
19 | |
20 #if defined(WEBRTC_WIN) | |
21 #ifndef WIN32_LEAN_AND_MEAN | |
22 #define WIN32_LEAN_AND_MEAN | |
23 #endif | |
24 #include <windows.h> | |
25 #include <mmsystem.h> | |
26 #include <sys/timeb.h> | |
27 #endif | |
28 | |
29 #include "webrtc/base/checks.h" | |
30 #include "webrtc/base/timeutils.h" | |
31 | |
32 namespace rtc { | |
33 | |
34 ClockInterface* g_clock = nullptr; | |
35 | |
36 ClockInterface* SetClockForTesting(ClockInterface* clock) { | |
37 ClockInterface* prev = g_clock; | |
38 g_clock = clock; | |
39 return prev; | |
40 } | |
41 | |
42 ClockInterface* GetClockForTesting() { | |
43 return g_clock; | |
44 } | |
45 | |
46 int64_t SystemTimeNanos() { | |
47 int64_t ticks; | |
48 #if defined(WEBRTC_MAC) | |
49 static mach_timebase_info_data_t timebase; | |
50 if (timebase.denom == 0) { | |
51 // Get the timebase if this is the first time we run. | |
52 // Recommended by Apple's QA1398. | |
53 if (mach_timebase_info(&timebase) != KERN_SUCCESS) { | |
54 RTC_NOTREACHED(); | |
55 } | |
56 } | |
57 // Use timebase to convert absolute time tick units into nanoseconds. | |
58 ticks = mach_absolute_time() * timebase.numer / timebase.denom; | |
59 #elif defined(WEBRTC_POSIX) | |
60 struct timespec ts; | |
61 // TODO(deadbeef): Do we need to handle the case when CLOCK_MONOTONIC is not | |
62 // supported? | |
63 clock_gettime(CLOCK_MONOTONIC, &ts); | |
64 ticks = kNumNanosecsPerSec * static_cast<int64_t>(ts.tv_sec) + | |
65 static_cast<int64_t>(ts.tv_nsec); | |
66 #elif defined(WEBRTC_WIN) | |
67 static volatile LONG last_timegettime = 0; | |
68 static volatile int64_t num_wrap_timegettime = 0; | |
69 volatile LONG* last_timegettime_ptr = &last_timegettime; | |
70 DWORD now = timeGetTime(); | |
71 // Atomically update the last gotten time | |
72 DWORD old = InterlockedExchange(last_timegettime_ptr, now); | |
73 if (now < old) { | |
74 // If now is earlier than old, there may have been a race between threads. | |
75 // 0x0fffffff ~3.1 days, the code will not take that long to execute | |
76 // so it must have been a wrap around. | |
77 if (old > 0xf0000000 && now < 0x0fffffff) { | |
78 num_wrap_timegettime++; | |
79 } | |
80 } | |
81 ticks = now + (num_wrap_timegettime << 32); | |
82 // TODO(deadbeef): Calculate with nanosecond precision. Otherwise, we're | |
83 // just wasting a multiply and divide when doing Time() on Windows. | |
84 ticks = ticks * kNumNanosecsPerMillisec; | |
85 #else | |
86 #error Unsupported platform. | |
87 #endif | |
88 return ticks; | |
89 } | |
90 | |
91 int64_t SystemTimeMillis() { | |
92 return static_cast<int64_t>(SystemTimeNanos() / kNumNanosecsPerMillisec); | |
93 } | |
94 | |
95 int64_t TimeNanos() { | |
96 if (g_clock) { | |
97 return g_clock->TimeNanos(); | |
98 } | |
99 return SystemTimeNanos(); | |
100 } | |
101 | |
102 uint32_t Time32() { | |
103 return static_cast<uint32_t>(TimeNanos() / kNumNanosecsPerMillisec); | |
104 } | |
105 | |
106 int64_t TimeMillis() { | |
107 return TimeNanos() / kNumNanosecsPerMillisec; | |
108 } | |
109 | |
110 int64_t TimeMicros() { | |
111 return TimeNanos() / kNumNanosecsPerMicrosec; | |
112 } | |
113 | |
114 int64_t TimeAfter(int64_t elapsed) { | |
115 RTC_DCHECK_GE(elapsed, 0); | |
116 return TimeMillis() + elapsed; | |
117 } | |
118 | |
119 int32_t TimeDiff32(uint32_t later, uint32_t earlier) { | |
120 return later - earlier; | |
121 } | |
122 | |
123 int64_t TimeDiff(int64_t later, int64_t earlier) { | |
124 return later - earlier; | |
125 } | |
126 | |
127 TimestampWrapAroundHandler::TimestampWrapAroundHandler() | |
128 : last_ts_(0), num_wrap_(-1) {} | |
129 | |
130 int64_t TimestampWrapAroundHandler::Unwrap(uint32_t ts) { | |
131 if (num_wrap_ == -1) { | |
132 last_ts_ = ts; | |
133 num_wrap_ = 0; | |
134 return ts; | |
135 } | |
136 | |
137 if (ts < last_ts_) { | |
138 if (last_ts_ >= 0xf0000000 && ts < 0x0fffffff) | |
139 ++num_wrap_; | |
140 } else if ((ts - last_ts_) > 0xf0000000) { | |
141 // Backwards wrap. Unwrap with last wrap count and don't update last_ts_. | |
142 return ts + ((num_wrap_ - 1) << 32); | |
143 } | |
144 | |
145 last_ts_ = ts; | |
146 return ts + (num_wrap_ << 32); | |
147 } | |
148 | |
149 int64_t TmToSeconds(const std::tm& tm) { | |
150 static short int mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | |
151 static short int cumul_mdays[12] = {0, 31, 59, 90, 120, 151, | |
152 181, 212, 243, 273, 304, 334}; | |
153 int year = tm.tm_year + 1900; | |
154 int month = tm.tm_mon; | |
155 int day = tm.tm_mday - 1; // Make 0-based like the rest. | |
156 int hour = tm.tm_hour; | |
157 int min = tm.tm_min; | |
158 int sec = tm.tm_sec; | |
159 | |
160 bool expiry_in_leap_year = (year % 4 == 0 && | |
161 (year % 100 != 0 || year % 400 == 0)); | |
162 | |
163 if (year < 1970) | |
164 return -1; | |
165 if (month < 0 || month > 11) | |
166 return -1; | |
167 if (day < 0 || day >= mdays[month] + (expiry_in_leap_year && month == 2 - 1)) | |
168 return -1; | |
169 if (hour < 0 || hour > 23) | |
170 return -1; | |
171 if (min < 0 || min > 59) | |
172 return -1; | |
173 if (sec < 0 || sec > 59) | |
174 return -1; | |
175 | |
176 day += cumul_mdays[month]; | |
177 | |
178 // Add number of leap days between 1970 and the expiration year, inclusive. | |
179 day += ((year / 4 - 1970 / 4) - (year / 100 - 1970 / 100) + | |
180 (year / 400 - 1970 / 400)); | |
181 | |
182 // We will have added one day too much above if expiration is during a leap | |
183 // year, and expiration is in January or February. | |
184 if (expiry_in_leap_year && month <= 2 - 1) // |month| is zero based. | |
185 day -= 1; | |
186 | |
187 // Combine all variables into seconds from 1970-01-01 00:00 (except |month| | |
188 // which was accumulated into |day| above). | |
189 return (((static_cast<int64_t> | |
190 (year - 1970) * 365 + day) * 24 + hour) * 60 + min) * 60 + sec; | |
191 } | |
192 | |
193 int64_t TimeUTCMicros() { | |
194 #if defined(WEBRTC_POSIX) | |
195 struct timeval time; | |
196 gettimeofday(&time, nullptr); | |
197 // Convert from second (1.0) and microsecond (1e-6). | |
198 return (static_cast<int64_t>(time.tv_sec) * rtc::kNumMicrosecsPerSec + | |
199 time.tv_usec); | |
200 | |
201 #elif defined(WEBRTC_WIN) | |
202 struct _timeb time; | |
203 _ftime(&time); | |
204 // Convert from second (1.0) and milliseconds (1e-3). | |
205 return (static_cast<int64_t>(time.time) * rtc::kNumMicrosecsPerSec + | |
206 static_cast<int64_t>(time.millitm) * rtc::kNumMicrosecsPerMillisec); | |
207 #endif | |
208 } | |
209 | |
210 } // namespace rtc | |
OLD | NEW |