* 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;