Bug 1264199: P2. Ensure the AudioStream only ever receive the same content format. r=kinetik
☠☠ backed out by 30c5dbcee7dd ☠ ☠
authorJean-Yves Avenard <jyavenard@mozilla.com>
Wed, 13 Apr 2016 17:30:23 +1000
changeset 331849 d3677ae4c8ecb9aa68e750bb1966cef127edc6dc
parent 331848 d08288654ec9a96d7b685c18efac351551d8fc35
child 331850 02f781a573b45dba4b69ab7b7b52d76f4243d658
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
@@ -47,20 +47,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)
@@ -312,23 +308,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);