Bug 1264199: P2. Ensure the AudioStream only ever receive the same content format. r=kinetik
☠☠ backed out by 39ea6efa54bb ☠ ☠
authorJean-Yves Avenard <jyavenard@mozilla.com>
Wed, 13 Apr 2016 17:30:23 +1000
changeset 332146 d01ac4659cb4cd9871cd11d8e529864ebf78ea05
parent 332145 198add1ad218719bb6034299afa6b841fcd1ec46
child 332147 697006992f04bd04454a74f997a5fe8e15ff3eb4
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik
bugs1264199
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1264199: P2. Ensure the AudioStream only ever receive the same content format. r=kinetik The audio is automatically converted to always match the format of the first processed sample. This is a temporary approach, as it would be preferred to use a final sampling rate not causing too much quality loss. MozReview-Commit-ID: Lo3827aon43
dom/media/mediasink/DecodedAudioDataSink.cpp
--- a/dom/media/mediasink/DecodedAudioDataSink.cpp
+++ b/dom/media/mediasink/DecodedAudioDataSink.cpp
@@ -51,20 +51,16 @@ DecodedAudioDataSink::DecodedAudioDataSi
   , mFramesParsed(0)
   , mLastEndTime(0)
 {
   bool resampling = gfxPrefs::AudioSinkResampling();
   uint32_t resamplingRate = gfxPrefs::AudioSinkResampleRate();
   mOutputRate = resampling ? resamplingRate : mInfo.mRate;
   mOutputChannels = mInfo.mChannels > 2 && gfxPrefs::AudioSinkForceStereo()
                       ? 2 : mInfo.mChannels;
-  mConverter =
-    MakeUnique<AudioConverter>(
-      AudioConfig(mInfo.mChannels, mInfo.mRate),
-      AudioConfig(mOutputChannels, mOutputRate));
 }
 
 DecodedAudioDataSink::~DecodedAudioDataSink()
 {
 }
 
 RefPtr<GenericPromise>
 DecodedAudioDataSink::Init(const PlaybackParams& aParams)
@@ -319,23 +315,46 @@ DecodedAudioDataSink::NotifyAudioNeeded(
     RefPtr<AudioData> data =
       dont_AddRef(AudioQueue().PopFront().take()->As<AudioData>());
 
     // Ignore the element with 0 frames and try next.
     if (!data->mFrames) {
       continue;
     }
 
-    // Ignore invalid samples.
-    if (data->mRate != mConverter->InputConfig().Rate() ||
-        data->mChannels != mConverter->InputConfig().Channels()) {
-      NS_WARNING(nsPrintfCString(
-        "mismatched sample format, data=%p rate=%u channels=%u frames=%u",
-        data->mAudioData.get(), data->mRate, data->mChannels, data->mFrames).get());
-      continue;
+    if (!mConverter ||
+        (data->mRate != mConverter->InputConfig().Rate() ||
+         data->mChannels != mConverter->InputConfig().Channels())) {
+      SINK_LOG_V("Audio format changed from %u@%uHz to %u@%uHz",
+                 mConverter? mConverter->InputConfig().Channels() : 0,
+                 mConverter ? mConverter->InputConfig().Rate() : 0,
+                 data->mChannels, data->mRate);
+
+      // mFramesParsed indicates the current playtime in frames at the current
+      // input sampling rate. Recalculate it per the new sampling rate.
+      if (mFramesParsed) {
+        // We minimize overflow.
+        uint32_t oldRate = mConverter->InputConfig().Rate();
+        uint32_t newRate = data->mRate;
+        int64_t major = mFramesParsed / oldRate;
+        int64_t remainder = mFramesParsed % oldRate;
+        CheckedInt64 result =
+          CheckedInt64(remainder) * newRate / oldRate + major * oldRate;
+        if (!result.isValid()) {
+          NS_WARNING("Int overflow in DecodedAudioDataSink");
+          mErrored = true;
+          return;
+        }
+        mFramesParsed = result.value();
+      }
+
+      mConverter =
+        MakeUnique<AudioConverter>(
+          AudioConfig(data->mChannels, data->mRate),
+          AudioConfig(mOutputChannels, mOutputRate));
     }
 
     // See if there's a gap in the audio. If there is, push silence into the
     // audio hardware, so we can play across the gap.
     // Calculate the timestamp of the next chunk of audio in numbers of
     // samples.
     CheckedInt64 sampleTime = UsecsToFrames(data->mTime - mStartTime,
                                             data->mRate);