Bug 1446346 - Do not clamp or jitter the AudioContext's CurrentTime if its interval is larger than our precision. r=jib, a=RyanVM
authorTom Ritter <tom@mozilla.com>
Tue, 17 Apr 2018 15:35:51 -0500
changeset 802191 c7e494e5888d67d5822143985fca6fd42c303b90
parent 802190 d06fb3839361bda1f0c4af69fe6aec7846dc00b4
child 802192 3ac8f220f7e6524be3f8753544cd46bec50dd5a7
push id111850
push userbmo:tom@mozilla.com
push dateThu, 31 May 2018 16:41:37 +0000
reviewersjib, RyanVM
bugs1446346
milestone60.0.2
Bug 1446346 - Do not clamp or jitter the AudioContext's CurrentTime if its interval is larger than our precision. r=jib, a=RyanVM MozReview-Commit-ID: Bc1cto3pBKL
browser/components/resistfingerprinting/test/mochitest/test_reduce_time_precision.html
dom/media/webaudio/AudioContext.cpp
toolkit/components/resistfingerprinting/nsRFPService.cpp
toolkit/components/resistfingerprinting/nsRFPService.h
--- a/browser/components/resistfingerprinting/test/mochitest/test_reduce_time_precision.html
+++ b/browser/components/resistfingerprinting/test/mochitest/test_reduce_time_precision.html
@@ -170,16 +170,26 @@ https://trac.torproject.org/projects/tor
     if (resistFingerprinting) {
       expectedPrecision = expectedPrecision < 100 ? 100 : expectedPrecision;
     }
 
     // Loop through each timeStampCode, evaluate it,
     // and check if it is rounded
     for (let timeStampCode of timeStampCodesDOM) {
       let timeStamp = eval(timeStampCode);
+
+      // Audio Contexts increment in intervals of (minimum) 5.4ms, so we don't
+      // clamp/jitter if the timer precision is les than that.
+      // (Technically on MBPs they increment in intervals of 2.6 but this is
+      // non-standard and will eventually be changed. We don't cover this situation
+      // because we don't really support arbitrary Timer Precision, especially in
+      // the 2.6 - 5.4ms interval.)
+      if (timeStampCode.includes("audioContext") && expectedPrecision < 5.4)
+        continue;
+
       ok(isRounded(timeStamp, expectedPrecision),
         "pref: " + prefname + " - '" +
          "'" + timeStampCode +
          "' should be rounded to nearest " +
          expectedPrecision + " ms; saw " +
          timeStamp);
     }
   }
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -649,27 +649,32 @@ AudioContext::DestinationStream() const
   return nullptr;
 }
 
 double
 AudioContext::CurrentTime()
 {
   MediaStream* stream = Destination()->Stream();
 
-  if (!mIsStarted &&
-    stream->StreamTimeToSeconds(stream->GetCurrentTime()) == 0) {
-      return 0;
+  double rawTime = stream->StreamTimeToSeconds(stream->GetCurrentTime());
+
+  // CurrentTime increments in intervals of 128/sampleRate. If the Timer
+  // Precision Reduction is smaller than this interval, the jittered time
+  // can always be reversed to the raw step of the interval. In that case
+  // we can simply return the un-reduced time; and avoid breaking tests.
+  // We have to convert each variable into a common magnitude, we choose ms.
+  if ((128/mSampleRate) * 1000.0 > nsRFPService::TimerResolution() / 1000.0) {
+    return rawTime;
   }
 
   // The value of a MediaStream's CurrentTime will always advance forward; it will never
   // reset (even if one rewinds a video.) Therefore we can use a single Random Seed
   // initialized at the same time as the object.
   return nsRFPService::ReduceTimePrecisionAsSecs(
-    stream->StreamTimeToSeconds(stream->GetCurrentTime()),
-    GetRandomTimelineSeed());
+    rawTime, GetRandomTimelineSeed());
 }
 
 void AudioContext::DisconnectFromOwner()
 {
   mIsDisconnecting = true;
   Shutdown();
   DOMEventTargetHelper::DisconnectFromOwner();
 }
--- a/toolkit/components/resistfingerprinting/nsRFPService.cpp
+++ b/toolkit/components/resistfingerprinting/nsRFPService.cpp
@@ -102,18 +102,19 @@ nsRFPService::GetOrCreate()
 
     ClearOnShutdown(&sRFPService);
     sInitialized = true;
   }
 
   return sRFPService;
 }
 
-inline double
-TimerResolution()
+/* static */
+double
+nsRFPService::TimerResolution()
 {
   if(nsRFPService::IsResistFingerprintingEnabled()) {
     return max(100000.0, (double)sResolutionUSec);
   }
   return sResolutionUSec;
 }
 
 /* static */
--- a/toolkit/components/resistfingerprinting/nsRFPService.h
+++ b/toolkit/components/resistfingerprinting/nsRFPService.h
@@ -157,16 +157,17 @@ class nsRFPService final : public nsIObs
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   static nsRFPService* GetOrCreate();
   static bool IsResistFingerprintingEnabled();
   static bool IsTimerPrecisionReductionEnabled(TimerPrecisionType aType);
+  static double TimerResolution();
 
   enum TimeScale {
     Seconds      = 1,
     MilliSeconds = 1000,
     MicroSeconds = 1000000
   };
 
   // The following Reduce methods can be called off main thread.