Bug 1127171 - Put mozCaptureStream operations in the same lock. r=roc a=lmandel
authorJW Wang <jwwang@mozilla.com>
Wed, 28 Jan 2015 18:57:00 -0500
changeset 249760 8f0a84889c63aee5b0c05ec7a49c9cba1fa2be75
parent 249759 0c58c1cc9ae798c17e8cdc4dcdb26387e338e77b
child 249761 d89186268fb48a66a04d71f4a0a69c96a847eaa8
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, lmandel
bugs1127171
milestone37.0a2
Bug 1127171 - Put mozCaptureStream operations in the same lock. r=roc a=lmandel
dom/html/HTMLMediaElement.cpp
dom/media/MediaDecoder.cpp
dom/media/MediaDecoder.h
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1874,17 +1874,16 @@ HTMLMediaElement::CaptureStreamInternal(
   out->mFinishWhenEnded = aFinishWhenEnded;
 
   mAudioCaptured = true;
   // Block the output stream initially.
   // Decoders are responsible for removing the block while they are playing
   // back into the output stream.
   out->mStream->GetStream()->ChangeExplicitBlockerCount(1);
   if (mDecoder) {
-    mDecoder->SetAudioCaptured(true);
     mDecoder->AddOutputStream(
         out->mStream->GetStream()->AsProcessedStream(), aFinishWhenEnded);
   }
   nsRefPtr<DOMMediaStream> result = out->mStream;
   return result.forget();
 }
 
 already_AddRefed<DOMMediaStream>
@@ -2689,17 +2688,16 @@ nsresult HTMLMediaElement::FinishDecoder
   // Set mDecoder now so if methods like GetCurrentSrc get called between
   // here and Load(), they work.
   mDecoder = aDecoder;
 
   // Tell the decoder about its MediaResource now so things like principals are
   // available immediately.
   mDecoder->SetResource(aStream);
   mDecoder->SetAudioChannel(mAudioChannel);
-  mDecoder->SetAudioCaptured(mAudioCaptured);
   mDecoder->SetVolume(mMuted ? 0.0 : mVolume);
   mDecoder->SetPreservesPitch(mPreservesPitch);
   mDecoder->SetPlaybackRate(mPlaybackRate);
   if (mPreloadAction == HTMLMediaElement::PRELOAD_METADATA) {
     mDecoder->SetMinimizePrerollUntilPlaybackStarts();
   }
 
   for (uint32_t i = 0; i < mOutputStreams.Length(); ++i) {
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -258,25 +258,16 @@ void MediaDecoder::SetVolume(double aVol
 {
   MOZ_ASSERT(NS_IsMainThread());
   mInitialVolume = aVolume;
   if (mDecoderStateMachine) {
     mDecoderStateMachine->SetVolume(aVolume);
   }
 }
 
-void MediaDecoder::SetAudioCaptured(bool aCaptured)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  mInitialAudioCaptured = aCaptured;
-  if (mDecoderStateMachine) {
-    mDecoderStateMachine->SetAudioCaptured(aCaptured);
-  }
-}
-
 void MediaDecoder::ConnectDecodedStreamToOutputStream(OutputStreamData* aStream)
 {
   NS_ASSERTION(!aStream->mPort, "Already connected?");
 
   // The output stream must stay in sync with the decoded stream, so if
   // either stream is blocked, we block the other.
   aStream->mPort = aStream->mStream->AllocateInputPort(mDecodedStream->mStream,
       MediaInputPort::FLAG_BLOCK_INPUT | MediaInputPort::FLAG_BLOCK_OUTPUT);
@@ -355,23 +346,16 @@ MediaDecoder::DecodedStreamGraphListener
 {
   if (event == EVENT_FINISHED) {
     nsCOMPtr<nsIRunnable> event =
       NS_NewRunnableMethod(this, &DecodedStreamGraphListener::DoNotifyFinished);
     aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
   }
 }
 
-void MediaDecoder::RecreateDecodedStreamIfNecessary(int64_t aStartTimeUSecs)
-{
-  if (mInitialAudioCaptured) {
-    RecreateDecodedStream(aStartTimeUSecs);
-  }
-}
-
 void MediaDecoder::DestroyDecodedStream()
 {
   MOZ_ASSERT(NS_IsMainThread());
   GetReentrantMonitor().AssertCurrentThreadIn();
 
   if (GetDecodedStream()) {
     GetStateMachine()->ResyncMediaStreamClock();
   } else {
@@ -465,19 +449,23 @@ void MediaDecoder::RecreateDecodedStream
 void MediaDecoder::AddOutputStream(ProcessedMediaStream* aStream,
                                    bool aFinishWhenEnded)
 {
   MOZ_ASSERT(NS_IsMainThread());
   DECODER_LOG("AddOutputStream aStream=%p!", aStream);
 
   {
     ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
-    if (!mDecodedStream) {
-      RecreateDecodedStream(mDecoderStateMachine ?
-          int64_t(mDecoderStateMachine->GetCurrentTime()*USECS_PER_S) : 0);
+    if (mDecoderStateMachine) {
+      mDecoderStateMachine->SetAudioCaptured();
+    }
+    if (!GetDecodedStream()) {
+      int64_t t = mDecoderStateMachine ?
+                  mDecoderStateMachine->GetCurrentTimeUs() : 0;
+      RecreateDecodedStream(t);
     }
     OutputStreamData* os = mOutputStreams.AppendElement();
     os->Init(aStream, aFinishWhenEnded);
     ConnectDecodedStreamToOutputStream(os);
     if (aFinishWhenEnded) {
       // Ensure that aStream finishes the moment mDecodedStream does.
       aStream->SetAutofinish(true);
     }
@@ -667,17 +655,19 @@ nsresult MediaDecoder::InitializeStateMa
   return ScheduleStateMachineThread();
 }
 
 void MediaDecoder::SetStateMachineParameters()
 {
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   mDecoderStateMachine->SetDuration(mDuration);
   mDecoderStateMachine->SetVolume(mInitialVolume);
-  mDecoderStateMachine->SetAudioCaptured(mInitialAudioCaptured);
+  if (GetDecodedStream()) {
+    mDecoderStateMachine->SetAudioCaptured();
+  }
   SetPlaybackRate(mInitialPlaybackRate);
   mDecoderStateMachine->SetPreservesPitch(mInitialPreservesPitch);
   if (mMinimizePreroll) {
     mDecoderStateMachine->SetMinimizePrerollUntilPlaybackStarts();
   }
 }
 
 void MediaDecoder::SetMinimizePrerollUntilPlaybackStarts()
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -369,19 +369,16 @@ public:
   virtual void NotifyOwnerActivityChanged();
 
   void UpdateDormantState(bool aDormantTimeout, bool aActivity);
 
   // Pause video playback.
   virtual void Pause();
   // Adjust the speed of the playback, optionally with pitch correction,
   virtual void SetVolume(double aVolume);
-  // Sets whether audio is being captured. If it is, we won't play any
-  // of our audio.
-  virtual void SetAudioCaptured(bool aCaptured);
 
   virtual void NotifyWaitingForResourcesStatusChanged() MOZ_OVERRIDE;
 
   virtual void SetPlaybackRate(double aPlaybackRate);
   void SetPreservesPitch(bool aPreservesPitch);
 
   // Directs the decoder to not preroll extra samples until the media is
   // played. This reduces the memory overhead of media elements that may
@@ -852,19 +849,16 @@ public:
 
   // Returns true if we're logically playing, that is, if the Play() has
   // been called and Pause() has not or we have not yet reached the end
   // of media. This is irrespective of the seeking state; if the owner
   // calls Play() and then Seek(), we still count as logically playing.
   // The decoder monitor must be held.
   bool IsLogicallyPlaying();
 
-  // Re-create a decoded stream if audio being captured
-  void RecreateDecodedStreamIfNecessary(int64_t aStartTimeUSecs);
-
 #ifdef MOZ_EME
   // This takes the decoder monitor.
   virtual nsresult SetCDMProxy(CDMProxy* aProxy) MOZ_OVERRIDE;
 
   // Decoder monitor must be held.
   virtual CDMProxy* GetCDMProxy() MOZ_OVERRIDE;
 #endif
 
@@ -1063,19 +1057,16 @@ protected:
   double mInitialPlaybackRate;
   bool mInitialPreservesPitch;
 
   // Duration of the media resource. Set to -1 if unknown.
   // Set when the metadata is loaded. Accessed on the main thread
   // only.
   int64_t mDuration;
 
-  // True when playback should start with audio captured (not playing).
-  bool mInitialAudioCaptured;
-
   // True if the media is seekable (i.e. supports random access).
   bool mMediaSeekable;
 
   // True if the media is same-origin with the element. Data can only be
   // passed to MediaStreams when this is true.
   bool mSameOriginMedia;
 
   /******
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1396,47 +1396,57 @@ void MediaDecoderStateMachine::SetVolume
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   mVolume = volume;
   if (mAudioSink) {
     mAudioSink->SetVolume(mVolume);
   }
 }
 
-void MediaDecoderStateMachine::SetAudioCaptured(bool aCaptured)
+void MediaDecoderStateMachine::SetAudioCaptured()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
-  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  if (!mAudioCaptured && aCaptured && !mStopAudioThread) {
+  AssertCurrentThreadInMonitor();
+  if (!mAudioCaptured && !mStopAudioThread) {
     // Make sure the state machine runs as soon as possible. That will
     // stop the audio sink.
     // If mStopAudioThread is true then we're already stopping the audio sink
     // and since we set mAudioCaptured to true, nothing can start it again.
     ScheduleStateMachine();
 
     if (HasAudio()) {
       // The audio clock is active so force a resync now in case the audio
       // clock is ahead of us (observed on Android), since after mAudioCaptured
       // gets set can't call GetAudioClock().
       ResyncAudioClock();
     }
   }
-  mAudioCaptured = aCaptured;
+  mAudioCaptured = true;
 }
 
 double MediaDecoderStateMachine::GetCurrentTime() const
 {
   NS_ASSERTION(NS_IsMainThread() ||
                OnStateMachineThread() ||
                OnDecodeThread(),
                "Should be on main, decode, or state machine thread.");
 
   return static_cast<double>(mCurrentFrameTime) / static_cast<double>(USECS_PER_S);
 }
 
+int64_t MediaDecoderStateMachine::GetCurrentTimeUs() const
+{
+  NS_ASSERTION(NS_IsMainThread() ||
+               OnStateMachineThread() ||
+               OnDecodeThread(),
+               "Should be on main, decode, or state machine thread.");
+
+  return mCurrentFrameTime;
+}
+
 bool MediaDecoderStateMachine::IsRealTime() const {
   return mScheduler->IsRealTime();
 }
 
 int64_t MediaDecoderStateMachine::GetDuration()
 {
   AssertCurrentThreadInMonitor();
 
@@ -1796,17 +1806,19 @@ MediaDecoderStateMachine::StartSeek(cons
   seekTime = std::min(seekTime, end);
   seekTime = std::max(mStartTime, seekTime);
   NS_ASSERTION(seekTime >= mStartTime && seekTime <= end,
                "Can only seek in range [0,duration]");
   mSeekTarget = SeekTarget(seekTime, aTarget.mType);
 
   DECODER_LOG("Changed state to SEEKING (to %lld)", mSeekTarget.mTime);
   SetState(DECODER_STATE_SEEKING);
-  mDecoder->RecreateDecodedStreamIfNecessary(seekTime - mStartTime);
+  if (mAudioCaptured) {
+    mDecoder->RecreateDecodedStream(seekTime - mStartTime);
+  }
   ScheduleStateMachine();
 }
 
 void MediaDecoderStateMachine::StopAudioThread()
 {
   NS_ASSERTION(OnDecodeThread() || OnStateMachineThread(),
                "Should be on decode thread or state machine thread");
   AssertCurrentThreadInMonitor();
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -150,17 +150,17 @@ public:
   State GetState() {
     AssertCurrentThreadInMonitor();
     return mState;
   }
 
   // Set the audio volume. The decoder monitor must be obtained before
   // calling this.
   void SetVolume(double aVolume);
-  void SetAudioCaptured(bool aCapture);
+  void SetAudioCaptured();
 
   // Check if the decoder needs to become dormant state.
   bool IsDormantNeeded();
   // Set/Unset dormant state.
   void SetDormant(bool aDormant);
   void Shutdown();
   void ShutdownReader();
   void FinishShutdown();
@@ -236,16 +236,17 @@ public:
   // Must be called from the main thread.
   // The decoder monitor must be held with exactly one lock count.
   void StartSeek(const SeekTarget& aTarget);
 
   // Returns the current playback position in seconds.
   // Called from the main thread to get the current frame time. The decoder
   // monitor must be obtained before calling this.
   double GetCurrentTime() const;
+  int64_t GetCurrentTimeUs() const;
 
   // Clear the flag indicating that a playback position change event
   // is currently queued. This is called from the main thread and must
   // be called with the decode monitor held.
   void ClearPositionChangeFlag();
 
   // Update the playback position. This can result in a timeupdate event
   // and an invalidate of the frame being dispatched asynchronously if