Bug 1264199: P5. Perform all downmixing operations in DecodedAudioDataSink. r=kinetik
☠☠ backed out by 30c5dbcee7dd ☠ ☠
authorJean-Yves Avenard <jyavenard@mozilla.com>
Wed, 13 Apr 2016 20:25:50 +1000
changeset 331852 b79b62146120ca32cbe16d6283a0ab25b8d13c0e
parent 331851 f587df589b69827d23336fa528560130dc86dd39
child 331853 f484b42cbddaa4ff6a2407d5886db24c30b59537
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: P5. Perform all downmixing operations in DecodedAudioDataSink. r=kinetik Performing all audio processing operations in the same place, allows to simplify the code. Additionally, if accessibility.monoaudio.enable is not set, we always upmix mono to stereo so that if the first audio stream seen was mono, we aren't stuck playing all future streams in mono. MozReview-Commit-ID: 5yANN6PLFhX
dom/media/AudioStream.cpp
dom/media/AudioStream.h
dom/media/mediasink/DecodedAudioDataSink.cpp
--- a/dom/media/AudioStream.cpp
+++ b/dom/media/AudioStream.cpp
@@ -124,17 +124,16 @@ AudioStream::AudioStream(DataSource& aSo
   , mInRate(0)
   , mOutRate(0)
   , mChannels(0)
   , mOutChannels(0)
   , mAudioClock(this)
   , mTimeStretcher(nullptr)
   , mDumpFile(nullptr)
   , mState(INITIALIZED)
-  , mIsMonoAudioEnabled(gfxPrefs::MonoAudio())
   , mDataSource(aSource)
 {
 }
 
 AudioStream::~AudioStream()
 {
   LOG("deleted, state %d", mState);
   MOZ_ASSERT(mState == SHUTDOWN && !mCubebStream,
@@ -326,17 +325,17 @@ AudioStream::Init(uint32_t aNumChannels,
   if (!CubebUtils::GetCubebContext()) {
     return NS_ERROR_FAILURE;
   }
 
   MOZ_LOG(gAudioStreamLog, LogLevel::Debug,
     ("%s  channels: %d, rate: %d for %p", __FUNCTION__, aNumChannels, aRate, this));
   mInRate = mOutRate = aRate;
   mChannels = aNumChannels;
-  mOutChannels = mIsMonoAudioEnabled ? 1 : aNumChannels;
+  mOutChannels = aNumChannels;
 
   mDumpFile = OpenDumpFile(this);
 
   cubeb_stream_params params;
   params.rate = aRate;
   params.channels = mOutChannels;
 #if defined(__ANDROID__)
 #if defined(MOZ_B2G)
@@ -348,21 +347,16 @@ AudioStream::Init(uint32_t aNumChannels,
   if (params.stream_type == CUBEB_STREAM_TYPE_MAX) {
     return NS_ERROR_INVALID_ARG;
   }
 #endif
 
   params.format = ToCubebFormat<AUDIO_OUTPUT_FORMAT>::value;
   mAudioClock.Init();
 
-  if (mIsMonoAudioEnabled) {
-    AudioConfig inConfig(mChannels, mInRate);
-    AudioConfig outConfig(mOutChannels, mOutRate);
-    mAudioConverter = MakeUnique<AudioConverter>(inConfig, outConfig);
-  }
   return OpenCubeb(params);
 }
 
 // This code used to live inside AudioStream::Init(), but on Mac (others?)
 // it has been known to take 300-800 (or even 8500) ms to execute(!)
 nsresult
 AudioStream::OpenCubeb(cubeb_stream_params &aParams)
 {
@@ -547,31 +541,27 @@ AudioStream::GetPositionInFramesUnlocked
 bool
 AudioStream::IsPaused()
 {
   MonitorAutoLock mon(mMonitor);
   return mState == STOPPED;
 }
 
 bool
-AudioStream::Downmix(Chunk* aChunk)
+AudioStream::IsValidAudioFormat(Chunk* aChunk)
 {
   if (aChunk->Rate() != mInRate) {
     LOGW("mismatched sample %u, mInRate=%u", aChunk->Rate(), mInRate);
     return false;
   }
 
   if (aChunk->Channels() > 8) {
     return false;
   }
 
-  if (mAudioConverter) {
-    mAudioConverter->Process(aChunk->GetWritable(), aChunk->Frames());
-  }
-
   return true;
 }
 
 void
 AudioStream::GetUnprocessed(AudioBufferWriter& aWriter)
 {
   mMonitor.AssertCurrentThreadOwns();
 
@@ -590,20 +580,20 @@ AudioStream::GetUnprocessed(AudioBufferW
   }
 
   while (aWriter.Available() > 0) {
     UniquePtr<Chunk> c = mDataSource.PopFrames(aWriter.Available());
     if (c->Frames() == 0) {
       break;
     }
     MOZ_ASSERT(c->Frames() <= aWriter.Available());
-    if (Downmix(c.get())) {
+    if (IsValidAudioFormat(c.get())) {
       aWriter.Write(c->Data(), c->Frames());
     } else {
-      // Write silence if downmixing fails.
+      // Write silence if invalid format.
       aWriter.WriteZeros(c->Frames());
     }
   }
 }
 
 void
 AudioStream::GetTimeStretched(AudioBufferWriter& aWriter)
 {
@@ -618,20 +608,20 @@ AudioStream::GetTimeStretched(AudioBuffe
   uint32_t toPopFrames = ceil(aWriter.Available() * playbackRate);
 
   while (mTimeStretcher->numSamples() < aWriter.Available()) {
     UniquePtr<Chunk> c = mDataSource.PopFrames(toPopFrames);
     if (c->Frames() == 0) {
       break;
     }
     MOZ_ASSERT(c->Frames() <= toPopFrames);
-    if (Downmix(c.get())) {
+    if (IsValidAudioFormat(c.get())) {
       mTimeStretcher->putSamples(c->Data(), c->Frames());
     } else {
-      // Write silence if downmixing fails.
+      // Write silence if invalid format.
       AutoTArray<AudioDataValue, 1000> buf;
       buf.SetLength(mOutChannels * c->Frames());
       memset(buf.Elements(), 0, buf.Length() * sizeof(AudioDataValue));
       mTimeStretcher->putSamples(buf.Elements(), c->Frames());
     }
   }
 
   auto timeStretcher = mTimeStretcher;
--- a/dom/media/AudioStream.h
+++ b/dom/media/AudioStream.h
@@ -328,18 +328,19 @@ private:
   }
 
 
   long DataCallback(void* aBuffer, long aFrames);
   void StateCallback(cubeb_state aState);
 
   nsresult EnsureTimeStretcherInitializedUnlocked();
 
-  // Return true if downmixing succeeds otherwise false.
-  bool Downmix(Chunk* aChunk);
+  // Return true if audio frames are valid (correct sampling rate and valid
+  // channel count) otherwise false.
+  bool IsValidAudioFormat(Chunk* aChunk);
 
   void GetUnprocessed(AudioBufferWriter& aWriter);
   void GetTimeStretched(AudioBufferWriter& aWriter);
 
   void StartUnlocked();
 
   // The monitor is held to protect all access to member variables.
   Monitor mMonitor;
@@ -369,19 +370,15 @@ private:
     STOPPED,     // Stopped by a call to Pause().
     DRAINED,     // StateCallback has indicated that the drain is complete.
     ERRORED,     // Stream disabled due to an internal error.
     SHUTDOWN     // Shutdown has been called
   };
 
   StreamState mState;
   bool mIsFirst;
-  // Get this value from the preference, if true, we would downmix the stereo.
-  bool mIsMonoAudioEnabled;
 
   DataSource& mDataSource;
-
-  UniquePtr<AudioConverter> mAudioConverter;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/mediasink/DecodedAudioDataSink.cpp
+++ b/dom/media/mediasink/DecodedAudioDataSink.cpp
@@ -58,18 +58,20 @@ DecodedAudioDataSink::DecodedAudioDataSi
     // content provider want change from those rates mid-stream.
     mOutputRate = mInfo.mRate;
   } else {
     // We will resample all data to match cubeb's preferred sampling rate.
     mOutputRate = AudioStream::GetPreferredRate();
   }
   MOZ_DIAGNOSTIC_ASSERT(mOutputRate, "output rate can't be 0.");
 
-  mOutputChannels = mInfo.mChannels > 2 && gfxPrefs::AudioSinkForceStereo()
-                      ? 2 : mInfo.mChannels;
+  bool monoAudioEnabled = gfxPrefs::MonoAudio();
+
+  mOutputChannels = monoAudioEnabled
+    ? 1 : (gfxPrefs::AudioSinkForceStereo() ? 2 : mInfo.mChannels);
 }
 
 DecodedAudioDataSink::~DecodedAudioDataSink()
 {
 }
 
 RefPtr<GenericPromise>
 DecodedAudioDataSink::Init(const PlaybackParams& aParams)