Bug 1564422 - Change `outputLatency` and `getOutputTimestamp` when `resistFingerPrinting` is enabled. r=tjr
authorPaul Adenot <paul@paul.cx>
Fri, 12 Jul 2019 11:27:25 +0000 (2019-07-12)
changeset 482569 c96e81ba64f307b402fc6df24a3e7c256ea854a3
parent 482568 de7190bf40fd3c940929365df71cfc2401f47cac
child 482570 b94a7e373671d9de449c05cef676e5391a4854db
push id36284
push userapavel@mozilla.com
push dateFri, 12 Jul 2019 21:43:58 +0000 (2019-07-12)
treeherdermozilla-central@cd685b4cff6d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstjr
bugs1564422
milestone70.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1564422 - Change `outputLatency` and `getOutputTimestamp` when `resistFingerPrinting` is enabled. r=tjr When Firefox is configured to resist fingerprinting, the latency figure returned is the most commonly found on a particular OS. For Android, I got data from [0], roughly copy/pasted the table into a file and did: ``` cat file | cut -d $'\t' -f4 | grep "^[[:digit:]]" | cut -d ' ' -f 1 | sort -h | uniq -c | sort -h ``` which indicated that 40ms was a good number for round trip latency (input to output). Since this is for output latency only and the audio path is roughly symmetrical in terms of duration, we report 20ms. For OSX, 512 is always used with the default hardware in Firefox, with this patch, it's always 512 regardless of the setup. On Linux/Pulse, we use 25ms [1] always, and this is adjusted by PulseAudio. This makes it always return 25ms. On Windows, there is a wide variety of configurations, but it's common to be in the ballpark of 80ms output (this is very empirical, by testing a bunch of hardware over the years). For other OSes, we use 2048 frames (adjusted to the sample-rate). [0]: https://superpowered.com/latency [1]: https://searchfox.org/mozilla-central/source/media/libcubeb/src/cubeb_pulse.c#725 Differential Revision: https://phabricator.services.mozilla.com/D37723
dom/media/webaudio/AudioContext.cpp
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -519,48 +519,65 @@ already_AddRefed<PeriodicWave> AudioCont
 
 AudioListener* AudioContext::Listener() {
   if (!mListener) {
     mListener = new AudioListener(this);
   }
   return mListener;
 }
 
-double AudioContext::OutputLatency() { return Graph()->AudioOutputLatency(); }
+double AudioContext::OutputLatency() {
+  // When reduceFingerprinting is enabled, return a latency figure that is
+  // fixed, but plausible for the platform.
+  double latency_s = 0.0;
+  if (nsRFPService::IsResistFingerprintingEnabled()) {
+#ifdef XP_MACOSX
+    latency_s = 512. / mSampleRate;
+#elif MOZ_WIDGET_ANDROID
+    latency_s = 0.020;
+#elif XP_WIN
+    latency_s = 0.04;
+#else  // Catchall for other OSes, including Linux.
+    latency_s = 0.025;
+#endif
+  } else {
+    return Graph()->AudioOutputLatency();
+  }
+  return latency_s;
+}
 
 void AudioContext::GetOutputTimestamp(AudioTimestamp& aTimeStamp) {
   if (!Destination()) {
     aTimeStamp.mContextTime.Construct(0.0);
     aTimeStamp.mPerformanceTime.Construct(0.0);
     return;
   }
 
   // The currentTime currently being output is the currentTime minus the audio
-  // output latency.
+  // output latency. The resolution of CurrentTime() is already reduced.
   aTimeStamp.mContextTime.Construct(
       std::max(0.0, CurrentTime() - OutputLatency()));
   nsPIDOMWindowInner* parent = GetParentObject();
   Performance* perf = parent ? parent->GetPerformance() : nullptr;
   if (perf) {
-    // Convert to milliseconds.
+    // perf->Now() already has reduced resolution here, no need to do it again.
     aTimeStamp.mPerformanceTime.Construct(
         std::max(0., perf->Now() - (OutputLatency() * 1000.)));
   } else {
     aTimeStamp.mPerformanceTime.Construct(0.0);
   }
 }
 
 Worklet* AudioContext::GetAudioWorklet(ErrorResult& aRv) {
   if (!mWorklet) {
     mWorklet = AudioWorkletImpl::CreateWorklet(this, aRv);
   }
 
   return mWorklet;
 }
-
 bool AudioContext::IsRunning() const {
   return mAudioContextState == AudioContextState::Running;
 }
 
 already_AddRefed<Promise> AudioContext::DecodeAudioData(
     const ArrayBuffer& aBuffer,
     const Optional<OwningNonNull<DecodeSuccessCallback>>& aSuccessCallback,
     const Optional<OwningNonNull<DecodeErrorCallback>>& aFailureCallback,