* Revert clock.cc changes made in 6178, but keep the changes to the test.
* Use the new appoach proposed by jib in https://review.webrtc.org/10439004/ to fix the windows clock issue.
BUg=3325
R=niklas.enbom@webrtc.org, stefan@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/15569005
git-svn-id: http://webrtc.googlecode.com/svn/trunk@6273 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/system_wrappers/source/clock.cc b/webrtc/system_wrappers/source/clock.cc
index b341a5f..aa80f8f 100644
--- a/webrtc/system_wrappers/source/clock.cc
+++ b/webrtc/system_wrappers/source/clock.cc
@@ -33,6 +33,99 @@
static_cast<int64_t>(ntp_frac_ms + 0.5);
}
+#if defined(_WIN32)
+
+struct reference_point {
+ FILETIME file_time;
+ LARGE_INTEGER counterMS;
+};
+
+struct WindowsHelpTimer {
+ volatile LONG _timeInMs;
+ volatile LONG _numWrapTimeInMs;
+ reference_point _ref_point;
+
+ volatile LONG _sync_flag;
+};
+
+void Synchronize(WindowsHelpTimer* help_timer) {
+ const LONG start_value = 0;
+ const LONG new_value = 1;
+ const LONG synchronized_value = 2;
+
+ LONG compare_flag = new_value;
+ while (help_timer->_sync_flag == start_value) {
+ const LONG new_value = 1;
+ compare_flag = InterlockedCompareExchange(
+ &help_timer->_sync_flag, new_value, start_value);
+ }
+ if (compare_flag != start_value) {
+ // This thread was not the one that incremented the sync flag.
+ // Block until synchronization finishes.
+ while (compare_flag != synchronized_value) {
+ ::Sleep(0);
+ }
+ return;
+ }
+ // Only the synchronizing thread gets here so this part can be
+ // considered single threaded.
+
+ // set timer accuracy to 1 ms
+ timeBeginPeriod(1);
+ FILETIME ft0 = { 0, 0 },
+ ft1 = { 0, 0 };
+ //
+ // Spin waiting for a change in system time. Get the matching
+ // performance counter value for that time.
+ //
+ ::GetSystemTimeAsFileTime(&ft0);
+ do {
+ ::GetSystemTimeAsFileTime(&ft1);
+
+ help_timer->_ref_point.counterMS.QuadPart = ::timeGetTime();
+ ::Sleep(0);
+ } while ((ft0.dwHighDateTime == ft1.dwHighDateTime) &&
+ (ft0.dwLowDateTime == ft1.dwLowDateTime));
+ help_timer->_ref_point.file_time = ft1;
+ timeEndPeriod(1);
+}
+
+void get_time(WindowsHelpTimer* help_timer, FILETIME& current_time) {
+ // we can't use query performance counter due to speed stepping
+ DWORD t = timeGetTime();
+ // NOTE: we have a missmatch in sign between _timeInMs(LONG) and
+ // (DWORD) however we only use it here without +- etc
+ volatile LONG* timeInMsPtr = &help_timer->_timeInMs;
+ // Make sure that we only inc wrapper once.
+ DWORD old = InterlockedExchange(timeInMsPtr, t);
+ if(old > t) {
+ // wrap
+ help_timer->_numWrapTimeInMs++;
+ }
+ LARGE_INTEGER elapsedMS;
+ elapsedMS.HighPart = help_timer->_numWrapTimeInMs;
+ elapsedMS.LowPart = t;
+
+ elapsedMS.QuadPart = elapsedMS.QuadPart -
+ help_timer->_ref_point.counterMS.QuadPart;
+
+ // Translate to 100-nanoseconds intervals (FILETIME resolution)
+ // and add to reference FILETIME to get current FILETIME.
+ ULARGE_INTEGER filetime_ref_as_ul;
+
+ filetime_ref_as_ul.HighPart =
+ help_timer->_ref_point.file_time.dwHighDateTime;
+ filetime_ref_as_ul.LowPart =
+ help_timer->_ref_point.file_time.dwLowDateTime;
+ filetime_ref_as_ul.QuadPart +=
+ (ULONGLONG)((elapsedMS.QuadPart)*1000*10);
+
+ // Copy to result
+ current_time.dwHighDateTime = filetime_ref_as_ul.HighPart;
+ current_time.dwLowDateTime = filetime_ref_as_ul.LowPart;
+}
+#endif
+
class RealTimeClock : public Clock {
// Return a timestamp in milliseconds relative to some arbitrary source; the
// source is fixed for this clock.
@@ -86,7 +179,8 @@
#if defined(_WIN32)
class WindowsRealTimeClock : public RealTimeClock {
public:
- WindowsRealTimeClock() {}
+ WindowsRealTimeClock(WindowsHelpTimer* helpTimer)
+ : _helpTimer(helpTimer) {}
virtual ~WindowsRealTimeClock() {}
@@ -98,7 +192,9 @@
uint64_t Time;
struct timeval tv;
- GetSystemTimeAsFileTime(&StartTime);
+ // We can't use query performance counter since they can change depending on
+ // speed stepping.
+ get_time(_helpTimer, StartTime);
Time = (((uint64_t) StartTime.dwHighDateTime) << 32) +
(uint64_t) StartTime.dwLowDateTime;
@@ -110,6 +206,8 @@
tv.tv_usec = (uint32_t)((Time % (uint64_t)10000000) / 10);
return tv;
}
+
+ WindowsHelpTimer* _helpTimer;
};
#elif ((defined WEBRTC_LINUX) || (defined WEBRTC_MAC))
@@ -131,9 +229,31 @@
};
#endif
+
+#if defined(_WIN32)
+// Keeps the global state for the Windows implementation of RtpRtcpClock.
+// Note that this is a POD. Only PODs are allowed to have static storage
+// duration according to the Google Style guide.
+//
+// Note that on Windows, GetSystemTimeAsFileTime has poorer (up to 15 ms)
+// resolution than the media timers, hence the WindowsHelpTimer context
+// object and Synchronize API to sync the two.
+//
+// We only sync up once, which means that on Windows, our realtime clock
+// wont respond to system time/date changes without a program restart.
+// TODO(henrike): We should probably call sync more often to catch
+// drift and time changes for parity with other platforms.
+
+static WindowsHelpTimer *SyncGlobalHelpTimer() {
+ static WindowsHelpTimer global_help_timer = {0, 0, {{ 0, 0}, 0}, 0};
+ Synchronize(&global_help_timer);
+ return &global_help_timer;
+}
+#endif
+
Clock* Clock::GetRealTimeClock() {
#if defined(_WIN32)
- static WindowsRealTimeClock clock;
+ static WindowsRealTimeClock clock(SyncGlobalHelpTimer());
return &clock;
#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
static UnixRealTimeClock clock;