Backed out 5 changesets (bug 1187817) for making test_mediatrack_consuming_mediaresource.html extremely failure-prone on B2G. a=me
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 28 Jul 2015 14:36:49 -0400
changeset 286615 42521959e9b93b68690c60c6130a5b1012b13aa9
parent 286614 b92398507d914889b185ee4821866ed01f68b142
child 286634 833403badc41c2e63b0dcd542beace00de64ea15
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme
bugs1187817
milestone42.0a1
backs outae2e2dda1eec5fcd90ab8c1bc9d7b8e4c5413d17
74386997e5fb675f2710fbb9e3188e9254027c9e
d31a0c93969f3190cd8a148d13588335ddee82de
cf38bd59eb44ac9e78ac96c78b51a3b604f96e1a
264dad192c22bad82d56abbd50f20ff5055e7064
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 5 changesets (bug 1187817) for making test_mediatrack_consuming_mediaresource.html extremely failure-prone on B2G. a=me Backed out changeset ae2e2dda1eec (bug 1187817) Backed out changeset 74386997e5fb (bug 1187817) Backed out changeset d31a0c93969f (bug 1187817) Backed out changeset cf38bd59eb44 (bug 1187817) Backed out changeset 264dad192c22 (bug 1187817)
dom/media/AudioSink.cpp
dom/media/AudioSink.h
--- a/dom/media/AudioSink.cpp
+++ b/dom/media/AudioSink.cpp
@@ -31,17 +31,23 @@ AudioSink::AudioSink(MediaQueue<AudioDat
   , mMonitor("AudioSink::mMonitor")
   , mState(AUDIOSINK_STATE_INIT)
   , mAudioLoopScheduled(false)
   , mStartTime(aStartTime)
   , mWritten(0)
   , mLastGoodPosition(0)
   , mInfo(aInfo)
   , mChannel(aChannel)
+  , mVolume(1.0)
+  , mPlaybackRate(1.0)
+  , mPreservesPitch(false)
   , mStopAudioThread(false)
+  , mSetVolume(false)
+  , mSetPlaybackRate(false)
+  , mSetPreservesPitch(false)
   , mPlaying(true)
 {
 }
 
 void
 AudioSink::SetState(State aState)
 {
   AssertOnAudioThread();
@@ -122,31 +128,25 @@ AudioSink::HasUnplayedFrames()
   // Experimentation suggests that GetPositionInFrames() is zero-indexed,
   // so we need to add 1 here before comparing it to mWritten.
   return mAudioStream && mAudioStream->GetPositionInFrames() + 1 < mWritten;
 }
 
 void
 AudioSink::Shutdown()
 {
-  {
-    ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
-    if (mAudioStream) {
-      mAudioStream->Cancel();
-    }
+  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+  mStopAudioThread = true;
+  if (mAudioStream) {
+    mAudioStream->Cancel();
   }
-  nsRefPtr<AudioSink> self = this;
-  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
-    self->mStopAudioThread = true;
-    if (!self->mAudioLoopScheduled) {
-      self->AudioLoop();
-    }
-  });
-  DispatchTask(r.forget());
+  ScheduleNextLoopCrossThread();
 
+  // Exit the monitor so audio loop can enter the monitor and finish its job.
+  ReentrantMonitorAutoExit exit(GetReentrantMonitor());
   mThread->Shutdown();
   mThread = nullptr;
   if (mAudioStream) {
     mAudioStream->Shutdown();
     mAudioStream = nullptr;
   }
 
   // Should've reached the final state after shutdown.
@@ -154,76 +154,44 @@ AudioSink::Shutdown()
              mState == AUDIOSINK_STATE_ERROR);
   // Should have no pending state change.
   MOZ_ASSERT(mPendingState.isNothing());
 }
 
 void
 AudioSink::SetVolume(double aVolume)
 {
-  AssertNotOnAudioThread();
-  nsRefPtr<AudioSink> self = this;
-  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
-    if (self->mState == AUDIOSINK_STATE_PLAYING) {
-      self->mAudioStream->SetVolume(aVolume);
-    }
-  });
-  DispatchTask(r.forget());
+  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+  mVolume = aVolume;
+  mSetVolume = true;
 }
 
 void
 AudioSink::SetPlaybackRate(double aPlaybackRate)
 {
-  AssertNotOnAudioThread();
-  MOZ_ASSERT(aPlaybackRate != 0, "Don't set the playbackRate to 0 on AudioStream");
-  nsRefPtr<AudioSink> self = this;
-  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
-    if (self->mState == AUDIOSINK_STATE_PLAYING) {
-      self->mAudioStream->SetPlaybackRate(aPlaybackRate);
-    }
-  });
-  DispatchTask(r.forget());
+  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+  NS_ASSERTION(mPlaybackRate != 0, "Don't set the playbackRate to 0 on AudioStream");
+  mPlaybackRate = aPlaybackRate;
+  mSetPlaybackRate = true;
 }
 
 void
 AudioSink::SetPreservesPitch(bool aPreservesPitch)
 {
-  AssertNotOnAudioThread();
-  nsRefPtr<AudioSink> self = this;
-  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
-    if (self->mState == AUDIOSINK_STATE_PLAYING) {
-      self->mAudioStream->SetPreservesPitch(aPreservesPitch);
-    }
-  });
-  DispatchTask(r.forget());
+  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+  mPreservesPitch = aPreservesPitch;
+  mSetPreservesPitch = true;
 }
 
 void
 AudioSink::SetPlaying(bool aPlaying)
 {
-  AssertNotOnAudioThread();
-  nsRefPtr<AudioSink> self = this;
-  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
-    if (self->mState != AUDIOSINK_STATE_PLAYING ||
-        self->mPlaying == aPlaying) {
-      return;
-    }
-    self->mPlaying = aPlaying;
-    // pause/resume AudioStream as necessary.
-    if (!aPlaying && !self->mAudioStream->IsPaused()) {
-      self->mAudioStream->Pause();
-    } else if (aPlaying && self->mAudioStream->IsPaused()) {
-      self->mAudioStream->Resume();
-    }
-    // Wake up the audio loop to play next sample.
-    if (aPlaying && !self->mAudioLoopScheduled) {
-      self->AudioLoop();
-    }
-  });
-  DispatchTask(r.forget());
+  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+  mPlaying = aPlaying;
+  ScheduleNextLoopCrossThread();
 }
 
 void
 AudioSink::NotifyData()
 {
   ScheduleNextLoopCrossThread();
 }
 
@@ -238,69 +206,82 @@ AudioSink::InitializeAudioStream()
                                   mChannel, AudioStream::HighLatency);
   if (NS_FAILED(rv)) {
     audioStream->Shutdown();
     return rv;
   }
 
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   mAudioStream = audioStream;
+  UpdateStreamSettings();
 
   return NS_OK;
 }
 
 void
 AudioSink::Drain()
 {
-  AssertOnAudioThread();
   MOZ_ASSERT(mPlaying && !mAudioStream->IsPaused());
+  AssertCurrentThreadInMonitor();
   // If the media was too short to trigger the start of the audio stream,
   // start it now.
   mAudioStream->Start();
-  mAudioStream->Drain();
+  {
+    ReentrantMonitorAutoExit exit(GetReentrantMonitor());
+    mAudioStream->Drain();
+  }
 }
 
 void
 AudioSink::Cleanup()
 {
-  AssertOnAudioThread();
+  AssertCurrentThreadInMonitor();
   mEndPromise.Resolve(true, __func__);
   // Since the promise if resolved asynchronously, we don't shutdown
   // AudioStream here so MDSM::ResyncAudioClock can get the correct
   // audio position.
 }
 
 bool
 AudioSink::ExpectMoreAudioData()
 {
   return AudioQueue().GetSize() == 0 && !AudioQueue().IsFinished();
 }
 
 bool
 AudioSink::WaitingForAudioToPlay()
 {
-  AssertOnAudioThread();
   // Return true if we're not playing, and we're not shutting down, or we're
   // playing and we've got no audio to play.
+  AssertCurrentThreadInMonitor();
   if (!mStopAudioThread && (!mPlaying || ExpectMoreAudioData())) {
+    if (!mPlaying && !mAudioStream->IsPaused()) {
+      mAudioStream->Pause();
+    }
     return true;
   }
   return false;
 }
 
 bool
 AudioSink::IsPlaybackContinuing()
 {
-  AssertOnAudioThread();
+  AssertCurrentThreadInMonitor();
+  if (mPlaying && mAudioStream->IsPaused()) {
+    mAudioStream->Resume();
+  }
+
   // If we're shutting down, captured, or at EOS, break out and exit the audio
   // thread.
   if (mStopAudioThread || AudioQueue().AtEndOfStream()) {
     return false;
   }
 
+  UpdateStreamSettings();
+
   return true;
 }
 
 void
 AudioSink::AudioLoop()
 {
   AssertOnAudioThread();
   mAudioLoopScheduled = false;
@@ -315,23 +296,26 @@ AudioSink::AudioLoop()
         SetState(AUDIOSINK_STATE_ERROR);
         break;
       }
       SetState(AUDIOSINK_STATE_PLAYING);
       break;
     }
 
     case AUDIOSINK_STATE_PLAYING: {
-      if (WaitingForAudioToPlay()) {
-        // NotifyData() will schedule next loop.
-        break;
-      }
-      if (!IsPlaybackContinuing()) {
-        SetState(AUDIOSINK_STATE_COMPLETE);
-        break;
+      {
+        ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+        if (WaitingForAudioToPlay()) {
+          // NotifyData() will schedule next loop.
+          break;
+        }
+        if (!IsPlaybackContinuing()) {
+          SetState(AUDIOSINK_STATE_COMPLETE);
+          break;
+        }
       }
       if (!PlayAudio()) {
         SetState(AUDIOSINK_STATE_COMPLETE);
         break;
       }
       // Schedule next loop to play next sample.
       ScheduleNextLoop();
       break;
@@ -394,17 +378,17 @@ AudioSink::PlayAudio()
   }
 
   return true;
 }
 
 void
 AudioSink::FinishAudioLoop()
 {
-  AssertOnAudioThread();
+  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   MOZ_ASSERT(mStopAudioThread || AudioQueue().AtEndOfStream());
   if (!mStopAudioThread && mPlaying) {
     Drain();
   }
   SINK_LOG("AudioLoop complete");
   Cleanup();
   SINK_LOG("AudioLoop exit");
 }
@@ -446,16 +430,50 @@ AudioSink::PlayFromAudioQueue()
   }
 
   StartAudioStreamPlaybackIfNeeded();
 
   return audio->mFrames;
 }
 
 void
+AudioSink::UpdateStreamSettings()
+{
+  AssertCurrentThreadInMonitor();
+
+  bool setVolume = mSetVolume;
+  bool setPlaybackRate = mSetPlaybackRate;
+  bool setPreservesPitch = mSetPreservesPitch;
+  double volume = mVolume;
+  double playbackRate = mPlaybackRate;
+  bool preservesPitch = mPreservesPitch;
+
+  mSetVolume = false;
+  mSetPlaybackRate = false;
+  mSetPreservesPitch = false;
+
+  {
+    ReentrantMonitorAutoExit exit(GetReentrantMonitor());
+    if (setVolume) {
+      mAudioStream->SetVolume(volume);
+    }
+
+    if (setPlaybackRate &&
+        NS_FAILED(mAudioStream->SetPlaybackRate(playbackRate))) {
+      NS_WARNING("Setting the playback rate failed in AudioSink.");
+    }
+
+    if (setPreservesPitch &&
+      NS_FAILED(mAudioStream->SetPreservesPitch(preservesPitch))) {
+      NS_WARNING("Setting the pitch preservation failed in AudioSink.");
+    }
+  }
+}
+
+void
 AudioSink::StartAudioStreamPlaybackIfNeeded()
 {
   // This value has been chosen empirically.
   const uint32_t MIN_WRITE_BEFORE_START_USECS = 200000;
 
   // We want to have enough data in the buffer to start the stream.
   if (static_cast<double>(mAudioStream->GetWritten()) / mAudioStream->GetRate() >=
       static_cast<double>(MIN_WRITE_BEFORE_START_USECS) / USECS_PER_S) {
--- a/dom/media/AudioSink.h
+++ b/dom/media/AudioSink.h
@@ -109,16 +109,18 @@ private:
   // impossibly large chunk of memory in order to play back silence. Called
   // on the audio thread.
   uint32_t PlaySilence(uint32_t aFrames);
 
   // Pops an audio chunk from the front of the audio queue, and pushes its
   // audio data to the audio hardware.  Called on the audio thread.
   uint32_t PlayFromAudioQueue();
 
+  void UpdateStreamSettings();
+
   // If we have already written enough frames to the AudioStream, start the
   // playback.
   void StartAudioStreamPlaybackIfNeeded();
   void WriteSilence(uint32_t aFrames);
 
   MediaQueue<AudioData>& AudioQueue() const {
     return mAudioQueue;
   }
@@ -165,18 +167,26 @@ private:
   // position returned by GetPosition() is mono-increasing in spite of audio
   // stream error.
   int64_t mLastGoodPosition;
 
   const AudioInfo mInfo;
 
   dom::AudioChannel mChannel;
 
+  double mVolume;
+  double mPlaybackRate;
+  bool mPreservesPitch;
+
   bool mStopAudioThread;
 
+  bool mSetVolume;
+  bool mSetPlaybackRate;
+  bool mSetPreservesPitch;
+
   bool mPlaying;
 
   MozPromiseHolder<GenericPromise> mEndPromise;
 };
 
 } // namespace mozilla
 
 #endif