Backed out 47 changesets (bug 1656438) for bustages on DynamicResampler.cpp . CLOSED TREE
authorNarcis Beleuzu <nbeleuzu@mozilla.com>
Tue, 15 Sep 2020 20:15:27 +0300
changeset 548770 845077201b0c0f9632d21204392cba49cde2b9fb
parent 548769 c1bcb0dd0820298dffb9fa42cae935a4dcd27063
child 548771 935e2bd873b00cae7d7b18df982794c28245f90f
push id37787
push usermalexandru@mozilla.com
push dateWed, 16 Sep 2020 09:56:56 +0000
treeherdermozilla-central@a451ebba378e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1656438
milestone82.0a1
backs outdc497e6c016dd674022108988537a795f947a7d2
780a6b48d8768c1674ead299610decc5a5d56507
a9baeaefbb85de572b671c8061709d78fdec423b
297b4dbd2380da30e0f3b4fe6bfdedd71c45fc93
8c3c64217bf68f86874d4680770058efed9ddaf3
d51cd6827d3ba86150eff158e70c1d74bf4e61aa
1e48be97c8ad01fe15d158058d56f5a4f3b3e6fc
44d075680b27cc48a6f895b4bbf873bbfc803ca5
64c35518d82f786cd43902824324c51e93d5dc54
159e8137d4ada779f76f290d4a1de8757ee4ae86
0546062cc05378912b9af8bdb8a5bccdf82e3efb
18079c57927648be8fecad6c8e73cf35c3bbdda3
b6f3e65401b430dcb9df75ea2eb19f67b366aae4
cfbc65954235d19e763d338823a019e678fe43e2
d35cf2a0b6592242222e79c6698a9217c13152fd
5da08b28c7b55c8a85f09fe7b0e084584eee0fbf
8071a5b82a628a5774eb86a253798b281f183861
4f2aeff6e0e40cd50671a2150e7880b9a8dbd71e
4bb23c1083190fa3b3edde6a67ba08bd9ab55f47
90c2ec79a8fc082613cf19b21e34dee4c5be9f3f
ffb479620b65385266a8fb7d51dccb2497c83866
9e9f40be7bd76281f8bc831731ec5f0c233b92c0
664f66d512ff3fe8d9816a7aa6c1765096e9c2eb
ce3a1f7b1c79e0bb52f25a74f30e8155831d4b0d
8e59070e92eaecc733caab3cb052c9d1c10a6012
fd84761e9af8ed0932b9a6398ae9af189442bcfb
50ec7aa8a44aa2a4cf67d998a70d6fb6bac6ce6a
338a090e2657aa452f18cb90ea648e8e03f57184
1f262745a8444014cdfda2f275232dc8dbb2e3b7
3b904a06afd14c868e8290da73fd6347e02d7759
d5c5afc9239fa2a7295b10812410d80c3365d135
9351b87ca40be021c87ac95da80ac31f226767ca
2baecf74521e8f09be82b49443f1bb4c10c97e35
8571622fc9a0016bb4e083a78a00622d4af9362a
c4ad7c72bc9c8db070f16599bb4fd09bd599f0ce
e505d1d051c498600650fe7d622afe9f5220b885
a51bb724a78cdb3554d2085adde9d17b3c1908fc
8cacc0e96a3ecc7a4d84bce039e2c92800a275aa
58838694eb673b885d33fc5dfeae2332a3331bf3
2baa906a480dba9e2089447e991a2302373d2050
52e1ae3a4fd7269903cf57c7927200a40d2986c8
1da839e0562dd54ef399500b0d855932195cab93
55c9c22b0a138b9d151d9765686fbdc875e07739
d116b82ffad94a0705f73fc63ce080333a729b9e
b640887eca0e04d1c7e4e7f2ca680f0da37a0ed7
5be36600b09230b1d0f83fdc1514184528368cd4
7b07bbe610ae8bf851aef98f10d90719e31c8bf1
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
Backed out 47 changesets (bug 1656438) for bustages on DynamicResampler.cpp . CLOSED TREE Backed out changeset dc497e6c016d (bug 1656438) Backed out changeset 780a6b48d876 (bug 1656438) Backed out changeset a9baeaefbb85 (bug 1656438) Backed out changeset 297b4dbd2380 (bug 1656438) Backed out changeset 8c3c64217bf6 (bug 1656438) Backed out changeset d51cd6827d3b (bug 1656438) Backed out changeset 1e48be97c8ad (bug 1656438) Backed out changeset 44d075680b27 (bug 1656438) Backed out changeset 64c35518d82f (bug 1656438) Backed out changeset 159e8137d4ad (bug 1656438) Backed out changeset 0546062cc053 (bug 1656438) Backed out changeset 18079c579276 (bug 1656438) Backed out changeset b6f3e65401b4 (bug 1656438) Backed out changeset cfbc65954235 (bug 1656438) Backed out changeset d35cf2a0b659 (bug 1656438) Backed out changeset 5da08b28c7b5 (bug 1656438) Backed out changeset 8071a5b82a62 (bug 1656438) Backed out changeset 4f2aeff6e0e4 (bug 1656438) Backed out changeset 4bb23c108319 (bug 1656438) Backed out changeset 90c2ec79a8fc (bug 1656438) Backed out changeset ffb479620b65 (bug 1656438) Backed out changeset 9e9f40be7bd7 (bug 1656438) Backed out changeset 664f66d512ff (bug 1656438) Backed out changeset ce3a1f7b1c79 (bug 1656438) Backed out changeset 8e59070e92ea (bug 1656438) Backed out changeset fd84761e9af8 (bug 1656438) Backed out changeset 50ec7aa8a44a (bug 1656438) Backed out changeset 338a090e2657 (bug 1656438) Backed out changeset 1f262745a844 (bug 1656438) Backed out changeset 3b904a06afd1 (bug 1656438) Backed out changeset d5c5afc9239f (bug 1656438) Backed out changeset 9351b87ca40b (bug 1656438) Backed out changeset 2baecf74521e (bug 1656438) Backed out changeset 8571622fc9a0 (bug 1656438) Backed out changeset c4ad7c72bc9c (bug 1656438) Backed out changeset e505d1d051c4 (bug 1656438) Backed out changeset a51bb724a78c (bug 1656438) Backed out changeset 8cacc0e96a3e (bug 1656438) Backed out changeset 58838694eb67 (bug 1656438) Backed out changeset 2baa906a480d (bug 1656438) Backed out changeset 52e1ae3a4fd7 (bug 1656438) Backed out changeset 1da839e0562d (bug 1656438) Backed out changeset 55c9c22b0a13 (bug 1656438) Backed out changeset d116b82ffad9 (bug 1656438) Backed out changeset b640887eca0e (bug 1656438) Backed out changeset 5be36600b092 (bug 1656438) Backed out changeset 7b07bbe610ae (bug 1656438)
dom/media/AudioDriftCorrection.h
dom/media/AudioRingBuffer.cpp
dom/media/AudioRingBuffer.h
dom/media/DynamicResampler.cpp
dom/media/DynamicResampler.h
dom/media/MediaTrackGraph.cpp
dom/media/gtest/AudioGenerator.cpp
dom/media/gtest/AudioGenerator.h
dom/media/gtest/AudioVerifier.h
dom/media/gtest/MockCubeb.h
dom/media/gtest/TestAudioCallbackDriver.cpp
dom/media/gtest/TestAudioDriftCorrection.cpp
dom/media/gtest/TestAudioRingBuffer.cpp
dom/media/gtest/TestAudioTrackEncoder.cpp
dom/media/gtest/TestAudioTrackGraph.cpp
dom/media/gtest/TestDynamicResampler.cpp
dom/media/gtest/TestMediaDataEncoder.cpp
dom/media/gtest/moz.build
dom/media/webrtc/MediaEngineDefault.cpp
dom/media/webrtc/SineWaveGenerator.h
media/libspeex_resampler/integer-halving.patch
media/libspeex_resampler/src/arch.h
media/libspeex_resampler/src/fixed_generic.h
media/libspeex_resampler/src/resample.c
media/libspeex_resampler/update.sh
modules/libpref/init/StaticPrefList.yaml
tools/lint/file-whitespace.yml
--- a/dom/media/AudioDriftCorrection.h
+++ b/dom/media/AudioDriftCorrection.h
@@ -5,18 +5,16 @@
 
 #ifndef MOZILLA_AUDIO_DRIFT_CORRECTION_H_
 #define MOZILLA_AUDIO_DRIFT_CORRECTION_H_
 
 #include "DynamicResampler.h"
 
 namespace mozilla {
 
-extern LazyLogModule gMediaTrackGraphLog;
-
 /**
  * ClockDrift calculates the diverge of the source clock from the nominal
  * (provided) rate compared to the target clock, which is considered the master
  * clock. In the case of different sampling rates, it is assumed that resampling
  * will take place so the returned correction is estimated after the resampling.
  * That means that resampling is taken into account in the calculations but it
  * does appear in the correction. The correction must be applied to the top of
  * the resampling.
@@ -25,113 +23,118 @@ extern LazyLogModule gMediaTrackGraphLog
  * buffered data and estimates the correction needed. The correction logic has
  * been created with two things in mind. First, not to run out of frames because
  * that means the audio will glitch. Second, not to change the correction very
  * often because this will result in a change in the resampling ratio. The
  * resampler recreates its internal memory when the ratio changes which has a
  * performance impact.
  *
  * The pref `media.clock drift.buffering` can be used to configure the desired
- * internal buffering. Right now it is at 50ms. But it can be increased if there
+ * internal buffering. Right now it is at 5ms. But it can be increased if there
  * are audio quality problems.
  */
 class ClockDrift final {
  public:
   /**
    * Provide the nominal source and the target sample rate.
    */
-  ClockDrift(uint32_t aSourceRate, uint32_t aTargetRate,
-             uint32_t aDesiredBuffering)
+  ClockDrift(int32_t aSourceRate, int32_t aTargetRate)
       : mSourceRate(aSourceRate),
         mTargetRate(aTargetRate),
-        mDesiredBuffering(aDesiredBuffering) {}
+        mDesiredBuffering(5 * mSourceRate / 100) {
+    if (Preferences::HasUserValue("media.clockdrift.buffering")) {
+      int msecs = Preferences::GetInt("media.clockdrift.buffering");
+      mDesiredBuffering = msecs * mSourceRate / 100;
+    }
+  }
 
   /**
    * The correction in the form of a ratio. A correction of 0.98 means that the
    * target is 2% slower compared to the source or 1.03 which means that the
    * target is 3% faster than the source.
    */
   float GetCorrection() { return mCorrection; }
 
   /**
    * Update the available source frames, target frames, and the current
-   * buffer, in every iteration. If the conditions are met a new correction is
+   * buffering, in every iteration. If the condition are met a new correction is
    * calculated. A new correction is calculated in the following cases:
-   *   1. Every mAdjustmentIntervalMs milliseconds (1000ms).
-   *   2. Every time we run low on buffered frames (less than 20ms).
+   *   1. Every 100 iterations which mean every 100 calls of this method.
+   *   2. Every time we run out of buffered frames (less than 2ms).
    * In addition to that, the correction is clamped to 10% to avoid sound
    * distortion so the result will be in [0.9, 1.1].
    */
-  void UpdateClock(uint32_t aSourceFrames, uint32_t aTargetFrames,
-                   uint32_t aBufferedFrames, uint32_t aRemainingFrames) {
-    if (mSourceClock >= mSourceRate / 10 || mTargetClock >= mTargetRate / 10) {
-      // Only update the correction if 100ms has passed since last update.
-      if (aBufferedFrames < mDesiredBuffering * 4 / 10 /*40%*/ ||
-          aRemainingFrames < mDesiredBuffering * 4 / 10 /*40%*/) {
-        // We are getting close to the lower or upper bound of the internal
-        // buffer. Steer clear.
-        CalculateCorrection(0.9, aBufferedFrames, aRemainingFrames);
-      } else if ((mTargetClock * 1000 / mTargetRate) >= mAdjustmentIntervalMs ||
-                 (mSourceClock * 1000 / mSourceRate) >= mAdjustmentIntervalMs) {
-        // The adjustment interval has passed on one side. Recalculate.
-        CalculateCorrection(0.6, aBufferedFrames, aRemainingFrames);
-      }
+  void UpdateClock(int aSourceClock, int aTargetClock, int aBufferedFrames) {
+    if (mIterations == mAdjustementWindow) {
+      CalculateCorrection(aBufferedFrames);
+    } else if (aBufferedFrames < 2 * mSourceRate / 100 /*20ms*/) {
+      BufferedFramesCorrection(aBufferedFrames);
     }
-    mTargetClock += aTargetFrames;
-    mSourceClock += aSourceFrames;
+    mTargetClock += aTargetClock;
+    mSourceClock += aSourceClock;
+    ++mIterations;
   }
 
  private:
-  /**
-   * aCalculationWeight is a percentage [0, 1] with which the calculated
-   * correction will be weighted. The existing correction will be weighted with
-   * 1 - aCalculationWeight. This gives some inertia to the speed at which the
-   * correction changes, for smoother changes.
-   */
-  void CalculateCorrection(float aCalculationWeight, uint32_t aBufferedFrames,
-                           uint32_t aRemainingFrames) {
-    // We want to maintain the desired buffer
-    uint32_t bufferedFramesDiff = aBufferedFrames - mDesiredBuffering;
-    uint32_t resampledSourceClock =
-        std::max(1u, mSourceClock + bufferedFramesDiff);
+  void CalculateCorrection(int aBufferedFrames) {
+    // We want to maintain 4 ms buffered
+    int32_t bufferedFramesDiff = aBufferedFrames - mDesiredBuffering;
+    int32_t resampledSourceClock = mSourceClock + bufferedFramesDiff;
     if (mTargetRate != mSourceRate) {
-      resampledSourceClock *= static_cast<float>(mTargetRate) / mSourceRate;
+      resampledSourceClock =
+          resampledSourceClock *
+          (static_cast<float>(mTargetRate) / static_cast<float>(mSourceRate));
     }
+    mCorrection = (float)mTargetClock / resampledSourceClock;
 
-    MOZ_LOG(gMediaTrackGraphLog, LogLevel::Verbose,
-            ("ClockDrift %p Calculated correction %.3f (with weight: %.1f -> "
-             "%.3f) (buffer: %u, desired: %u, remaining: %u)",
-             this, static_cast<float>(mTargetClock) / resampledSourceClock,
-             aCalculationWeight,
-             (1 - aCalculationWeight) * mCorrection +
-                 aCalculationWeight * mTargetClock / resampledSourceClock,
-             aBufferedFrames, mDesiredBuffering, aRemainingFrames));
-
-    mCorrection = (1 - aCalculationWeight) * mCorrection +
-                  aCalculationWeight * mTargetClock / resampledSourceClock;
-
-    // Clamp to range [0.9, 1.1] to avoid distortion
+    // Clamp to ragnge [0.9, 1.1] to avoid distortion
     mCorrection = std::min(std::max(mCorrection, 0.9f), 1.1f);
 
-    // Reset the counters to prepare for the next period.
+    // If previous correction slightly smaller  (-1%) ignore it to avoid
+    // recalculations. Don't do it when is greater (+1%) to avoid risking
+    // running out of frames.
+    if (mPreviousCorrection - mCorrection <= 0.01 &&
+        mPreviousCorrection - mCorrection > 0) {
+      mCorrection = mPreviousCorrection;
+    }
+    mPreviousCorrection = mCorrection;
+
+    // Reset the counters to preper for the new period.
+    mIterations = 0;
     mTargetClock = 0;
     mSourceClock = 0;
   }
 
- public:
-  const uint32_t mSourceRate;
-  const uint32_t mTargetRate;
-  const uint32_t mAdjustmentIntervalMs = 1000;
-  const uint32_t mDesiredBuffering;
+  void BufferedFramesCorrection(int aBufferedFrames) {
+    int32_t bufferedFramesDiff = aBufferedFrames - mDesiredBuffering;
+    int32_t resampledSourceClock = mSourceRate + bufferedFramesDiff;
+    if (mTargetRate != mSourceRate) {
+      resampledSourceClock = resampledSourceClock *
+                             (static_cast<float>(mTargetRate) / mSourceRate);
+    }
+    MOZ_ASSERT(mTargetRate > resampledSourceClock);
+    mPreviousCorrection = mCorrection;
+    mCorrection +=
+        static_cast<float>(mTargetRate) / resampledSourceClock - 1.0f;
+    // Clamp to range [0.9, 1.1] to avoid distortion
+    mCorrection = std::min(std::max(mCorrection, 0.9f), 1.1f);
+  }
 
  private:
-  float mCorrection = 1.0;
+  const int32_t mSourceRate;
+  const int32_t mTargetRate;
 
-  uint32_t mSourceClock = 0;
-  uint32_t mTargetClock = 0;
+  float mCorrection = 1.0;
+  float mPreviousCorrection = 1.0;
+  const int32_t mAdjustementWindow = 100;
+  int32_t mDesiredBuffering;  // defult: 5ms
+
+  int32_t mSourceClock = 0;
+  int32_t mTargetClock = 0;
+  int32_t mIterations = 0;
 };
 
 /**
  * Correct the drift between two independent clocks, the source, and the target
  * clock. The target clock is the master clock so the correction syncs the drift
  * of the source clock to the target. The nominal sampling rates of source and
  * target must be provided. If the source and the target operate in different
  * sample rate the drift correction will be performed on the top of resampling
@@ -145,61 +148,51 @@ class ClockDrift final {
  *
  * The class is not thread-safe. The construction can happen in any thread but
  * the member method must be used in a single thread that can be different than
  * the construction thread. Appropriate for being used in the high priority
  * audio thread.
  */
 class AudioDriftCorrection final {
  public:
-  AudioDriftCorrection(uint32_t aSourceRate, uint32_t aTargetRate)
-      : mDesiredBuffering(
-            std::max(5, Preferences::GetInt("media.clockdrift.buffering", 50)) *
-            aSourceRate / 1000),
-        mTargetRate(aTargetRate),
-        mClockDrift(aSourceRate, aTargetRate, mDesiredBuffering),
-        mResampler(aSourceRate, aTargetRate, mDesiredBuffering) {}
+  AudioDriftCorrection(int32_t aSourceRate, int32_t aTargetRate)
+      : mClockDrift(aSourceRate, aTargetRate),
+        mResampler(aSourceRate, aTargetRate, aTargetRate / 20 /*50ms*/),
+        mTargetRate(aTargetRate) {}
 
   /**
    * The source audio frames and request the number of target audio frames must
    * be provided. The duration of the source and the output is considered as the
    * source clock and the target clock. The input is buffered internally so some
    * latency exists. The returned AudioSegment must be cleaned up because the
    * internal buffer will be reused after 100ms. If the drift correction (and
    * possible resampling) is not possible due to lack of input data an empty
    * AudioSegment will be returned. Not thread-safe.
    */
   AudioSegment RequestFrames(const AudioSegment& aInput,
-                             uint32_t aOutputFrames) {
+                             int32_t aOutputFrames) {
     // Very important to go first since the Dynamic will get the sample format
     // from the chunk.
     if (aInput.GetDuration()) {
       // Always go through the resampler because the clock might shift later.
       mResampler.AppendInput(aInput);
     }
     mClockDrift.UpdateClock(aInput.GetDuration(), aOutputFrames,
-                            mResampler.InputDuration(),
-                            mResampler.InputRemainingDuration());
+                            mResampler.InputDuration());
     TrackRate receivingRate = mTargetRate * mClockDrift.GetCorrection();
     // Update resampler's rate if there is a new correction.
     mResampler.UpdateOutRate(receivingRate);
     // If it does not have enough frames the result will be an empty segment.
     AudioSegment output = mResampler.Resample(aOutputFrames);
     if (output.IsEmpty()) {
-      NS_WARNING("Got nothing from the resampler");
       output.AppendNullData(aOutputFrames);
     }
     return output;
   }
 
-  // Only accessible from the same thread that is driving RequestFrames().
-  uint32_t CurrentBuffering() const { return mResampler.InputDuration(); }
-
-  const uint32_t mDesiredBuffering;
-  const uint32_t mTargetRate;
-
  private:
   ClockDrift mClockDrift;
   AudioResampler mResampler;
+  const int32_t mTargetRate;
 };
 
 };     // namespace mozilla
 #endif /* MOZILLA_AUDIO_DRIFT_CORRECTION_H_ */
--- a/dom/media/AudioRingBuffer.cpp
+++ b/dom/media/AudioRingBuffer.cpp
@@ -30,45 +30,45 @@ class RingBuffer final {
         mMemoryBuffer(std::move(aMemoryBuffer)) {
     MOZ_ASSERT(std::is_trivial<T>::value);
     MOZ_ASSERT(!mStorage.IsEmpty());
   }
 
   /**
    * Write `aSamples` number of zeros in the buffer.
    */
-  uint32_t WriteSilence(uint32_t aSamples) {
+  int WriteSilence(int aSamples) {
     MOZ_ASSERT(aSamples);
     return Write(Span<T>(), aSamples);
   }
 
   /**
    * Copy `aBuffer` to the RingBuffer.
    */
-  uint32_t Write(const Span<const T>& aBuffer) {
+  int Write(const Span<const T>& aBuffer) {
     MOZ_ASSERT(!aBuffer.IsEmpty());
     return Write(aBuffer, aBuffer.Length());
   }
 
  private:
   /**
    * Copy `aSamples` number of elements from `aBuffer` to the RingBuffer. If
    * `aBuffer` is empty append `aSamples` of zeros.
    */
-  uint32_t Write(const Span<const T>& aBuffer, uint32_t aSamples) {
+  int Write(const Span<const T>& aBuffer, int aSamples) {
     MOZ_ASSERT(aSamples > 0 &&
                aBuffer.Length() <= static_cast<uint32_t>(aSamples));
 
     if (IsFull()) {
       return 0;
     }
 
-    uint32_t toWrite = std::min(AvailableWrite(), aSamples);
-    uint32_t part1 = std::min(Capacity() - mWriteIndex, toWrite);
-    uint32_t part2 = toWrite - part1;
+    int toWrite = std::min(AvailableWrite(), aSamples);
+    int part1 = std::min(Capacity() - mWriteIndex, toWrite);
+    int part2 = toWrite - part1;
 
     Span<T> part1Buffer = mStorage.Subspan(mWriteIndex, part1);
     Span<T> part2Buffer = mStorage.To(part2);
 
     if (!aBuffer.IsEmpty()) {
       Span<const T> fromPart1 = aBuffer.To(part1);
       Span<const T> fromPart2 = aBuffer.Subspan(part1, part2);
 
@@ -85,55 +85,54 @@ class RingBuffer final {
     return toWrite;
   }
 
  public:
   /**
    * Copy `aSamples` number of elements from `aBuffer` to the RingBuffer. The
    * `aBuffer` does not change.
    */
-  uint32_t Write(const RingBuffer& aBuffer, uint32_t aSamples) {
+  int Write(const RingBuffer& aBuffer, int aSamples) {
     MOZ_ASSERT(aSamples);
 
     if (IsFull()) {
       return 0;
     }
 
-    uint32_t toWriteThis = std::min(AvailableWrite(), aSamples);
-    uint32_t toReadThat = std::min(aBuffer.AvailableRead(), toWriteThis);
-    uint32_t part1 =
-        std::min(aBuffer.Capacity() - aBuffer.mReadIndex, toReadThat);
-    uint32_t part2 = toReadThat - part1;
+    int toWriteThis = std::min(AvailableWrite(), aSamples);
+    int toReadThat = std::min(aBuffer.AvailableRead(), toWriteThis);
+    int part1 = std::min(aBuffer.Capacity() - aBuffer.mReadIndex, toReadThat);
+    int part2 = toReadThat - part1;
 
     Span<T> part1Buffer = aBuffer.mStorage.Subspan(aBuffer.mReadIndex, part1);
-    DebugOnly<uint32_t> ret = Write(part1Buffer);
+    DebugOnly<int> ret = Write(part1Buffer);
     MOZ_ASSERT(ret == part1);
     if (part2) {
       Span<T> part2Buffer = aBuffer.mStorage.To(part2);
       ret = Write(part2Buffer);
       MOZ_ASSERT(ret == part2);
     }
 
     return toReadThat;
   }
 
   /**
    * Copy `aBuffer.Length()` number of elements from RingBuffer to `aBuffer`.
    */
-  uint32_t Read(const Span<T>& aBuffer) {
+  int Read(const Span<T>& aBuffer) {
     MOZ_ASSERT(!aBuffer.IsEmpty());
-    MOZ_ASSERT(aBuffer.size() <= std::numeric_limits<uint32_t>::max());
+    MOZ_ASSERT(aBuffer.size() <= std::numeric_limits<int>::max());
 
     if (IsEmpty()) {
       return 0;
     }
 
-    uint32_t toRead = std::min<uint32_t>(AvailableRead(), aBuffer.Length());
-    uint32_t part1 = std::min(Capacity() - mReadIndex, toRead);
-    uint32_t part2 = toRead - part1;
+    int toRead = std::min(AvailableRead(), static_cast<int>(aBuffer.Length()));
+    int part1 = std::min(Capacity() - mReadIndex, toRead);
+    int part2 = toRead - part1;
 
     Span<T> part1Buffer = mStorage.Subspan(mReadIndex, part1);
     Span<T> part2Buffer = mStorage.To(part2);
 
     Span<T> toPart1 = aBuffer.To(part1);
     Span<T> toPart2 = aBuffer.Subspan(part1, part2);
 
     CopySpan(toPart1, part1Buffer);
@@ -160,65 +159,64 @@ class RingBuffer final {
    *
    * In general, the problem with ring buffers is that they cannot provide one
    * linear chunk of memory so extra copies, to a linear buffer, are often
    * needed. This method bridge that gap by breaking the ring buffer's
    * internal read memory into linear pieces and making it available through
    * the `aCallable`. In the body of the `aCallable` those buffers can be used
    * directly without any copy or intermediate steps.
    */
-  uint32_t ReadNoCopy(
-      std::function<uint32_t(const Span<const T>&)>&& aCallable) {
+  int ReadNoCopy(std::function<int(const Span<const T>&)>&& aCallable) {
     if (IsEmpty()) {
       return 0;
     }
 
-    uint32_t part1 = std::min(Capacity() - mReadIndex, AvailableRead());
-    uint32_t part2 = AvailableRead() - part1;
+    int part1 = std::min(Capacity() - mReadIndex, AvailableRead());
+    int part2 = AvailableRead() - part1;
 
     Span<T> part1Buffer = mStorage.Subspan(mReadIndex, part1);
-    uint32_t toRead = aCallable(part1Buffer);
+    int toRead = aCallable(part1Buffer);
     MOZ_ASSERT(toRead <= part1);
 
     if (toRead == part1 && part2) {
       Span<T> part2Buffer = mStorage.To(part2);
       toRead += aCallable(part2Buffer);
       MOZ_ASSERT(toRead <= part1 + part2);
     }
 
     mReadIndex = NextIndex(mReadIndex, toRead);
 
     return toRead;
   }
 
   /**
    * Remove the next `aSamples` number of samples from the ring buffer.
    */
-  uint32_t Discard(uint32_t aSamples) {
+  int Discard(int aSamples) {
     MOZ_ASSERT(aSamples);
 
     if (IsEmpty()) {
       return 0;
     }
 
-    uint32_t toDiscard = std::min(AvailableRead(), aSamples);
+    int toDiscard = std::min(AvailableRead(), aSamples);
     mReadIndex = NextIndex(mReadIndex, toDiscard);
 
     return toDiscard;
   }
 
   /**
    * Empty the ring buffer.
    */
-  uint32_t Clear() {
+  int Clear() {
     if (IsEmpty()) {
       return 0;
     }
 
-    uint32_t toDiscard = AvailableRead();
+    int toDiscard = AvailableRead();
     mReadIndex = NextIndex(mReadIndex, toDiscard);
 
     return toDiscard;
   }
 
   /**
    * Returns true if the full capacity of the ring buffer is being used. When
    * full any attempt to write more samples to the ring buffer will fail.
@@ -229,59 +227,60 @@ class RingBuffer final {
    * Returns true if the ring buffer is empty. When empty any attempt to read
    * more samples from the ring buffer will fail.
    */
   bool IsEmpty() const { return mWriteIndex == mReadIndex; }
 
   /**
    * The number of samples available for writing.
    */
-  uint32_t AvailableWrite() const {
+  int AvailableWrite() const {
     /* We subtract one element here to always keep at least one sample
      * free in the buffer, to distinguish between full and empty array. */
-    uint32_t rv = mReadIndex - mWriteIndex - 1;
+    int rv = mReadIndex - mWriteIndex - 1;
     if (mWriteIndex >= mReadIndex) {
       rv += Capacity();
     }
     return rv;
   }
 
   /**
    * The number of samples available for reading.
    */
-  uint32_t AvailableRead() const {
+  int AvailableRead() const {
     if (mWriteIndex >= mReadIndex) {
       return mWriteIndex - mReadIndex;
     }
     return mWriteIndex + Capacity() - mReadIndex;
   }
 
  private:
-  uint32_t NextIndex(uint32_t aIndex, uint32_t aStep) const {
+  int NextIndex(int aIndex, int aStep) const {
+    MOZ_ASSERT(aStep >= 0);
     MOZ_ASSERT(aStep < Capacity());
     MOZ_ASSERT(aIndex < Capacity());
     return (aIndex + aStep) % Capacity();
   }
 
-  uint32_t Capacity() const { return mStorage.Length(); }
+  int32_t Capacity() const { return mStorage.Length(); }
 
   Span<T> ConvertToSpan(const AlignedByteBuffer& aOther) const {
     MOZ_ASSERT(aOther.Length() >= sizeof(T));
     return Span<T>(reinterpret_cast<T*>(aOther.Data()),
                    aOther.Length() / sizeof(T));
   }
 
   void CopySpan(Span<T>& aTo, const Span<const T>& aFrom) {
     MOZ_ASSERT(aTo.Length() == aFrom.Length());
     std::copy(aFrom.cbegin(), aFrom.cend(), aTo.begin());
   }
 
  private:
-  uint32_t mReadIndex = 0;
-  uint32_t mWriteIndex = 0;
+  int mReadIndex = 0;
+  int mWriteIndex = 0;
   /* Points to the mMemoryBuffer. */
   const Span<T> mStorage;
   /* The actual allocated memory set from outside. It is set in the ctor and it
    * is not used again. It is here to control the lifetime of the memory. The
    * memory is accessed through the mStorage. The idea is that the memory used
    * from the RingBuffer can be pre-allocated. */
   const AlignedByteBuffer mMemoryBuffer;
 };
@@ -292,19 +291,20 @@ class RingBuffer final {
 class AudioRingBuffer::AudioRingBufferPrivate {
  public:
   AudioSampleFormat mSampleFormat = AUDIO_FORMAT_SILENCE;
   Maybe<RingBuffer<float>> mFloatRingBuffer;
   Maybe<RingBuffer<int16_t>> mIntRingBuffer;
   Maybe<AlignedByteBuffer> mBackingBuffer;
 };
 
-AudioRingBuffer::AudioRingBuffer(uint32_t aSizeInBytes)
+AudioRingBuffer::AudioRingBuffer(int aSizeInBytes)
     : mPtr(MakeUnique<AudioRingBufferPrivate>()) {
   MOZ_ASSERT(aSizeInBytes > 0);
+  MOZ_ASSERT(aSizeInBytes < std::numeric_limits<int>::max());
   mPtr->mBackingBuffer.emplace(aSizeInBytes);
   MOZ_ASSERT(mPtr->mBackingBuffer);
 }
 
 AudioRingBuffer::~AudioRingBuffer() = default;
 
 void AudioRingBuffer::SetSampleFormat(AudioSampleFormat aFormat) {
   MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_SILENCE);
@@ -318,100 +318,99 @@ void AudioRingBuffer::SetSampleFormat(Au
     mPtr->mIntRingBuffer.emplace(mPtr->mBackingBuffer.extract());
     MOZ_ASSERT(!mPtr->mBackingBuffer);
     return;
   }
   mPtr->mFloatRingBuffer.emplace(mPtr->mBackingBuffer.extract());
   MOZ_ASSERT(!mPtr->mBackingBuffer);
 }
 
-uint32_t AudioRingBuffer::Write(const Span<const float>& aBuffer) {
+int AudioRingBuffer::Write(const Span<const float>& aBuffer) {
   MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
   MOZ_ASSERT(!mPtr->mIntRingBuffer);
   MOZ_ASSERT(!mPtr->mBackingBuffer);
   return mPtr->mFloatRingBuffer->Write(aBuffer);
 }
 
-uint32_t AudioRingBuffer::Write(const Span<const int16_t>& aBuffer) {
+int AudioRingBuffer::Write(const Span<const int16_t>& aBuffer) {
   MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16);
   MOZ_ASSERT(!mPtr->mFloatRingBuffer);
   MOZ_ASSERT(!mPtr->mBackingBuffer);
   return mPtr->mIntRingBuffer->Write(aBuffer);
 }
 
-uint32_t AudioRingBuffer::Write(const AudioRingBuffer& aBuffer,
-                                uint32_t aSamples) {
+int AudioRingBuffer::Write(const AudioRingBuffer& aBuffer, int aSamples) {
   MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16 ||
              mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
   MOZ_ASSERT(!mPtr->mBackingBuffer);
   if (mPtr->mSampleFormat == AUDIO_FORMAT_S16) {
     MOZ_ASSERT(!mPtr->mFloatRingBuffer);
     return mPtr->mIntRingBuffer->Write(aBuffer.mPtr->mIntRingBuffer.ref(),
                                        aSamples);
   }
   MOZ_ASSERT(!mPtr->mIntRingBuffer);
   return mPtr->mFloatRingBuffer->Write(aBuffer.mPtr->mFloatRingBuffer.ref(),
                                        aSamples);
 }
 
-uint32_t AudioRingBuffer::WriteSilence(uint32_t aSamples) {
+int AudioRingBuffer::WriteSilence(int aSamples) {
   MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16 ||
              mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
   MOZ_ASSERT(!mPtr->mBackingBuffer);
   if (mPtr->mSampleFormat == AUDIO_FORMAT_S16) {
     MOZ_ASSERT(!mPtr->mFloatRingBuffer);
     return mPtr->mIntRingBuffer->WriteSilence(aSamples);
   }
   MOZ_ASSERT(!mPtr->mIntRingBuffer);
   return mPtr->mFloatRingBuffer->WriteSilence(aSamples);
 }
 
-uint32_t AudioRingBuffer::Read(const Span<float>& aBuffer) {
+int AudioRingBuffer::Read(const Span<float>& aBuffer) {
   MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
   MOZ_ASSERT(!mPtr->mIntRingBuffer);
   MOZ_ASSERT(!mPtr->mBackingBuffer);
   return mPtr->mFloatRingBuffer->Read(aBuffer);
 }
 
-uint32_t AudioRingBuffer::Read(const Span<int16_t>& aBuffer) {
+int AudioRingBuffer::Read(const Span<int16_t>& aBuffer) {
   MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16);
   MOZ_ASSERT(!mPtr->mFloatRingBuffer);
   MOZ_ASSERT(!mPtr->mBackingBuffer);
   return mPtr->mIntRingBuffer->Read(aBuffer);
 }
 
-uint32_t AudioRingBuffer::ReadNoCopy(
-    std::function<uint32_t(const Span<const float>&)>&& aCallable) {
+int AudioRingBuffer::ReadNoCopy(
+    std::function<int(const Span<const float>&)>&& aCallable) {
   MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
   MOZ_ASSERT(!mPtr->mIntRingBuffer);
   MOZ_ASSERT(!mPtr->mBackingBuffer);
   return mPtr->mFloatRingBuffer->ReadNoCopy(std::move(aCallable));
 }
 
-uint32_t AudioRingBuffer::ReadNoCopy(
-    std::function<uint32_t(const Span<const int16_t>&)>&& aCallable) {
+int AudioRingBuffer::ReadNoCopy(
+    std::function<int(const Span<const int16_t>&)>&& aCallable) {
   MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16);
   MOZ_ASSERT(!mPtr->mFloatRingBuffer);
   MOZ_ASSERT(!mPtr->mBackingBuffer);
   return mPtr->mIntRingBuffer->ReadNoCopy(std::move(aCallable));
 }
 
-uint32_t AudioRingBuffer::Discard(uint32_t aSamples) {
+int AudioRingBuffer::Discard(int aSamples) {
   MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16 ||
              mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
   MOZ_ASSERT(!mPtr->mBackingBuffer);
   if (mPtr->mSampleFormat == AUDIO_FORMAT_S16) {
     MOZ_ASSERT(!mPtr->mFloatRingBuffer);
     return mPtr->mIntRingBuffer->Discard(aSamples);
   }
   MOZ_ASSERT(!mPtr->mIntRingBuffer);
   return mPtr->mFloatRingBuffer->Discard(aSamples);
 }
 
-uint32_t AudioRingBuffer::Clear() {
+int AudioRingBuffer::Clear() {
   MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16 ||
              mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
   MOZ_ASSERT(!mPtr->mBackingBuffer);
   if (mPtr->mSampleFormat == AUDIO_FORMAT_S16) {
     MOZ_ASSERT(!mPtr->mFloatRingBuffer);
     MOZ_ASSERT(mPtr->mIntRingBuffer);
     return mPtr->mIntRingBuffer->Clear();
   }
@@ -439,29 +438,29 @@ bool AudioRingBuffer::IsEmpty() const {
   if (mPtr->mSampleFormat == AUDIO_FORMAT_S16) {
     MOZ_ASSERT(!mPtr->mFloatRingBuffer);
     return mPtr->mIntRingBuffer->IsEmpty();
   }
   MOZ_ASSERT(!mPtr->mIntRingBuffer);
   return mPtr->mFloatRingBuffer->IsEmpty();
 }
 
-uint32_t AudioRingBuffer::AvailableWrite() const {
+int AudioRingBuffer::AvailableWrite() const {
   MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16 ||
              mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
   MOZ_ASSERT(!mPtr->mBackingBuffer);
   if (mPtr->mSampleFormat == AUDIO_FORMAT_S16) {
     MOZ_ASSERT(!mPtr->mFloatRingBuffer);
     return mPtr->mIntRingBuffer->AvailableWrite();
   }
   MOZ_ASSERT(!mPtr->mIntRingBuffer);
   return mPtr->mFloatRingBuffer->AvailableWrite();
 }
 
-uint32_t AudioRingBuffer::AvailableRead() const {
+int AudioRingBuffer::AvailableRead() const {
   MOZ_ASSERT(mPtr->mSampleFormat == AUDIO_FORMAT_S16 ||
              mPtr->mSampleFormat == AUDIO_FORMAT_FLOAT32);
   MOZ_ASSERT(!mPtr->mBackingBuffer);
   if (mPtr->mSampleFormat == AUDIO_FORMAT_S16) {
     MOZ_ASSERT(!mPtr->mFloatRingBuffer);
     return mPtr->mIntRingBuffer->AvailableRead();
   }
   MOZ_ASSERT(!mPtr->mIntRingBuffer);
--- a/dom/media/AudioRingBuffer.h
+++ b/dom/media/AudioRingBuffer.h
@@ -17,99 +17,97 @@ namespace mozilla {
  * AudioRingBuffer works with audio sample format float or short. The
  * implementation wrap around the RingBuffer thus it is not thread-safe. Reads
  * and writes must happen in the same thread which may be different than the
  * construction thread. The memory is pre-allocated in the constructor. The
  * sample format has to be specified in order to be used.
  */
 class AudioRingBuffer final {
  public:
-  explicit AudioRingBuffer(uint32_t aSizeInBytes);
+  explicit AudioRingBuffer(int aSizeInBytes);
   ~AudioRingBuffer();
 
   /**
    * Set the sample format to either short or float. The sample format must be
    * set before the using any other method.
    */
   void SetSampleFormat(AudioSampleFormat aFormat);
 
   /**
    * Write `aBuffer.Length()` number of samples when the format is float.
    */
-  uint32_t Write(const Span<const float>& aBuffer);
+  int Write(const Span<const float>& aBuffer);
 
   /**
    * Write `aBuffer.Length()` number of samples when the format is short.
    */
-  uint32_t Write(const Span<const int16_t>& aBuffer);
+  int Write(const Span<const int16_t>& aBuffer);
 
   /**
    * Write `aSamples` number of samples from `aBuffer`. Note the `aBuffer` does
    * not change.
    */
-  uint32_t Write(const AudioRingBuffer& aBuffer, uint32_t aSamples);
+  int Write(const AudioRingBuffer& aBuffer, int aSamples);
 
   /**
    * Write `aSamples` number of zeros.
    */
-  uint32_t WriteSilence(uint32_t aSamples);
+  int WriteSilence(int aSamples);
 
   /**
    * Read `aBuffer.Length()` number of samples when the format is float.
    */
-  uint32_t Read(const Span<float>& aBuffer);
+  int Read(const Span<float>& aBuffer);
 
   /**
    * Read `aBuffer.Length()` number of samples when the format is short.
    */
-  uint32_t Read(const Span<int16_t>& aBuffer);
+  int Read(const Span<int16_t>& aBuffer);
 
   /**
    * Read the internal buffer without extra copies when sample format is float.
    * Check also the RingBuffer::ReadNoCopy() for more details.
    */
-  uint32_t ReadNoCopy(
-      std::function<uint32_t(const Span<const float>&)>&& aCallable);
+  int ReadNoCopy(std::function<int(const Span<const float>&)>&& aCallable);
 
   /**
    * Read the internal buffer without extra copies when sample format is short.
    * Check also the RingBuffer::ReadNoCopy() for more details.
    */
-  uint32_t ReadNoCopy(
-      std::function<uint32_t(const Span<const int16_t>&)>&& aCallable);
+  int ReadNoCopy(std::function<int(const Span<const int16_t>&)>&& aCallable);
 
   /**
    * Remove `aSamples` number of samples.
    */
-  uint32_t Discard(uint32_t aSamples);
+  int Discard(int aSamples);
 
   /**
    * Remove all available samples.
    */
-  uint32_t Clear();
+  int Clear();
 
   /**
    * Return true if the buffer is full.
    */
   bool IsFull() const;
 
   /**
    * Return true if the buffer is empty.
    */
   bool IsEmpty() const;
 
   /**
    * Return the number of samples available for writing.
    */
-  uint32_t AvailableWrite() const;
+  int AvailableWrite() const;
 
   /**
    * Return the number of samples available for reading.
    */
-  uint32_t AvailableRead() const;
+  int AvailableRead() const;
 
  private:
   class AudioRingBufferPrivate;
   UniquePtr<AudioRingBufferPrivate> mPtr;
 };
 
 }  // namespace mozilla
 
--- a/dom/media/DynamicResampler.cpp
+++ b/dom/media/DynamicResampler.cpp
@@ -2,19 +2,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DynamicResampler.h"
 
 namespace mozilla {
 
-DynamicResampler::DynamicResampler(uint32_t aInRate, uint32_t aOutRate,
+DynamicResampler::DynamicResampler(int aInRate, int aOutRate,
                                    uint32_t aPreBufferFrames)
-    : mInRate(aInRate), mPreBufferFrames(aPreBufferFrames), mOutRate(aOutRate) {
+    : mInRate(aInRate), mOutRate(aOutRate), mPreBufferFrames(aPreBufferFrames) {
   MOZ_ASSERT(aInRate);
   MOZ_ASSERT(aOutRate);
   UpdateResampler(mOutRate, STEREO);
 }
 
 DynamicResampler::~DynamicResampler() {
   if (mResampler) {
     speex_resampler_destroy(mResampler);
@@ -30,81 +30,83 @@ void DynamicResampler::SetSampleFormat(A
     b.SetSampleFormat(mSampleFormat);
   }
   if (mPreBufferFrames) {
     AppendInputSilence(mPreBufferFrames);
   }
 }
 
 bool DynamicResampler::Resample(float* aOutBuffer, uint32_t* aOutFrames,
-                                uint32_t aChannelIndex) {
+                                int aChannelIndex) {
   MOZ_ASSERT(mSampleFormat == AUDIO_FORMAT_FLOAT32);
   return ResampleInternal(aOutBuffer, aOutFrames, aChannelIndex);
 }
 
 bool DynamicResampler::Resample(int16_t* aOutBuffer, uint32_t* aOutFrames,
-                                uint32_t aChannelIndex) {
+                                int aChannelIndex) {
   MOZ_ASSERT(mSampleFormat == AUDIO_FORMAT_S16);
   return ResampleInternal(aOutBuffer, aOutFrames, aChannelIndex);
 }
 
 void DynamicResampler::ResampleInternal(const float* aInBuffer,
                                         uint32_t* aInFrames, float* aOutBuffer,
                                         uint32_t* aOutFrames,
-                                        uint32_t aChannelIndex) {
+                                        int aChannelIndex) {
   MOZ_ASSERT(mResampler);
   MOZ_ASSERT(mChannels);
   MOZ_ASSERT(mInRate);
   MOZ_ASSERT(mOutRate);
 
   MOZ_ASSERT(aInBuffer);
   MOZ_ASSERT(aInFrames);
   MOZ_ASSERT(*aInFrames > 0);
   MOZ_ASSERT(aOutBuffer);
   MOZ_ASSERT(aOutFrames);
   MOZ_ASSERT(*aOutFrames > 0);
 
+  MOZ_ASSERT(aChannelIndex >= 0);
   MOZ_ASSERT(aChannelIndex <= mChannels);
 
 #ifdef DEBUG
   int rv =
 #endif
       speex_resampler_process_float(mResampler, aChannelIndex, aInBuffer,
                                     aInFrames, aOutBuffer, aOutFrames);
   MOZ_ASSERT(rv == RESAMPLER_ERR_SUCCESS);
 }
 
 void DynamicResampler::ResampleInternal(const int16_t* aInBuffer,
                                         uint32_t* aInFrames,
                                         int16_t* aOutBuffer,
                                         uint32_t* aOutFrames,
-                                        uint32_t aChannelIndex) {
+                                        int aChannelIndex) {
   MOZ_ASSERT(mResampler);
   MOZ_ASSERT(mChannels);
   MOZ_ASSERT(mInRate);
   MOZ_ASSERT(mOutRate);
 
   MOZ_ASSERT(aInBuffer);
   MOZ_ASSERT(aInFrames);
   MOZ_ASSERT(*aInFrames > 0);
   MOZ_ASSERT(aOutBuffer);
   MOZ_ASSERT(aOutFrames);
   MOZ_ASSERT(*aOutFrames > 0);
 
+  MOZ_ASSERT(aChannelIndex >= 0);
   MOZ_ASSERT(aChannelIndex <= mChannels);
 
 #ifdef DEBUG
   int rv =
 #endif
       speex_resampler_process_int(mResampler, aChannelIndex, aInBuffer,
                                   aInFrames, aOutBuffer, aOutFrames);
   MOZ_ASSERT(rv == RESAMPLER_ERR_SUCCESS);
 }
 
-void DynamicResampler::UpdateResampler(uint32_t aOutRate, uint32_t aChannels) {
+void DynamicResampler::UpdateResampler(int aOutRate, int aChannels) {
   MOZ_ASSERT(aOutRate);
   MOZ_ASSERT(aChannels);
 
   if (mChannels != aChannels) {
     mResampler = speex_resampler_init(aChannels, mInRate, aOutRate,
                                       SPEEX_RESAMPLER_QUALITY_MIN, nullptr);
     MOZ_ASSERT(mResampler);
     mChannels = aChannels;
@@ -112,36 +114,36 @@ void DynamicResampler::UpdateResampler(u
     // Between mono and stereo changes, keep always allocated 2 channels to
     // avoid reallocations in the most common case.
     if ((mChannels == STEREO || mChannels == 1) &&
         mInternalInBuffer.Length() == STEREO) {
       // Don't worry if format is not set it will write silence then.
       if ((mSampleFormat == AUDIO_FORMAT_S16 ||
            mSampleFormat == AUDIO_FORMAT_FLOAT32) &&
           mChannels == STEREO) {
-        // The mono channel is always up to date. When we are going from mono
+        // The mono channel is allways up to date. When we are going from mono
         // to stereo upmix the mono to stereo channel
-        uint32_t bufferedDuration = mInternalInBuffer[0].AvailableRead();
+        int bufferedDuration = mInternalInBuffer[0].AvailableRead();
         mInternalInBuffer[1].Clear();
         if (bufferedDuration) {
           mInternalInBuffer[1].Write(mInternalInBuffer[0], bufferedDuration);
         }
       }
       // Maintain stereo size
       mInputTail.SetLength(STEREO);
       WarmUpResampler(false);
       return;
     }
     // upmix or downmix, for now just clear but it has to be updated
     // because allocates and this is executed in audio thread.
     mInternalInBuffer.Clear();
-    for (uint32_t i = 0; i < mChannels; ++i) {
-      // Pre-allocate something big, twice the pre-buffer, or at least 100ms.
-      AudioRingBuffer* b = mInternalInBuffer.AppendElement(
-          sizeof(float) * std::max(2 * mPreBufferFrames, mInRate / 10));
+    for (int i = 0; i < mChannels; ++i) {
+      // Pre-allocate something big, 100ms of audio.
+      AudioRingBuffer* b =
+          mInternalInBuffer.AppendElement(sizeof(float) * mInRate / 10);
       if (mSampleFormat != AUDIO_FORMAT_SILENCE) {
         // In ctor this update is not needed
         b->SetSampleFormat(mSampleFormat);
       }
     }
     mInputTail.SetLength(mChannels);
     return;
   }
@@ -158,17 +160,17 @@ void DynamicResampler::UpdateResampler(u
         speex_resampler_set_rate(mResampler, mInRate, aOutRate);
     MOZ_ASSERT(rv == RESAMPLER_ERR_SUCCESS);
     mOutRate = aOutRate;
   }
 }
 
 void DynamicResampler::WarmUpResampler(bool aSkipLatency) {
   MOZ_ASSERT(mInputTail.Length());
-  for (uint32_t i = 0; i < mChannels; ++i) {
+  for (int i = 0; i < mChannels; ++i) {
     if (!mInputTail[i].Length()) {
       continue;
     }
     uint32_t inFrames = mInputTail[i].Length();
     uint32_t outFrames = 5 * TailBuffer::MAXSIZE;  // something big
     if (mSampleFormat == AUDIO_FORMAT_S16) {
       short outBuffer[5 * TailBuffer::MAXSIZE] = {};
       ResampleInternal(mInputTail[i].Buffer<short>(), &inFrames, outBuffer,
@@ -199,96 +201,90 @@ void DynamicResampler::AppendInput(const
 }
 void DynamicResampler::AppendInput(const nsTArray<const int16_t*>& aInBuffer,
                                    uint32_t aInFrames) {
   MOZ_ASSERT(mSampleFormat == AUDIO_FORMAT_S16);
   AppendInputInternal(aInBuffer, aInFrames);
 }
 
 bool DynamicResampler::EnoughInFrames(uint32_t aOutFrames,
-                                      uint32_t aChannelIndex) const {
+                                      int aChannelIndex) const {
   if (mInRate == mOutRate) {
     return InFramesBuffered(aChannelIndex) >= aOutFrames;
   }
   if (!(mOutRate % mInRate) && !(aOutFrames % mOutRate / mInRate)) {
     return InFramesBuffered(aChannelIndex) >= aOutFrames / (mOutRate / mInRate);
   }
   if (!(mInRate % mOutRate) && !(aOutFrames % mOutRate / mInRate)) {
     return InFramesBuffered(aChannelIndex) >= aOutFrames * mInRate / mOutRate;
   }
   return InFramesBuffered(aChannelIndex) > aOutFrames * mInRate / mOutRate;
 }
 
 bool DynamicResampler::CanResample(uint32_t aOutFrames) const {
-  for (uint32_t i = 0; i < mChannels; ++i) {
+  for (int i = 0; i < mChannels; ++i) {
     if (!EnoughInFrames(aOutFrames, i)) {
       return false;
     }
   }
   return true;
 }
 
 void DynamicResampler::AppendInputSilence(const uint32_t aInFrames) {
   MOZ_ASSERT(aInFrames);
   MOZ_ASSERT(mChannels);
   MOZ_ASSERT(mInternalInBuffer.Length() >= (uint32_t)mChannels);
-  for (uint32_t i = 0; i < mChannels; ++i) {
+  for (int i = 0; i < mChannels; ++i) {
     mInternalInBuffer[i].WriteSilence(aInFrames);
   }
 }
 
-uint32_t DynamicResampler::InFramesBuffered(uint32_t aChannelIndex) const {
+uint32_t DynamicResampler::InFramesBuffered(int aChannelIndex) const {
   MOZ_ASSERT(mChannels);
+  MOZ_ASSERT(aChannelIndex >= 0);
   MOZ_ASSERT(aChannelIndex <= mChannels);
-  MOZ_ASSERT(aChannelIndex <= mInternalInBuffer.Length());
+  MOZ_ASSERT((uint32_t)aChannelIndex <= mInternalInBuffer.Length());
   return mInternalInBuffer[aChannelIndex].AvailableRead();
 }
 
-uint32_t DynamicResampler::InFramesLeftToBuffer(uint32_t aChannelIndex) const {
-  MOZ_ASSERT(mChannels);
-  MOZ_ASSERT(aChannelIndex <= mChannels);
-  MOZ_ASSERT(aChannelIndex <= mInternalInBuffer.Length());
-  return mInternalInBuffer[aChannelIndex].AvailableWrite();
-}
-
-AudioChunkList::AudioChunkList(uint32_t aTotalDuration, uint32_t aChannels) {
-  uint32_t numOfChunks = aTotalDuration / mChunkCapacity;
+AudioChunkList::AudioChunkList(int aTotalDuration, int aChannels) {
+  int numOfChunks = aTotalDuration / mChunkCapacity;
   if (aTotalDuration % mChunkCapacity) {
     ++numOfChunks;
   }
   CreateChunks(numOfChunks, aChannels);
 }
 
-void AudioChunkList::CreateChunks(uint32_t aNumOfChunks, uint32_t aChannels) {
+void AudioChunkList::CreateChunks(int aNumOfChunks, int aChannels) {
   MOZ_ASSERT(!mChunks.Length());
   MOZ_ASSERT(aNumOfChunks);
   MOZ_ASSERT(aChannels);
   mChunks.AppendElements(aNumOfChunks);
 
   for (AudioChunk& chunk : mChunks) {
     AutoTArray<nsTArray<float>, STEREO> buffer;
     buffer.AppendElements(aChannels);
 
     AutoTArray<const float*, STEREO> bufferPtrs;
     bufferPtrs.AppendElements(aChannels);
 
-    for (uint32_t i = 0; i < aChannels; ++i) {
+    for (int i = 0; i < aChannels; ++i) {
       float* ptr = buffer[i].AppendElements(mChunkCapacity);
       bufferPtrs[i] = ptr;
     }
 
     chunk.mBuffer = new mozilla::SharedChannelArrayBuffer(std::move(buffer));
     chunk.mChannelData.AppendElements(aChannels);
-    for (uint32_t i = 0; i < aChannels; ++i) {
+    for (int i = 0; i < aChannels; ++i) {
       chunk.mChannelData[i] = bufferPtrs[i];
     }
   }
 }
 
-void AudioChunkList::UpdateToMonoOrStereo(uint32_t aChannels) {
+void AudioChunkList::UpdateToMonoOrStereo(int aChannels) {
   MOZ_ASSERT(mChunks.Length());
   MOZ_ASSERT(mSampleFormat == AUDIO_FORMAT_S16 ||
              mSampleFormat == AUDIO_FORMAT_FLOAT32);
   MOZ_ASSERT(aChannels == 1 || aChannels == 2);
 
   for (AudioChunk& chunk : mChunks) {
     MOZ_ASSERT(chunk.ChannelCount() != (uint32_t)aChannels);
     MOZ_ASSERT(chunk.ChannelCount() == 1 || chunk.ChannelCount() == 2);
@@ -334,34 +330,34 @@ AudioChunk& AudioChunkList::GetNext() {
   chunk.mDuration = 0;
   chunk.mVolume = 1.0f;
   chunk.mPrincipalHandle = PRINCIPAL_HANDLE_NONE;
   chunk.mBufferFormat = mSampleFormat;
   IncrementIndex();
   return chunk;
 }
 
-void AudioChunkList::Update(uint32_t aChannels) {
+void AudioChunkList::Update(int aChannels) {
   MOZ_ASSERT(mChunks.Length());
-  if (mChunks[0].ChannelCount() == aChannels) {
+  if (mChunks[0].ChannelCount() == (uint32_t)aChannels) {
     return;
   }
 
   // Special handling between mono and stereo to avoid reallocations.
   if (aChannels <= 2 && mChunks[0].ChannelCount() <= 2) {
     UpdateToMonoOrStereo(aChannels);
     return;
   }
 
-  uint32_t numOfChunks = mChunks.Length();
+  int numOfChunks = static_cast<int>(mChunks.Length());
   mChunks.ClearAndRetainStorage();
   CreateChunks(numOfChunks, aChannels);
 }
 
-AudioResampler::AudioResampler(uint32_t aInRate, uint32_t aOutRate,
+AudioResampler::AudioResampler(int aInRate, int aOutRate,
                                uint32_t aPreBufferFrames)
     : mResampler(aInRate, aOutRate, aPreBufferFrames),
       mOutputChunks(aOutRate / 10, STEREO) {}
 
 void AudioResampler::AppendInput(const AudioSegment& aInSegment) {
   MOZ_ASSERT(aInSegment.GetDuration());
   for (AudioSegment::ConstChunkIterator iter(aInSegment); !iter.IsEnded();
        iter.Next()) {
@@ -410,21 +406,21 @@ AudioSegment AudioResampler::Resample(ui
   // Not enough input frames abort. We check for the requested frames plus one.
   // This is to make sure that the individual resample iteration that will
   // follow up, will have enough frames even if one of them consume an extra
   // frame.
   if (!mResampler.CanResample(aOutFrames + 1)) {
     return segment;
   }
 
-  uint32_t totalFrames = aOutFrames;
+  int totalFrames = aOutFrames;
   while (totalFrames) {
     MOZ_ASSERT(totalFrames > 0);
     AudioChunk& chunk = mOutputChunks.GetNext();
-    uint32_t outFrames = std::min(totalFrames, mOutputChunks.ChunkCapacity());
+    int outFrames = std::min(totalFrames, mOutputChunks.ChunkCapacity());
     totalFrames -= outFrames;
 
     for (uint32_t i = 0; i < chunk.ChannelCount(); ++i) {
       uint32_t outFramesUsed = outFrames;
       if (chunk.mBufferFormat == AUDIO_FORMAT_FLOAT32) {
 #ifdef DEBUG
         bool rv =
 #endif
@@ -434,41 +430,35 @@ AudioSegment AudioResampler::Resample(ui
       } else {
 #ifdef DEBUG
         bool rv =
 #endif
             mResampler.Resample(chunk.ChannelDataForWrite<int16_t>(i),
                                 &outFramesUsed, i);
         MOZ_ASSERT(rv);
       }
-      MOZ_ASSERT(outFramesUsed == outFrames);
+      MOZ_ASSERT(outFramesUsed == (uint32_t)outFrames);
       chunk.mDuration = outFrames;
     }
 
     // Create a copy in order to consume that copy and not the pre-allocated
     // chunk
     AudioChunk tmp = chunk;
     segment.AppendAndConsumeChunk(&tmp);
   }
 
   return segment;
 }
 
-void AudioResampler::Update(uint32_t aOutRate, uint32_t aChannels) {
+void AudioResampler::Update(int aOutRate, int aChannels) {
   mResampler.UpdateResampler(aOutRate, aChannels);
   mOutputChunks.Update(aChannels);
 }
 
-uint32_t AudioResampler::InputDuration() const {
+int AudioResampler::InputDuration() const {
   if (!mIsSampleFormatSet) {
-    return mResampler.mPreBufferFrames;
+    return 0;
   }
-  return mResampler.InFramesBuffered(0);
-}
-
-uint32_t AudioResampler::InputRemainingDuration() const {
-  if (!mIsSampleFormatSet) {
-    return mResampler.mPreBufferFrames;
-  }
-  return mResampler.InFramesLeftToBuffer(0);
+  MOZ_ASSERT((int)mResampler.InFramesBuffered(0) >= 0);
+  return (int)mResampler.InFramesBuffered(0);
 }
 
 }  // namespace mozilla
--- a/dom/media/DynamicResampler.h
+++ b/dom/media/DynamicResampler.h
@@ -8,17 +8,17 @@
 
 #include "AudioRingBuffer.h"
 #include "AudioSegment.h"
 
 #include <speex/speex_resampler.h>
 
 namespace mozilla {
 
-const uint32_t STEREO = 2;
+const int STEREO = 2;
 
 /**
  * DynamicResampler allows updating on the fly the output sample rate and the
  * number of channels. In addition to that, it maintains an internal buffer for
  * the input data and allows pre-buffering as well. The Resample() method
  * strives to provide the requested number of output frames by using the input
  * data including any pre-buffering. If this is not possible then it will not
  * attempt to resample and it will return failure.
@@ -38,103 +38,97 @@ const uint32_t STEREO = 2;
  */
 class DynamicResampler final {
  public:
   /**
    * Provide the initial input and output rate and the amount of pre-buffering.
    * The channel count will be set to stereo. Memory allocation will take
    * place. The input buffer is non-interleaved.
    */
-  DynamicResampler(uint32_t aInRate, uint32_t aOutRate,
-                   uint32_t aPreBufferFrames = 0);
+  DynamicResampler(int aInRate, int aOutRate, uint32_t aPreBufferFrames = 0);
   ~DynamicResampler();
 
   /**
    * Set the sample format type to float or short.
    */
   void SetSampleFormat(AudioSampleFormat aFormat);
-  uint32_t GetOutRate() const { return mOutRate; }
-  uint32_t GetChannels() const { return mChannels; }
+  int GetOutRate() const { return mOutRate; }
+  int GetChannels() const { return mChannels; }
 
   /**
    * Append `aInFrames` number of frames from `aInBuffer` to the internal input
    * buffer. Memory copy/move takes place.
    */
   void AppendInput(const nsTArray<const float*>& aInBuffer, uint32_t aInFrames);
   void AppendInput(const nsTArray<const int16_t*>& aInBuffer,
                    uint32_t aInFrames);
   /**
    * Append `aInFrames` number of frames of silence to the internal input
    * buffer. Memory copy/move takes place.
    */
   void AppendInputSilence(const uint32_t aInFrames);
   /**
    * Return the number of frames stored in the internal input buffer.
    */
-  uint32_t InFramesBuffered(uint32_t aChannelIndex) const;
-  /**
-   * Return the number of frames left to store in the internal input buffer.
-   */
-  uint32_t InFramesLeftToBuffer(uint32_t aChannelIndex) const;
+  uint32_t InFramesBuffered(int aChannelIndex) const;
 
   /*
    * Resampler as much frame is needed from the internal input buffer to the
    * `aOutBuffer` in order to provide all `aOutFrames` and return true. If there
    * not enough input frames to provide the requested output frames no
    * resampling is attempted and false is returned.
    */
-  bool Resample(float* aOutBuffer, uint32_t* aOutFrames,
-                uint32_t aChannelIndex);
-  bool Resample(int16_t* aOutBuffer, uint32_t* aOutFrames,
-                uint32_t aChannelIndex);
+  bool Resample(float* aOutBuffer, uint32_t* aOutFrames, int aChannelIndex);
+  bool Resample(int16_t* aOutBuffer, uint32_t* aOutFrames, int aChannelIndex);
 
   /**
    * Update the output rate or/and the channel count. If a value is not updated
    * compared to the current one nothing happens. Changing the `aOutRate`
    * results in recalculation in the resampler. Changing `aChannels` results in
    * the reallocation of the internal input buffer with the exception of
    * changes between mono to stereo and vice versa where no reallocation takes
    * place. A stereo internal input buffer is always maintained even if the
    * sound is mono.
    */
-  void UpdateResampler(uint32_t aOutRate, uint32_t aChannels);
+  void UpdateResampler(int aOutRate, int aChannels);
 
   /**
    * Returns true if the resampler has enough input data to provide to the
    * output of the `Resample()` method `aOutFrames` number of frames. This is a
    * way to know in advance if the `Resampler` method will return true or false
    * given that nothing changes in between.
    */
   bool CanResample(uint32_t aOutFrames) const;
 
  private:
   template <typename T>
   void AppendInputInternal(const nsTArray<const T*>& aInBuffer,
                            uint32_t aInFrames) {
     MOZ_ASSERT(aInBuffer.Length() == (uint32_t)mChannels);
-    for (uint32_t i = 0; i < mChannels; ++i) {
+    for (int i = 0; i < mChannels; ++i) {
       PushInFrames(aInBuffer[i], aInFrames, i);
     }
   }
 
   void ResampleInternal(const float* aInBuffer, uint32_t* aInFrames,
                         float* aOutBuffer, uint32_t* aOutFrames,
-                        uint32_t aChannelIndex);
+                        int aChannelIndex);
   void ResampleInternal(const int16_t* aInBuffer, uint32_t* aInFrames,
                         int16_t* aOutBuffer, uint32_t* aOutFrames,
-                        uint32_t aChannelIndex);
+                        int aChannelIndex);
 
   template <typename T>
   bool ResampleInternal(T* aOutBuffer, uint32_t* aOutFrames,
-                        uint32_t aChannelIndex) {
+                        int aChannelIndex) {
     MOZ_ASSERT(mInRate);
     MOZ_ASSERT(mOutRate);
     MOZ_ASSERT(mChannels);
+    MOZ_ASSERT(aChannelIndex >= 0);
     MOZ_ASSERT(aChannelIndex <= mChannels);
-    MOZ_ASSERT(aChannelIndex <= mInternalInBuffer.Length());
+    MOZ_ASSERT((uint32_t)aChannelIndex <= mInternalInBuffer.Length());
     MOZ_ASSERT(aOutFrames);
     MOZ_ASSERT(*aOutFrames);
 
     // Not enough input, don't do anything
     if (!EnoughInFrames(*aOutFrames, aChannelIndex)) {
       *aOutFrames = 0;
       return false;
     }
@@ -148,17 +142,17 @@ class DynamicResampler final {
       mInputTail[aChannelIndex].StoreTail<T>(aOutBuffer, *aOutFrames);
       return true;
     }
 
     uint32_t totalOutFramesNeeded = *aOutFrames;
 
     mInternalInBuffer[aChannelIndex].ReadNoCopy(
         [this, &aOutBuffer, &totalOutFramesNeeded,
-         aChannelIndex](const Span<const T>& aInBuffer) -> uint32_t {
+         aChannelIndex](const Span<const T>& aInBuffer) -> int {
           if (!totalOutFramesNeeded) {
             return 0;
           }
           uint32_t outFramesResampled = totalOutFramesNeeded;
           uint32_t inFrames = aInBuffer.Length();
           ResampleInternal(aInBuffer.data(), &inFrames, aOutBuffer,
                            &outFramesResampled, aChannelIndex);
           aOutBuffer += outFramesResampled;
@@ -166,43 +160,42 @@ class DynamicResampler final {
           mInputTail[aChannelIndex].StoreTail<T>(aInBuffer);
           return inFrames;
         });
 
     MOZ_ASSERT(totalOutFramesNeeded == 0);
     return true;
   }
 
-  bool EnoughInFrames(uint32_t aOutFrames, uint32_t aChannelIndex) const;
+  bool EnoughInFrames(uint32_t aOutFrames, int aChannelIndex) const;
 
   template <typename T>
   void PushInFrames(const T* aInBuffer, const uint32_t aInFrames,
-                    uint32_t aChannelIndex) {
+                    int aChannelIndex) {
     MOZ_ASSERT(aInBuffer);
     MOZ_ASSERT(aInFrames);
     MOZ_ASSERT(mChannels);
+    MOZ_ASSERT(aChannelIndex >= 0);
     MOZ_ASSERT(aChannelIndex <= mChannels);
-    MOZ_ASSERT(aChannelIndex <= mInternalInBuffer.Length());
+    MOZ_ASSERT((uint32_t)aChannelIndex <= mInternalInBuffer.Length());
     mInternalInBuffer[aChannelIndex].Write(Span(aInBuffer, aInFrames));
   }
 
   void WarmUpResampler(bool aSkipLatency);
 
- public:
-  const uint32_t mInRate;
-  const uint32_t mPreBufferFrames;
-
  private:
-  uint32_t mChannels = 0;
-  uint32_t mOutRate;
+  int mChannels = 0;
+  const int mInRate;
+  int mOutRate;
 
   AutoTArray<AudioRingBuffer, STEREO> mInternalInBuffer;
 
   SpeexResamplerState* mResampler = nullptr;
   AudioSampleFormat mSampleFormat = AUDIO_FORMAT_SILENCE;
+  const uint32_t mPreBufferFrames;
 
   class TailBuffer {
    public:
     template <typename T>
     T* Buffer() {
       return reinterpret_cast<T*>(mBuffer);
     }
     /* Store the MAXSIZE last elements of the buffer. */
@@ -212,25 +205,25 @@ class DynamicResampler final {
     }
     template <typename T>
     void StoreTail(const T* aInBuffer, uint32_t aInFrames) {
       if (aInFrames >= MAXSIZE) {
         PodCopy(Buffer<T>(), aInBuffer + aInFrames - MAXSIZE, MAXSIZE);
         mSize = MAXSIZE;
       } else {
         PodCopy(Buffer<T>(), aInBuffer, aInFrames);
-        mSize = aInFrames;
+        mSize = static_cast<int>(aInFrames);
       }
     }
-    uint32_t Length() { return mSize; }
-    static const uint32_t MAXSIZE = 20;
+    int Length() { return mSize; }
+    static const int MAXSIZE = 20;
 
    private:
     float mBuffer[MAXSIZE] = {};
-    uint32_t mSize = 0;
+    int mSize = 0;
   };
   AutoTArray<TailBuffer, STEREO> mInputTail;
 };
 
 /**
  * AudioChunkList provides a way to have preallocated audio buffers in
  * AudioSegment. The idea is that the amount of  AudioChunks is created in
  * advance. Each AudioChunk is able to hold a specific amount of audio
@@ -268,17 +261,17 @@ class DynamicResampler final {
  * always be used to query the total capacity.
  */
 class AudioChunkList {
  public:
   /**
    * Constructor, the final total duration might be different from the requested
    * `aTotalDuration`. Memory allocation takes place.
    */
-  AudioChunkList(uint32_t aTotalDuration, uint32_t aChannels);
+  AudioChunkList(int aTotalDuration, int aChannels);
   AudioChunkList(const AudioChunkList&) = delete;
   AudioChunkList(AudioChunkList&&) = delete;
   ~AudioChunkList() = default;
 
   /**
    * Set sample format. It must be done before any other method being used.
    */
   void SetSampleFormat(AudioSampleFormat aFormat);
@@ -296,48 +289,48 @@ class AudioChunkList {
    * ```
    * This way no memory allocation or copy, takes place.
    */
   AudioChunk& GetNext();
 
   /**
    * Get the capacity of each individual AudioChunk in the list.
    */
-  uint32_t ChunkCapacity() const {
+  int ChunkCapacity() const {
     MOZ_ASSERT(mSampleFormat == AUDIO_FORMAT_S16 ||
                mSampleFormat == AUDIO_FORMAT_FLOAT32);
     return mChunkCapacity;
   }
   /**
    * Get the total capacity of AudioChunkList.
    */
-  uint32_t TotalCapacity() const {
+  int TotalCapacity() const {
     MOZ_ASSERT(mSampleFormat == AUDIO_FORMAT_S16 ||
                mSampleFormat == AUDIO_FORMAT_FLOAT32);
-    return CheckedInt<uint32_t>(mChunkCapacity * mChunks.Length()).value();
+    return CheckedInt<int>(mChunkCapacity * mChunks.Length()).value();
   }
 
   /**
    * Update the channel count of the AudioChunkList. Memory allocation is
    * taking place.
    */
-  void Update(uint32_t aChannels);
+  void Update(int aChannels);
 
  private:
   void IncrementIndex() {
     ++mIndex;
-    mIndex = CheckedInt<uint32_t>(mIndex % mChunks.Length()).value();
+    mIndex = CheckedInt<int>(mIndex % mChunks.Length()).value();
   }
-  void CreateChunks(uint32_t aNumOfChunks, uint32_t aChannels);
-  void UpdateToMonoOrStereo(uint32_t aChannels);
+  void CreateChunks(int aNumOfChunks, int aChannels);
+  void UpdateToMonoOrStereo(int aChannels);
 
  private:
   nsTArray<AudioChunk> mChunks;
-  uint32_t mIndex = 0;
-  uint32_t mChunkCapacity = 128;
+  int mIndex = 0;
+  int mChunkCapacity = 128;
   AudioSampleFormat mSampleFormat = AUDIO_FORMAT_SILENCE;
 };
 
 /**
  * Audio Resampler is a resampler able to change the output rate and channels
  * count on the fly. The API is simple and it is based in AudioSegment in order
  * to be used MTG. All memory allocations, for input and output buffers, happen
  * in the constructor and when channel count changes. The memory is recycled in
@@ -351,54 +344,48 @@ class AudioChunkList {
  * resampler method must be cleaned up in order to be able for the `AudioChunk`s
  * that it consists of to be reused. For `MediaTrack::mSegment` this happens
  * every ~50ms (look at MediaTrack::AdvanceTimeVaryingValuesToCurrentTime). Thus
  * memory capacity of 100ms has been preallocated for internal input and output
  * buffering.
  */
 class AudioResampler final {
  public:
-  AudioResampler(uint32_t aInRate, uint32_t aOutRate,
-                 uint32_t aPreBufferFrames = 0);
+  AudioResampler(int aInRate, int aOutRate, uint32_t aPreBufferFrames = 0);
 
   /**
    * Append input data into the resampler internal buffer. Copy/move of the
    * memory is taking place. Also, the channel count will change according to
    * the channel count of the chunks.
    */
   void AppendInput(const AudioSegment& aInSegment);
-  /**
-   * Get the duration of the internal input buffer in frames.
+  /*
+   * Get the duration of internal input buffer in frames.
    */
-  uint32_t InputDuration() const;
-  /**
-   * Get the duration of the remaining space in the internal input buffer in
-   * frames.
-   */
-  uint32_t InputRemainingDuration() const;
+  int InputDuration() const;
 
   /*
    * Reguest `aOutFrames` of audio in the output sample rate. The internal
    * buffered input is used. If there is no enough input for that amount of
    * output and empty AudioSegment is returned
    */
   AudioSegment Resample(uint32_t aOutFrames);
 
   /*
    * Updates the output rate that will be used by the resampler.
    */
-  void UpdateOutRate(uint32_t aOutRate) {
+  void UpdateOutRate(int aOutRate) {
     Update(aOutRate, mResampler.GetChannels());
   }
 
  private:
-  void UpdateChannels(uint32_t aChannels) {
+  void UpdateChannels(int aChannels) {
     Update(mResampler.GetOutRate(), aChannels);
   }
-  void Update(uint32_t aOutRate, uint32_t aChannels);
+  void Update(int aOutRate, int aChannels);
 
  private:
   DynamicResampler mResampler;
   AudioChunkList mOutputChunks;
   bool mIsSampleFormatSet = false;
 };
 
 }  // namespace mozilla
--- a/dom/media/MediaTrackGraph.cpp
+++ b/dom/media/MediaTrackGraph.cpp
@@ -2399,19 +2399,19 @@ void MediaTrack::AdvanceTimeVaryingValue
   mStartTime += aBlockedTime;
 
   if (!mSegment) {
     // No data to be forgotten.
     return;
   }
 
   TrackTime time = aCurrentTime - mStartTime;
-  // Only prune if there is a reasonable chunk (50ms) to forget, so we don't
-  // spend too much time pruning segments.
-  const TrackTime minChunkSize = mSampleRate * 50 / 1000;
+  // Only prune if there is a reasonable chunk (50ms @ 48kHz) to forget, so we
+  // don't spend too much time pruning segments.
+  const TrackTime minChunkSize = 2400;
   if (time < mForgottenTime + minChunkSize) {
     return;
   }
 
   mForgottenTime = std::min(GetEnd() - 1, time);
   mSegment->ForgetUpTo(mForgottenTime);
 }
 
new file mode 100644
--- /dev/null
+++ b/dom/media/gtest/AudioGenerator.cpp
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+#include "AudioGenerator.h"
+
+#include "AudioSegment.h"
+
+using namespace mozilla;
+
+AudioGenerator::AudioGenerator(int32_t aChannels, int32_t aSampleRate)
+    : mGenerator(aSampleRate, 1000), mChannels(aChannels) {}
+
+void AudioGenerator::Generate(AudioSegment& aSegment, const int32_t& aSamples) {
+  CheckedInt<size_t> bufferSize(sizeof(int16_t));
+  bufferSize *= aSamples;
+  RefPtr<SharedBuffer> buffer = SharedBuffer::Create(bufferSize);
+  int16_t* dest = static_cast<int16_t*>(buffer->Data());
+  mGenerator.generate(dest, aSamples);
+  AutoTArray<const int16_t*, 1> channels;
+  for (int32_t i = 0; i < mChannels; i++) {
+    channels.AppendElement(dest);
+  }
+  aSegment.AppendFrames(buffer.forget(), channels, aSamples,
+                        PRINCIPAL_HANDLE_NONE);
+}
--- a/dom/media/gtest/AudioGenerator.h
+++ b/dom/media/gtest/AudioGenerator.h
@@ -1,80 +1,27 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
-#ifndef DOM_MEDIA_GTEST_AUDIO_GENERATOR_H_
-#define DOM_MEDIA_GTEST_AUDIO_GENERATOR_H_
-
-#include "AudioSegment.h"
-#include "prtime.h"
-#include "SineWaveGenerator.h"
-
-namespace mozilla {
-
-template <typename Sample>
-class AudioGenerator {
- public:
-  AudioGenerator(uint32_t aChannels, uint32_t aSampleRate,
-                 uint32_t aFrequency = 1000)
-      : mChannels(aChannels),
-        mSampleRate(aSampleRate),
-        mFrequency(aFrequency),
-        mGenerator(aSampleRate, aFrequency) {}
-
-  void Generate(mozilla::AudioSegment& aSegment, const uint32_t& aSamples) {
-    SetInterleaved(false);
-    CheckedInt<size_t> bufferSize(sizeof(Sample));
-    bufferSize *= aSamples;
-    RefPtr<SharedBuffer> buffer = SharedBuffer::Create(bufferSize);
-    Sample* dest = static_cast<Sample*>(buffer->Data());
-    mGenerator.generate(dest, aSamples);
-    AutoTArray<const Sample*, 1> channels;
-    for (uint32_t i = 0; i < mChannels; ++i) {
-      channels.AppendElement(dest);
-    }
-    aSegment.AppendFrames(buffer.forget(), channels, aSamples,
-                          PRINCIPAL_HANDLE_NONE);
-  }
-
-  void GenerateInterleaved(Sample* aBuffer, const uint32_t& aFrames) {
-    SetInterleaved(true);
-    mGenerator.generate(aBuffer, aFrames * mChannels);
-  }
-
-  void SetInterleaved(bool aInterleaved) {
-    if (aInterleaved == mInterleaved) {
-      return;
-    }
-    mInterleaved = aInterleaved;
-    if (mInterleaved) {
-      TrackTicks offset = Offset();
-      mGenerator =
-          SineWaveGenerator<Sample>(mSampleRate, mFrequency, mChannels);
-      mGenerator.SetOffset(offset * mChannels);
-    } else {
-      TrackTicks offset = Offset();
-      mGenerator = SineWaveGenerator<Sample>(mSampleRate, mFrequency);
-      mGenerator.SetOffset(offset / mChannels);
-    }
-  }
-
-  void SetOffset(TrackTicks aFrames) { mGenerator.SetOffset(aFrames); }
-
-  TrackTicks Offset() const { return mGenerator.Offset(); }
-
-  static float Amplitude() { return SineWaveGenerator<Sample>::Amplitude(); }
-
-  const uint32_t mChannels;
-  const uint32_t mSampleRate;
-  const uint32_t mFrequency;
-
- private:
-  bool mInterleaved = false;
-  mozilla::SineWaveGenerator<Sample> mGenerator;
-};
-
-}  // namespace mozilla
-
-#endif  // DOM_MEDIA_GTEST_AUDIO_GENERATOR_H_
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+#ifndef DOM_MEDIA_GTEST_AUDIO_GENERATOR_H_
+#define DOM_MEDIA_GTEST_AUDIO_GENERATOR_H_
+
+#include "prtime.h"
+#include "SineWaveGenerator.h"
+
+namespace mozilla {
+class AudioSegment;
+}
+
+class AudioGenerator {
+ public:
+  AudioGenerator(int32_t aChannels, int32_t aSampleRate);
+  void Generate(mozilla::AudioSegment& aSegment, const int32_t& aSamples);
+
+ private:
+  mozilla::SineWaveGenerator mGenerator;
+  const int32_t mChannels;
+};
+
+#endif  // DOM_MEDIA_GTEST_AUDIO_GENERATOR_H_
deleted file mode 100644
--- a/dom/media/gtest/AudioVerifier.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
-#ifndef DOM_MEDIA_GTEST_AUDIOVERIFIER_H_
-#define DOM_MEDIA_GTEST_AUDIOVERIFIER_H_
-
-#include "AudioGenerator.h"
-
-namespace mozilla {
-
-template <typename Sample>
-class AudioVerifier {
- public:
-  explicit AudioVerifier(uint32_t aRate, uint32_t aFrequency)
-      : mRate(aRate), mFrequency(aFrequency) {}
-
-  // Only the mono channel is taken into account.
-  void AppendData(const AudioSegment& segment) {
-    for (AudioSegment::ConstChunkIterator iter(segment); !iter.IsEnded();
-         iter.Next()) {
-      const AudioChunk& c = *iter;
-      if (c.IsNull()) {
-        for (int i = 0; i < c.GetDuration(); ++i) {
-          CheckSample(0);
-        }
-      } else {
-        const Sample* buffer = c.ChannelData<Sample>()[0];
-        for (int i = 0; i < c.GetDuration(); ++i) {
-          CheckSample(buffer[i]);
-        }
-      }
-    }
-  }
-
-  void AppendDataInterleaved(const Sample* aBuffer, uint32_t aFrames,
-                             uint32_t aChannels) {
-    for (uint32_t i = 0; i < aFrames * aChannels; i += aChannels) {
-      CheckSample(aBuffer[i]);
-    }
-  }
-
-  float EstimatedFreq() const {
-    if (mTotalFramesSoFar == PreSilenceSamples()) {
-      return 0;
-    }
-    if (mSumPeriodInSamples == 0) {
-      return 0;
-    }
-    if (mZeroCrossCount <= 1) {
-      return 0;
-    }
-    return mRate /
-           (static_cast<float>(mSumPeriodInSamples) / (mZeroCrossCount - 1));
-  }
-
-  // Returns the maximum difference in value between two adjacent samples along
-  // the sine curve.
-  Sample MaxMagnitudeDifference() {
-    return static_cast<Sample>(AudioGenerator<Sample>::Amplitude() *
-                               sin(2 * M_PI * mFrequency / mRate));
-  }
-
-  bool PreSilenceEnded() const {
-    return mTotalFramesSoFar > mPreSilenceSamples;
-  }
-  uint64_t PreSilenceSamples() const { return mPreSilenceSamples; }
-  uint32_t CountDiscontinuities() const { return mDiscontinuitiesCount; }
-
- private:
-  void CheckSample(Sample aCurrentSample) {
-    ++mTotalFramesSoFar;
-    // Avoid pre-silence
-    if (!CountPreSilence(aCurrentSample)) {
-      CountZeroCrossing(aCurrentSample);
-      CountDiscontinuities(aCurrentSample);
-    }
-
-    mPrevious = aCurrentSample;
-  }
-
-  bool CountPreSilence(Sample aCurrentSample) {
-    if (IsZero(aCurrentSample) && mPreSilenceSamples == mTotalFramesSoFar - 1) {
-      ++mPreSilenceSamples;
-      return true;
-    }
-    if (IsZero(mPrevious) && aCurrentSample > 0 &&
-        aCurrentSample < 2 * MaxMagnitudeDifference() &&
-        mPreSilenceSamples == mTotalFramesSoFar - 1) {
-      // Previous zero considered the first sample of the waveform.
-      --mPreSilenceSamples;
-    }
-    return false;
-  }
-
-  // Positive to negative direction
-  void CountZeroCrossing(Sample aCurrentSample) {
-    if (mPrevious > 0 && aCurrentSample <= 0) {
-      if (mZeroCrossCount++) {
-        MOZ_ASSERT(mZeroCrossCount > 1);
-        mSumPeriodInSamples += mTotalFramesSoFar - mLastZeroCrossPosition;
-      }
-      mLastZeroCrossPosition = mTotalFramesSoFar;
-    }
-  }
-
-  void CountDiscontinuities(Sample aCurrentSample) {
-    mDiscontinuitiesCount += fabs(fabs(aCurrentSample) - fabs(mPrevious)) >
-                             3 * MaxMagnitudeDifference();
-  }
-
-  bool IsZero(float aValue) { return fabs(aValue) < 1e-8; }
-  bool IsZero(short aValue) { return aValue == 0; }
-
- private:
-  const uint32_t mRate;
-  const uint32_t mFrequency;
-
-  uint32_t mZeroCrossCount = 0;
-  uint64_t mLastZeroCrossPosition = 0;
-  uint64_t mSumPeriodInSamples = 0;
-
-  uint64_t mTotalFramesSoFar = 0;
-  uint64_t mPreSilenceSamples = 0;
-
-  uint32_t mDiscontinuitiesCount = 0;
-  // This is needed to connect the previous buffers.
-  Sample mPrevious = {};
-};
-
-}  // namespace mozilla
-
-#endif  // DOM_MEDIA_GTEST_AUDIOVERIFIER_H_
--- a/dom/media/gtest/MockCubeb.h
+++ b/dom/media/gtest/MockCubeb.h
@@ -1,28 +1,41 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef MOCKCUBEB_H_
 #define MOCKCUBEB_H_
 
 #include "AudioDeviceInfo.h"
-#include "AudioGenerator.h"
-#include "AudioVerifier.h"
-#include "MediaEventSource.h"
 #include "nsTArray.h"
 
 #include <thread>
 #include <atomic>
 #include <chrono>
 
-namespace mozilla {
+using namespace std::chrono_literals;
+using namespace mozilla;
+
+const long NUM_OF_FRAMES = 512;
 const uint32_t NUM_OF_CHANNELS = 2;
 
+#ifdef LOG
+#  undef LOG
+#endif
+//#define LOGGING_ENABLED
+#ifdef LOGGING_ENABLED
+#  if defined(__ANDROID__)
+#    define LOG(args...) \
+      __android_log_print(ANDROID_LOG_INFO, "MockCubeb", ##args)
+#  else
+#    define LOG(args...)       \
+      fprintf(stderr, ##args); \
+      fprintf(stderr, "\n")
+#  endif
+#else
+#  define LOG(...)
+#endif
+
 struct cubeb_ops {
   int (*init)(cubeb** context, char const* context_name);
   char const* (*get_backend_id)(cubeb* context);
   int (*get_max_channel_count)(cubeb* context, uint32_t* max_channels);
   int (*get_min_latency)(cubeb* context, cubeb_stream_params params,
                          uint32_t* latency_ms);
   int (*get_preferred_sample_rate)(cubeb* context, uint32_t* rate);
   int (*enumerate_devices)(cubeb* context, cubeb_device_type type,
@@ -111,159 +124,125 @@ cubeb_ops const mock_ops = {
     /*.stream_get_position =*/NULL,
     /*.stream_get_latency =*/NULL,
     /*.stream_set_volume =*/cubeb_mock_stream_set_volume,
     /*.stream_set_panning =*/NULL,
     /*.stream_get_current_device =*/NULL,
     /*.stream_device_destroy =*/NULL,
     /*.stream_register_device_changed_callback =*/NULL,
     /*.register_device_collection_changed =*/
-
     cubeb_mock_register_device_collection_changed};
 
 // Represents the fake cubeb_stream. The context instance is needed to
 // provide access on cubeb_ops struct.
 class MockCubebStream {
  public:
   MockCubebStream(cubeb* aContext, cubeb_devid aInputDevice,
                   cubeb_stream_params* aInputStreamParams,
                   cubeb_devid aOutputDevice,
                   cubeb_stream_params* aOutputStreamParams,
                   cubeb_data_callback aDataCallback,
                   cubeb_state_callback aStateCallback, void* aUserPtr)
       : context(aContext),
-        mHasInput(aInputStreamParams),
-        mHasOutput(aOutputStreamParams),
         mDataCallback(aDataCallback),
         mStateCallback(aStateCallback),
         mUserPtr(aUserPtr),
+        mSampleRate(aInputStreamParams ? aInputStreamParams->rate
+                                       : aOutputStreamParams->rate),
         mInputDeviceID(aInputDevice),
-        mOutputDeviceID(aOutputDevice),
-        mAudioGenerator(NUM_OF_CHANNELS,
-                        aInputStreamParams ? aInputStreamParams->rate
-                                           : aOutputStreamParams->rate,
-                        100 /* aFrequency */),
-        mAudioVerifier(aInputStreamParams ? aInputStreamParams->rate
-                                          : aOutputStreamParams->rate,
-                       100 /* aFrequency */) {
-    if (aInputStreamParams) {
-      mInputParams = *aInputStreamParams;
-    }
-    if (aOutputStreamParams) {
-      mOutputParams = *aOutputStreamParams;
-    }
+        mOutputDeviceID(aOutputDevice) {
+    LOG("MockCubeb(%p) StreamInit: Input id = %p, Output id = %p", this,
+        mInputDeviceID, mOutputDeviceID);
   }
 
-  ~MockCubebStream() = default;
-
-  int Start();
-  int Stop();
-
-  cubeb_devid GetInputDeviceID() const { return mInputDeviceID; }
-  cubeb_devid GetOutputDeviceID() const { return mOutputDeviceID; }
+  ~MockCubebStream() { assert(!mFakeAudioThread); }
 
-  uint32_t InputChannels() const { return mAudioGenerator.mChannels; }
-  uint32_t InputSampleRate() const { return mAudioGenerator.mSampleRate; }
-  uint32_t InputFrequency() const { return mAudioGenerator.mFrequency; }
-
-  void SetDriftFactor(float aDriftFactor) { mDriftFactor = aDriftFactor; }
-  void ForceError() { mForceErrorState = true; }
-
-  MediaEventSource<uint32_t>& FramesProcessedEvent() {
-    return mFramesProcessedEvent;
+  int Start() {
+    assert(!mFakeAudioThread);
+    mStreamStop = false;
+    mFakeAudioThread.reset(new std::thread(ThreadFunction_s, this));
+    assert(mFakeAudioThread);
+    cubeb_stream* stream = reinterpret_cast<cubeb_stream*>(this);
+    mStateCallback(stream, mUserPtr, CUBEB_STATE_STARTED);
+    return CUBEB_OK;
   }
 
-  MediaEventSource<Tuple<uint64_t, float, uint32_t>>&
-  OutputVerificationEvent() {
-    return mOutputVerificationEvent;
+  int Stop() {
+    assert(mFakeAudioThread);
+    mStreamStop = true;
+    mFakeAudioThread->join();
+    mFakeAudioThread.reset();
+    cubeb_stream* stream = reinterpret_cast<cubeb_stream*>(this);
+    mStateCallback(stream, mUserPtr, CUBEB_STATE_STOPPED);
+    return CUBEB_OK;
   }
 
-  MediaEventSource<void>& ErrorForcedEvent() { return mErrorForcedEvent; }
+  cubeb_devid GetInputDeviceID() { return mInputDeviceID; }
+  cubeb_devid GetOutputDeviceID() { return mOutputDeviceID; }
 
-  void Process10Ms() {
-    if (mStreamStop) {
-      return;
-    }
+  void ForceError() { mForceErrorState = true; }
 
-    const long nrFrames = static_cast<uint32_t>(
-        (mHasOutput ? mOutputParams.rate : mInputParams.rate) * mDriftFactor *
-        10 / PR_MSEC_PER_SEC);
-    if (mInputParams.rate) {
-      mAudioGenerator.GenerateInterleaved(mInputBuffer, nrFrames);
-    }
-    cubeb_stream* stream = reinterpret_cast<cubeb_stream*>(this);
-    const long outframes =
-        mDataCallback(stream, mUserPtr, mHasInput ? mInputBuffer : nullptr,
-                      mHasOutput ? mOutputBuffer : nullptr, nrFrames);
+ private:
+  // Simulates the audio thread. The thread is created at Start anda destroyed
+  // at Stop. At next StreamStart a new thread is created.
+  static void ThreadFunction_s(MockCubebStream* that) {
+    that->ThreadFunction();
+  }
 
-    mAudioVerifier.AppendDataInterleaved(mOutputBuffer, outframes,
-                                         NUM_OF_CHANNELS);
-
-    if (mAudioVerifier.PreSilenceEnded()) {
-      mFramesProcessedEvent.Notify(outframes);
-    }
-
-    if (outframes < nrFrames) {
-      mStateCallback(stream, mUserPtr, CUBEB_STATE_DRAINED);
-      mStreamStop = true;
-      return;
-    }
-    if (mForceErrorState) {
-      mForceErrorState = false;
-      mStateCallback(stream, mUserPtr, CUBEB_STATE_ERROR);
-      mErrorForcedEvent.Notify();
-      mStreamStop = true;
-      return;
+  void ThreadFunction() {
+    while (!mStreamStop) {
+      cubeb_stream* stream = reinterpret_cast<cubeb_stream*>(this);
+      long outframes = mDataCallback(stream, mUserPtr, nullptr, mOutputBuffer,
+                                     NUM_OF_FRAMES);
+      if (outframes < NUM_OF_FRAMES) {
+        mStateCallback(stream, mUserPtr, CUBEB_STATE_DRAINED);
+        break;
+      }
+      if (mForceErrorState) {
+        mStateCallback(stream, mUserPtr, CUBEB_STATE_ERROR);
+        break;
+      }
+      std::this_thread::sleep_for(
+          std::chrono::milliseconds(NUM_OF_FRAMES * 1000 / mSampleRate));
     }
   }
 
  public:
   cubeb* context = nullptr;
 
-  const bool mHasInput;
-  const bool mHasOutput;
-
  private:
+  // Thread that simulates the audio thread.
+  std::unique_ptr<std::thread> mFakeAudioThread;
   // Signal to the audio thread that stream is stopped.
   std::atomic_bool mStreamStop{true};
   // The audio buffer used on data callback.
-  AudioDataValue mOutputBuffer[NUM_OF_CHANNELS * 1920] = {};
-  AudioDataValue mInputBuffer[NUM_OF_CHANNELS * 1920] = {};
+  float mOutputBuffer[NUM_OF_CHANNELS * NUM_OF_FRAMES];
   // The audio callback
   cubeb_data_callback mDataCallback = nullptr;
   // The stream state callback
   cubeb_state_callback mStateCallback = nullptr;
   // Stream's user data
   void* mUserPtr = nullptr;
-  // The stream params
-  cubeb_stream_params mOutputParams = {};
-  cubeb_stream_params mInputParams = {};
+  // The stream sample rate
+  uint32_t mSampleRate = 0;
   /* Device IDs */
   cubeb_devid mInputDeviceID;
   cubeb_devid mOutputDeviceID;
 
-  std::atomic<float> mDriftFactor{1.0};
-  std::atomic_bool mFastMode{false};
   std::atomic_bool mForceErrorState{false};
-  AudioGenerator<AudioDataValue> mAudioGenerator;
-  AudioVerifier<AudioDataValue> mAudioVerifier;
-
-  MediaEventProducer<uint32_t> mFramesProcessedEvent;
-  MediaEventProducer<Tuple<uint64_t, float, uint32_t>> mOutputVerificationEvent;
-  MediaEventProducer<void> mErrorForcedEvent;
 };
 
 // This class has two facets: it is both a fake cubeb backend that is intended
 // to be used for testing, and passed to Gecko code that expects a normal
 // backend, but is also controllable by the test code to decide what the backend
 // should do, depending on what is being tested.
 class MockCubeb {
  public:
-  MockCubeb() : ops(&mock_ops) {}
-  ~MockCubeb() { MOZ_ASSERT(!mFakeAudioThread); };
+  MockCubeb() : ops(&mock_ops) { LOG("MockCubeb(%p) created", this); }
+  ~MockCubeb() = default;
   // Cubeb backend implementation
   // This allows passing this class as a cubeb* instance.
   cubeb* AsCubebContext() { return reinterpret_cast<cubeb*>(this); }
   // Fill in the collection parameter with all devices of aType.
   int EnumerateDevices(cubeb_device_type aType,
                        cubeb_device_collection* collection) {
 #ifdef ANDROID
     EXPECT_TRUE(false) << "This is not to be called on Android.";
@@ -414,139 +393,54 @@ class MockCubeb {
                  cubeb_devid aOutputDevice,
                  cubeb_stream_params* aOutputStreamParams,
                  cubeb_data_callback aDataCallback,
                  cubeb_state_callback aStateCallback, void* aUserPtr) {
     MockCubebStream* mockStream = new MockCubebStream(
         aContext, aInputDevice, aInputStreamParams, aOutputDevice,
         aOutputStreamParams, aDataCallback, aStateCallback, aUserPtr);
     *aStream = reinterpret_cast<cubeb_stream*>(mockStream);
-    mStreamInitEvent.Notify(mockStream);
+    mCurrentMockStream = mockStream;
     return CUBEB_OK;
   }
 
   void StreamDestroy(cubeb_stream* aStream) {
-    mStreamDestroyEvent.Notify();
     MockCubebStream* mockStream = reinterpret_cast<MockCubebStream*>(aStream);
     delete mockStream;
   }
 
-  void GoFaster() { mFastMode = true; }
-  void DontGoFaster() { mFastMode = false; }
-
-  MediaEventSource<MockCubebStream*>& StreamInitEvent() {
-    return mStreamInitEvent;
-  }
-  MediaEventSource<void>& StreamDestroyEvent() { return mStreamDestroyEvent; }
-
-  // MockCubeb specific API
-  void StartStream(MockCubebStream* aStream) {
-    auto streams = mLiveStreams.Lock();
-    MOZ_ASSERT(!streams->Contains(aStream));
-    streams->AppendElement(aStream);
-    if (!mFakeAudioThread) {
-      mFakeAudioThread = WrapUnique(new std::thread(ThreadFunction_s, this));
-    }
-  }
-
-  void StopStream(MockCubebStream* aStream) {
-    UniquePtr<std::thread> audioThread;
-    {
-      auto streams = mLiveStreams.Lock();
-      MOZ_ASSERT(streams->Contains(aStream));
-      streams->RemoveElement(aStream);
-      MOZ_ASSERT(mFakeAudioThread);
-      if (streams->IsEmpty()) {
-        audioThread = std::move(mFakeAudioThread);
-      }
-    }
-    if (audioThread) {
-      audioThread->join();
-    }
-  }
-
-  // Simulates the audio thread. The thread is created at Start and destroyed
-  // at Stop. At next StreamStart a new thread is created.
-  static void ThreadFunction_s(MockCubeb* aContext) {
-    aContext->ThreadFunction();
-  }
-
-  void ThreadFunction() {
-    while (true) {
-      {
-        auto streams = mLiveStreams.Lock();
-        for (auto& stream : *streams) {
-          stream->Process10Ms();
-        }
-        if (streams->IsEmpty()) {
-          break;
-        }
-      }
-      std::this_thread::sleep_for(
-          std::chrono::microseconds(mFastMode ? 0 : 10 * PR_USEC_PER_MSEC));
-    }
-  }
+  MockCubebStream* CurrentStream() { return mCurrentMockStream; }
 
  private:
   // This needs to have the exact same memory layout as a real cubeb backend.
   // It's very important for this `ops` member to be the very first member of
-  // the class, and to not have any virtual members (to avoid having a
-  // vtable).
+  // the class, and to not have any virtual members (to avoid having a vtable).
   const cubeb_ops* ops;
   // The callback to call when the device list has been changed.
   cubeb_device_collection_changed_callback
       mInputDeviceCollectionChangeCallback = nullptr;
   cubeb_device_collection_changed_callback
       mOutputDeviceCollectionChangeCallback = nullptr;
   // The pointer to pass in the callback.
   void* mInputDeviceCollectionChangeUserPtr = nullptr;
   void* mOutputDeviceCollectionChangeUserPtr = nullptr;
   void* mUserPtr = nullptr;
-  // Whether or not this backend supports device collection change
-  // notification via a system callback. If not, Gecko is expected to re-query
-  // the list every time.
+  // Whether or not this backend supports device collection change notification
+  // via a system callback. If not, Gecko is expected to re-query the list every
+  // time.
   bool mSupportsDeviceCollectionChangedCallback = true;
   // Our input and output devices.
   nsTArray<cubeb_device_info> mInputDevices;
   nsTArray<cubeb_device_info> mOutputDevices;
 
-  // The streams that are currently running.
-  DataMutex<nsTArray<MockCubebStream*>> mLiveStreams{"MockCubeb::mLiveStreams"};
-  // Thread that simulates the audio thread, shared across MockCubebStreams to
-  // avoid unintended drift. This is set together with mLiveStreams, under the
-  // mLiveStreams DataMutex.
-  UniquePtr<std::thread> mFakeAudioThread;
-  // Whether to run the fake audio thread in fast mode, not caring about wall
-  // clock time. false is default and means data is processed every 10ms. When
-  // true we sleep(0) between iterations instead of 10ms.
-  std::atomic<bool> mFastMode{false};
-
-  MediaEventProducer<MockCubebStream*> mStreamInitEvent;
-  MediaEventProducer<void> mStreamDestroyEvent;
+  // The latest cubeb stream. The init of a stream happens in a helper thread
+  // inside Gecko so a synchronization method is needed.
+  std::atomic<MockCubebStream*> mCurrentMockStream{nullptr};
 };
 
-int MockCubebStream::Start() {
-  mStreamStop = false;
-  reinterpret_cast<MockCubeb*>(context)->StartStream(this);
-  cubeb_stream* stream = reinterpret_cast<cubeb_stream*>(this);
-  mStateCallback(stream, mUserPtr, CUBEB_STATE_STARTED);
-  return CUBEB_OK;
-}
-
-int MockCubebStream::Stop() {
-  mStreamStop = true;
-  mOutputVerificationEvent.Notify(MakeTuple(
-      mAudioVerifier.PreSilenceSamples(), mAudioVerifier.EstimatedFreq(),
-      mAudioVerifier.CountDiscontinuities()));
-  reinterpret_cast<MockCubeb*>(context)->StopStream(this);
-  cubeb_stream* stream = reinterpret_cast<cubeb_stream*>(this);
-  mStateCallback(stream, mUserPtr, CUBEB_STATE_STOPPED);
-  return CUBEB_OK;
-}
-
 void cubeb_mock_destroy(cubeb* context) {
   delete reinterpret_cast<MockCubeb*>(context);
 }
 
 int cubeb_mock_enumerate_devices(cubeb* context, cubeb_device_type type,
                                  cubeb_device_collection* out) {
   MockCubeb* mock = reinterpret_cast<MockCubeb*>(context);
   return mock->EnumerateDevices(type, out);
@@ -609,17 +503,17 @@ static char const* cubeb_mock_get_backen
 }
 
 static int cubeb_mock_stream_set_volume(cubeb_stream* stream, float volume) {
   return CUBEB_OK;
 }
 
 int cubeb_mock_get_min_latency(cubeb* context, cubeb_stream_params params,
                                uint32_t* latency_ms) {
-  *latency_ms = 10;
+  *latency_ms = NUM_OF_FRAMES;
   return CUBEB_OK;
 }
 
 int cubeb_mock_get_max_channel_count(cubeb* context, uint32_t* max_channels) {
   *max_channels = NUM_OF_CHANNELS;
   return CUBEB_OK;
 }
 
@@ -743,11 +637,10 @@ void AddDevices(MockCubeb* mock, uint32_
         DeviceTemplate(reinterpret_cast<void*>(i + 1), deviceType);
     // Make it so that the last device is the default input device.
     if (i == device_count - 1) {
       device.preferred = CUBEB_DEVICE_PREF_ALL;
     }
     mock->AddDevice(device);
   }
 }
-}  // namespace mozilla
 
 #endif  // MOCKCUBEB_H_
--- a/dom/media/gtest/TestAudioCallbackDriver.cpp
+++ b/dom/media/gtest/TestAudioCallbackDriver.cpp
@@ -11,20 +11,20 @@
 #include "gtest/gtest.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/UniquePtr.h"
 #include "nsTArray.h"
 
 #include "MockCubeb.h"
 
-using namespace mozilla;
 using IterationResult = GraphInterface::IterationResult;
 using ::testing::NiceMock;
 using ::testing::Return;
+using namespace mozilla;
 
 class MockGraphInterface : public GraphInterface {
   NS_DECL_THREADSAFE_ISUPPORTS
   MOCK_METHOD4(NotifyOutputData,
                void(AudioDataValue*, size_t, TrackRate, uint32_t));
   MOCK_METHOD0(NotifyStarted, void());
   MOCK_METHOD4(NotifyInputData,
                void(const AudioDataValue*, size_t, TrackRate, uint32_t));
--- a/dom/media/gtest/TestAudioDriftCorrection.cpp
+++ b/dom/media/gtest/TestAudioDriftCorrection.cpp
@@ -1,374 +1,503 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AudioDriftCorrection.h"
-#include "AudioGenerator.h"
-#include "AudioVerifier.h"
 
 #include "gmock/gmock.h"
 #include "gtest/gtest-printers.h"
 #include "gtest/gtest.h"
 
-// Runs UpdateClock() and checks that the reported correction level doesn't
-// change for enough time to trigger a correction update on the first
-// following UpdateClock(). Returns the first reported correction level.
-static float RunUntilCorrectionUpdate(ClockDrift& aC, uint32_t aSource,
-                                      uint32_t aTarget, uint32_t aBuffering,
-                                      uint32_t aSaturation,
-                                      uint32_t aSourceOffset = 0,
-                                      uint32_t aTargetOffset = 0) {
-  Maybe<float> correction;
-  for (uint32_t s = aSourceOffset, t = aTargetOffset;
-       s < aC.mSourceRate && t < aC.mTargetRate; s += aSource, t += aTarget) {
-    aC.UpdateClock(aSource, aTarget, aBuffering, aSaturation);
-    if (correction) {
-      EXPECT_FLOAT_EQ(aC.GetCorrection(), *correction)
-          << "s=" << s << "; t=" << t;
-    } else {
-      correction = Some(aC.GetCorrection());
-    }
-  }
-  return *correction;
-};
-
 TEST(TestClockDrift, Basic)
 {
-  // Keep buffered frames to the wanted level in order to not affect that test.
-  const uint32_t buffered = 5 * 480;
-
-  ClockDrift c(48000, 48000, buffered);
+  ClockDrift c(48000, 48000);
   EXPECT_EQ(c.GetCorrection(), 1.0);
 
-  EXPECT_FLOAT_EQ(RunUntilCorrectionUpdate(c, 480, 480, buffered, buffered),
-                  1.0);
-  EXPECT_FLOAT_EQ(
-      RunUntilCorrectionUpdate(c, 480, 480 + 48, buffered, buffered), 1.0);
-  EXPECT_FLOAT_EQ(RunUntilCorrectionUpdate(c, 480, 480, buffered, buffered),
-                  1.06);
-  EXPECT_FLOAT_EQ(
-      RunUntilCorrectionUpdate(c, 480 + 48, 480, buffered, buffered), 1.024);
+  // Keep buffered frames to the wanted level in order to not affect that test.
+  for (int i = 0; i < 100; ++i) {
+    c.UpdateClock(480, 480, 5 * 480);
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0);
+  }
+
+  for (int i = 0; i < 100; ++i) {
+    c.UpdateClock(480, 480 + 48, 5 * 480);
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0);
+  }
 
-  c.UpdateClock(0, 0, 5 * 480, 5 * 480);
-  EXPECT_FLOAT_EQ(c.GetCorrection(), 0.95505452);
+  for (int i = 0; i < 100; ++i) {
+    c.UpdateClock(480, 480, 5 * 480);
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.1);
+  }
+
+  for (int i = 0; i < 100; ++i) {
+    c.UpdateClock(480 + 48, 480, 5 * 480);
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0);
+  }
+
+  c.UpdateClock(0, 0, 5 * 480);
+  EXPECT_FLOAT_EQ(c.GetCorrection(), 0.90909094);
 }
 
 TEST(TestClockDrift, BasicResampler)
 {
-  // Keep buffered frames to the wanted level in order to not affect that test.
-  const uint32_t buffered = 5 * 240;
-
-  ClockDrift c(24000, 48000, buffered);
+  ClockDrift c(24000, 48000);
+  for (int i = 0; i < 100; ++i) {
+    c.UpdateClock(240, 480, 5 * 240);
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0);
+  }
 
   // Keep buffered frames to the wanted level in order to not affect that test.
-  EXPECT_FLOAT_EQ(RunUntilCorrectionUpdate(c, 240, 480, buffered, buffered),
-                  1.0);
+  for (int i = 0; i < 100; ++i) {
+    c.UpdateClock(240, 480 + 48, 5 * 240);  // +10%
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0);
+  }
 
-  // +10%
-  EXPECT_FLOAT_EQ(
-      RunUntilCorrectionUpdate(c, 240, 480 + 48, buffered, buffered), 1.0);
-
-  // +10%
-  EXPECT_FLOAT_EQ(
-      RunUntilCorrectionUpdate(c, 240 + 24, 480, buffered, buffered), 1.06);
+  for (int i = 0; i < 100; ++i) {
+    c.UpdateClock(240 + 24, 480, 5 * 240);  // +10%
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.1);
+  }
 
-  // -10%
-  EXPECT_FLOAT_EQ(
-      RunUntilCorrectionUpdate(c, 240, 480 - 48, buffered, buffered),
-      0.96945453);
+  for (int i = 0; i < 100; ++i) {
+    c.UpdateClock(240, 480 - 48, 5 * 240);  // -10%
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 0.90909094);
+  }
 
-  // +5%, -5%
-  EXPECT_FLOAT_EQ(
-      RunUntilCorrectionUpdate(c, 240 + 12, 480 - 24, buffered, buffered),
-      0.92778182);
+  for (int i = 0; i < 100; ++i) {
+    c.UpdateClock(240 + 12, 480 - 24, 5 * 240);  //-5%, -5%
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 0.90909094);
+  }
 
-  c.UpdateClock(0, 0, buffered, buffered);
-  EXPECT_FLOAT_EQ(c.GetCorrection(), 0.91396987);
+  c.UpdateClock(0, 0, 5 * 240);
+  EXPECT_FLOAT_EQ(c.GetCorrection(), 0.90909094);
 }
 
 TEST(TestClockDrift, BufferedInput)
 {
-  ClockDrift c(48000, 48000, 5 * 480);
+  ClockDrift c(48000, 48000);
   EXPECT_EQ(c.GetCorrection(), 1.0);
 
-  EXPECT_FLOAT_EQ(RunUntilCorrectionUpdate(c, 480, 480, 5 * 480, 8 * 480), 1.0);
+  for (int i = 0; i < 100; ++i) {
+    c.UpdateClock(480, 480, 5 * 480);
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0);
+  }
+  c.UpdateClock(480, 480, 0);  // 0 buffered on 100th iteration
+  EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0526316);
 
-  c.UpdateClock(480, 480, 0, 10 * 480);  // 0 buffered when updating correction
-  EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0473685);
-  EXPECT_FLOAT_EQ(
-      RunUntilCorrectionUpdate(c, 480, 480, 3 * 480, 7 * 480, 480, 480),
-      1.0473685);
+  for (int i = 0; i < 99; ++i) {
+    c.UpdateClock(480, 480, 2 * 480);
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0526316);
+  }
+  c.UpdateClock(480, 480, 2 * 480);
+  EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0309278);
 
-  c.UpdateClock(480, 480, 3 * 480, 7 * 480);
-  EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0311923);
-  EXPECT_FLOAT_EQ(
-      RunUntilCorrectionUpdate(c, 480, 480, 5 * 480, 5 * 480, 480, 480),
-      1.0311923);
+  for (int i = 0; i < 99; ++i) {
+    c.UpdateClock(480, 480, 5 * 480);
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0309278);
+  }
+  c.UpdateClock(480, 480, 5 * 480);
+  EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0);
 
-  c.UpdateClock(480, 480, 5 * 480, 5 * 480);
-  EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0124769);
-  EXPECT_FLOAT_EQ(
-      RunUntilCorrectionUpdate(c, 480, 480, 7 * 480, 3 * 480, 480, 480),
-      1.0124769);
-
-  c.UpdateClock(480, 480, 7 * 480, 3 * 480);
-  EXPECT_FLOAT_EQ(c.GetCorrection(), 0.99322605);
+  for (int i = 0; i < 99; ++i) {
+    c.UpdateClock(480, 480, 7 * 480);
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0);
+  }
+  c.UpdateClock(480, 480, 7 * 480);
+  EXPECT_FLOAT_EQ(c.GetCorrection(), 0.980392);
 }
 
 TEST(TestClockDrift, BufferedInputWithResampling)
 {
-  ClockDrift c(24000, 48000, 5 * 240);
+  ClockDrift c(24000, 48000);
   EXPECT_EQ(c.GetCorrection(), 1.0);
 
-  EXPECT_FLOAT_EQ(RunUntilCorrectionUpdate(c, 240, 480, 5 * 240, 5 * 240), 1.0);
+  for (int i = 0; i < 100; ++i) {
+    c.UpdateClock(240, 480, 5 * 240);
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0);
+  }
+  c.UpdateClock(240, 480, 0);  // 0 buffered on 100th iteration
+  EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0526316);
 
-  c.UpdateClock(240, 480, 0, 10 * 240);  // 0 buffered when updating correction
-  EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0473685);
-  EXPECT_FLOAT_EQ(
-      RunUntilCorrectionUpdate(c, 240, 480, 3 * 240, 7 * 240, 240, 480),
-      1.0473685);
+  for (int i = 0; i < 99; ++i) {
+    c.UpdateClock(240, 480, 2 * 240);
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0526316);
+  }
+  c.UpdateClock(240, 480, 2 * 240);
+  EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0309278);
 
-  c.UpdateClock(240, 480, 3 * 240, 7 * 240);
-  EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0311923);
-  EXPECT_FLOAT_EQ(
-      RunUntilCorrectionUpdate(c, 240, 480, 5 * 240, 5 * 240, 240, 480),
-      1.0311923);
+  for (int i = 0; i < 99; ++i) {
+    c.UpdateClock(240, 480, 5 * 240);
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0309278);
+  }
+  c.UpdateClock(240, 480, 5 * 240);
+  EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0);
 
-  c.UpdateClock(240, 480, 5 * 240, 5 * 240);
-  EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0124769);
-  EXPECT_FLOAT_EQ(
-      RunUntilCorrectionUpdate(c, 240, 480, 7 * 240, 3 * 240, 240, 480),
-      1.0124769);
-
-  c.UpdateClock(240, 480, 7 * 240, 3 * 240);
-  EXPECT_FLOAT_EQ(c.GetCorrection(), 0.99322605);
+  for (int i = 0; i < 99; ++i) {
+    c.UpdateClock(240, 480, 7 * 240);
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0);
+  }
+  c.UpdateClock(240, 480, 7 * 240);
+  EXPECT_FLOAT_EQ(c.GetCorrection(), 0.980392);
 }
 
 TEST(TestClockDrift, Clamp)
 {
-  // Keep buffered frames to the wanted level in order to not affect that test.
-  const uint32_t buffered = 5 * 480;
-
-  ClockDrift c(48000, 48000, buffered);
+  ClockDrift c(48000, 48000);
 
-  // +30%
-  EXPECT_FLOAT_EQ(
-      RunUntilCorrectionUpdate(c, 480, 480 + 3 * 48, buffered, buffered), 1.0);
-
-  // -30%
-  EXPECT_FLOAT_EQ(
-      RunUntilCorrectionUpdate(c, 480, 480 - 3 * 48, buffered, buffered), 1.1);
-
-  c.UpdateClock(0, 0, buffered, buffered);
+  for (int i = 0; i < 100; ++i) {
+    c.UpdateClock(480, 480 + 2 * 48, 5 * 480);  // +20%
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0);
+  }
+  for (int i = 0; i < 100; ++i) {
+    c.UpdateClock(480, 480 - 2 * 48, 5 * 480);  // -20%
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.1);
+  }
+  c.UpdateClock(0, 0, 5 * 480);
   EXPECT_FLOAT_EQ(c.GetCorrection(), 0.9);
 }
 
 TEST(TestClockDrift, SmallDiff)
 {
-  // Keep buffered frames to the wanted level in order to not affect that test.
-  const uint32_t buffered = 5 * 480;
-
-  ClockDrift c(48000, 48000, buffered);
+  ClockDrift c(48000, 48000);
 
-  EXPECT_FLOAT_EQ(RunUntilCorrectionUpdate(c, 480 + 4, 480, buffered, buffered),
-                  1.0);
-  EXPECT_FLOAT_EQ(RunUntilCorrectionUpdate(c, 480 + 5, 480, buffered, buffered),
-                  0.99504131);
-  EXPECT_FLOAT_EQ(RunUntilCorrectionUpdate(c, 480, 480, buffered, buffered),
-                  0.991831);
-  EXPECT_FLOAT_EQ(RunUntilCorrectionUpdate(c, 480, 480 + 4, buffered, buffered),
-                  0.99673241);
-  c.UpdateClock(0, 0, buffered, buffered);
-  EXPECT_FLOAT_EQ(c.GetCorrection(), 1.003693);
+  for (int i = 0; i < 100; ++i) {
+    c.UpdateClock(480 + 4, 480, 5 * 480);
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0);
+  }
+  for (int i = 0; i < 100; ++i) {
+    c.UpdateClock(480 + 5, 480, 5 * 480);
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0);
+  }
+  for (int i = 0; i < 100; ++i) {
+    c.UpdateClock(480, 480, 5 * 480);
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 0.98969072);
+  }
+  // Reset to 1.0 again
+  for (int i = 0; i < 100; ++i) {
+    c.UpdateClock(480, 480 + 4, 5 * 480);  // +0.83%
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0);
+  }
+  c.UpdateClock(0, 0, 5 * 480);
+  EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0083333);
 }
 
 TEST(TestClockDrift, SmallBufferedFrames)
 {
-  ClockDrift c(48000, 48000, 5 * 480);
+  ClockDrift c(48000, 48000);
 
   EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0);
-  for (uint32_t i = 0; i < 10; ++i) {
-    c.UpdateClock(480, 480, 5 * 480, 5 * 480);
-  }
+  c.UpdateClock(480, 480, 5 * 480);
   EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0);
-  c.UpdateClock(480, 480, 0, 10 * 480);
-  EXPECT_FLOAT_EQ(c.GetCorrection(), 1.1);
+  c.UpdateClock(480, 480, 0);
+  EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0526316);
 
-  EXPECT_FLOAT_EQ(
-      RunUntilCorrectionUpdate(c, 480, 480, 5 * 480, 5 * 480, 24000, 24000),
-      1.1);
-  c.UpdateClock(480, 480, 0, 10 * 480);
+  for (int i = 0; i < 50; ++i) {
+    c.UpdateClock(480, 480, 5 * 480);
+    EXPECT_FLOAT_EQ(c.GetCorrection(), 1.0526316);
+  }
+  c.UpdateClock(480, 480, 0);
   EXPECT_FLOAT_EQ(c.GetCorrection(), 1.1);
 }
 
+template <typename T>
+class AudioToneGenerator {
+ public:
+  static_assert(std::is_same<T, int16_t>::value ||
+                std::is_same<T, float>::value);
+
+  explicit AudioToneGenerator(int32_t aRate) : mRate(aRate) {
+    MOZ_ASSERT(mRate > 0);
+  }
+
+  void Write(AudioChunk& aChunk) {
+    float time = mTime;
+    for (uint32_t i = 0; i < aChunk.ChannelCount(); ++i) {
+      mTime = time;  // reset the time for each channel
+      T* buffer = aChunk.ChannelDataForWrite<T>(0);
+      Write(buffer, aChunk.GetDuration());
+    }
+  }
+
+  void Write(T* aBuffer, int32_t aFrames) {
+    for (int i = 0; i < aFrames; ++i) {
+      double value = Amplitude() * sin(2 * M_PI * mFrequency * mTime + mPhase);
+      aBuffer[i] = static_cast<T>(value);
+      mTime += mDeltaTime;
+    }
+  }
+
+  T MaxMagnitudeDifference() {
+    return static_cast<T>(Amplitude() *
+                          sin(2 * M_PI * mFrequency * mDeltaTime + mPhase));
+  }
+
+  const int32_t mRate;
+  const int32_t mFrequency = 100;
+  const float mPhase = 0.0;
+  const float mDeltaTime = 1.0f / mRate;
+
+  static T Amplitude() {
+    if (std::is_same<T, int16_t>::value) {
+      return 19384;  // int16_t::max / 2
+    }
+    return 0.5f;  // 1.0f / 2
+  }
+
+ private:
+  float mTime = 0.0;
+};
+
+template <typename T>
+class AudioToneVerifier {
+ public:
+  explicit AudioToneVerifier(int32_t aRate)
+      : mRate(aRate), mExpectedTone(aRate) {
+    MOZ_ASSERT(mRate > 0);
+  }
+
+  // Only the mono channel is taken into account.
+  void AppendData(const AudioSegment& segment) {
+    for (AudioSegment::ConstChunkIterator iter(segment); !iter.IsEnded();
+         iter.Next()) {
+      const AudioChunk& c = *iter;
+      CheckBuffer(c.ChannelData<T>()[0], c.GetDuration());
+    }
+  }
+
+  int32_t EstimatedFreq() const {
+    if (mTotalFramesSoFar == PreSilenceSamples() || mZeroCrossCount <= 1) {
+      return 0.0f;
+    }
+    MOZ_ASSERT(mZeroCrossCount > 1);
+    return mRate / (mSumPeriodInSamples / (mZeroCrossCount - 1));
+  }
+
+  int64_t PreSilenceSamples() const {
+    // The first sample of the sinewave is zero.
+    MOZ_ASSERT(mPreSilenceSamples >= 1);
+    return mPreSilenceSamples - 1;
+  }
+
+  int32_t CountDiscontinuities() const {
+    // Every discontinuity is counted twice one on current sample and one more
+    // on previous sample.
+    return mDiscontinuitiesCount / 2;
+  }
+
+ private:
+  void CheckBuffer(const T* aBuffer, int32_t aSamples) {
+    for (int i = 0; i < aSamples; ++i) {
+      ++mTotalFramesSoFar;
+      // Avoid pre-silence
+      if (!CountPreSilence(aBuffer[i])) {
+        CountZeroCrossing(aBuffer[i]);
+        CountDiscontinuities(aBuffer[i]);
+      }
+
+      mPrevious = aBuffer[i];
+    }
+  }
+
+  bool CountPreSilence(T aCurrentSample) {
+    if (IsZero(aCurrentSample) && mPreSilenceSamples == mTotalFramesSoFar - 1) {
+      ++mPreSilenceSamples;
+      return true;
+    }
+    return false;
+  }
+
+  // Positive to negative direction
+  void CountZeroCrossing(T aCurrentSample) {
+    if (mPrevious > 0 && aCurrentSample <= 0) {
+      if (mZeroCrossCount++) {
+        MOZ_ASSERT(mZeroCrossCount > 1);
+        mSumPeriodInSamples += mTotalFramesSoFar - mLastZeroCrossPosition;
+      }
+      mLastZeroCrossPosition = mTotalFramesSoFar;
+    }
+  }
+
+  void CountDiscontinuities(T aCurrentSample) {
+    mDiscontinuitiesCount += fabs(fabs(aCurrentSample) - fabs(mPrevious)) >
+                             2 * mExpectedTone.MaxMagnitudeDifference();
+  }
+
+  bool IsZero(float a) { return fabs(a) < 1e-8; }
+  bool IsZero(short a) { return a == 0; }
+
+ private:
+  const int32_t mRate;
+  AudioToneGenerator<T> mExpectedTone;
+
+  int32_t mZeroCrossCount = 0;
+  int64_t mLastZeroCrossPosition = 0;
+  int64_t mSumPeriodInSamples = 0;
+
+  int64_t mTotalFramesSoFar = 0;
+  int64_t mPreSilenceSamples = 0;
+
+  int32_t mDiscontinuitiesCount = 0;
+  // This is needed to connect previous the previous buffers.
+  T mPrevious = {};
+};
+
 // Print the mono channel of a segment.
 void printAudioSegment(const AudioSegment& segment) {
   for (AudioSegment::ConstChunkIterator iter(segment); !iter.IsEnded();
        iter.Next()) {
     const AudioChunk& c = *iter;
-    for (uint32_t i = 0; i < c.GetDuration(); ++i) {
+    for (int i = 0; i < c.GetDuration(); ++i) {
       if (c.mBufferFormat == AUDIO_FORMAT_FLOAT32) {
         printf("%f\n", c.ChannelData<float>()[0][i]);
       } else {
         printf("%d\n", c.ChannelData<int16_t>()[0][i]);
       }
     }
   }
 }
 
 template <class T>
-AudioChunk CreateAudioChunk(uint32_t aFrames, uint32_t aChannels,
+AudioChunk CreateAudioChunk(uint32_t aFrames, int aChannels,
                             AudioSampleFormat aSampleFormat);
 
 void testAudioCorrection(int32_t aSourceRate, int32_t aTargetRate) {
-  const uint32_t channels = 1;
-  const uint32_t sampleRateTransmitter = aSourceRate;
-  const uint32_t sampleRateReceiver = aTargetRate;
-  const uint32_t frequency = 100;
+  const int32_t sampleRateTransmitter = aSourceRate;
+  const int32_t sampleRateReceiver = aTargetRate;
   AudioDriftCorrection ad(sampleRateTransmitter, sampleRateReceiver);
 
-  AudioGenerator<AudioDataValue> tone(channels, sampleRateTransmitter,
-                                      frequency);
-  AudioVerifier<AudioDataValue> inToneVerifier(sampleRateTransmitter,
-                                               frequency);
-  AudioVerifier<AudioDataValue> outToneVerifier(sampleRateReceiver, frequency);
+  AudioToneGenerator<AudioDataValue> tone(sampleRateTransmitter);
+  AudioToneVerifier<AudioDataValue> inToneVerifier(sampleRateTransmitter);
+  AudioToneVerifier<AudioDataValue> outToneVerifier(sampleRateReceiver);
 
-  uint32_t sourceFrames;
-  const uint32_t targetFrames = sampleRateReceiver / 100;
+  int32_t sourceFrames;
+  const int32_t targetFrames = sampleRateReceiver / 100;
 
-  // Run for some time: 3 * 1050 = 3150 iterations
-  for (uint32_t j = 0; j < 3; ++j) {
+  // Run for some time: 6 * 250 = 1500 iterations
+  for (int j = 0; j < 6; ++j) {
     // apply some drift
     if (j % 2 == 0) {
-      sourceFrames =
-          sampleRateTransmitter * /*1.02*/ 102 / 100 / /*1s->10ms*/ 100;
+      sourceFrames = sampleRateTransmitter / 100 + 10;
     } else {
-      sourceFrames =
-          sampleRateTransmitter * /*0.98*/ 98 / 100 / /*1s->10ms*/ 100;
+      sourceFrames = sampleRateTransmitter / 100 - 10;
     }
 
-    // 10.5 seconds, allows for at least 10 correction changes, to stabilize
-    // around the desired buffer.
-    for (uint32_t n = 0; n < 1050; ++n) {
+    for (int n = 0; n < 250; ++n) {
       // Create the input (sine tone)
+      AudioChunk chunk = CreateAudioChunk<AudioDataValue>(sourceFrames, 1,
+                                                          AUDIO_OUTPUT_FORMAT);
+      tone.Write(chunk);
       AudioSegment inSegment;
-      tone.Generate(inSegment, sourceFrames);
+      inSegment.AppendAndConsumeChunk(&chunk);
       inToneVerifier.AppendData(inSegment);
       // Print the input for debugging
       // printAudioSegment(inSegment);
 
       // Get the output of the correction
       AudioSegment outSegment = ad.RequestFrames(inSegment, targetFrames);
       EXPECT_EQ(outSegment.GetDuration(), targetFrames);
       // Print the output for debugging
       // printAudioSegment(outSegment);
       outToneVerifier.AppendData(outSegment);
     }
   }
-
-  EXPECT_NEAR(ad.CurrentBuffering(),
-              ad.mDesiredBuffering - sampleRateTransmitter / 100, 512);
+  EXPECT_EQ(inToneVerifier.EstimatedFreq(), tone.mFrequency);
+  EXPECT_EQ(inToneVerifier.PreSilenceSamples(), 0);
+  EXPECT_EQ(inToneVerifier.CountDiscontinuities(), 0);
 
-  EXPECT_NEAR(inToneVerifier.EstimatedFreq(), tone.mFrequency, 1.0f);
-  EXPECT_EQ(inToneVerifier.PreSilenceSamples(), 0U);
-  EXPECT_EQ(inToneVerifier.CountDiscontinuities(), 0U);
-
-  EXPECT_NEAR(outToneVerifier.EstimatedFreq(), tone.mFrequency, 1.0f);
-  // The expected pre-silence is 50ms plus the resampling.
-  EXPECT_GE(outToneVerifier.PreSilenceSamples(), aTargetRate * 50 / 1000U);
-  EXPECT_EQ(outToneVerifier.CountDiscontinuities(), 0U);
+  EXPECT_EQ(outToneVerifier.EstimatedFreq(), tone.mFrequency);
+  // The expected pre-silence is 50ms plus the resampling, this is roughly more
+  // than 2000 frames for the samples rates being used here
+  EXPECT_GT(outToneVerifier.PreSilenceSamples(), 2000);
+  EXPECT_EQ(outToneVerifier.CountDiscontinuities(), 0);
 }
 
 TEST(TestAudioDriftCorrection, Basic)
 {
-  printf("Testing AudioCorrection 48 -> 48\n");
   testAudioCorrection(48000, 48000);
-  printf("Testing AudioCorrection 48 -> 44.1\n");
   testAudioCorrection(48000, 44100);
-  printf("Testing AudioCorrection 44.1 -> 48\n");
   testAudioCorrection(44100, 48000);
-  printf("Testing AudioCorrection 23458 -> 25113\n");
-  testAudioCorrection(23458, 25113);
 }
 
-void testMonoToStereoInput(uint32_t aSourceRate, uint32_t aTargetRate) {
-  const uint32_t frequency = 100;
-  const uint32_t sampleRateTransmitter = aSourceRate;
-  const uint32_t sampleRateReceiver = aTargetRate;
+void testMonoToStereoInput(int aSourceRate, int aTargetRate) {
+  const int32_t sampleRateTransmitter = aSourceRate;
+  const int32_t sampleRateReceiver = aTargetRate;
   AudioDriftCorrection ad(sampleRateTransmitter, sampleRateReceiver);
 
-  AudioGenerator<AudioDataValue> monoTone(1, sampleRateTransmitter, frequency);
-  AudioGenerator<AudioDataValue> stereoTone(2, sampleRateTransmitter,
-                                            frequency);
-  AudioVerifier<AudioDataValue> inToneVerify(sampleRateTransmitter, frequency);
-  AudioVerifier<AudioDataValue> outToneVerify(sampleRateReceiver, frequency);
+  AudioToneGenerator<AudioDataValue> tone(sampleRateTransmitter);
+  AudioToneVerifier<AudioDataValue> inToneVerify(sampleRateTransmitter);
+  AudioToneVerifier<AudioDataValue> outToneVerify(sampleRateReceiver);
 
-  uint32_t sourceFrames;
-  const uint32_t targetFrames = sampleRateReceiver / 100;
+  int32_t sourceFrames;
+  const int32_t targetFrames = sampleRateReceiver / 100;
 
   // Run for some time: 6 * 250 = 1500 iterations
-  for (uint32_t j = 0; j < 6; ++j) {
+  for (int j = 0; j < 6; ++j) {
     // apply some drift
     if (j % 2 == 0) {
       sourceFrames = sampleRateTransmitter / 100 + 10;
     } else {
       sourceFrames = sampleRateTransmitter / 100 - 10;
     }
 
-    for (uint32_t n = 0; n < 250; ++n) {
-      // Create the input (sine tone) of two chunks.
+    for (int n = 0; n < 250; ++n) {
+      // Create the input (sine tone)
+      AudioChunk chunk = CreateAudioChunk<AudioDataValue>(sourceFrames / 2, 1,
+                                                          AUDIO_OUTPUT_FORMAT);
+      tone.Write(chunk);
+
+      AudioChunk chunk2 = CreateAudioChunk<AudioDataValue>(sourceFrames / 2, 2,
+                                                           AUDIO_OUTPUT_FORMAT);
+      tone.Write(chunk2);
+
       AudioSegment inSegment;
-      monoTone.Generate(inSegment, sourceFrames / 2);
-      stereoTone.SetOffset(monoTone.Offset());
-      stereoTone.Generate(inSegment, sourceFrames / 2);
-      monoTone.SetOffset(stereoTone.Offset());
+      inSegment.AppendAndConsumeChunk(&chunk);
+      inSegment.AppendAndConsumeChunk(&chunk2);
       inToneVerify.AppendData(inSegment);
       // Print the input for debugging
       // printAudioSegment(inSegment);
 
       // Get the output of the correction
       AudioSegment outSegment = ad.RequestFrames(inSegment, targetFrames);
       EXPECT_EQ(outSegment.GetDuration(), targetFrames);
       // Print the output for debugging
       // printAudioSegment(outSegment);
       outToneVerify.AppendData(outSegment);
     }
   }
-  EXPECT_EQ(inToneVerify.EstimatedFreq(), frequency);
-  EXPECT_EQ(inToneVerify.PreSilenceSamples(), 0U);
-  EXPECT_EQ(inToneVerify.CountDiscontinuities(), 0U);
+  EXPECT_EQ(inToneVerify.EstimatedFreq(), tone.mFrequency);
+  EXPECT_EQ(inToneVerify.PreSilenceSamples(), 0);
+  EXPECT_EQ(inToneVerify.CountDiscontinuities(), 0);
 
-  EXPECT_GT(outToneVerify.CountDiscontinuities(), 0U)
+  EXPECT_GT(outToneVerify.CountDiscontinuities(), 0)
       << "Expect discontinuities";
-  EXPECT_NE(outToneVerify.EstimatedFreq(), frequency)
+  EXPECT_NE(outToneVerify.EstimatedFreq(), tone.mFrequency)
       << "Estimation is not accurate due to discontinuities";
   // The expected pre-silence is 50ms plus the resampling. However, due to
   // discontinuities pre-silence is expected only in the first iteration which
   // is routhly a little more than 400 frames for the chosen sample rates.
-  EXPECT_GT(outToneVerify.PreSilenceSamples(), 400U);
+  EXPECT_GT(outToneVerify.PreSilenceSamples(), 400);
 }
 
 TEST(TestAudioDriftCorrection, MonoToStereoInput)
 {
   testMonoToStereoInput(48000, 48000);
   testMonoToStereoInput(48000, 44100);
   testMonoToStereoInput(44100, 48000);
 }
 
 TEST(TestAudioDriftCorrection, NotEnoughFrames)
 {
-  const uint32_t sampleRateTransmitter = 48000;
-  const uint32_t sampleRateReceiver = 48000;
+  const int32_t sampleRateTransmitter = 48000;
+  const int32_t sampleRateReceiver = 48000;
   AudioDriftCorrection ad(sampleRateTransmitter, sampleRateReceiver);
-  const uint32_t targetFrames = sampleRateReceiver / 100;
+  const int32_t targetFrames = sampleRateReceiver / 100;
 
-  for (uint32_t i = 0; i < 7; ++i) {
+  for (int i = 0; i < 7; ++i) {
     // Input is something small, 10 frames here, in order to dry out fast,
     // after 4 iterations
     AudioChunk chunk = CreateAudioChunk<float>(10, 1, AUDIO_FORMAT_FLOAT32);
     AudioSegment inSegment;
     inSegment.AppendAndConsumeChunk(&chunk);
 
     AudioSegment outSegment = ad.RequestFrames(inSegment, targetFrames);
     EXPECT_EQ(outSegment.GetDuration(), targetFrames);
@@ -379,22 +508,22 @@ TEST(TestAudioDriftCorrection, NotEnough
       // buffered data so the output is silence.
       EXPECT_TRUE(outSegment.IsNull());
     }
   }
 }
 
 TEST(TestAudioDriftCorrection, CrashInAudioResampler)
 {
-  const uint32_t sampleRateTransmitter = 48000;
-  const uint32_t sampleRateReceiver = 48000;
+  const int32_t sampleRateTransmitter = 48000;
+  const int32_t sampleRateReceiver = 48000;
   AudioDriftCorrection ad(sampleRateTransmitter, sampleRateReceiver);
-  const uint32_t targetFrames = sampleRateReceiver / 100;
+  const int32_t targetFrames = sampleRateReceiver / 100;
 
-  for (uint32_t i = 0; i < 100; ++i) {
+  for (int i = 0; i < 100; ++i) {
     AudioChunk chunk = CreateAudioChunk<float>(sampleRateTransmitter / 1000, 1,
                                                AUDIO_FORMAT_FLOAT32);
     AudioSegment inSegment;
     inSegment.AppendAndConsumeChunk(&chunk);
 
     AudioSegment outSegment = ad.RequestFrames(inSegment, targetFrames);
     EXPECT_EQ(outSegment.GetDuration(), targetFrames);
   }
--- a/dom/media/gtest/TestAudioRingBuffer.cpp
+++ b/dom/media/gtest/TestAudioRingBuffer.cpp
@@ -9,419 +9,418 @@
 
 TEST(TestAudioRingBuffer, BasicFloat)
 {
   AudioRingBuffer ringBuffer(11 * sizeof(float));
   ringBuffer.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
 
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
 
-  uint32_t rv = ringBuffer.WriteSilence(4);
-  EXPECT_EQ(rv, 4u);
+  int rv = ringBuffer.WriteSilence(4);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 6u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 4u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 6);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 4);
 
   float in[4] = {.1, .2, .3, .4};
   rv = ringBuffer.Write(Span(in, 4));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 2u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 8u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 2);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 8);
 
   rv = ringBuffer.WriteSilence(4);
-  EXPECT_EQ(rv, 2u);
+  EXPECT_EQ(rv, 2);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 0u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 10u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 0);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 10);
 
   rv = ringBuffer.Write(Span(in, 4));
-  EXPECT_EQ(rv, 0u);
+  EXPECT_EQ(rv, 0);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 0u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 10u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 0);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 10);
 
   float out[4] = {};
   rv = ringBuffer.Read(Span(out, 4));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 4u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 6u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 4);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 6);
   for (float f : out) {
     EXPECT_FLOAT_EQ(f, 0.0);
   }
 
   rv = ringBuffer.Read(Span(out, 4));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 8u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 2u);
-  for (uint32_t i = 0; i < 4; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 8);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 2);
+  for (int i = 0; i < 4; ++i) {
     EXPECT_FLOAT_EQ(in[i], out[i]);
   }
 
   rv = ringBuffer.Read(Span(out, 4));
-  EXPECT_EQ(rv, 2u);
+  EXPECT_EQ(rv, 2);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
-  for (uint32_t i = 0; i < 2; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
+  for (int i = 0; i < 2; ++i) {
     EXPECT_FLOAT_EQ(out[i], 0.0);
   }
 
   rv = ringBuffer.Clear();
-  EXPECT_EQ(rv, 0u);
+  EXPECT_EQ(rv, 0);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
 }
 
 TEST(TestAudioRingBuffer, BasicShort)
 {
   AudioRingBuffer ringBuffer(11 * sizeof(short));
   ringBuffer.SetSampleFormat(AUDIO_FORMAT_S16);
 
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
 
-  uint32_t rv = ringBuffer.WriteSilence(4);
-  EXPECT_EQ(rv, 4u);
+  int rv = ringBuffer.WriteSilence(4);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 6u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 4u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 6);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 4);
 
   short in[4] = {1, 2, 3, 4};
   rv = ringBuffer.Write(Span(in, 4));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 2u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 8u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 2);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 8);
 
   rv = ringBuffer.WriteSilence(4);
-  EXPECT_EQ(rv, 2u);
+  EXPECT_EQ(rv, 2);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 0u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 10u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 0);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 10);
 
   rv = ringBuffer.Write(Span(in, 4));
-  EXPECT_EQ(rv, 0u);
+  EXPECT_EQ(rv, 0);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 0u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 10u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 0);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 10);
 
   short out[4] = {};
   rv = ringBuffer.Read(Span(out, 4));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 4u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 6u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 4);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 6);
   for (float f : out) {
     EXPECT_EQ(f, 0);
   }
 
   rv = ringBuffer.Read(Span(out, 4));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 8u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 2u);
-  for (uint32_t i = 0; i < 4; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 8);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 2);
+  for (int i = 0; i < 4; ++i) {
     EXPECT_EQ(in[i], out[i]);
   }
 
   rv = ringBuffer.Read(Span(out, 4));
-  EXPECT_EQ(rv, 2u);
+  EXPECT_EQ(rv, 2);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
-  for (uint32_t i = 0; i < 2; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
+  for (int i = 0; i < 2; ++i) {
     EXPECT_EQ(out[i], 0);
   }
 
   rv = ringBuffer.Clear();
-  EXPECT_EQ(rv, 0u);
+  EXPECT_EQ(rv, 0);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
 }
 
 TEST(TestAudioRingBuffer, BasicFloat2)
 {
   AudioRingBuffer ringBuffer(11 * sizeof(float));
   ringBuffer.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
 
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
 
   float in[4] = {.1, .2, .3, .4};
-  uint32_t rv = ringBuffer.Write(Span(in, 4));
-  EXPECT_EQ(rv, 4u);
+  int rv = ringBuffer.Write(Span(in, 4));
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 6u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 4u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 6);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 4);
 
   rv = ringBuffer.Write(Span(in, 4));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 2u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 8u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 2);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 8);
 
   float out[4] = {};
   rv = ringBuffer.Read(Span(out, 4));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 6u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 4u);
-  for (uint32_t i = 0; i < 4; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 6);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 4);
+  for (int i = 0; i < 4; ++i) {
     EXPECT_FLOAT_EQ(in[i], out[i]);
   }
 
   // WriteIndex = 12
   rv = ringBuffer.Write(Span(in, 4));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 2u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 8u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 2);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 8);
 
   rv = ringBuffer.Read(Span(out, 4));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 6u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 4u);
-  for (uint32_t i = 0; i < 4; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 6);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 4);
+  for (int i = 0; i < 4; ++i) {
     EXPECT_FLOAT_EQ(in[i], out[i]);
   }
 
   rv = ringBuffer.Read(Span(out, 8));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
-  for (uint32_t i = 0; i < 4; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
+  for (int i = 0; i < 4; ++i) {
     EXPECT_FLOAT_EQ(in[i], out[i]);
   }
 
   rv = ringBuffer.Read(Span(out, 8));
-  EXPECT_EQ(rv, 0u);
+  EXPECT_EQ(rv, 0);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
-  for (uint32_t i = 0; i < 4; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
+  for (int i = 0; i < 4; ++i) {
     EXPECT_FLOAT_EQ(in[i], out[i]);
   }
 
   // WriteIndex = 16
   rv = ringBuffer.Write(Span(in, 4));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 6u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 4u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 6);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 4);
 
   rv = ringBuffer.Write(Span(in, 4));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 2u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 8u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 2);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 8);
 
   rv = ringBuffer.Write(Span(in, 4));
-  EXPECT_EQ(rv, 2u);
+  EXPECT_EQ(rv, 2);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 0u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 10u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 0);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 10);
 
   rv = ringBuffer.Write(Span(in, 4));
-  EXPECT_EQ(rv, 0u);
+  EXPECT_EQ(rv, 0);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 0u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 10u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 0);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 10);
 }
 
 TEST(TestAudioRingBuffer, BasicShort2)
 {
   AudioRingBuffer ringBuffer(11 * sizeof(int16_t));
   ringBuffer.SetSampleFormat(AUDIO_FORMAT_S16);
 
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
 
   int16_t in[4] = {1, 2, 3, 4};
-  uint32_t rv = ringBuffer.Write(Span(in, 4));
-  EXPECT_EQ(rv, 4u);
+  int rv = ringBuffer.Write(Span(in, 4));
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 6u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 4u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 6);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 4);
 
   rv = ringBuffer.Write(Span(in, 4));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 2u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 8u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 2);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 8);
 
   int16_t out[4] = {};
   rv = ringBuffer.Read(Span(out, 4));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 6u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 4u);
-  for (uint32_t i = 0; i < 4; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 6);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 4);
+  for (int i = 0; i < 4; ++i) {
     EXPECT_EQ(in[i], out[i]);
   }
 
   // WriteIndex = 12
   rv = ringBuffer.Write(Span(in, 4));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 2u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 8u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 2);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 8);
 
   rv = ringBuffer.Read(Span(out, 4));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 6u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 4u);
-  for (uint32_t i = 0; i < 4; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 6);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 4);
+  for (int i = 0; i < 4; ++i) {
     EXPECT_EQ(in[i], out[i]);
   }
 
   rv = ringBuffer.Read(Span(out, 8));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
-  for (uint32_t i = 0; i < 4; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
+  for (int i = 0; i < 4; ++i) {
     EXPECT_EQ(in[i], out[i]);
   }
 
   rv = ringBuffer.Read(Span(out, 8));
-  EXPECT_EQ(rv, 0u);
+  EXPECT_EQ(rv, 0);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
-  for (uint32_t i = 0; i < 4; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
+  for (int i = 0; i < 4; ++i) {
     EXPECT_EQ(in[i], out[i]);
   }
 
   // WriteIndex = 16
   rv = ringBuffer.Write(Span(in, 4));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 6u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 4u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 6);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 4);
 
   rv = ringBuffer.Write(Span(in, 4));
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 2u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 8u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 2);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 8);
 
   rv = ringBuffer.Write(Span(in, 4));
-  EXPECT_EQ(rv, 2u);
+  EXPECT_EQ(rv, 2);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 0u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 10u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 0);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 10);
 
   rv = ringBuffer.Write(Span(in, 4));
-  EXPECT_EQ(rv, 0u);
+  EXPECT_EQ(rv, 0);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 0u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 10u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 0);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 10);
 }
 
 TEST(TestAudioRingBuffer, NoCopyFloat)
 {
   AudioRingBuffer ringBuffer(11 * sizeof(float));
   ringBuffer.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
 
   float in[8] = {.0, .1, .2, .3, .4, .5, .6, .7};
   ringBuffer.Write(Span(in, 6));
   //  v ReadIndex
   // [x0: .0, x1: .1, x2: .2, x3: .3, x4: .4,
   //  x5: .5, x6: .0, x7: .0, x8: .0, x9: .0, x10: .0]
 
   float out[10] = {};
   float* out_ptr = out;
 
-  uint32_t rv =
-      ringBuffer.ReadNoCopy([&out_ptr](const Span<const float> aInBuffer) {
-        PodMove(out_ptr, aInBuffer.data(), aInBuffer.Length());
-        out_ptr += aInBuffer.Length();
-        return aInBuffer.Length();
-      });
-  EXPECT_EQ(rv, 6u);
+  int rv = ringBuffer.ReadNoCopy([&out_ptr](const Span<const float> aInBuffer) {
+    PodMove(out_ptr, aInBuffer.data(), aInBuffer.Length());
+    out_ptr += aInBuffer.Length();
+    return aInBuffer.Length();
+  });
+  EXPECT_EQ(rv, 6);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
-  for (uint32_t i = 0; i < rv; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
+  for (int i = 0; i < rv; ++i) {
     EXPECT_FLOAT_EQ(out[i], in[i]);
   }
 
   ringBuffer.Write(Span(in, 8));
   // Now the buffer contains:
   // [x0: .5, x1: .6, x2: .2, x3: .3, x4: .4,
   //  x5: .5, x6: .0, x7: .1, x8: .2, x9: .3, x10: .4
   //          ^ ReadIndex
   out_ptr = out;  // reset the pointer before lambdas reuse
   rv = ringBuffer.ReadNoCopy([&out_ptr](const Span<const float> aInBuffer) {
     PodMove(out_ptr, aInBuffer.data(), aInBuffer.Length());
     out_ptr += aInBuffer.Length();
     return aInBuffer.Length();
   });
-  EXPECT_EQ(rv, 8u);
+  EXPECT_EQ(rv, 8);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
-  for (uint32_t i = 0; i < rv; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
+  for (int i = 0; i < rv; ++i) {
     EXPECT_FLOAT_EQ(out[i], in[i]);
   }
 }
 
 TEST(TestAudioRingBuffer, NoCopyShort)
 {
   AudioRingBuffer ringBuffer(11 * sizeof(short));
   ringBuffer.SetSampleFormat(AUDIO_FORMAT_S16);
@@ -430,48 +429,47 @@ TEST(TestAudioRingBuffer, NoCopyShort)
   ringBuffer.Write(Span(in, 6));
   //  v ReadIndex
   // [x0: 0, x1: 1, x2: 2, x3: 3, x4: 4,
   //  x5: 5, x6: 0, x7: 0, x8: 0, x9: 0, x10: 0]
 
   short out[10] = {};
   short* out_ptr = out;
 
-  uint32_t rv =
-      ringBuffer.ReadNoCopy([&out_ptr](const Span<const short> aInBuffer) {
-        PodMove(out_ptr, aInBuffer.data(), aInBuffer.Length());
-        out_ptr += aInBuffer.Length();
-        return aInBuffer.Length();
-      });
-  EXPECT_EQ(rv, 6u);
+  int rv = ringBuffer.ReadNoCopy([&out_ptr](const Span<const short> aInBuffer) {
+    PodMove(out_ptr, aInBuffer.data(), aInBuffer.Length());
+    out_ptr += aInBuffer.Length();
+    return aInBuffer.Length();
+  });
+  EXPECT_EQ(rv, 6);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
-  for (uint32_t i = 0; i < rv; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
+  for (int i = 0; i < rv; ++i) {
     EXPECT_EQ(out[i], in[i]);
   }
 
   ringBuffer.Write(Span(in, 8));
   // Now the buffer contains:
   // [x0: 5, x1: 6, x2: 2, x3: 3, x4: 4,
   //  x5: 5, x6: 0, x7: 1, x8: 2, x9: 3, x10: 4
   //          ^ ReadIndex
   out_ptr = out;  // reset the pointer before lambdas reuse
   rv = ringBuffer.ReadNoCopy([&out_ptr](const Span<const short> aInBuffer) {
     PodMove(out_ptr, aInBuffer.data(), aInBuffer.Length());
     out_ptr += aInBuffer.Length();
     return aInBuffer.Length();
   });
-  EXPECT_EQ(rv, 8u);
+  EXPECT_EQ(rv, 8);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
-  for (uint32_t i = 0; i < rv; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
+  for (int i = 0; i < rv; ++i) {
     EXPECT_EQ(out[i], in[i]);
   }
 }
 
 TEST(TestAudioRingBuffer, NoCopyFloat2)
 {
   AudioRingBuffer ringBuffer(11 * sizeof(float));
   ringBuffer.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
@@ -479,136 +477,131 @@ TEST(TestAudioRingBuffer, NoCopyFloat2)
   float in[8] = {.0, .1, .2, .3, .4, .5, .6, .7};
   ringBuffer.Write(Span(in, 6));
   //  v ReadIndex
   // [x0: .0, x1: .1, x2: .2, x3: .3, x4: .4,
   //  x5: .5, x6: .0, x7: .0, x8: .0, x9: .0, x10: .0]
 
   float out[10] = {};
   float* out_ptr = out;
-  uint32_t total_frames = 3;
+  int total_frames = 3;
 
-  uint32_t rv = ringBuffer.ReadNoCopy(
+  int rv = ringBuffer.ReadNoCopy(
       [&out_ptr, &total_frames](const Span<const float>& aInBuffer) {
-        uint32_t inFramesUsed =
-            std::min<uint32_t>(total_frames, aInBuffer.Length());
+        int inFramesUsed = std::min<int>(total_frames, aInBuffer.Length());
         PodMove(out_ptr, aInBuffer.data(), inFramesUsed);
         out_ptr += inFramesUsed;
         total_frames -= inFramesUsed;
         return inFramesUsed;
       });
   //                          v ReadIndex
   // [x0: .0, x1: .1, x2: .2, x3: .3, x4: .4,
   //  x5: .5, x6: .0, x7: .0, x8: .0, x9: .0, x10: .0]
-  EXPECT_EQ(rv, 3u);
+  EXPECT_EQ(rv, 3);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 7u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 3u);
-  for (uint32_t i = 0; i < rv; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 7);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 3);
+  for (int i = 0; i < rv; ++i) {
     EXPECT_FLOAT_EQ(out[i], in[i]);
   }
 
   total_frames = 3;
   rv = ringBuffer.ReadNoCopy(
       [&out_ptr, &total_frames](const Span<const float>& aInBuffer) {
-        uint32_t inFramesUsed =
-            std::min<uint32_t>(total_frames, aInBuffer.Length());
+        int inFramesUsed = std::min<int>(total_frames, aInBuffer.Length());
         PodMove(out_ptr, aInBuffer.data(), inFramesUsed);
         out_ptr += inFramesUsed;
         total_frames -= inFramesUsed;
         return inFramesUsed;
       });
   // [x0: .0, x1: .1, x2: .2, x3: .3, x4: .4,
   //  x5: .5, x6: .0, x7: .0, x8: .0, x9: .0, x10: .0]
   //          ^ ReadIndex
-  EXPECT_EQ(rv, 3u);
+  EXPECT_EQ(rv, 3);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
-  for (uint32_t i = 0; i < rv; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
+  for (int i = 0; i < rv; ++i) {
     EXPECT_FLOAT_EQ(out[i + 3], in[i + 3]);
   }
 
   ringBuffer.Write(Span(in, 8));
   // Now the buffer contains:
   // [x0: .5, x1: .6, x2: .7, x3: .3, x4: .4,
   //  x5: .5, x6: .0, x7: .1, x8: .2, x9: .3, x10: .4
   //          ^ ReadIndex
 
   // reset the pointer before lambdas reuse
   out_ptr = out;
   total_frames = 3;
   rv = ringBuffer.ReadNoCopy(
       [&out_ptr, &total_frames](const Span<const float>& aInBuffer) {
-        uint32_t inFramesUsed =
-            std::min<uint32_t>(total_frames, aInBuffer.Length());
+        int inFramesUsed = std::min<int>(total_frames, aInBuffer.Length());
         PodMove(out_ptr, aInBuffer.data(), inFramesUsed);
         out_ptr += inFramesUsed;
         total_frames -= inFramesUsed;
         return inFramesUsed;
       });
   // Now the buffer contains:
   // [x0: .5, x1: .6, x2: .2, x3: .3, x4: .4,
   //  x5: .5, x6: .0, x7: .1, x8: .2, x9: .3, x10: .4
   //                                  ^ ReadIndex
-  EXPECT_EQ(rv, 3u);
+  EXPECT_EQ(rv, 3);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 5u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 5u);
-  for (uint32_t i = 0; i < rv; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 5);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 5);
+  for (int i = 0; i < rv; ++i) {
     EXPECT_FLOAT_EQ(out[i], in[i]);
   }
 
   total_frames = 3;
   rv = ringBuffer.ReadNoCopy(
       [&out_ptr, &total_frames](const Span<const float>& aInBuffer) {
-        uint32_t inFramesUsed =
-            std::min<uint32_t>(total_frames, aInBuffer.Length());
+        int inFramesUsed = std::min<int>(total_frames, aInBuffer.Length());
         PodMove(out_ptr, aInBuffer.data(), inFramesUsed);
         out_ptr += inFramesUsed;
         total_frames -= inFramesUsed;
         return inFramesUsed;
       });
   // Now the buffer contains:
   //          v ReadIndex
   // [x0: .5, x1: .6, x2: .7, x3: .3, x4: .4,
   //  x5: .5, x6: .0, x7: .1, x8: .2, x9: .3, x10: .4
-  EXPECT_EQ(rv, 3u);
+  EXPECT_EQ(rv, 3);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 8u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 2u);
-  for (uint32_t i = 0; i < rv; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 8);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 2);
+  for (int i = 0; i < rv; ++i) {
     EXPECT_FLOAT_EQ(out[i + 3], in[i + 3]);
   }
 
   total_frames = 3;
   rv = ringBuffer.ReadNoCopy(
       [&out_ptr, &total_frames](const Span<const float>& aInBuffer) {
-        uint32_t inFramesUsed =
-            std::min<uint32_t>(total_frames, aInBuffer.Length());
+        int inFramesUsed = std::min<int>(total_frames, aInBuffer.Length());
         PodMove(out_ptr, aInBuffer.data(), inFramesUsed);
         out_ptr += inFramesUsed;
         total_frames -= inFramesUsed;
         return inFramesUsed;
       });
   // Now the buffer contains:
   //                          v ReadIndex
   // [x0: .5, x1: .6, x2: .7, x3: .3, x4: .4,
   //  x5: .5, x6: .0, x7: .1, x8: .2, x9: .3, x10: .4
-  EXPECT_EQ(rv, 2u);
-  EXPECT_EQ(total_frames, 1u);
+  EXPECT_EQ(rv, 2);
+  EXPECT_EQ(total_frames, 1);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
-  for (uint32_t i = 0; i < rv; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
+  for (int i = 0; i < rv; ++i) {
     EXPECT_FLOAT_EQ(out[i + 6], in[i + 6]);
   }
 }
 
 TEST(TestAudioRingBuffer, NoCopyShort2)
 {
   AudioRingBuffer ringBuffer(11 * sizeof(short));
   ringBuffer.SetSampleFormat(AUDIO_FORMAT_S16);
@@ -616,270 +609,265 @@ TEST(TestAudioRingBuffer, NoCopyShort2)
   short in[8] = {0, 1, 2, 3, 4, 5, 6, 7};
   ringBuffer.Write(Span(in, 6));
   //  v ReadIndex
   // [x0: 0, x1: 1, x2: 2, x3: 3, x4: 4,
   //  x5: 5, x6: 0, x7: 0, x8: 0, x9: 0, x10: 0]
 
   short out[10] = {};
   short* out_ptr = out;
-  uint32_t total_frames = 3;
+  int total_frames = 3;
 
-  uint32_t rv = ringBuffer.ReadNoCopy(
+  int rv = ringBuffer.ReadNoCopy(
       [&out_ptr, &total_frames](const Span<const short>& aInBuffer) {
-        uint32_t inFramesUsed =
-            std::min<uint32_t>(total_frames, aInBuffer.Length());
+        int inFramesUsed = std::min<int>(total_frames, aInBuffer.Length());
         PodMove(out_ptr, aInBuffer.data(), inFramesUsed);
         out_ptr += inFramesUsed;
         total_frames -= inFramesUsed;
         return inFramesUsed;
       });
   //                       v ReadIndex
   // [x0: 0, x1: 1, x2: 2, x3: 3, x4: 4,
   //  x5: 5, x6: 0, x7: 0, x8: 0, x9: 0, x10: 0]
-  EXPECT_EQ(rv, 3u);
+  EXPECT_EQ(rv, 3);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 7u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 3u);
-  for (uint32_t i = 0; i < rv; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 7);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 3);
+  for (int i = 0; i < rv; ++i) {
     EXPECT_EQ(out[i], in[i]);
   }
 
   total_frames = 3;
   rv = ringBuffer.ReadNoCopy(
       [&out_ptr, &total_frames](const Span<const short>& aInBuffer) {
-        uint32_t inFramesUsed =
-            std::min<uint32_t>(total_frames, aInBuffer.Length());
+        int inFramesUsed = std::min<int>(total_frames, aInBuffer.Length());
         PodMove(out_ptr, aInBuffer.data(), inFramesUsed);
         out_ptr += inFramesUsed;
         total_frames -= inFramesUsed;
         return inFramesUsed;
       });
   // [x0: 0, x1: 1, x2: 2, x3: 3, x4: 4,
   //  x5: 5, x6: 0, x7: 0, x8: 0, x9: 0, x10: .0]
   //         ^ ReadIndex
-  EXPECT_EQ(rv, 3u);
+  EXPECT_EQ(rv, 3);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
-  for (uint32_t i = 0; i < rv; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
+  for (int i = 0; i < rv; ++i) {
     EXPECT_EQ(out[i + 3], in[i + 3]);
   }
 
   ringBuffer.Write(Span(in, 8));
   // Now the buffer contains:
   // [x0: 5, x1: 6, x2: 7, x3: 3, x4: 4,
   //  x5: 5, x6: 0, x7: 1, x8: 2, x9: 3, x10: 4
   //         ^ ReadIndex
 
   // reset the pointer before lambdas reuse
   out_ptr = out;
   total_frames = 3;
   rv = ringBuffer.ReadNoCopy(
       [&out_ptr, &total_frames](const Span<const short>& aInBuffer) {
-        uint32_t inFramesUsed =
-            std::min<uint32_t>(total_frames, aInBuffer.Length());
+        int inFramesUsed = std::min<int>(total_frames, aInBuffer.Length());
         PodMove(out_ptr, aInBuffer.data(), inFramesUsed);
         out_ptr += inFramesUsed;
         total_frames -= inFramesUsed;
         return inFramesUsed;
       });
   // Now the buffer contains:
   // [x0: 5, x1: 6, x2: 2, x3: 3, x4: 4,
   //  x5: 5, x6: 0, x7: 1, x8: 2, x9: 3, x10: 4
   //                              ^ ReadIndex
-  EXPECT_EQ(rv, 3u);
+  EXPECT_EQ(rv, 3);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 5u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 5u);
-  for (uint32_t i = 0; i < rv; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 5);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 5);
+  for (int i = 0; i < rv; ++i) {
     EXPECT_EQ(out[i], in[i]);
   }
 
   total_frames = 3;
   rv = ringBuffer.ReadNoCopy(
       [&out_ptr, &total_frames](const Span<const short>& aInBuffer) {
-        uint32_t inFramesUsed =
-            std::min<uint32_t>(total_frames, aInBuffer.Length());
+        int inFramesUsed = std::min<int>(total_frames, aInBuffer.Length());
         PodMove(out_ptr, aInBuffer.data(), inFramesUsed);
         out_ptr += inFramesUsed;
         total_frames -= inFramesUsed;
         return inFramesUsed;
       });
   // Now the buffer contains:
   //         v ReadIndex
   // [x0: 5, x1: 6, x2: 7, x3: 3, x4: 4,
   //  x5: 5, x6: 0, x7: 1, x8: 2, x9: 3, x10: 4
-  EXPECT_EQ(rv, 3u);
+  EXPECT_EQ(rv, 3);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 8u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 2u);
-  for (uint32_t i = 0; i < rv; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 8);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 2);
+  for (int i = 0; i < rv; ++i) {
     EXPECT_EQ(out[i + 3], in[i + 3]);
   }
 
   total_frames = 3;
   rv = ringBuffer.ReadNoCopy(
       [&out_ptr, &total_frames](const Span<const short>& aInBuffer) {
-        uint32_t inFramesUsed =
-            std::min<uint32_t>(total_frames, aInBuffer.Length());
+        int inFramesUsed = std::min<int>(total_frames, aInBuffer.Length());
         PodMove(out_ptr, aInBuffer.data(), inFramesUsed);
         out_ptr += inFramesUsed;
         total_frames -= inFramesUsed;
         return inFramesUsed;
       });
   // Now the buffer contains:
   //                       v ReadIndex
   // [x0: 5, x1: 6, x2: 7, x3: 3, x4: 4,
   //  x5: 5, x6: 0, x7: 1, x8: 2, x9: 3, x10: 4
-  EXPECT_EQ(rv, 2u);
-  EXPECT_EQ(total_frames, 1u);
+  EXPECT_EQ(rv, 2);
+  EXPECT_EQ(total_frames, 1);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
-  for (uint32_t i = 0; i < rv; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
+  for (int i = 0; i < rv; ++i) {
     EXPECT_EQ(out[i + 6], in[i + 6]);
   }
 }
 
 TEST(TestAudioRingBuffer, DiscardFloat)
 {
   AudioRingBuffer ringBuffer(11 * sizeof(float));
   ringBuffer.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
 
   float in[8] = {.0, .1, .2, .3, .4, .5, .6, .7};
   ringBuffer.Write(Span(in, 8));
 
-  uint32_t rv = ringBuffer.Discard(3);
-  EXPECT_EQ(rv, 3u);
+  int rv = ringBuffer.Discard(3);
+  EXPECT_EQ(rv, 3);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 5u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 5u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 5);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 5);
 
   float out[8] = {};
   rv = ringBuffer.Read(Span(out, 3));
-  EXPECT_EQ(rv, 3u);
+  EXPECT_EQ(rv, 3);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 8u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 2u);
-  for (uint32_t i = 0; i < rv; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 8);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 2);
+  for (int i = 0; i < rv; ++i) {
     EXPECT_FLOAT_EQ(out[i], in[i + 3]);
   }
 
   rv = ringBuffer.Discard(3);
-  EXPECT_EQ(rv, 2u);
+  EXPECT_EQ(rv, 2);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
 
   ringBuffer.WriteSilence(4);
   rv = ringBuffer.Discard(6);
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
 }
 
 TEST(TestAudioRingBuffer, DiscardShort)
 {
   AudioRingBuffer ringBuffer(11 * sizeof(short));
   ringBuffer.SetSampleFormat(AUDIO_FORMAT_S16);
 
   short in[8] = {0, 1, 2, 3, 4, 5, 6, 7};
   ringBuffer.Write(Span(in, 8));
 
-  uint32_t rv = ringBuffer.Discard(3);
-  EXPECT_EQ(rv, 3u);
+  int rv = ringBuffer.Discard(3);
+  EXPECT_EQ(rv, 3);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 5u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 5u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 5);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 5);
 
   short out[8] = {};
   rv = ringBuffer.Read(Span(out, 3));
-  EXPECT_EQ(rv, 3u);
+  EXPECT_EQ(rv, 3);
   EXPECT_TRUE(!ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 8u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 2u);
-  for (uint32_t i = 0; i < rv; ++i) {
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 8);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 2);
+  for (int i = 0; i < rv; ++i) {
     EXPECT_EQ(out[i], in[i + 3]);
   }
 
   rv = ringBuffer.Discard(3);
-  EXPECT_EQ(rv, 2u);
+  EXPECT_EQ(rv, 2);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
 
   ringBuffer.WriteSilence(4);
   rv = ringBuffer.Discard(6);
-  EXPECT_EQ(rv, 4u);
+  EXPECT_EQ(rv, 4);
   EXPECT_TRUE(ringBuffer.IsEmpty());
   EXPECT_TRUE(!ringBuffer.IsFull());
-  EXPECT_EQ(ringBuffer.AvailableWrite(), 10u);
-  EXPECT_EQ(ringBuffer.AvailableRead(), 0u);
+  EXPECT_EQ(ringBuffer.AvailableWrite(), 10);
+  EXPECT_EQ(ringBuffer.AvailableRead(), 0);
 }
 
 TEST(TestRingBuffer, WriteFromRing1)
 {
   AudioRingBuffer ringBuffer1(11 * sizeof(float));
   ringBuffer1.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
   AudioRingBuffer ringBuffer2(11 * sizeof(float));
   ringBuffer2.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
 
   float in[4] = {.1, .2, .3, .4};
-  uint32_t rv = ringBuffer1.Write(Span<const float>(in, 4));
-  EXPECT_EQ(rv, 4u);
+  int rv = ringBuffer1.Write(Span<const float>(in, 4));
+  EXPECT_EQ(rv, 4);
 
-  EXPECT_EQ(ringBuffer2.AvailableRead(), 0u);
+  EXPECT_EQ(ringBuffer2.AvailableRead(), 0);
   rv = ringBuffer2.Write(ringBuffer1, 4);
-  EXPECT_EQ(rv, 4u);
-  EXPECT_EQ(ringBuffer2.AvailableRead(), 4u);
+  EXPECT_EQ(rv, 4);
+  EXPECT_EQ(ringBuffer2.AvailableRead(), 4);
 
   float out[4] = {};
   rv = ringBuffer2.Read(Span<float>(out, 4));
-  EXPECT_EQ(rv, 4u);
-  for (uint32_t i = 0; i < 4; ++i) {
+  EXPECT_EQ(rv, 4);
+  for (int i = 0; i < 4; ++i) {
     EXPECT_FLOAT_EQ(in[i], out[i]);
   }
 }
 
 TEST(TestRingBuffer, WriteFromRing2)
 {
   AudioRingBuffer ringBuffer1(11 * sizeof(float));
   ringBuffer1.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
   AudioRingBuffer ringBuffer2(11 * sizeof(float));
   ringBuffer2.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
 
   // Advance the index
   ringBuffer2.WriteSilence(8);
   ringBuffer2.Clear();
 
   float in[4] = {.1, .2, .3, .4};
-  uint32_t rv = ringBuffer1.Write(Span<const float>(in, 4));
-  EXPECT_EQ(rv, 4u);
+  int rv = ringBuffer1.Write(Span<const float>(in, 4));
+  EXPECT_EQ(rv, 4);
   rv = ringBuffer2.Write(ringBuffer1, 4);
-  EXPECT_EQ(rv, 4u);
-  EXPECT_EQ(ringBuffer2.AvailableRead(), 4u);
+  EXPECT_EQ(rv, 4);
+  EXPECT_EQ(ringBuffer2.AvailableRead(), 4);
 
   float out[4] = {};
   rv = ringBuffer2.Read(Span<float>(out, 4));
-  EXPECT_EQ(rv, 4u);
-  for (uint32_t i = 0; i < 4; ++i) {
+  EXPECT_EQ(rv, 4);
+  for (int i = 0; i < 4; ++i) {
     EXPECT_FLOAT_EQ(in[i], out[i]);
   }
 }
 
 TEST(TestRingBuffer, WriteFromRing3)
 {
   AudioRingBuffer ringBuffer1(11 * sizeof(float));
   ringBuffer1.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
@@ -888,103 +876,103 @@ TEST(TestRingBuffer, WriteFromRing3)
 
   // Advance the index
   ringBuffer2.WriteSilence(8);
   ringBuffer2.Clear();
   ringBuffer2.WriteSilence(4);
   ringBuffer2.Clear();
 
   float in[4] = {.1, .2, .3, .4};
-  uint32_t rv = ringBuffer1.Write(Span<const float>(in, 4));
-  EXPECT_EQ(rv, 4u);
+  int rv = ringBuffer1.Write(Span<const float>(in, 4));
+  EXPECT_EQ(rv, 4);
   rv = ringBuffer2.Write(ringBuffer1, 4);
-  EXPECT_EQ(rv, 4u);
-  EXPECT_EQ(ringBuffer2.AvailableRead(), 4u);
+  EXPECT_EQ(rv, 4);
+  EXPECT_EQ(ringBuffer2.AvailableRead(), 4);
 
   float out[4] = {};
   rv = ringBuffer2.Read(Span<float>(out, 4));
-  EXPECT_EQ(rv, 4u);
-  for (uint32_t i = 0; i < 4; ++i) {
+  EXPECT_EQ(rv, 4);
+  for (int i = 0; i < 4; ++i) {
     EXPECT_FLOAT_EQ(in[i], out[i]);
   }
 }
 
 TEST(TestAudioRingBuffer, WriteFromRingShort)
 {
   AudioRingBuffer ringBuffer1(11 * sizeof(short));
   ringBuffer1.SetSampleFormat(AUDIO_FORMAT_S16);
 
   short in[8] = {0, 1, 2, 3, 4, 5, 6, 7};
-  uint32_t rv = ringBuffer1.Write(Span(in, 8));
-  EXPECT_EQ(rv, 8u);
+  int rv = ringBuffer1.Write(Span(in, 8));
+  EXPECT_EQ(rv, 8);
 
   AudioRingBuffer ringBuffer2(11 * sizeof(short));
   ringBuffer2.SetSampleFormat(AUDIO_FORMAT_S16);
 
   rv = ringBuffer2.Write(ringBuffer1, 4);
-  EXPECT_EQ(rv, 4u);
-  EXPECT_EQ(ringBuffer2.AvailableRead(), 4u);
-  EXPECT_EQ(ringBuffer1.AvailableRead(), 8u);
+  EXPECT_EQ(rv, 4);
+  EXPECT_EQ(ringBuffer2.AvailableRead(), 4);
+  EXPECT_EQ(ringBuffer1.AvailableRead(), 8);
 
   short out[4] = {};
   rv = ringBuffer2.Read(Span(out, 4));
-  for (uint32_t i = 0; i < rv; ++i) {
+  for (int i = 0; i < rv; ++i) {
     EXPECT_EQ(out[i], in[i]);
   }
 
   rv = ringBuffer2.Write(ringBuffer1, 4);
-  EXPECT_EQ(rv, 4u);
-  EXPECT_EQ(ringBuffer2.AvailableRead(), 4u);
-  EXPECT_EQ(ringBuffer1.AvailableRead(), 8u);
+  EXPECT_EQ(rv, 4);
+  EXPECT_EQ(ringBuffer2.AvailableRead(), 4);
+  EXPECT_EQ(ringBuffer1.AvailableRead(), 8);
 
   ringBuffer1.Discard(4);
   rv = ringBuffer2.Write(ringBuffer1, 4);
-  EXPECT_EQ(rv, 4u);
-  EXPECT_EQ(ringBuffer2.AvailableRead(), 8u);
-  EXPECT_EQ(ringBuffer1.AvailableRead(), 4u);
+  EXPECT_EQ(rv, 4);
+  EXPECT_EQ(ringBuffer2.AvailableRead(), 8);
+  EXPECT_EQ(ringBuffer1.AvailableRead(), 4);
 
   short out2[8] = {};
   rv = ringBuffer2.Read(Span(out2, 8));
-  for (uint32_t i = 0; i < rv; ++i) {
+  for (int i = 0; i < rv; ++i) {
     EXPECT_EQ(out2[i], in[i]);
   }
 }
 
 TEST(TestAudioRingBuffer, WriteFromRingFloat)
 {
   AudioRingBuffer ringBuffer1(11 * sizeof(float));
   ringBuffer1.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
 
   float in[8] = {.0, .1, .2, .3, .4, .5, .6, .7};
-  uint32_t rv = ringBuffer1.Write(Span(in, 8));
-  EXPECT_EQ(rv, 8u);
+  int rv = ringBuffer1.Write(Span(in, 8));
+  EXPECT_EQ(rv, 8);
 
   AudioRingBuffer ringBuffer2(11 * sizeof(float));
   ringBuffer2.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
 
   rv = ringBuffer2.Write(ringBuffer1, 4);
-  EXPECT_EQ(rv, 4u);
-  EXPECT_EQ(ringBuffer2.AvailableRead(), 4u);
-  EXPECT_EQ(ringBuffer1.AvailableRead(), 8u);
+  EXPECT_EQ(rv, 4);
+  EXPECT_EQ(ringBuffer2.AvailableRead(), 4);
+  EXPECT_EQ(ringBuffer1.AvailableRead(), 8);
 
   float out[4] = {};
   rv = ringBuffer2.Read(Span(out, 4));
-  for (uint32_t i = 0; i < rv; ++i) {
+  for (int i = 0; i < rv; ++i) {
     EXPECT_FLOAT_EQ(out[i], in[i]);
   }
 
   rv = ringBuffer2.Write(ringBuffer1, 4);
-  EXPECT_EQ(rv, 4u);
-  EXPECT_EQ(ringBuffer2.AvailableRead(), 4u);
-  EXPECT_EQ(ringBuffer1.AvailableRead(), 8u);
+  EXPECT_EQ(rv, 4);
+  EXPECT_EQ(ringBuffer2.AvailableRead(), 4);
+  EXPECT_EQ(ringBuffer1.AvailableRead(), 8);
 
   ringBuffer1.Discard(4);
   rv = ringBuffer2.Write(ringBuffer1, 4);
-  EXPECT_EQ(rv, 4u);
-  EXPECT_EQ(ringBuffer2.AvailableRead(), 8u);
-  EXPECT_EQ(ringBuffer1.AvailableRead(), 4u);
+  EXPECT_EQ(rv, 4);
+  EXPECT_EQ(ringBuffer2.AvailableRead(), 8);
+  EXPECT_EQ(ringBuffer1.AvailableRead(), 4);
 
   float out2[8] = {};
   rv = ringBuffer2.Read(Span(out2, 8));
-  for (uint32_t i = 0; i < rv; ++i) {
+  for (int i = 0; i < rv; ++i) {
     EXPECT_FLOAT_EQ(out2[i], in[i]);
   }
 }
--- a/dom/media/gtest/TestAudioTrackEncoder.cpp
+++ b/dom/media/gtest/TestAudioTrackEncoder.cpp
@@ -2,17 +2,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gtest/gtest.h"
 #include "OpusTrackEncoder.h"
 
 #include "AudioGenerator.h"
-#include "AudioSampleFormat.h"
 
 using namespace mozilla;
 
 class TestOpusTrackEncoder : public OpusTrackEncoder {
  public:
   TestOpusTrackEncoder() : OpusTrackEncoder(90000) {}
 
   // Return true if it has successfully initialized the Opus encoder.
@@ -98,57 +97,57 @@ TEST(OpusAudioTrackEncoder, Init)
     encoder.TryInit(segment, segment.GetDuration());
     EXPECT_FALSE(encoder.IsInitialized());
   }
 
   {
     // For non-null segments we should init immediately
     OpusTrackEncoder encoder(48000);
     AudioSegment segment;
-    AudioGenerator<AudioDataValue> generator(2, 48000);
+    AudioGenerator generator(2, 48000);
     generator.Generate(segment, 1);
     encoder.TryInit(segment, segment.GetDuration());
     EXPECT_TRUE(encoder.IsInitialized());
   }
 
   {
     // Test low sample rate bound
     OpusTrackEncoder encoder(7999);
     AudioSegment segment;
-    AudioGenerator<AudioDataValue> generator(2, 7999);
+    AudioGenerator generator(2, 7999);
     generator.Generate(segment, 1);
     encoder.TryInit(segment, segment.GetDuration());
     EXPECT_FALSE(encoder.IsInitialized());
   }
 
   {
     // Test low sample rate bound
     OpusTrackEncoder encoder(8000);
     AudioSegment segment;
-    AudioGenerator<AudioDataValue> generator(2, 8000);
+    AudioGenerator generator(2, 8000);
     generator.Generate(segment, 1);
     encoder.TryInit(segment, segment.GetDuration());
     EXPECT_TRUE(encoder.IsInitialized());
   }
 
   {
     // Test high sample rate bound
     OpusTrackEncoder encoder(192001);
     AudioSegment segment;
-    AudioGenerator<AudioDataValue> generator(2, 192001);
+    AudioGenerator generator(2, 192001);
     generator.Generate(segment, 1);
     encoder.TryInit(segment, segment.GetDuration());
     EXPECT_FALSE(encoder.IsInitialized());
   }
 
   {
     // Test high sample rate bound
     OpusTrackEncoder encoder(192000);
     AudioSegment segment;
-    AudioGenerator<AudioDataValue> generator(2, 192000);
+    AudioGenerator generator(2, 192000);
     generator.Generate(segment, 1);
     encoder.TryInit(segment, segment.GetDuration());
     EXPECT_TRUE(encoder.IsInitialized());
   }
 }
 
 static int TestOpusResampler(int aChannels, int aSamplingRate) {
   TestOpusTrackEncoder encoder;
@@ -190,17 +189,17 @@ TEST(OpusAudioTrackEncoder, FetchMetadat
 TEST(OpusAudioTrackEncoder, FrameEncode)
 {
   const int32_t channels = 1;
   const int32_t sampleRate = 44100;
   TestOpusTrackEncoder encoder;
   EXPECT_TRUE(encoder.TestOpusRawCreation(channels, sampleRate));
 
   // Generate five seconds of raw audio data.
-  AudioGenerator<AudioDataValue> generator(channels, sampleRate);
+  AudioGenerator generator(channels, sampleRate);
   AudioSegment segment;
   const int32_t samples = sampleRate * 5;
   generator.Generate(segment, samples);
 
   encoder.AppendAudioSegment(std::move(segment));
 
   nsTArray<RefPtr<EncodedFrame>> frames;
   EXPECT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(frames)));
--- a/dom/media/gtest/TestAudioTrackGraph.cpp
+++ b/dom/media/gtest/TestAudioTrackGraph.cpp
@@ -4,140 +4,18 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MediaTrackGraphImpl.h"
 
 #include "gmock/gmock.h"
 #include "gtest/gtest-printers.h"
 #include "gtest/gtest.h"
 
-#include "CrossGraphPort.h"
-#include "MediaEngineWebRTCAudio.h"
+#include "GMPTestMonitor.h"
 #include "MockCubeb.h"
-#include "mozilla/Preferences.h"
-
-#define DRIFT_BUFFERING_PREF "media.clockdrift.buffering"
-
-namespace {
-/**
- * Waits for an occurrence of aEvent on the current thread (by blocking it,
- * except tasks added to the event loop may run) and returns the event's
- * templated value, if it's non-void.
- *
- * The caller must be wary of eventloop issues, in
- * particular cases where we rely on a stable state runnable, but there is never
- * a task to trigger stable state. In such cases it is the responsibility of the
- * caller to create the needed tasks, as JS would. A noteworthy API that relies
- * on stable state is MediaTrackGraph::GetInstance.
- */
-template <typename T>
-T WaitFor(MediaEventSource<T>& aEvent) {
-  Maybe<T> value;
-  MediaEventListener listener = aEvent.Connect(
-      AbstractThread::GetCurrent(), [&](T aValue) { value = Some(aValue); });
-  SpinEventLoopUntil<ProcessFailureBehavior::IgnoreAndContinue>(
-      [&] { return value.isSome(); });
-  listener.Disconnect();
-  return value.value();
-}
-
-/**
- * Specialization of WaitFor<T> for void.
- */
-void WaitFor(MediaEventSource<void>& aEvent) {
-  bool done = false;
-  MediaEventListener listener =
-      aEvent.Connect(AbstractThread::GetCurrent(), [&] { done = true; });
-  SpinEventLoopUntil<ProcessFailureBehavior::IgnoreAndContinue>(
-      [&] { return done; });
-  listener.Disconnect();
-}
-
-/**
- * Variant of WaitFor that blocks the caller until a MozPromise has either been
- * resolved or rejected.
- */
-template <typename R, typename E, bool Exc>
-Result<R, E> WaitFor(const RefPtr<MozPromise<R, E, Exc>>& aPromise) {
-  Maybe<Result<R, E>> result;
-  aPromise->Then(
-      GetCurrentSerialEventTarget(), __func__,
-      [&](R aResult) { result = Some(Result<R, E>(aResult)); },
-      [&](E aError) { result = Some(Result<R, E>(aError)); });
-  SpinEventLoopUntil<ProcessFailureBehavior::IgnoreAndContinue>(
-      [&] { return result.isSome(); });
-  return result.extract();
-}
-
-/**
- * A variation of WaitFor that takes a callback to be called each time aEvent is
- * raised. Blocks the caller until the callback function returns true.
- */
-template <typename T, typename CallbackFunction>
-void WaitUntil(MediaEventSource<T>& aEvent, const CallbackFunction& aF) {
-  bool done = false;
-  MediaEventListener listener =
-      aEvent.Connect(AbstractThread::GetCurrent(), [&](T aValue) {
-        if (!done) {
-          done = aF(aValue);
-        }
-      });
-  SpinEventLoopUntil<ProcessFailureBehavior::IgnoreAndContinue>(
-      [&] { return done; });
-  listener.Disconnect();
-}
-
-// Short-hand for InvokeAsync on the current thread.
-#define Invoke(f) InvokeAsync(GetCurrentSerialEventTarget(), __func__, f)
-
-// Short-hand for DispatchToCurrentThread with a function.
-#define DispatchFunction(f) \
-  NS_DispatchToCurrentThread(NS_NewRunnableFunction(__func__, f))
-
-// Short-hand for DispatchToCurrentThread with a method with arguments
-#define DispatchMethod(t, m, args...) \
-  NS_DispatchToCurrentThread(NewRunnableMethod(__func__, t, m, ##args))
-
-/*
- * Common ControlMessages
- */
-class StartInputProcessing : public ControlMessage {
-  RefPtr<AudioInputProcessing> mInputProcessing;
-
- public:
-  explicit StartInputProcessing(AudioInputProcessing* aInputProcessing)
-      : ControlMessage(nullptr), mInputProcessing(aInputProcessing) {}
-  void Run() override { mInputProcessing->Start(); }
-};
-
-class StopInputProcessing : public ControlMessage {
-  RefPtr<AudioInputProcessing> mInputProcessing;
-
- public:
-  explicit StopInputProcessing(AudioInputProcessing* aInputProcessing)
-      : ControlMessage(nullptr), mInputProcessing(aInputProcessing) {}
-  void Run() override { mInputProcessing->Stop(); }
-};
-
-}  // namespace
-
-/*
- * The set of tests here are a bit special. In part because they're async and
- * depends on the graph thread to function. In part because they depend on main
- * thread stable state to send messages to the graph.
- *
- * Any message sent from the main thread to the graph through the graph's
- * various APIs are scheduled to run in stable state. Stable state occurs after
- * a task in the main thread eventloop has run to completion.
- *
- * Since gtests are generally sync and on main thread, calling into the graph
- * may schedule a stable state runnable but with no task in the eventloop to
- * trigger stable state. Therefore care must be taken to always call into the
- * graph from a task, typically via InvokeAsync or a dispatch to main thread.
- */
 
 TEST(TestAudioTrackGraph, DifferentDeviceIDs)
 {
   MockCubeb* cubeb = new MockCubeb();
   CubebUtils::ForceSetCubebContext(cubeb->AsCubebContext());
 
   MediaTrackGraph* g1 = MediaTrackGraph::GetInstance(
       MediaTrackGraph::AUDIO_THREAD_DRIVER, /*window*/ nullptr,
@@ -154,344 +32,157 @@ TEST(TestAudioTrackGraph, DifferentDevic
       MediaTrackGraph::REQUEST_DEFAULT_SAMPLE_RATE,
       /*OutputDeviceID*/ nullptr);
 
   MediaTrackGraph* g2_2 = MediaTrackGraph::GetInstance(
       MediaTrackGraph::AUDIO_THREAD_DRIVER, /*window*/ nullptr,
       MediaTrackGraph::REQUEST_DEFAULT_SAMPLE_RATE,
       /*OutputDeviceID*/ reinterpret_cast<cubeb_devid>(1));
 
-  EXPECT_NE(g1, g2) << "Different graphs due to different device ids";
+  EXPECT_NE(g1, g2) << "Different graphs have due to different device ids";
   EXPECT_EQ(g1, g1_2) << "Same graphs for same device ids";
   EXPECT_EQ(g2, g2_2) << "Same graphs for same device ids";
 
-  for (MediaTrackGraph* g : {g1, g2}) {
-    // Dummy track to make graph rolling. Add it and remove it to remove the
-    // graph from the global hash table and let it shutdown.
+  // Dummy track to make graph rolling. Add it and remove it to remove the
+  // graph from the global hash table and let it shutdown.
+  RefPtr<SourceMediaTrack> dummySource1 =
+      g1->CreateSourceTrack(MediaSegment::AUDIO);
+  RefPtr<SourceMediaTrack> dummySource2 =
+      g2->CreateSourceTrack(MediaSegment::AUDIO);
+
+  // Use a test monitor and a counter to wait for the current Graphs. It will
+  // wait for the Graphs to init and shutting down before the test finish.
+  // Otherwise, the workflow of the current graphs might affect the following
+  // tests (cubeb is a single instance process-wide).
+  GMPTestMonitor testMonitor;
+  Atomic<int> counter{0};
 
-    using SourceTrackPromise = MozPromise<SourceMediaTrack*, nsresult, true>;
-    auto p = Invoke([g] {
-      return SourceTrackPromise::CreateAndResolve(
-          g->CreateSourceTrack(MediaSegment::AUDIO), __func__);
-    });
+  /* Use a ControlMessage to signal that the Graph has requested shutdown. */
+  class Message : public ControlMessage {
+   public:
+    explicit Message(MediaTrack* aTrack) : ControlMessage(aTrack) {}
+    void Run() override {
+      MOZ_ASSERT(mTrack->GraphImpl()->CurrentDriver()->AsAudioCallbackDriver());
+      if (++(*mCounter) == 2) {
+        mTestMonitor->SetFinished();
+      }
+    }
+    void RunDuringShutdown() override {
+      // During shutdown we still want the listener's NotifyRemoved to be
+      // called, since not doing that might block shutdown of other modules.
+      Run();
+    }
+    GMPTestMonitor* mTestMonitor = nullptr;
+    Atomic<int>* mCounter = nullptr;
+  };
 
-    WaitFor(cubeb->StreamInitEvent());
-    RefPtr<SourceMediaTrack> dummySource = WaitFor(p).unwrap();
+  UniquePtr<Message> message1 = MakeUnique<Message>(dummySource1);
+  message1->mTestMonitor = &testMonitor;
+  message1->mCounter = &counter;
+  dummySource1->GraphImpl()->AppendMessage(std::move(message1));
 
-    DispatchMethod(dummySource, &SourceMediaTrack::Destroy);
+  UniquePtr<Message> message2 = MakeUnique<Message>(dummySource2);
+  message2->mTestMonitor = &testMonitor;
+  message2->mCounter = &counter;
+  dummySource2->GraphImpl()->AppendMessage(std::move(message2));
 
-    WaitFor(cubeb->StreamDestroyEvent());
-  }
+  dummySource1->Destroy();
+  dummySource2->Destroy();
+
+  testMonitor.AwaitFinished();
 }
 
 TEST(TestAudioTrackGraph, SetOutputDeviceID)
 {
   MockCubeb* cubeb = new MockCubeb();
   CubebUtils::ForceSetCubebContext(cubeb->AsCubebContext());
 
+  EXPECT_EQ(cubeb->CurrentStream(), nullptr)
+      << "Cubeb stream has not been initialized yet";
+
   // Set the output device id in GetInstance method confirm that it is the one
   // used in cubeb_stream_init.
   MediaTrackGraph* graph = MediaTrackGraph::GetInstance(
       MediaTrackGraph::AUDIO_THREAD_DRIVER, /*window*/ nullptr,
       MediaTrackGraph::REQUEST_DEFAULT_SAMPLE_RATE,
       /*OutputDeviceID*/ reinterpret_cast<cubeb_devid>(2));
 
   // Dummy track to make graph rolling. Add it and remove it to remove the
   // graph from the global hash table and let it shutdown.
-  RefPtr<SourceMediaTrack> dummySource;
-  DispatchFunction(
-      [&] { dummySource = graph->CreateSourceTrack(MediaSegment::AUDIO); });
-
-  MockCubebStream* stream = WaitFor(cubeb->StreamInitEvent());
+  RefPtr<SourceMediaTrack> dummySource =
+      graph->CreateSourceTrack(MediaSegment::AUDIO);
 
-  EXPECT_EQ(stream->GetOutputDeviceID(), reinterpret_cast<cubeb_devid>(2))
-      << "After init confirm the expected output device id";
+  GMPTestMonitor mon;
+  RefPtr<GenericPromise> p = graph->NotifyWhenDeviceStarted(dummySource);
+  p->Then(GetMainThreadSerialEventTarget(), __func__,
+          [&mon, cubeb, dummySource]() {
+            EXPECT_EQ(cubeb->CurrentStream()->GetOutputDeviceID(),
+                      reinterpret_cast<cubeb_devid>(2))
+                << "After init confirm the expected output device id";
+            // Test has finished, destroy the track to shutdown the MTG.
+            dummySource->Destroy();
+            mon.SetFinished();
+          });
 
-  // Test has finished, destroy the track to shutdown the MTG.
-  DispatchMethod(dummySource, &SourceMediaTrack::Destroy);
-  WaitFor(cubeb->StreamDestroyEvent());
+  mon.AwaitFinished();
 }
 
 TEST(TestAudioTrackGraph, NotifyDeviceStarted)
 {
   MockCubeb* cubeb = new MockCubeb();
   CubebUtils::ForceSetCubebContext(cubeb->AsCubebContext());
 
   MediaTrackGraph* graph = MediaTrackGraph::GetInstance(
       MediaTrackGraph::AUDIO_THREAD_DRIVER, /*window*/ nullptr,
       MediaTrackGraph::REQUEST_DEFAULT_SAMPLE_RATE, nullptr);
 
-  RefPtr<SourceMediaTrack> dummySource;
-  Unused << WaitFor(Invoke([&] {
-    // Dummy track to make graph rolling. Add it and remove it to remove the
-    // graph from the global hash table and let it shutdown.
-    dummySource = graph->CreateSourceTrack(MediaSegment::AUDIO);
+  // Dummy track to make graph rolling. Add it and remove it to remove the
+  // graph from the global hash table and let it shutdown.
+  RefPtr<SourceMediaTrack> dummySource =
+      graph->CreateSourceTrack(MediaSegment::AUDIO);
 
-    return graph->NotifyWhenDeviceStarted(dummySource);
-  }));
+  RefPtr<GenericPromise> p = graph->NotifyWhenDeviceStarted(dummySource);
 
-  {
-    MediaTrackGraphImpl* graph = dummySource->GraphImpl();
-    MonitorAutoLock lock(graph->GetMonitor());
-    EXPECT_TRUE(graph->CurrentDriver()->AsAudioCallbackDriver());
-    EXPECT_TRUE(graph->CurrentDriver()->ThreadRunning());
-  }
+  GMPTestMonitor mon;
+  p->Then(GetMainThreadSerialEventTarget(), __func__, [&mon, dummySource]() {
+    {
+      MediaTrackGraphImpl* graph = dummySource->GraphImpl();
+      MonitorAutoLock lock(graph->GetMonitor());
+      EXPECT_TRUE(graph->CurrentDriver()->AsAudioCallbackDriver());
+      EXPECT_TRUE(graph->CurrentDriver()->ThreadRunning());
+    }
+    // Test has finished, destroy the track to shutdown the MTG.
+    dummySource->Destroy();
+    mon.SetFinished();
+  });
 
-  // Test has finished, destroy the track to shutdown the MTG.
-  DispatchMethod(dummySource, &SourceMediaTrack::Destroy);
-  WaitFor(cubeb->StreamDestroyEvent());
+  mon.AwaitFinished();
 }
 
 TEST(TestAudioTrackGraph, ErrorStateCrash)
 {
   MockCubeb* cubeb = new MockCubeb();
   CubebUtils::ForceSetCubebContext(cubeb->AsCubebContext());
 
   MediaTrackGraph* graph = MediaTrackGraph::GetInstance(
       MediaTrackGraph::AUDIO_THREAD_DRIVER, /*window*/ nullptr,
       MediaTrackGraph::REQUEST_DEFAULT_SAMPLE_RATE, nullptr);
 
-  RefPtr<SourceMediaTrack> dummySource;
-  auto started = Invoke([&] {
-    // Dummy track to make graph rolling. Add it and remove it to remove the
-    // graph from the global hash table and let it shutdown.
-    dummySource = graph->CreateSourceTrack(MediaSegment::AUDIO);
-    return graph->NotifyWhenDeviceStarted(dummySource);
-  });
-
-  MockCubebStream* stream = WaitFor(cubeb->StreamInitEvent());
-  Result<bool, nsresult> rv = WaitFor(started);
-  EXPECT_TRUE(rv.unwrapOr(false));
-
-  // Force a cubeb state_callback error and see that we don't crash.
-  DispatchFunction([&] { stream->ForceError(); });
-  WaitFor(stream->ErrorForcedEvent());
-
-  // Test has finished, destroy the track to shut down the MTG.
-  DispatchMethod(dummySource, &SourceMediaTrack::Destroy);
-  WaitFor(cubeb->StreamDestroyEvent());
-}
-
-TEST(TestAudioTrackGraph, SourceTrack)
-{
-  MockCubeb* cubeb = new MockCubeb();
-  CubebUtils::ForceSetCubebContext(cubeb->AsCubebContext());
-
-  MediaTrackGraph* graph = MediaTrackGraph::GetInstance(
-      MediaTrackGraph::AUDIO_THREAD_DRIVER, /*window*/ nullptr,
-      MediaTrackGraph::REQUEST_DEFAULT_SAMPLE_RATE, nullptr);
-
-  RefPtr<SourceMediaTrack> sourceTrack;
-  RefPtr<ProcessedMediaTrack> outputTrack;
-  RefPtr<MediaInputPort> port;
-  Unused << WaitFor(Invoke([&] {
-    sourceTrack = graph->CreateSourceTrack(MediaSegment::AUDIO);
-    outputTrack = graph->CreateForwardedInputTrack(MediaSegment::AUDIO);
-    port = outputTrack->AllocateInputPort(sourceTrack);
-
-    outputTrack->AddAudioOutput(reinterpret_cast<void*>(1));
-
-    return graph->NotifyWhenDeviceStarted(sourceTrack);
-  }));
-
-  RefPtr<AudioInputProcessing> listener;
-  RefPtr<AudioInputProcessingPullListener> pullListener;
-  DispatchFunction([&] {
-    /* Primary graph: Open Audio Input through SourceMediaTrack */
-    listener = new AudioInputProcessing(2, sourceTrack, PRINCIPAL_HANDLE_NONE);
-    listener->SetPassThrough(true);
-
-    pullListener = new AudioInputProcessingPullListener(listener);
-
-    sourceTrack->AddListener(pullListener);
+  // Dummy track to make graph rolling. Add it and remove it to remove the
+  // graph from the global hash table and let it shutdown.
+  RefPtr<SourceMediaTrack> dummySource =
+      graph->CreateSourceTrack(MediaSegment::AUDIO);
 
-    sourceTrack->GraphImpl()->AppendMessage(
-        MakeUnique<StartInputProcessing>(listener));
-    sourceTrack->SetPullingEnabled(true);
-    // Device id does not matter. Ignore.
-    sourceTrack->OpenAudioInput((void*)1, listener);
-  });
-
-  auto p = Invoke([&] { return graph->NotifyWhenDeviceStarted(sourceTrack); });
-  MockCubebStream* stream = WaitFor(cubeb->StreamInitEvent());
-  EXPECT_TRUE(stream->mHasInput);
-  Unused << WaitFor(p);
-
-  // Wait for a second worth of audio data.
-  cubeb->GoFaster();
-  uint32_t totalFrames = 0;
-  WaitUntil(stream->FramesProcessedEvent(), [&](uint32_t aFrames) {
-    totalFrames += aFrames;
-    return totalFrames > static_cast<uint32_t>(graph->GraphRate());
-  });
-  cubeb->DontGoFaster();
+  RefPtr<GenericPromise> p = graph->NotifyWhenDeviceStarted(dummySource);
 
-  // Clean up.
-  DispatchFunction([&] {
-    outputTrack->RemoveAudioOutput((void*)1);
-    outputTrack->Destroy();
-    port->Destroy();
-    sourceTrack->GraphImpl()->AppendMessage(
-        MakeUnique<StopInputProcessing>(listener));
-    sourceTrack->RemoveListener(pullListener);
-    sourceTrack->SetPullingEnabled(false);
-    Maybe<CubebUtils::AudioDeviceID> id =
-        Some(reinterpret_cast<CubebUtils::AudioDeviceID>(1));
-    sourceTrack->CloseAudioInput(id);
-    sourceTrack->Destroy();
-  });
-
-  uint32_t inputRate = stream->InputSampleRate();
-  uint32_t inputFrequency = stream->InputFrequency();
-  uint64_t preSilenceSamples;
-  uint32_t estimatedFreq;
-  uint32_t nrDiscontinuities;
-  Tie(preSilenceSamples, estimatedFreq, nrDiscontinuities) =
-      WaitFor(stream->OutputVerificationEvent());
-
-  EXPECT_EQ(estimatedFreq, inputFrequency);
-  // TODO (Bug 1656438) - this is intermittent
-  // EXPECT_GE(preSilenceSamples, inputRate / 100 /* 10 ms */);
-  // Waveform may start after the beginning. In this case, there is a gap
-  // at the beginning and the end which is counted as discontinuity.
-  EXPECT_GE(nrDiscontinuities, 0U);
-  EXPECT_LE(nrDiscontinuities, 2U);
-}
-
-void TestCrossGraphPort(uint32_t aInputRate, uint32_t aOutputRate,
-                        float aDriftFactor) {
-  std::cerr << "TestCrossGraphPort input: " << aInputRate
-            << ", output: " << aOutputRate << ", driftFactor: " << aDriftFactor
-            << std::endl;
-
-  MockCubeb* cubeb = new MockCubeb();
-  CubebUtils::ForceSetCubebContext(cubeb->AsCubebContext());
-
-  /* Primary graph: Create the graph and a SourceMediaTrack. */
-  MediaTrackGraph* primary =
-      MediaTrackGraph::GetInstance(MediaTrackGraph::AUDIO_THREAD_DRIVER,
-                                   /*window*/ nullptr, aInputRate, nullptr);
+  GMPTestMonitor mon;
 
-  RefPtr<SourceMediaTrack> sourceTrack;
-  DispatchFunction(
-      [&] { sourceTrack = primary->CreateSourceTrack(MediaSegment::AUDIO); });
-  WaitFor(cubeb->StreamInitEvent());
-
-  /* Partner graph: Create graph and the CrossGraphReceiver. */
-  MediaTrackGraph* partner = MediaTrackGraph::GetInstance(
-      MediaTrackGraph::AUDIO_THREAD_DRIVER, /*window*/ nullptr, aOutputRate,
-      /*OutputDeviceID*/ reinterpret_cast<cubeb_devid>(1));
-
-  RefPtr<CrossGraphReceiver> receiver;
-  RefPtr<CrossGraphTransmitter> transmitter;
-  RefPtr<MediaInputPort> port;
-  RefPtr<AudioInputProcessing> listener;
-  RefPtr<AudioInputProcessingPullListener> pullListener;
-  DispatchFunction([&] {
-    receiver = partner->CreateCrossGraphReceiver(primary->GraphRate());
-
-    /* Primary graph: Create CrossGraphTransmitter */
-    transmitter = primary->CreateCrossGraphTransmitter(receiver);
-
-    /* How the source track connects to another ProcessedMediaTrack.
-     * Check in MediaManager how it is connected to AudioStreamTrack. */
-    port = transmitter->AllocateInputPort(sourceTrack);
-    receiver->AddAudioOutput((void*)1);
-
-    /* Primary graph: Open Audio Input through SourceMediaTrack */
-    listener = new AudioInputProcessing(2, sourceTrack, PRINCIPAL_HANDLE_NONE);
-    listener->SetPassThrough(true);
-
-    pullListener = new AudioInputProcessingPullListener(listener);
-
-    sourceTrack->AddListener(pullListener);
-
-    sourceTrack->GraphImpl()->AppendMessage(
-        MakeUnique<StartInputProcessing>(listener));
-    sourceTrack->SetPullingEnabled(true);
-    // Device id does not matter. Ignore.
-    sourceTrack->OpenAudioInput((void*)1, listener);
-  });
-
-  MockCubebStream* inputStream = nullptr;
-  MockCubebStream* partnerStream = nullptr;
-  // Wait for the streams to be created.
-  WaitUntil(cubeb->StreamInitEvent(), [&](MockCubebStream* aStream) {
-    if (aStream->mHasInput) {
-      inputStream = aStream;
-    } else {
-      partnerStream = aStream;
-    }
-    return inputStream && partnerStream;
-  });
-
-  partnerStream->SetDriftFactor(aDriftFactor);
+  p->Then(GetMainThreadSerialEventTarget(), __func__,
+          [&mon, dummySource, cubeb]() {
+            cubeb->CurrentStream()->ForceError();
+            std::this_thread::sleep_for(std::chrono::milliseconds(50));
+            // Test has finished, destroy the track to shutdown the MTG.
+            dummySource->Destroy();
+            mon.SetFinished();
+          });
 
-  cubeb->GoFaster();
-  // Wait for 3s worth of audio data on the receiver stream.
-  uint32_t totalFrames = 0;
-  WaitUntil(partnerStream->FramesProcessedEvent(), [&](uint32_t aFrames) {
-    totalFrames += aFrames;
-    return totalFrames > static_cast<uint32_t>(partner->GraphRate() * 3);
-  });
-  cubeb->DontGoFaster();
-
-  DispatchFunction([&] {
-    // Clean up on MainThread
-    receiver->RemoveAudioOutput((void*)1);
-    receiver->Destroy();
-    transmitter->Destroy();
-    port->Destroy();
-    sourceTrack->GraphImpl()->AppendMessage(
-        MakeUnique<StopInputProcessing>(listener));
-    sourceTrack->RemoveListener(pullListener);
-    sourceTrack->SetPullingEnabled(false);
-    Maybe<CubebUtils::AudioDeviceID> id =
-        Some(reinterpret_cast<CubebUtils::AudioDeviceID>(1));
-    sourceTrack->CloseAudioInput(id);
-    sourceTrack->Destroy();
-  });
-
-  uint32_t inputFrequency = inputStream->InputFrequency();
-  uint32_t partnerRate = partnerStream->InputSampleRate();
-
-  uint64_t preSilenceSamples;
-  float estimatedFreq;
-  uint32_t nrDiscontinuities;
-  Tie(preSilenceSamples, estimatedFreq, nrDiscontinuities) =
-      WaitFor(partnerStream->OutputVerificationEvent());
-
-  EXPECT_NEAR(estimatedFreq, inputFrequency / aDriftFactor, 5);
-  EXPECT_GE(preSilenceSamples, partnerRate / 100 /* 10ms */);
-  EXPECT_LE(nrDiscontinuities, 2U);
+  mon.AwaitFinished();
 }
-
-TEST(TestAudioTrackGraph, CrossGraphPort)
-{
-  TestCrossGraphPort(44100, 44100, 1);
-  TestCrossGraphPort(44100, 44100, 1.08);
-  TestCrossGraphPort(44100, 44100, 0.92);
-
-  TestCrossGraphPort(48000, 44100, 1);
-  TestCrossGraphPort(48000, 44100, 1.08);
-  TestCrossGraphPort(48000, 44100, 0.92);
-
-  TestCrossGraphPort(44100, 48000, 1);
-  TestCrossGraphPort(44100, 48000, 1.08);
-  TestCrossGraphPort(44100, 48000, 0.92);
-
-  TestCrossGraphPort(52110, 17781, 1);
-  TestCrossGraphPort(52110, 17781, 1.08);
-  TestCrossGraphPort(52110, 17781, 0.92);
-}
-
-TEST(TestAudioTrackGraph, CrossGraphPortLargeBuffer)
-{
-  const int32_t oldBuffering = Preferences::GetInt(DRIFT_BUFFERING_PREF);
-  Preferences::SetInt(DRIFT_BUFFERING_PREF, 5000);
-
-  TestCrossGraphPort(44100, 44100, 1.02);
-  TestCrossGraphPort(48000, 44100, 1.08);
-  TestCrossGraphPort(44100, 48000, 0.95);
-  TestCrossGraphPort(52110, 17781, 0.92);
-
-  Preferences::SetInt(DRIFT_BUFFERING_PREF, oldBuffering);
-}
--- a/dom/media/gtest/TestDynamicResampler.cpp
+++ b/dom/media/gtest/TestDynamicResampler.cpp
@@ -10,19 +10,19 @@
 #include "DynamicResampler.h"
 
 using namespace mozilla;
 
 TEST(TestDynamicResampler, SameRates_Float1)
 {
   const uint32_t in_frames = 100;
   const uint32_t out_frames = 100;
-  uint32_t channels = 2;
-  uint32_t in_rate = 44100;
-  uint32_t out_rate = 44100;
+  int channels = 2;
+  int in_rate = 44100;
+  int out_rate = 44100;
 
   DynamicResampler dr(in_rate, out_rate);
   dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
   EXPECT_EQ(dr.GetOutRate(), out_rate);
   EXPECT_EQ(dr.GetChannels(), channels);
 
   // float in_ch1[] = {.1, .2, .3, .4, .5, .6, .7, .8, .9, 1.0};
   // float in_ch2[] = {.1, .2, .3, .4, .5, .6, .7, .8, .9, 1.0};
@@ -76,19 +76,19 @@ TEST(TestDynamicResampler, SameRates_Flo
   EXPECT_FALSE(rv);
   EXPECT_EQ(out_frames_used, 0u);
 }
 
 TEST(TestDynamicResampler, SameRates_Short1)
 {
   uint32_t in_frames = 2;
   uint32_t out_frames = 2;
-  uint32_t channels = 2;
-  uint32_t in_rate = 44100;
-  uint32_t out_rate = 44100;
+  int channels = 2;
+  int in_rate = 44100;
+  int out_rate = 44100;
 
   DynamicResampler dr(in_rate, out_rate);
   dr.SetSampleFormat(AUDIO_FORMAT_S16);
   EXPECT_EQ(dr.GetOutRate(), out_rate);
   EXPECT_EQ(dr.GetChannels(), channels);
 
   short in_ch1[] = {1, 2, 3};
   short in_ch2[] = {4, 5, 6};
@@ -121,19 +121,19 @@ TEST(TestDynamicResampler, SameRates_Sho
   EXPECT_FALSE(rv);
   EXPECT_EQ(out_frames, 0u);
 }
 
 TEST(TestDynamicResampler, SameRates_Float2)
 {
   uint32_t in_frames = 3;
   uint32_t out_frames = 2;
-  uint32_t channels = 2;
-  uint32_t in_rate = 44100;
-  uint32_t out_rate = 44100;
+  int channels = 2;
+  int in_rate = 44100;
+  int out_rate = 44100;
 
   DynamicResampler dr(in_rate, out_rate);
   dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
 
   float in_ch1[] = {0.1, 0.2, 0.3};
   float in_ch2[] = {0.4, 0.5, 0.6};
   AutoTArray<const float*, 2> in_buffer;
   in_buffer.AppendElements(channels);
@@ -176,19 +176,19 @@ TEST(TestDynamicResampler, SameRates_Flo
   EXPECT_FALSE(rv);
   EXPECT_EQ(out_frames, 0u);
 }
 
 TEST(TestDynamicResampler, SameRates_Short2)
 {
   uint32_t in_frames = 3;
   uint32_t out_frames = 2;
-  uint32_t channels = 2;
-  uint32_t in_rate = 44100;
-  uint32_t out_rate = 44100;
+  int channels = 2;
+  int in_rate = 44100;
+  int out_rate = 44100;
 
   DynamicResampler dr(in_rate, out_rate);
   dr.SetSampleFormat(AUDIO_FORMAT_S16);
 
   short in_ch1[] = {1, 2, 3};
   short in_ch2[] = {4, 5, 6};
   AutoTArray<const short*, 2> in_buffer;
   in_buffer.AppendElements(channels);
@@ -231,19 +231,19 @@ TEST(TestDynamicResampler, SameRates_Sho
   EXPECT_FALSE(rv);
   EXPECT_EQ(out_frames, 0u);
 }
 
 TEST(TestDynamicResampler, SameRates_Float3)
 {
   uint32_t in_frames = 2;
   uint32_t out_frames = 3;
-  uint32_t channels = 2;
-  uint32_t in_rate = 44100;
-  uint32_t out_rate = 44100;
+  int channels = 2;
+  int in_rate = 44100;
+  int out_rate = 44100;
 
   DynamicResampler dr(in_rate, out_rate);
   dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
 
   float in_ch1[] = {0.1, 0.2, 0.3};
   float in_ch2[] = {0.4, 0.5, 0.6};
   AutoTArray<const float*, 2> in_buffer;
   in_buffer.AppendElements(channels);
@@ -279,19 +279,19 @@ TEST(TestDynamicResampler, SameRates_Flo
     EXPECT_FLOAT_EQ(in_ch2[i], out_ch2[i]);
   }
 }
 
 TEST(TestDynamicResampler, SameRates_Short3)
 {
   uint32_t in_frames = 2;
   uint32_t out_frames = 3;
-  uint32_t channels = 2;
-  uint32_t in_rate = 44100;
-  uint32_t out_rate = 44100;
+  int channels = 2;
+  int in_rate = 44100;
+  int out_rate = 44100;
 
   DynamicResampler dr(in_rate, out_rate);
   dr.SetSampleFormat(AUDIO_FORMAT_S16);
 
   short in_ch1[] = {1, 2, 3};
   short in_ch2[] = {4, 5, 6};
   AutoTArray<const short*, 2> in_buffer;
   in_buffer.AppendElements(channels);
@@ -327,19 +327,19 @@ TEST(TestDynamicResampler, SameRates_Sho
     EXPECT_EQ(in_ch2[i], out_ch2[i]);
   }
 }
 
 TEST(TestDynamicResampler, UpdateOutRate_Float)
 {
   uint32_t in_frames = 10;
   uint32_t out_frames = 40;
-  uint32_t channels = 2;
-  uint32_t in_rate = 24000;
-  uint32_t out_rate = 48000;
+  int channels = 2;
+  int in_rate = 24000;
+  int out_rate = 48000;
 
   uint32_t pre_buffer = 20;
 
   DynamicResampler dr(in_rate, out_rate, pre_buffer);
   dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
   EXPECT_EQ(dr.GetOutRate(), out_rate);
   EXPECT_EQ(dr.GetChannels(), channels);
 
@@ -385,19 +385,19 @@ TEST(TestDynamicResampler, UpdateOutRate
   EXPECT_TRUE(rv);
   EXPECT_EQ(out_frames, 18u);
 }
 
 TEST(TestDynamicResampler, UpdateOutRate_Short)
 {
   uint32_t in_frames = 10;
   uint32_t out_frames = 40;
-  uint32_t channels = 2;
-  uint32_t in_rate = 24000;
-  uint32_t out_rate = 48000;
+  int channels = 2;
+  int in_rate = 24000;
+  int out_rate = 48000;
 
   uint32_t pre_buffer = 20;
 
   DynamicResampler dr(in_rate, out_rate, pre_buffer);
   dr.SetSampleFormat(AUDIO_FORMAT_S16);
   EXPECT_EQ(dr.GetOutRate(), out_rate);
   EXPECT_EQ(dr.GetChannels(), channels);
 
@@ -443,111 +443,111 @@ TEST(TestDynamicResampler, UpdateOutRate
   EXPECT_TRUE(rv);
   EXPECT_EQ(out_frames, 18u);
 }
 
 TEST(TestDynamicResampler, BigRangeOutRates_Float)
 {
   uint32_t in_frames = 10;
   uint32_t out_frames = 10;
-  uint32_t channels = 2;
-  uint32_t in_rate = 44100;
-  uint32_t out_rate = 44100;
+  int channels = 2;
+  int in_rate = 44100;
+  int out_rate = 44100;
   uint32_t pre_buffer = 20;
 
   DynamicResampler dr(in_rate, out_rate, pre_buffer);
   dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
 
-  const uint32_t in_capacity = 40;
+  const int in_capacity = 40;
   float in_ch1[in_capacity] = {};
   float in_ch2[in_capacity] = {};
   for (uint32_t i = 0; i < in_capacity; ++i) {
     in_ch1[i] = in_ch2[i] = 0.01f * i;
   }
   AutoTArray<const float*, 2> in_buffer;
   in_buffer.AppendElements(channels);
   in_buffer[0] = in_ch1;
   in_buffer[1] = in_ch2;
 
-  const uint32_t out_capacity = 1000;
+  const int out_capacity = 1000;
   float out_ch1[out_capacity] = {};
   float out_ch2[out_capacity] = {};
 
-  for (uint32_t rate = 10000; rate < 90000; ++rate) {
+  for (int rate = 10000; rate < 90000; ++rate) {
     out_rate = rate;
     dr.UpdateResampler(out_rate, channels);
     EXPECT_EQ(dr.GetOutRate(), out_rate);
     EXPECT_EQ(dr.GetChannels(), channels);
     in_frames = 20;  // more than we need
     out_frames = in_frames * out_rate / in_rate;
     uint32_t expected_out_frames = out_frames;
-    for (uint32_t y = 0; y < 2; ++y) {
+    for (int y = 0; y < 2; ++y) {
       dr.AppendInput(in_buffer, in_frames);
       bool rv = dr.Resample(out_ch1, &out_frames, 0);
       EXPECT_TRUE(rv);
       EXPECT_EQ(out_frames, expected_out_frames);
       rv = dr.Resample(out_ch2, &out_frames, 1);
       EXPECT_TRUE(rv);
       EXPECT_EQ(out_frames, expected_out_frames);
     }
   }
 }
 
 TEST(TestDynamicResampler, BigRangeOutRates_Short)
 {
   uint32_t in_frames = 10;
   uint32_t out_frames = 10;
-  uint32_t channels = 2;
-  uint32_t in_rate = 44100;
-  uint32_t out_rate = 44100;
+  int channels = 2;
+  int in_rate = 44100;
+  int out_rate = 44100;
   uint32_t pre_buffer = 20;
 
   DynamicResampler dr(in_rate, out_rate, pre_buffer);
   dr.SetSampleFormat(AUDIO_FORMAT_S16);
 
-  const uint32_t in_capacity = 40;
+  const int in_capacity = 40;
   short in_ch1[in_capacity] = {};
   short in_ch2[in_capacity] = {};
   for (uint32_t i = 0; i < in_capacity; ++i) {
     in_ch1[i] = in_ch2[i] = i;
   }
   AutoTArray<const short*, 2> in_buffer;
   in_buffer.AppendElements(channels);
   in_buffer[0] = in_ch1;
   in_buffer[1] = in_ch2;
 
-  const uint32_t out_capacity = 1000;
+  const int out_capacity = 1000;
   short out_ch1[out_capacity] = {};
   short out_ch2[out_capacity] = {};
 
-  for (uint32_t rate = 10000; rate < 90000; ++rate) {
+  for (int rate = 10000; rate < 90000; ++rate) {
     out_rate = rate;
     dr.UpdateResampler(out_rate, channels);
     in_frames = 20;  // more than we need
     out_frames = in_frames * out_rate / in_rate;
     uint32_t expected_out_frames = out_frames;
-    for (uint32_t y = 0; y < 2; ++y) {
+    for (int y = 0; y < 2; ++y) {
       dr.AppendInput(in_buffer, in_frames);
       bool rv = dr.Resample(out_ch1, &out_frames, 0);
       EXPECT_TRUE(rv);
       EXPECT_EQ(out_frames, expected_out_frames);
       rv = dr.Resample(out_ch2, &out_frames, 1);
       EXPECT_TRUE(rv);
       EXPECT_EQ(out_frames, expected_out_frames);
     }
   }
 }
 
 TEST(TestDynamicResampler, UpdateChannels_Float)
 {
   uint32_t in_frames = 10;
   uint32_t out_frames = 10;
-  uint32_t channels = 2;
-  uint32_t in_rate = 44100;
-  uint32_t out_rate = 48000;
+  int channels = 2;
+  int in_rate = 44100;
+  int out_rate = 48000;
 
   DynamicResampler dr(in_rate, out_rate);
   dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
 
   float in_ch1[10] = {};
   float in_ch2[10] = {};
   for (uint32_t i = 0; i < in_frames; ++i) {
     in_ch1[i] = in_ch2[i] = 0.01f * i;
@@ -566,17 +566,17 @@ TEST(TestDynamicResampler, UpdateChannel
   EXPECT_EQ(out_frames, 10u);
   rv = dr.Resample(out_ch2, &out_frames, 1);
   EXPECT_TRUE(rv);
   EXPECT_EQ(out_frames, 10u);
 
   // Add 3rd channel
   dr.UpdateResampler(out_rate, 3);
   EXPECT_EQ(dr.GetOutRate(), out_rate);
-  EXPECT_EQ(dr.GetChannels(), 3u);
+  EXPECT_EQ(dr.GetChannels(), 3);
 
   float in_ch3[10] = {};
   for (uint32_t i = 0; i < in_frames; ++i) {
     in_ch3[i] = 0.01f * i;
   }
   in_buffer.AppendElement();
   in_buffer[2] = in_ch3;
   float out_ch3[10] = {};
@@ -598,17 +598,17 @@ TEST(TestDynamicResampler, UpdateChannel
     in_ch3[i] = 0.01f * i;
   }
   in_buffer.AppendElement();
   in_buffer[3] = in_ch4;
   float out_ch4[10] = {};
 
   dr.UpdateResampler(out_rate, 4);
   EXPECT_EQ(dr.GetOutRate(), out_rate);
-  EXPECT_EQ(dr.GetChannels(), 4u);
+  EXPECT_EQ(dr.GetChannels(), 4);
   dr.AppendInput(in_buffer, in_frames);
 
   rv = dr.Resample(out_ch1, &out_frames, 0);
   EXPECT_TRUE(rv);
   EXPECT_EQ(out_frames, 10u);
   rv = dr.Resample(out_ch2, &out_frames, 1);
   EXPECT_TRUE(rv);
   EXPECT_EQ(out_frames, 10u);
@@ -619,19 +619,19 @@ TEST(TestDynamicResampler, UpdateChannel
   EXPECT_TRUE(rv);
   EXPECT_EQ(out_frames, 10u);
 }
 
 TEST(TestDynamicResampler, UpdateChannels_Short)
 {
   uint32_t in_frames = 10;
   uint32_t out_frames = 10;
-  uint32_t channels = 2;
-  uint32_t in_rate = 44100;
-  uint32_t out_rate = 48000;
+  int channels = 2;
+  int in_rate = 44100;
+  int out_rate = 48000;
 
   DynamicResampler dr(in_rate, out_rate);
   dr.SetSampleFormat(AUDIO_FORMAT_S16);
 
   short in_ch1[10] = {};
   short in_ch2[10] = {};
   for (uint32_t i = 0; i < in_frames; ++i) {
     in_ch1[i] = in_ch2[i] = i;
@@ -650,17 +650,17 @@ TEST(TestDynamicResampler, UpdateChannel
   EXPECT_EQ(out_frames, 10u);
   rv = dr.Resample(out_ch2, &out_frames, 1);
   EXPECT_TRUE(rv);
   EXPECT_EQ(out_frames, 10u);
 
   // Add 3rd channel
   dr.UpdateResampler(out_rate, 3);
   EXPECT_EQ(dr.GetOutRate(), out_rate);
-  EXPECT_EQ(dr.GetChannels(), 3u);
+  EXPECT_EQ(dr.GetChannels(), 3);
 
   short in_ch3[10] = {};
   for (uint32_t i = 0; i < in_frames; ++i) {
     in_ch3[i] = i;
   }
   in_buffer.AppendElement();
   in_buffer[2] = in_ch3;
   short out_ch3[10] = {};
@@ -683,17 +683,17 @@ TEST(TestDynamicResampler, UpdateChannel
     in_ch3[i] = i;
   }
   in_buffer.AppendElement();
   in_buffer[3] = in_ch4;
   short out_ch4[10] = {};
 
   dr.UpdateResampler(out_rate, 4);
   EXPECT_EQ(dr.GetOutRate(), out_rate);
-  EXPECT_EQ(dr.GetChannels(), 4u);
+  EXPECT_EQ(dr.GetChannels(), 4);
   dr.AppendInput(in_buffer, in_frames);
 
   rv = dr.Resample(out_ch1, &out_frames, 0);
   EXPECT_TRUE(rv);
   EXPECT_EQ(out_frames, 10u);
   rv = dr.Resample(out_ch2, &out_frames, 1);
   EXPECT_TRUE(rv);
   EXPECT_EQ(out_frames, 10u);
@@ -704,96 +704,96 @@ TEST(TestDynamicResampler, UpdateChannel
   EXPECT_TRUE(rv);
   EXPECT_EQ(out_frames, 10u);
 }
 
 TEST(TestAudioChunkList, Basic1)
 {
   AudioChunkList list(256, 2);
   list.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
-  EXPECT_EQ(list.ChunkCapacity(), 128u);
-  EXPECT_EQ(list.TotalCapacity(), 256u);
+  EXPECT_EQ(list.ChunkCapacity(), 128);
+  EXPECT_EQ(list.TotalCapacity(), 256);
 
   AudioChunk& c1 = list.GetNext();
   float* c1_ch1 = c1.ChannelDataForWrite<float>(0);
   float* c1_ch2 = c1.ChannelDataForWrite<float>(1);
   EXPECT_EQ(c1.mBufferFormat, AUDIO_FORMAT_FLOAT32);
-  for (uint32_t i = 0; i < list.ChunkCapacity(); ++i) {
+  for (int i = 0; i < list.ChunkCapacity(); ++i) {
     c1_ch1[i] = c1_ch2[i] = 0.01f * static_cast<float>(i);
   }
   AudioChunk& c2 = list.GetNext();
   EXPECT_EQ(c2.mBufferFormat, AUDIO_FORMAT_FLOAT32);
   EXPECT_NE(c1.mBuffer.get(), c2.mBuffer.get());
   AudioChunk& c3 = list.GetNext();
   EXPECT_EQ(c3.mBufferFormat, AUDIO_FORMAT_FLOAT32);
   // Cycle
   EXPECT_EQ(c1.mBuffer.get(), c3.mBuffer.get());
   float* c3_ch1 = c3.ChannelDataForWrite<float>(0);
   float* c3_ch2 = c3.ChannelDataForWrite<float>(1);
-  for (uint32_t i = 0; i < list.ChunkCapacity(); ++i) {
+  for (int i = 0; i < list.ChunkCapacity(); ++i) {
     EXPECT_FLOAT_EQ(c1_ch1[i], c3_ch1[i]);
     EXPECT_FLOAT_EQ(c1_ch2[i], c3_ch2[i]);
   }
 }
 
 TEST(TestAudioChunkList, Basic2)
 {
   AudioChunkList list(256, 2);
   list.SetSampleFormat(AUDIO_FORMAT_S16);
-  EXPECT_EQ(list.ChunkCapacity(), 256u);
-  EXPECT_EQ(list.TotalCapacity(), 512u);
+  EXPECT_EQ(list.ChunkCapacity(), 256);
+  EXPECT_EQ(list.TotalCapacity(), 512);
 
   AudioChunk& c1 = list.GetNext();
   EXPECT_EQ(c1.mBufferFormat, AUDIO_FORMAT_S16);
   short* c1_ch1 = c1.ChannelDataForWrite<short>(0);
   short* c1_ch2 = c1.ChannelDataForWrite<short>(1);
-  for (uint32_t i = 0; i < list.ChunkCapacity(); ++i) {
+  for (int i = 0; i < list.ChunkCapacity(); ++i) {
     c1_ch1[i] = c1_ch2[i] = static_cast<short>(i);
   }
   AudioChunk& c2 = list.GetNext();
   EXPECT_EQ(c2.mBufferFormat, AUDIO_FORMAT_S16);
   EXPECT_NE(c1.mBuffer.get(), c2.mBuffer.get());
   AudioChunk& c3 = list.GetNext();
   EXPECT_EQ(c3.mBufferFormat, AUDIO_FORMAT_S16);
   AudioChunk& c4 = list.GetNext();
   EXPECT_EQ(c4.mBufferFormat, AUDIO_FORMAT_S16);
   // Cycle
   AudioChunk& c5 = list.GetNext();
   EXPECT_EQ(c5.mBufferFormat, AUDIO_FORMAT_S16);
   EXPECT_EQ(c1.mBuffer.get(), c5.mBuffer.get());
   short* c5_ch1 = c5.ChannelDataForWrite<short>(0);
   short* c5_ch2 = c5.ChannelDataForWrite<short>(1);
-  for (uint32_t i = 0; i < list.ChunkCapacity(); ++i) {
+  for (int i = 0; i < list.ChunkCapacity(); ++i) {
     EXPECT_EQ(c1_ch1[i], c5_ch1[i]);
     EXPECT_EQ(c1_ch2[i], c5_ch2[i]);
   }
 }
 
 TEST(TestAudioChunkList, Basic3)
 {
   AudioChunkList list(260, 2);
   list.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
-  EXPECT_EQ(list.ChunkCapacity(), 128u);
-  EXPECT_EQ(list.TotalCapacity(), 256u + 128u);
+  EXPECT_EQ(list.ChunkCapacity(), 128);
+  EXPECT_EQ(list.TotalCapacity(), 256 + 128);
 
   AudioChunk& c1 = list.GetNext();
   AudioChunk& c2 = list.GetNext();
   EXPECT_NE(c1.mBuffer.get(), c2.mBuffer.get());
   AudioChunk& c3 = list.GetNext();
   EXPECT_NE(c1.mBuffer.get(), c3.mBuffer.get());
   AudioChunk& c4 = list.GetNext();
   EXPECT_EQ(c1.mBuffer.get(), c4.mBuffer.get());
 }
 
 TEST(TestAudioChunkList, Basic4)
 {
   AudioChunkList list(260, 2);
   list.SetSampleFormat(AUDIO_FORMAT_S16);
-  EXPECT_EQ(list.ChunkCapacity(), 256u);
-  EXPECT_EQ(list.TotalCapacity(), 512u + 256u);
+  EXPECT_EQ(list.ChunkCapacity(), 256);
+  EXPECT_EQ(list.TotalCapacity(), 512 + 256);
 
   AudioChunk& c1 = list.GetNext();
   AudioChunk& c2 = list.GetNext();
   EXPECT_NE(c1.mBuffer.get(), c2.mBuffer.get());
   AudioChunk& c3 = list.GetNext();
   EXPECT_NE(c1.mBuffer.get(), c3.mBuffer.get());
   AudioChunk& c4 = list.GetNext();
   EXPECT_EQ(c1.mBuffer.get(), c4.mBuffer.get());
@@ -821,73 +821,73 @@ TEST(TestAudioChunkList, UpdateChannels)
 TEST(TestAudioChunkList, UpdateBetweenMonoAndStereo)
 {
   AudioChunkList list(256, 2);
   list.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
 
   AudioChunk& c1 = list.GetNext();
   float* c1_ch1 = c1.ChannelDataForWrite<float>(0);
   float* c1_ch2 = c1.ChannelDataForWrite<float>(1);
-  for (uint32_t i = 0; i < list.ChunkCapacity(); ++i) {
+  for (int i = 0; i < list.ChunkCapacity(); ++i) {
     c1_ch1[i] = c1_ch2[i] = 0.01f * static_cast<float>(i);
   }
 
   AudioChunk& c2 = list.GetNext();
   EXPECT_EQ(c1.ChannelCount(), 2u);
   EXPECT_EQ(c2.ChannelCount(), 2u);
 
   // Downmix to mono
   list.Update(1);
 
   AudioChunk& c3 = list.GetNext();
   float* c3_ch1 = c3.ChannelDataForWrite<float>(0);
-  for (uint32_t i = 0; i < list.ChunkCapacity(); ++i) {
+  for (int i = 0; i < list.ChunkCapacity(); ++i) {
     EXPECT_FLOAT_EQ(c3_ch1[i], c1_ch1[i]);
   }
 
   AudioChunk& c4 = list.GetNext();
   EXPECT_EQ(c3.ChannelCount(), 1u);
   EXPECT_EQ(c4.ChannelCount(), 1u);
   EXPECT_EQ(static_cast<SharedChannelArrayBuffer<float>*>(c3.mBuffer.get())
                 ->mBuffers[0]
                 .Length(),
-            list.ChunkCapacity());
+            (uint32_t)list.ChunkCapacity());
 
   // Upmix to stereo
   list.Update(2);
 
   AudioChunk& c5 = list.GetNext();
   AudioChunk& c6 = list.GetNext();
   EXPECT_EQ(c5.ChannelCount(), 2u);
   EXPECT_EQ(c6.ChannelCount(), 2u);
   EXPECT_EQ(static_cast<SharedChannelArrayBuffer<float>*>(c5.mBuffer.get())
                 ->mBuffers[0]
                 .Length(),
-            list.ChunkCapacity());
+            (uint32_t)list.ChunkCapacity());
   EXPECT_EQ(static_cast<SharedChannelArrayBuffer<float>*>(c5.mBuffer.get())
                 ->mBuffers[1]
                 .Length(),
-            list.ChunkCapacity());
+            (uint32_t)list.ChunkCapacity());
 
   // Downmix to mono
   list.Update(1);
 
   AudioChunk& c7 = list.GetNext();
   float* c7_ch1 = c7.ChannelDataForWrite<float>(0);
-  for (uint32_t i = 0; i < list.ChunkCapacity(); ++i) {
+  for (int i = 0; i < list.ChunkCapacity(); ++i) {
     EXPECT_FLOAT_EQ(c7_ch1[i], c1_ch1[i]);
   }
 
   AudioChunk& c8 = list.GetNext();
   EXPECT_EQ(c7.ChannelCount(), 1u);
   EXPECT_EQ(c8.ChannelCount(), 1u);
   EXPECT_EQ(static_cast<SharedChannelArrayBuffer<float>*>(c7.mBuffer.get())
                 ->mBuffers[0]
                 .Length(),
-            list.ChunkCapacity());
+            (uint32_t)list.ChunkCapacity());
 }
 
 TEST(TestAudioChunkList, ConsumeAndForget)
 {
   AudioSegment s;
   AudioChunkList list(256, 2);
   list.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
 
@@ -904,63 +904,63 @@ TEST(TestAudioChunkList, ConsumeAndForge
   EXPECT_EQ(c2.ChannelData<float>().Length(), 2u);
 
   s.ForgetUpTo(256);
   list.GetNext();
   list.GetNext();
 }
 
 template <class T>
-AudioChunk CreateAudioChunk(uint32_t aFrames, uint32_t aChannels,
+AudioChunk CreateAudioChunk(uint32_t aFrames, int aChannels,
                             AudioSampleFormat aSampleFormat) {
   AudioChunk chunk;
   nsTArray<nsTArray<T>> buffer;
   buffer.AppendElements(aChannels);
 
   nsTArray<const T*> bufferPtrs;
   bufferPtrs.AppendElements(aChannels);
 
-  for (uint32_t i = 0; i < aChannels; ++i) {
+  for (int i = 0; i < aChannels; ++i) {
     T* ptr = buffer[i].AppendElements(aFrames);
     bufferPtrs[i] = ptr;
     for (uint32_t j = 0; j < aFrames; ++j) {
       if (aSampleFormat == AUDIO_FORMAT_FLOAT32) {
         ptr[j] = 0.01 * j;
       } else {
         ptr[j] = j;
       }
     }
   }
 
   chunk.mBuffer = new mozilla::SharedChannelArrayBuffer(std::move(buffer));
   chunk.mBufferFormat = aSampleFormat;
   chunk.mChannelData.AppendElements(aChannels);
-  for (uint32_t i = 0; i < aChannels; ++i) {
+  for (int i = 0; i < aChannels; ++i) {
     chunk.mChannelData[i] = bufferPtrs[i];
   }
   chunk.mDuration = aFrames;
   return chunk;
 }
 
 template <class T>
-AudioSegment CreateAudioSegment(uint32_t aFrames, uint32_t aChannels,
+AudioSegment CreateAudioSegment(uint32_t aFrames, int aChannels,
                                 AudioSampleFormat aSampleFormat) {
   AudioSegment segment;
   AudioChunk chunk = CreateAudioChunk<T>(aFrames, aChannels, aSampleFormat);
   segment.AppendAndConsumeChunk(&chunk);
   return segment;
 }
 
 TEST(TestAudioResampler, OutAudioSegment_Float)
 {
   uint32_t in_frames = 10;
   uint32_t out_frames = 40;
-  uint32_t channels = 2;
-  uint32_t in_rate = 24000;
-  uint32_t out_rate = 48000;
+  int channels = 2;
+  int in_rate = 24000;
+  int out_rate = 48000;
 
   uint32_t pre_buffer = 21;
 
   AudioResampler dr(in_rate, out_rate, pre_buffer);
 
   AudioSegment inSegment =
       CreateAudioSegment<float>(in_frames, channels, AUDIO_FORMAT_FLOAT32);
   dr.AppendInput(inSegment);
@@ -994,19 +994,19 @@ TEST(TestAudioResampler, OutAudioSegment
   EXPECT_TRUE(!s1.IsNull());
   EXPECT_TRUE(!s1.IsEmpty());
 }
 
 TEST(TestAudioResampler, OutAudioSegment_Short)
 {
   uint32_t in_frames = 10;
   uint32_t out_frames = 40;
-  uint32_t channels = 2;
-  uint32_t in_rate = 24000;
-  uint32_t out_rate = 48000;
+  int channels = 2;
+  int in_rate = 24000;
+  int out_rate = 48000;
 
   uint32_t pre_buffer = 21;
 
   AudioResampler dr(in_rate, out_rate, pre_buffer);
 
   AudioSegment inSegment =
       CreateAudioSegment<short>(in_frames, channels, AUDIO_FORMAT_S16);
   dr.AppendInput(inSegment);
@@ -1040,19 +1040,19 @@ TEST(TestAudioResampler, OutAudioSegment
   EXPECT_TRUE(!s1.IsNull());
   EXPECT_TRUE(!s1.IsEmpty());
 }
 
 TEST(TestAudioResampler, OutAudioSegmentFail_Float)
 {
   const uint32_t in_frames = 130;
   const uint32_t out_frames = 300;
-  uint32_t channels = 2;
-  uint32_t in_rate = 24000;
-  uint32_t out_rate = 48000;
+  int channels = 2;
+  int in_rate = 24000;
+  int out_rate = 48000;
 
   uint32_t pre_buffer = 5;
 
   AudioResampler dr(in_rate, out_rate, pre_buffer);
   AudioSegment inSegment =
       CreateAudioSegment<float>(in_frames, channels, AUDIO_FORMAT_FLOAT32);
   dr.AppendInput(inSegment);
 
@@ -1062,19 +1062,19 @@ TEST(TestAudioResampler, OutAudioSegment
   EXPECT_TRUE(s.IsNull());
   EXPECT_TRUE(s.IsEmpty());
 }
 
 TEST(TestAudioResampler, InAudioSegment_Float)
 {
   uint32_t in_frames = 10;
   uint32_t out_frames = 40;
-  uint32_t channels = 2;
-  uint32_t in_rate = 24000;
-  uint32_t out_rate = 48000;
+  int channels = 2;
+  int in_rate = 24000;
+  int out_rate = 48000;
 
   uint32_t pre_buffer = 10;
   AudioResampler dr(in_rate, out_rate, pre_buffer);
 
   AudioSegment inSegment;
 
   AudioChunk chunk1;
   chunk1.SetNull(in_frames / 2);
@@ -1082,28 +1082,28 @@ TEST(TestAudioResampler, InAudioSegment_
 
   AudioChunk chunk2;
   nsTArray<nsTArray<float>> buffer;
   buffer.AppendElements(channels);
 
   nsTArray<const float*> bufferPtrs;
   bufferPtrs.AppendElements(channels);
 
-  for (uint32_t i = 0; i < channels; ++i) {
+  for (int i = 0; i < channels; ++i) {
     float* ptr = buffer[i].AppendElements(5);
     bufferPtrs[i] = ptr;
     for (uint32_t j = 0; j < 5; ++j) {
       ptr[j] = 0.01f * j;
     }
   }
 
   chunk2.mBuffer = new mozilla::SharedChannelArrayBuffer(std::move(buffer));
   chunk2.mBufferFormat = AUDIO_FORMAT_FLOAT32;
   chunk2.mChannelData.AppendElements(channels);
-  for (uint32_t i = 0; i < channels; ++i) {
+  for (int i = 0; i < channels; ++i) {
     chunk2.mChannelData[i] = bufferPtrs[i];
   }
   chunk2.mDuration = in_frames / 2;
   inSegment.AppendAndConsumeChunk(&chunk2);
 
   dr.AppendInput(inSegment);
   AudioSegment outSegment = dr.Resample(out_frames);
   // Faild because the first chunk is ignored
@@ -1116,19 +1116,19 @@ TEST(TestAudioResampler, InAudioSegment_
   EXPECT_EQ(outSegment2.GetDuration(), 40u);
   EXPECT_EQ(outSegment2.MaxChannelCount(), 2u);
 }
 
 TEST(TestAudioResampler, InAudioSegment_Short)
 {
   uint32_t in_frames = 10;
   uint32_t out_frames = 40;
-  uint32_t channels = 2;
-  uint32_t in_rate = 24000;
-  uint32_t out_rate = 48000;
+  int channels = 2;
+  int in_rate = 24000;
+  int out_rate = 48000;
 
   uint32_t pre_buffer = 10;
   AudioResampler dr(in_rate, out_rate, pre_buffer);
 
   AudioSegment inSegment;
 
   // The null chunk at the beginning will be ignored.
   AudioChunk chunk1;
@@ -1137,28 +1137,28 @@ TEST(TestAudioResampler, InAudioSegment_
 
   AudioChunk chunk2;
   nsTArray<nsTArray<short>> buffer;
   buffer.AppendElements(channels);
 
   nsTArray<const short*> bufferPtrs;
   bufferPtrs.AppendElements(channels);
 
-  for (uint32_t i = 0; i < channels; ++i) {
+  for (int i = 0; i < channels; ++i) {
     short* ptr = buffer[i].AppendElements(5);
     bufferPtrs[i] = ptr;
     for (uint32_t j = 0; j < 5; ++j) {
       ptr[j] = j;
     }
   }
 
   chunk2.mBuffer = new mozilla::SharedChannelArrayBuffer(std::move(buffer));
   chunk2.mBufferFormat = AUDIO_FORMAT_S16;
   chunk2.mChannelData.AppendElements(channels);
-  for (uint32_t i = 0; i < channels; ++i) {
+  for (int i = 0; i < channels; ++i) {
     chunk2.mChannelData[i] = bufferPtrs[i];
   }
   chunk2.mDuration = in_frames / 2;
   inSegment.AppendAndConsumeChunk(&chunk2);
 
   dr.AppendInput(inSegment);
   AudioSegment outSegment = dr.Resample(out_frames);
   // Faild because the first chunk is ignored
@@ -1170,19 +1170,19 @@ TEST(TestAudioResampler, InAudioSegment_
   EXPECT_EQ(outSegment2.GetDuration(), 40u);
   EXPECT_EQ(outSegment2.MaxChannelCount(), 2u);
 }
 
 TEST(TestAudioResampler, ChannelChange_MonoToStereo)
 {
   uint32_t in_frames = 10;
   uint32_t out_frames = 40;
-  // uint32_t channels = 2;
-  uint32_t in_rate = 24000;
-  uint32_t out_rate = 48000;
+  // int channels = 2;
+  int in_rate = 24000;
+  int out_rate = 48000;
 
   uint32_t pre_buffer = 0;
 
   AudioResampler dr(in_rate, out_rate, pre_buffer);
 
   AudioChunk monoChunk =
       CreateAudioChunk<float>(in_frames, 1, AUDIO_FORMAT_FLOAT32);
   AudioChunk stereoChunk =
@@ -1200,19 +1200,19 @@ TEST(TestAudioResampler, ChannelChange_M
   EXPECT_TRUE(!s.IsEmpty());
   EXPECT_EQ(s.MaxChannelCount(), 2u);
 }
 
 TEST(TestAudioResampler, ChannelChange_StereoToMono)
 {
   uint32_t in_frames = 10;
   uint32_t out_frames = 40;
-  // uint32_t channels = 2;
-  uint32_t in_rate = 24000;
-  uint32_t out_rate = 48000;
+  // int channels = 2;
+  int in_rate = 24000;
+  int out_rate = 48000;
 
   uint32_t pre_buffer = 0;
 
   AudioResampler dr(in_rate, out_rate, pre_buffer);
 
   AudioChunk monoChunk =
       CreateAudioChunk<float>(in_frames, 1, AUDIO_FORMAT_FLOAT32);
   AudioChunk stereoChunk =
@@ -1230,19 +1230,19 @@ TEST(TestAudioResampler, ChannelChange_S
   EXPECT_TRUE(!s.IsEmpty());
   EXPECT_EQ(s.MaxChannelCount(), 1u);
 }
 
 TEST(TestAudioResampler, ChannelChange_StereoToQuad)
 {
   uint32_t in_frames = 10;
   uint32_t out_frames = 40;
-  // uint32_t channels = 2;
-  uint32_t in_rate = 24000;
-  uint32_t out_rate = 48000;
+  // int channels = 2;
+  int in_rate = 24000;
+  int out_rate = 48000;
 
   uint32_t pre_buffer = 0;
 
   AudioResampler dr(in_rate, out_rate, pre_buffer);
 
   AudioChunk stereoChunk =
       CreateAudioChunk<float>(in_frames, 2, AUDIO_FORMAT_FLOAT32);
   AudioChunk quadChunk =
@@ -1265,19 +1265,19 @@ TEST(TestAudioResampler, ChannelChange_S
   EXPECT_TRUE(!s2.IsNull());
   EXPECT_TRUE(!s2.IsEmpty());
 }
 
 TEST(TestAudioResampler, ChannelChange_QuadToStereo)
 {
   uint32_t in_frames = 10;
   uint32_t out_frames = 40;
-  // uint32_t channels = 2;
-  uint32_t in_rate = 24000;
-  uint32_t out_rate = 48000;
+  // int channels = 2;
+  int in_rate = 24000;
+  int out_rate = 48000;
 
   AudioResampler dr(in_rate, out_rate);
 
   AudioChunk stereoChunk =
       CreateAudioChunk<float>(in_frames, 2, AUDIO_FORMAT_FLOAT32);
   AudioChunk quadChunk =
       CreateAudioChunk<float>(in_frames, 4, AUDIO_FORMAT_FLOAT32);
 
@@ -1298,39 +1298,39 @@ TEST(TestAudioResampler, ChannelChange_Q
   EXPECT_TRUE(!s2.IsNull());
   EXPECT_TRUE(!s2.IsEmpty());
 }
 
 void printAudioSegment(const AudioSegment& segment);
 
 TEST(TestAudioResampler, ChannelChange_Discontinuity)
 {
-  uint32_t in_rate = 24000;
-  uint32_t out_rate = 48000;
+  int in_rate = 24000;
+  int out_rate = 48000;
 
   const float amplitude = 0.5;
   const float frequency = 200;
   const float phase = 0.0;
   float time = 0.0;
   const float deltaTime = 1.0f / static_cast<float>(in_rate);
 
-  uint32_t in_frames = in_rate / 100;
-  uint32_t out_frames = out_rate / 100;
+  int in_frames = in_rate / 100;
+  int out_frames = out_rate / 100;
   AudioResampler dr(in_rate, out_rate);
 
   AudioChunk monoChunk =
       CreateAudioChunk<float>(in_frames, 1, AUDIO_FORMAT_FLOAT32);
-  for (uint32_t i = 0; i < monoChunk.GetDuration(); ++i) {
+  for (int i = 0; i < monoChunk.GetDuration(); ++i) {
     double value = amplitude * sin(2 * M_PI * frequency * time + phase);
     monoChunk.ChannelDataForWrite<float>(0)[i] = static_cast<float>(value);
     time += deltaTime;
   }
   AudioChunk stereoChunk =
       CreateAudioChunk<float>(in_frames, 2, AUDIO_FORMAT_FLOAT32);
-  for (uint32_t i = 0; i < stereoChunk.GetDuration(); ++i) {
+  for (int i = 0; i < stereoChunk.GetDuration(); ++i) {
     double value = amplitude * sin(2 * M_PI * frequency * time + phase);
     stereoChunk.ChannelDataForWrite<float>(0)[i] = static_cast<float>(value);
     if (stereoChunk.ChannelCount() == 2) {
       stereoChunk.ChannelDataForWrite<float>(1)[i] = value;
     }
     time += deltaTime;
   }
 
@@ -1354,39 +1354,39 @@ TEST(TestAudioResampler, ChannelChange_D
   EXPECT_EQ(s2.GetType(), MediaSegment::AUDIO);
   EXPECT_TRUE(!s2.IsNull());
   EXPECT_TRUE(!s2.IsEmpty());
   EXPECT_EQ(s2.MaxChannelCount(), 1u);
 }
 
 TEST(TestAudioResampler, ChannelChange_Discontinuity2)
 {
-  uint32_t in_rate = 24000;
-  uint32_t out_rate = 48000;
+  int in_rate = 24000;
+  int out_rate = 48000;
 
   const float amplitude = 0.5;
   const float frequency = 200;
   const float phase = 0.0;
   float time = 0.0;
   const float deltaTime = 1.0f / static_cast<float>(in_rate);
 
-  uint32_t in_frames = in_rate / 100;
-  uint32_t out_frames = out_rate / 100;
+  int in_frames = in_rate / 100;
+  int out_frames = out_rate / 100;
   AudioResampler dr(in_rate, out_rate, 10);
 
   AudioChunk monoChunk =
       CreateAudioChunk<float>(in_frames / 2, 1, AUDIO_FORMAT_FLOAT32);
-  for (uint32_t i = 0; i < monoChunk.GetDuration(); ++i) {
+  for (int i = 0; i < monoChunk.GetDuration(); ++i) {
     double value = amplitude * sin(2 * M_PI * frequency * time + phase);
     monoChunk.ChannelDataForWrite<float>(0)[i] = static_cast<float>(value);
     time += deltaTime;
   }
   AudioChunk stereoChunk =
       CreateAudioChunk<float>(in_frames / 2, 2, AUDIO_FORMAT_FLOAT32);
-  for (uint32_t i = 0; i < stereoChunk.GetDuration(); ++i) {
+  for (int i = 0; i < stereoChunk.GetDuration(); ++i) {
     double value = amplitude * sin(2 * M_PI * frequency * time + phase);
     stereoChunk.ChannelDataForWrite<float>(0)[i] = static_cast<float>(value);
     if (stereoChunk.ChannelCount() == 2) {
       stereoChunk.ChannelDataForWrite<float>(1)[i] = value;
     }
     time += deltaTime;
   }
 
@@ -1415,32 +1415,32 @@ TEST(TestAudioResampler, ChannelChange_D
   EXPECT_EQ(s2.GetType(), MediaSegment::AUDIO);
   EXPECT_TRUE(!s2.IsNull());
   EXPECT_TRUE(!s2.IsEmpty());
   EXPECT_EQ(s2.MaxChannelCount(), 2u);
 }
 
 TEST(TestAudioResampler, ChannelChange_Discontinuity3)
 {
-  uint32_t in_rate = 48000;
-  uint32_t out_rate = 48000;
+  int in_rate = 48000;
+  int out_rate = 48000;
 
   const float amplitude = 0.5;
   const float frequency = 200;
   const float phase = 0.0;
   float time = 0.0;
   const float deltaTime = 1.0f / static_cast<float>(in_rate);
 
-  uint32_t in_frames = in_rate / 100;
-  uint32_t out_frames = out_rate / 100;
+  int in_frames = in_rate / 100;
+  int out_frames = out_rate / 100;
   AudioResampler dr(in_rate, out_rate, 10);
 
   AudioChunk stereoChunk =
       CreateAudioChunk<float>(in_frames, 2, AUDIO_FORMAT_FLOAT32);
-  for (uint32_t i = 0; i < stereoChunk.GetDuration(); ++i) {
+  for (int i = 0; i < stereoChunk.GetDuration(); ++i) {
     double value = amplitude * sin(2 * M_PI * frequency * time + phase);
     stereoChunk.ChannelDataForWrite<float>(0)[i] = static_cast<float>(value);
     if (stereoChunk.ChannelCount() == 2) {
       stereoChunk.ChannelDataForWrite<float>(1)[i] = value;
     }
     time += deltaTime;
   }
 
--- a/dom/media/gtest/TestMediaDataEncoder.cpp
+++ b/dom/media/gtest/TestMediaDataEncoder.cpp
@@ -76,21 +76,19 @@ class MediaDataEncoderTest : public test
     }
 
     already_AddRefed<MediaData> GetFrame(const size_t aIndex) {
       Draw(aIndex);
       RefPtr<layers::PlanarYCbCrImage> img =
           new layers::RecyclingPlanarYCbCrImage(mRecycleBin);
       img->CopyData(mYUV);
       RefPtr<MediaData> frame = VideoData::CreateFromImage(
-          kImageSize, 0,
-          media::TimeUnit::FromMicroseconds(aIndex * FRAME_DURATION),
-          media::TimeUnit::FromMicroseconds(FRAME_DURATION), img,
-          (aIndex & 0xF) == 0,
-          media::TimeUnit::FromMicroseconds(aIndex * FRAME_DURATION));
+          kImageSize, 0, TimeUnit::FromMicroseconds(aIndex * FRAME_DURATION),
+          TimeUnit::FromMicroseconds(FRAME_DURATION), img, (aIndex & 0xF) == 0,
+          TimeUnit::FromMicroseconds(aIndex * FRAME_DURATION));
       return frame.forget();
     }
 
     void DrawChessboard(uint8_t* aAddr, const size_t aWidth,
                         const size_t aHeight, const size_t aOffset) {
       uint8_t pixels[2][BLOCK_SIZE];
       size_t x = aOffset % BLOCK_SIZE;
       if ((aOffset / BLOCK_SIZE) & 1) {
--- a/dom/media/gtest/moz.build
+++ b/dom/media/gtest/moz.build
@@ -10,16 +10,17 @@ DEFINES['ENABLE_SET_CUBEB_BACKEND'] = Tr
 
 LOCAL_INCLUDES += [
     '/media/webrtc/signaling/src/common',
     '/media/webrtc/trunk',
     '/media/webrtc/trunk/webrtc'
 ]
 
 UNIFIED_SOURCES += [
+    'AudioGenerator.cpp',
     'MockMediaResource.cpp',
     'TestAudioBuffers.cpp',
     'TestAudioCallbackDriver.cpp',
     'TestAudioCompactor.cpp',
     'TestAudioDriftCorrection.cpp',
     'TestAudioMixer.cpp',
     'TestAudioPacketizer.cpp',
     'TestAudioRingBuffer.cpp',
@@ -107,17 +108,16 @@ include('/ipc/chromium/chromium-config.m
 
 LOCAL_INCLUDES += [
     '/dom/media',
     '/dom/media/encoder',
     '/dom/media/gmp',
     '/dom/media/mp4',
     '/dom/media/platforms',
     '/dom/media/platforms/agnostic',
-    '/dom/media/webrtc',
     '/security/certverifier',
 ]
 
 FINAL_LIBRARY = 'xul-gtest'
 
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     CXXFLAGS += ['-Wno-error=shadow']
 
--- a/dom/media/webrtc/MediaEngineDefault.cpp
+++ b/dom/media/webrtc/MediaEngineDefault.cpp
@@ -353,29 +353,29 @@ void MediaEngineDefaultVideoSource::Gene
 // self-sustained until destruction, just forwarding calls to Pull().
 class AudioSourcePullListener : public MediaTrackListener {
  public:
   AudioSourcePullListener(RefPtr<SourceMediaTrack> aTrack,
                           const PrincipalHandle& aPrincipalHandle,
                           uint32_t aFrequency)
       : mTrack(std::move(aTrack)),
         mPrincipalHandle(aPrincipalHandle),
-        mSineGenerator(MakeUnique<SineWaveGenerator<int16_t>>(
-            mTrack->mSampleRate, aFrequency)) {
+        mSineGenerator(
+            MakeUnique<SineWaveGenerator>(mTrack->mSampleRate, aFrequency)) {
     MOZ_COUNT_CTOR(AudioSourcePullListener);
   }
 
   MOZ_COUNTED_DTOR(AudioSourcePullListener)
 
   void NotifyPull(MediaTrackGraph* aGraph, TrackTime aEndOfAppendedData,
                   TrackTime aDesiredTime) override;
 
   const RefPtr<SourceMediaTrack> mTrack;
   const PrincipalHandle mPrincipalHandle;
-  const UniquePtr<SineWaveGenerator<int16_t>> mSineGenerator;
+  const UniquePtr<SineWaveGenerator> mSineGenerator;
 };
 
 /**
  * Default audio source.
  */
 
 MediaEngineDefaultAudioSource::MediaEngineDefaultAudioSource() = default;
 
--- a/dom/media/webrtc/SineWaveGenerator.h
+++ b/dom/media/webrtc/SineWaveGenerator.h
@@ -5,45 +5,36 @@
 #ifndef SINEWAVEGENERATOR_H_
 #define SINEWAVEGENERATOR_H_
 
 #include "MediaSegment.h"
 
 namespace mozilla {
 
 // generate 1k sine wave per second
-template <typename Sample>
 class SineWaveGenerator {
-  static_assert(std::is_same<Sample, int16_t>::value ||
-                std::is_same<Sample, float>::value);
-
  public:
-  static const int bytesPerSample = sizeof(Sample);
+  static const int bytesPerSample = 2;
   static const int millisecondsPerSecond = PR_MSEC_PER_SEC;
 
-  /* If more than 1 channel, generated samples are interleaved. */
-  SineWaveGenerator(uint32_t aSampleRate, uint32_t aFrequency,
-                    uint32_t aChannels = 1)
-      : mTotalLength(aSampleRate * aChannels / aFrequency), mReadLength(0) {
-    MOZ_ASSERT(aChannels >= 1);
+  explicit SineWaveGenerator(uint32_t aSampleRate, uint32_t aFrequency)
+      : mTotalLength(aSampleRate / aFrequency), mReadLength(0) {
     // If we allow arbitrary frequencies, there's no guarantee we won't get
     // rounded here We could include an error term and adjust for it in
     // generation; not worth the trouble
     // MOZ_ASSERT(mTotalLength * aFrequency == aSampleRate);
-    mAudioBuffer = MakeUnique<Sample[]>(mTotalLength);
-    for (uint32_t i = 0; i < aSampleRate / aFrequency; ++i) {
-      for (uint32_t j = 0; j < aChannels; ++j) {
-        mAudioBuffer[i * aChannels + j] =
-            Amplitude() * sin(2 * M_PI * i * aChannels / mTotalLength);
-      }
+    mAudioBuffer = MakeUnique<int16_t[]>(mTotalLength);
+    for (int i = 0; i < mTotalLength; i++) {
+      // Set volume to -20db. It's from 32768.0 * 10^(-20/20) = 3276.8
+      mAudioBuffer[i] = (3276.8f * sin(2 * M_PI * i / mTotalLength));
     }
   }
 
   // NOTE: only safely called from a single thread (MTG callback)
-  void generate(Sample* aBuffer, TrackTicks aLengthInSamples) {
+  void generate(int16_t* aBuffer, TrackTicks aLengthInSamples) {
     TrackTicks remaining = aLengthInSamples;
 
     while (remaining) {
       TrackTicks processSamples = 0;
 
       if (mTotalLength - mReadLength >= remaining) {
         processSamples = remaining;
       } else {
@@ -55,29 +46,17 @@ class SineWaveGenerator {
       mReadLength += processSamples;
       remaining -= processSamples;
       if (mReadLength == mTotalLength) {
         mReadLength = 0;
       }
     }
   }
 
-  void SetOffset(TrackTicks aFrames) { mReadLength = aFrames % mTotalLength; }
-
-  TrackTicks Offset() const { return mReadLength; }
-
-  static float Amplitude() {
-    // Set volume to -20db.
-    if (std::is_same<Sample, int16_t>::value) {
-      return 3276.8;  // 32768.0 * 10^(-20/20) = 3276.8
-    }
-    return 0.1f;  // 1.0 * 10^(-20/20) = 0.1
-  }
-
  private:
-  UniquePtr<Sample[]> mAudioBuffer;
+  UniquePtr<int16_t[]> mAudioBuffer;
   TrackTicks mTotalLength;
   TrackTicks mReadLength;
 };
 
 }  // namespace mozilla
 
 #endif /* SINEWAVEGENERATOR_H_ */
deleted file mode 100644
--- a/media/libspeex_resampler/integer-halving.patch
+++ /dev/null
@@ -1,95 +0,0 @@
-diff --git a/media/libspeex_resampler/src/arch.h b/media/libspeex_resampler/src/arch.h
---- a/media/libspeex_resampler/src/arch.h
-+++ b/media/libspeex_resampler/src/arch.h
-@@ -172,26 +172,23 @@ typedef float spx_word32_t;
- #define SHL(a,shift)       (a)
- #define SATURATE(x,a) (x)
- 
- #define ADD16(a,b) ((a)+(b))
- #define SUB16(a,b) ((a)-(b))
- #define ADD32(a,b) ((a)+(b))
- #define SUB32(a,b) ((a)-(b))
- #define MULT16_16_16(a,b)     ((a)*(b))
-+#define MULT16_32_32(a,b)     ((a)*(b))
- #define MULT16_16(a,b)     ((spx_word32_t)(a)*(spx_word32_t)(b))
- #define MAC16_16(c,a,b)     ((c)+(spx_word32_t)(a)*(spx_word32_t)(b))
- 
--#define MULT16_32_Q11(a,b)     ((a)*(b))
--#define MULT16_32_Q13(a,b)     ((a)*(b))
--#define MULT16_32_Q14(a,b)     ((a)*(b))
- #define MULT16_32_Q15(a,b)     ((a)*(b))
- #define MULT16_32_P15(a,b)     ((a)*(b))
- 
--#define MAC16_32_Q11(c,a,b)     ((c)+(a)*(b))
- #define MAC16_32_Q15(c,a,b)     ((c)+(a)*(b))
- 
- #define MAC16_16_Q11(c,a,b)     ((c)+(a)*(b))
- #define MAC16_16_Q13(c,a,b)     ((c)+(a)*(b))
- #define MAC16_16_P13(c,a,b)     ((c)+(a)*(b))
- #define MULT16_16_Q11_32(a,b)     ((a)*(b))
- #define MULT16_16_Q13(a,b)     ((a)*(b))
- #define MULT16_16_Q14(a,b)     ((a)*(b))
-diff --git a/media/libspeex_resampler/src/fixed_generic.h b/media/libspeex_resampler/src/fixed_generic.h
---- a/media/libspeex_resampler/src/fixed_generic.h
-+++ b/media/libspeex_resampler/src/fixed_generic.h
-@@ -64,32 +64,27 @@
- 
- #define ADD16(a,b) ((spx_word16_t)((spx_word16_t)(a)+(spx_word16_t)(b)))
- #define SUB16(a,b) ((spx_word16_t)(a)-(spx_word16_t)(b))
- #define ADD32(a,b) ((spx_word32_t)(a)+(spx_word32_t)(b))
- #define SUB32(a,b) ((spx_word32_t)(a)-(spx_word32_t)(b))
- 
- 
- /* result fits in 16 bits */
--#define MULT16_16_16(a,b)     ((((spx_word16_t)(a))*((spx_word16_t)(b))))
-+#define MULT16_16_16(a,b)     (((spx_word16_t)(a))*((spx_word16_t)(b)))
-+/* result fits in 32 bits */
-+#define MULT16_32_32(a,b)     (((spx_word16_t)(a))*((spx_word32_t)(b)))
- 
- /* (spx_word32_t)(spx_word16_t) gives TI compiler a hint that it's 16x16->32 multiply */
- #define MULT16_16(a,b)     (((spx_word32_t)(spx_word16_t)(a))*((spx_word32_t)(spx_word16_t)(b)))
- 
- #define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b))))
--#define MULT16_32_Q12(a,b) ADD32(MULT16_16((a),SHR((b),12)), SHR(MULT16_16((a),((b)&0x00000fff)),12))
--#define MULT16_32_Q13(a,b) ADD32(MULT16_16((a),SHR((b),13)), SHR(MULT16_16((a),((b)&0x00001fff)),13))
--#define MULT16_32_Q14(a,b) ADD32(MULT16_16((a),SHR((b),14)), SHR(MULT16_16((a),((b)&0x00003fff)),14))
--
--#define MULT16_32_Q11(a,b) ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11))
--#define MAC16_32_Q11(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11)))
--
--#define MULT16_32_P15(a,b) ADD32(MULT16_16((a),SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15))
--#define MULT16_32_Q15(a,b) ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))
--#define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)))
-+#define MULT16_32_P15(a,b) ADD32(MULT16_32_32(a,SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15))
-+#define MULT16_32_Q15(a,b) ADD32(MULT16_32_32(a,SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))
-+#define MAC16_32_Q15(c,a,b) ADD32(c,MULT16_32_Q15(a,b))
- 
- 
- #define MAC16_16_Q11(c,a,b)     (ADD32((c),SHR(MULT16_16((a),(b)),11)))
- #define MAC16_16_Q13(c,a,b)     (ADD32((c),SHR(MULT16_16((a),(b)),13)))
- #define MAC16_16_P13(c,a,b)     (ADD32((c),SHR(ADD32(4096,MULT16_16((a),(b))),13)))
- 
- #define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11))
- #define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13))
-diff --git a/media/libspeex_resampler/src/resample.c b/media/libspeex_resampler/src/resample.c
---- a/media/libspeex_resampler/src/resample.c
-+++ b/media/libspeex_resampler/src/resample.c
-@@ -474,17 +474,17 @@ static int resampler_basic_interpolate_s
-         const spx_word16_t curr_in=iptr[j];
-         accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
-         accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
-         accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
-         accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
-       }
- 
-       cubic_coef(frac, interp);
--      sum = MULT16_32_Q15(interp[0],SHR32(accum[0], 1)) + MULT16_32_Q15(interp[1],SHR32(accum[1], 1)) + MULT16_32_Q15(interp[2],SHR32(accum[2], 1)) + MULT16_32_Q15(interp[3],SHR32(accum[3], 1));
-+      sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]);
-       sum = SATURATE32PSHR(sum, 15, 32767);
- #ifdef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE
-       } else {
-       cubic_coef(frac, interp);
-       sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);
-       }
- #endif
- 
--- a/media/libspeex_resampler/src/arch.h
+++ b/media/libspeex_resampler/src/arch.h
@@ -172,23 +172,26 @@ typedef float spx_word32_t;
 #define SHL(a,shift)       (a)
 #define SATURATE(x,a) (x)
 
 #define ADD16(a,b) ((a)+(b))
 #define SUB16(a,b) ((a)-(b))
 #define ADD32(a,b) ((a)+(b))
 #define SUB32(a,b) ((a)-(b))
 #define MULT16_16_16(a,b)     ((a)*(b))
-#define MULT16_32_32(a,b)     ((a)*(b))
 #define MULT16_16(a,b)     ((spx_word32_t)(a)*(spx_word32_t)(b))
 #define MAC16_16(c,a,b)     ((c)+(spx_word32_t)(a)*(spx_word32_t)(b))
 
+#define MULT16_32_Q11(a,b)     ((a)*(b))
+#define MULT16_32_Q13(a,b)     ((a)*(b))
+#define MULT16_32_Q14(a,b)     ((a)*(b))
 #define MULT16_32_Q15(a,b)     ((a)*(b))
 #define MULT16_32_P15(a,b)     ((a)*(b))
 
+#define MAC16_32_Q11(c,a,b)     ((c)+(a)*(b))
 #define MAC16_32_Q15(c,a,b)     ((c)+(a)*(b))
 
 #define MAC16_16_Q11(c,a,b)     ((c)+(a)*(b))
 #define MAC16_16_Q13(c,a,b)     ((c)+(a)*(b))
 #define MAC16_16_P13(c,a,b)     ((c)+(a)*(b))
 #define MULT16_16_Q11_32(a,b)     ((a)*(b))
 #define MULT16_16_Q13(a,b)     ((a)*(b))
 #define MULT16_16_Q14(a,b)     ((a)*(b))
--- a/media/libspeex_resampler/src/fixed_generic.h
+++ b/media/libspeex_resampler/src/fixed_generic.h
@@ -64,27 +64,32 @@
 
 #define ADD16(a,b) ((spx_word16_t)((spx_word16_t)(a)+(spx_word16_t)(b)))
 #define SUB16(a,b) ((spx_word16_t)(a)-(spx_word16_t)(b))
 #define ADD32(a,b) ((spx_word32_t)(a)+(spx_word32_t)(b))
 #define SUB32(a,b) ((spx_word32_t)(a)-(spx_word32_t)(b))
 
 
 /* result fits in 16 bits */
-#define MULT16_16_16(a,b)     (((spx_word16_t)(a))*((spx_word16_t)(b)))
-/* result fits in 32 bits */
-#define MULT16_32_32(a,b)     (((spx_word16_t)(a))*((spx_word32_t)(b)))
+#define MULT16_16_16(a,b)     ((((spx_word16_t)(a))*((spx_word16_t)(b))))
 
 /* (spx_word32_t)(spx_word16_t) gives TI compiler a hint that it's 16x16->32 multiply */
 #define MULT16_16(a,b)     (((spx_word32_t)(spx_word16_t)(a))*((spx_word32_t)(spx_word16_t)(b)))
 
 #define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b))))
-#define MULT16_32_P15(a,b) ADD32(MULT16_32_32(a,SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15))
-#define MULT16_32_Q15(a,b) ADD32(MULT16_32_32(a,SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))
-#define MAC16_32_Q15(c,a,b) ADD32(c,MULT16_32_Q15(a,b))
+#define MULT16_32_Q12(a,b) ADD32(MULT16_16((a),SHR((b),12)), SHR(MULT16_16((a),((b)&0x00000fff)),12))
+#define MULT16_32_Q13(a,b) ADD32(MULT16_16((a),SHR((b),13)), SHR(MULT16_16((a),((b)&0x00001fff)),13))
+#define MULT16_32_Q14(a,b) ADD32(MULT16_16((a),SHR((b),14)), SHR(MULT16_16((a),((b)&0x00003fff)),14))
+
+#define MULT16_32_Q11(a,b) ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11))
+#define MAC16_32_Q11(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11)))
+
+#define MULT16_32_P15(a,b) ADD32(MULT16_16((a),SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15))
+#define MULT16_32_Q15(a,b) ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))
+#define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)))
 
 
 #define MAC16_16_Q11(c,a,b)     (ADD32((c),SHR(MULT16_16((a),(b)),11)))
 #define MAC16_16_Q13(c,a,b)     (ADD32((c),SHR(MULT16_16((a),(b)),13)))
 #define MAC16_16_P13(c,a,b)     (ADD32((c),SHR(ADD32(4096,MULT16_16((a),(b))),13)))
 
 #define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11))
 #define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13))
--- a/media/libspeex_resampler/src/resample.c
+++ b/media/libspeex_resampler/src/resample.c
@@ -474,17 +474,17 @@ static int resampler_basic_interpolate_s
         const spx_word16_t curr_in=iptr[j];
         accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]);
         accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]);
         accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]);
         accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]);
       }
 
       cubic_coef(frac, interp);
-      sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]);
+      sum = MULT16_32_Q15(interp[0],SHR32(accum[0], 1)) + MULT16_32_Q15(interp[1],SHR32(accum[1], 1)) + MULT16_32_Q15(interp[2],SHR32(accum[2], 1)) + MULT16_32_Q15(interp[3],SHR32(accum[3], 1));
       sum = SATURATE32PSHR(sum, 15, 32767);
 #ifdef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE
       } else {
       cubic_coef(frac, interp);
       sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp);
       }
 #endif
 
--- a/media/libspeex_resampler/update.sh
+++ b/media/libspeex_resampler/update.sh
@@ -21,9 +21,8 @@ cp $1/COPYING .
 
 # apply outstanding local patches
 patch -p3 < outside-speex.patch
 patch -p3 < simd-detect-runtime.patch
 patch -p3 < set-skip-frac.patch
 patch -p3 < hugemem.patch
 patch -p3 < remove-empty-asm-clobber.patch
 patch -p3 < set-rate-overflow-no-return.patch
-patch -p3 < integer-halving.patch
--- a/modules/libpref/init/StaticPrefList.yaml
+++ b/modules/libpref/init/StaticPrefList.yaml
@@ -6752,21 +6752,21 @@
 #elif defined(XP_WIN) && defined(_X86_)
   value: @IS_EARLY_BETA_OR_EARLIER@
 #elif defined(XP_WIN) && !defined(_ARM64_)
   value: true
 #else
   value: false
 #endif
 
-# ClockDrift desired buffering in milliseconds
+# ClockDrift desired buffering
 - name: media.clockdrift.buffering
   type: int32_t
   mirror: always
-  value: 50
+  value: 5
 
 # If a resource is known to be smaller than this size (in kilobytes), a
 # memory-backed MediaCache may be used; otherwise the (single shared global)
 # file-backed MediaCache is used.
 - name: media.memory_cache_max_size
   type: uint32_t
   value: 8192        # Measured in KiB
   mirror: always
--- a/tools/lint/file-whitespace.yml
+++ b/tools/lint/file-whitespace.yml
@@ -37,16 +37,18 @@ file-whitespace:
         - dom/events/crashtests
         - dom/events/test
         - dom/file/tests/file_mozfiledataurl_inner.html
         - dom/html/crashtests
         - dom/html/reftests
         - dom/html/test
         - dom/jsurl/crashtests/344996-1.xhtml
         - dom/jsurl/test
+        - dom/media/gtest/AudioGenerator.cpp
+        - dom/media/gtest/AudioGenerator.h
         - dom/media/mediasource/test/crashtests/926665.html
         - dom/media/test
         - dom/media/tests
         - dom/media/webaudio/test
         - dom/media/webspeech/synth/test
         - dom/plugins/test
         - dom/smil/crashtests
         - dom/smil/test