Bug 1312337. Part 4 - remove ReaderQueue and its friends. draft
authorJW Wang <jwwang@mozilla.com>
Thu, 27 Oct 2016 16:06:05 +0800
changeset 432043 d4083d2aa33d643f9744f04a750421318f4dfcd4
parent 432042 f98cf5d779e0fccb6fe632d5f1b2ce08d240af09
child 432045 f57cad80798c8c61e62630757d8887f079d4ecdd
push id34177
push userjwwang@mozilla.com
push dateTue, 01 Nov 2016 05:20:21 +0000
bugs1312337
milestone52.0a1
Bug 1312337. Part 4 - remove ReaderQueue and its friends. MozReview-Commit-ID: Gg4IOPdjEeS
dom/media/MediaDecoderReader.cpp
dom/media/MediaDecoderReader.h
dom/media/MediaDecoderReaderWrapper.h
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
dom/media/MediaFormatReader.cpp
--- a/dom/media/MediaDecoderReader.cpp
+++ b/dom/media/MediaDecoderReader.cpp
@@ -61,187 +61,36 @@ public:
     const AudioData* audioData = static_cast<const AudioData*>(aObject);
     mSize += audioData->SizeOfIncludingThis(MallocSizeOf);
     return nullptr;
   }
 
   size_t mSize;
 };
 
-// The ReaderQueue is used to keep track of the numer of active readers to
-// enforce a given limit on the number of simultaneous active decoders.
-// Readers are added/removed during construction/destruction and are
-// suspended and resumed by the queue. The max number of active decoders is
-// controlled by the "media.decoder.limit" pref.
-class ReaderQueue
-{
-public:
-  static ReaderQueue& Instance()
-  {
-    static StaticMutex sMutex;
-    StaticMutexAutoLock lock(sMutex);
-
-    if (!sInstance) {
-      sInstance = new ReaderQueue;
-      sInstance->MaxNumActive(MediaPrefs::MediaDecoderLimit());
-      ClearOnShutdown(&sInstance, ShutdownPhase::Shutdown);
-    }
-    MOZ_ASSERT(sInstance);
-    return *sInstance;
-  }
-
-  void MaxNumActive(int32_t aNumActive)
-  {
-    MutexAutoLock lock(mMutex);
-
-    if (aNumActive < 0) {
-      mNumMaxActive = std::numeric_limits<uint32_t>::max();
-    } else {
-      mNumMaxActive = aNumActive;
-    }
-  }
-
-  void Add(MediaDecoderReader* aReader)
-  {
-    MutexAutoLock lock(mMutex);
-
-    if (mActive.Length() < mNumMaxActive) {
-      // Below active limit, resume the new reader.
-      mActive.AppendElement(aReader);
-      DispatchResume(aReader);
-    } else if (mActive.IsEmpty()) {
-      MOZ_ASSERT(mNumMaxActive == 0);
-      mSuspended.AppendElement(aReader);
-    } else {
-      // We're past the active limit, suspend an old reader and resume the new.
-      mActive.AppendElement(aReader);
-      MediaDecoderReader* suspendReader = mActive.ElementAt(0);
-      mSuspended.AppendElement(suspendReader);
-      mActive.RemoveElementAt(0);
-      DispatchSuspendResume(suspendReader, aReader);
-    }
-  }
-
-  void Remove(MediaDecoderReader* aReader)
-  {
-    MutexAutoLock lock(mMutex);
-
-    // Remove the reader from the queue. Note that the reader's IsSuspended
-    // state is updated on the task queue, so we cannot depend on it here to
-    // determine the factual suspension state.
-    DebugOnly<bool> suspended = mSuspended.RemoveElement(aReader);
-    bool active = mActive.RemoveElement(aReader);
-
-    MOZ_ASSERT(suspended || active, "Reader must be in the queue");
-
-    if (active && !mSuspended.IsEmpty()) {
-      // For each removed active reader, we resume a suspended one.
-      MediaDecoderReader* resumeReader = mSuspended.LastElement();
-      mActive.AppendElement(resumeReader);
-      mSuspended.RemoveElementAt(mSuspended.Length() - 1);
-      DispatchResume(resumeReader);
-    }
-  }
-
-private:
-  ReaderQueue()
-    : mNumMaxActive(std::numeric_limits<uint32_t>::max())
-    , mMutex("ReaderQueue:mMutex")
-  {
-  }
-
-  static void Resume(MediaDecoderReader* aReader)
-  {
-    if (!aReader->IsSuspended()) {
-      return;
-    }
-    aReader->SetIsSuspended(false);
-  }
-
-  static void Suspend(MediaDecoderReader* aReader)
-  {
-    if (aReader->IsSuspended()) {
-      return;
-    }
-    aReader->SetIsSuspended(true);
-
-    aReader->ReleaseResources();
-  }
-
-  static void DispatchResume(MediaDecoderReader* aReader)
-  {
-    RefPtr<MediaDecoderReader> reader = aReader;
-
-    nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction(
-      [reader]() {
-        Resume(reader);
-    });
-    reader->OwnerThread()->Dispatch(task.forget());
-  }
-
-  static void DispatchSuspend(MediaDecoderReader* aReader)
-  {
-    RefPtr<MediaDecoderReader> reader = aReader;
-
-    nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction(
-      [reader]() {
-        Suspend(reader);
-    });
-    reader->OwnerThread()->Dispatch(task.forget());
-  }
-
-  static void DispatchSuspendResume(MediaDecoderReader* aSuspend,
-                                    MediaDecoderReader* aResume)
-  {
-    RefPtr<MediaDecoderReader> suspend = aSuspend;
-    RefPtr<MediaDecoderReader> resume = aResume;
-
-    nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction(
-      [suspend, resume] () {
-        Suspend(suspend);
-        DispatchResume(resume);
-    });
-    suspend->OwnerThread()->Dispatch(task.forget());
-  }
-
-  static StaticAutoPtr<ReaderQueue> sInstance;
-
-  nsTArray<RefPtr<MediaDecoderReader>> mActive;
-  nsTArray<RefPtr<MediaDecoderReader>> mSuspended;
-  uint32_t mNumMaxActive;
-
-  mutable Mutex mMutex;
-};
-
-StaticAutoPtr<ReaderQueue> ReaderQueue::sInstance;
-
 MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder)
   : mAudioCompactor(mAudioQueue)
   , mDecoder(aDecoder)
   , mTaskQueue(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
                              /* aSupportsTailDispatch = */ true))
   , mWatchManager(this, mTaskQueue)
   , mBuffered(mTaskQueue, TimeIntervals(), "MediaDecoderReader::mBuffered (Canonical)")
   , mDuration(mTaskQueue, NullableTimeUnit(), "MediaDecoderReader::mDuration (Mirror)")
   , mIgnoreAudioOutputFormat(false)
   , mHitAudioDecodeError(false)
   , mShutdown(false)
-  , mIsSuspended(mTaskQueue, true,
-                 "MediaDecoderReader::mIsSuspended (Canonical)")
 {
   MOZ_COUNT_CTOR(MediaDecoderReader);
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mDecoder && mDecoder->DataArrivedEvent()) {
     mDataArrivedListener = mDecoder->DataArrivedEvent()->Connect(
       mTaskQueue, this, &MediaDecoderReader::NotifyDataArrived);
   }
 
-  ReaderQueue::Instance().Add(this);
-
   // Dispatch initialization that needs to happen on that task queue.
   mTaskQueue->Dispatch(NewRunnableMethod(this, &MediaDecoderReader::InitializationTask));
 }
 
 void
 MediaDecoderReader::InitializationTask()
 {
   if (!mDecoder) {
@@ -506,21 +355,18 @@ MediaDecoderReader::Shutdown()
   mBaseAudioPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
   mBaseVideoPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
 
   mDataArrivedListener.DisconnectIfExists();
 
   ReleaseResources();
   mDuration.DisconnectIfConnected();
   mBuffered.DisconnectAll();
-  mIsSuspended.DisconnectAll();
 
   // Shut down the watch manager before shutting down our task queue.
   mWatchManager.Shutdown();
 
   mDecoder = nullptr;
 
-  ReaderQueue::Instance().Remove(this);
-
   return mTaskQueue->BeginShutdown();
 }
 
 } // namespace mozilla
--- a/dom/media/MediaDecoderReader.h
+++ b/dom/media/MediaDecoderReader.h
@@ -284,32 +284,16 @@ public:
     return mTimedMetadataEvent;
   }
 
   MediaEventProducer<void>& MediaNotSeekableProducer()
   {
     return mOnMediaNotSeekable;
   }
 
-  bool IsSuspended() const
-  {
-    MOZ_ASSERT(OnTaskQueue());
-    return mIsSuspended;
-  }
-
-  void SetIsSuspended(bool aState)
-  {
-    MOZ_ASSERT(OnTaskQueue());
-    mIsSuspended = aState;
-  }
-
-  AbstractCanonical<bool>* CanonicalIsSuspended() {
-    return &mIsSuspended;
-  }
-
   // Switch the video decoder to BlankDecoderModule. It might takes effective
   // since a few samples later depends on how much demuxed samples are already
   // queued in the original video decoder.
   virtual void SetVideoBlankDecode(bool aIsBlankDecode) {}
 
 protected:
   virtual ~MediaDecoderReader();
 
@@ -446,16 +430,14 @@ private:
     return false;
   }
 
   // Promises used only for the base-class (sync->async adapter) implementation
   // of Request{Audio,Video}Data.
   MozPromiseHolder<MediaDataPromise> mBaseAudioPromise;
   MozPromiseHolder<MediaDataPromise> mBaseVideoPromise;
 
-  Canonical<bool> mIsSuspended;
-
   MediaEventListener mDataArrivedListener;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/MediaDecoderReaderWrapper.h
+++ b/dom/media/MediaDecoderReaderWrapper.h
@@ -107,19 +107,16 @@ public:
     return mReader->SizeOfVideoQueueInFrames();
   }
   void ReadUpdatedMetadata(MediaInfo* aInfo) {
     mReader->ReadUpdatedMetadata(aInfo);
   }
   AbstractCanonical<media::TimeIntervals>* CanonicalBuffered() {
     return mReader->CanonicalBuffered();
   }
-  AbstractCanonical<bool>* CanonicalIsSuspended() {
-    return mReader->CanonicalIsSuspended();
-  }
 
   void SetCDMProxy(CDMProxy* aProxy) { mReader->SetCDMProxy(aProxy); }
 
   void SetVideoBlankDecode(bool aIsBlankDecode);
 
 private:
   ~MediaDecoderReaderWrapper();
 
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1714,17 +1714,16 @@ ShutdownState::Enter()
 
   // Prevent dangling pointers by disconnecting the listeners.
   master->mAudioQueueListener.Disconnect();
   master->mVideoQueueListener.Disconnect();
   master->mMetadataManager.Disconnect();
 
   // Disconnect canonicals and mirrors before shutting down our task queue.
   master->mBuffered.DisconnectIfConnected();
-  master->mIsReaderSuspended.DisconnectIfConnected();
   master->mEstimatedDuration.DisconnectIfConnected();
   master->mExplicitDuration.DisconnectIfConnected();
   master->mPlayState.DisconnectIfConnected();
   master->mNextPlayState.DisconnectIfConnected();
   master->mVolume.DisconnectIfConnected();
   master->mPreservesPitch.DisconnectIfConnected();
   master->mSameOriginMedia.DisconnectIfConnected();
   master->mMediaPrincipalHandle.DisconnectIfConnected();
@@ -1788,17 +1787,16 @@ MediaDecoderStateMachine::MediaDecoderSt
   mSentLoadedMetadataEvent(false),
   mSentFirstFrameLoadedEvent(false),
   mVideoDecodeSuspended(false),
   mVideoDecodeSuspendTimer(mTaskQueue),
   mOutputStreamManager(new OutputStreamManager()),
   mResource(aDecoder->GetResource()),
   mAudioOffloading(false),
   INIT_MIRROR(mBuffered, TimeIntervals()),
-  INIT_MIRROR(mIsReaderSuspended, true),
   INIT_MIRROR(mEstimatedDuration, NullableTimeUnit()),
   INIT_MIRROR(mExplicitDuration, Maybe<double>()),
   INIT_MIRROR(mPlayState, MediaDecoder::PLAY_STATE_LOADING),
   INIT_MIRROR(mNextPlayState, MediaDecoder::PLAY_STATE_PAUSED),
   INIT_MIRROR(mVolume, 1.0),
   INIT_MIRROR(mPreservesPitch, true),
   INIT_MIRROR(mSameOriginMedia, false),
   INIT_MIRROR(mMediaPrincipalHandle, PRINCIPAL_HANDLE_NONE),
@@ -1846,34 +1844,32 @@ MediaDecoderStateMachine::~MediaDecoderS
 
 void
 MediaDecoderStateMachine::InitializationTask(MediaDecoder* aDecoder)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   // Connect mirrors.
   mBuffered.Connect(mReader->CanonicalBuffered());
-  mIsReaderSuspended.Connect(mReader->CanonicalIsSuspended());
   mEstimatedDuration.Connect(aDecoder->CanonicalEstimatedDuration());
   mExplicitDuration.Connect(aDecoder->CanonicalExplicitDuration());
   mPlayState.Connect(aDecoder->CanonicalPlayState());
   mNextPlayState.Connect(aDecoder->CanonicalNextPlayState());
   mVolume.Connect(aDecoder->CanonicalVolume());
   mPreservesPitch.Connect(aDecoder->CanonicalPreservesPitch());
   mSameOriginMedia.Connect(aDecoder->CanonicalSameOriginMedia());
   mMediaPrincipalHandle.Connect(aDecoder->CanonicalMediaPrincipalHandle());
   mPlaybackBytesPerSecond.Connect(aDecoder->CanonicalPlaybackBytesPerSecond());
   mPlaybackRateReliable.Connect(aDecoder->CanonicalPlaybackRateReliable());
   mDecoderPosition.Connect(aDecoder->CanonicalDecoderPosition());
   mMediaSeekable.Connect(aDecoder->CanonicalMediaSeekable());
   mMediaSeekableOnlyInBufferedRanges.Connect(aDecoder->CanonicalMediaSeekableOnlyInBufferedRanges());
 
   // Initialize watchers.
   mWatchManager.Watch(mBuffered, &MediaDecoderStateMachine::BufferedRangeUpdated);
-  mWatchManager.Watch(mIsReaderSuspended, &MediaDecoderStateMachine::ReaderSuspendedChanged);
   mWatchManager.Watch(mState, &MediaDecoderStateMachine::UpdateNextFrameStatus);
   mWatchManager.Watch(mAudioCompleted, &MediaDecoderStateMachine::UpdateNextFrameStatus);
   mWatchManager.Watch(mVideoCompleted, &MediaDecoderStateMachine::UpdateNextFrameStatus);
   mWatchManager.Watch(mVolume, &MediaDecoderStateMachine::VolumeChanged);
   mWatchManager.Watch(mPreservesPitch, &MediaDecoderStateMachine::PreservesPitchChanged);
   mWatchManager.Watch(mEstimatedDuration, &MediaDecoderStateMachine::RecomputeDuration);
   mWatchManager.Watch(mExplicitDuration, &MediaDecoderStateMachine::RecomputeDuration);
   mWatchManager.Watch(mObservedDuration, &MediaDecoderStateMachine::RecomputeDuration);
@@ -2493,19 +2489,18 @@ void MediaDecoderStateMachine::PlayState
   }
 
   mStateObj->HandlePlayStateChanged(mPlayState);
 }
 
 void MediaDecoderStateMachine::VisibilityChanged()
 {
   MOZ_ASSERT(OnTaskQueue());
-  DECODER_LOG("VisibilityChanged: mIsVisible=%d, "
-              "mVideoDecodeSuspended=%c, mIsReaderSuspended=%d",
-              mIsVisible.Ref(), mVideoDecodeSuspended ? 'T' : 'F', mIsReaderSuspended.Ref());
+  DECODER_LOG("VisibilityChanged: mIsVisible=%d, mVideoDecodeSuspended=%c",
+              mIsVisible.Ref(), mVideoDecodeSuspended ? 'T' : 'F');
 
   // Start timer to trigger suspended decoding state when going invisible.
   if (!mIsVisible) {
     TimeStamp target = TimeStamp::Now() + SuspendBackgroundVideoDelay();
 
     RefPtr<MediaDecoderStateMachine> self = this;
     mVideoDecodeSuspendTimer.Ensure(target,
                                     [=]() { self->OnSuspendTimerResolved(); },
@@ -2536,23 +2531,16 @@ void MediaDecoderStateMachine::BufferedR
     bool exists;
     media::TimeUnit end{mBuffered.Ref().GetEnd(&exists)};
     if (exists) {
       mObservedDuration = std::max(mObservedDuration.Ref(), end);
     }
   }
 }
 
-void MediaDecoderStateMachine::ReaderSuspendedChanged()
-{
-  MOZ_ASSERT(OnTaskQueue());
-  DECODER_LOG("ReaderSuspendedChanged: %d", mIsReaderSuspended.Ref());
-  SetDormant(mIsReaderSuspended);
-}
-
 RefPtr<MediaDecoder::SeekPromise>
 MediaDecoderStateMachine::Seek(SeekTarget aTarget)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   if (IsShutdown()) {
     return MediaDecoder::SeekPromise::CreateAndReject(/* aIgnored = */ true, __func__);
   }
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -775,18 +775,16 @@ private:
   void OnCDMProxyNotReady();
   RefPtr<CDMProxy> mCDMProxy;
   MozPromiseRequestHolder<MediaDecoder::CDMProxyPromise> mCDMProxyPromise;
 
 private:
   // The buffered range. Mirrored from the decoder thread.
   Mirror<media::TimeIntervals> mBuffered;
 
-  Mirror<bool> mIsReaderSuspended;
-
   // The duration according to the demuxer's current estimate, mirrored from the main thread.
   Mirror<media::NullableTimeUnit> mEstimatedDuration;
 
   // The duration explicitly set by JS, mirrored from the main thread.
   Mirror<Maybe<double>> mExplicitDuration;
 
   // The current play state and next play state, mirrored from the main thread.
   Mirror<MediaDecoder::PlayState> mPlayState;
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -794,20 +794,16 @@ MediaFormatReader::RequestVideoData(bool
     return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
   }
 
   if (mShutdown) {
     NS_WARNING("RequestVideoData on shutdown MediaFormatReader!");
     return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
   }
 
-  if (IsSuspended()) {
-    return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
-  }
-
   media::TimeUnit timeThreshold{media::TimeUnit::FromMicroseconds(aTimeThreshold)};
   // Ensure we have no pending seek going as ShouldSkip could return out of date
   // information.
   if (!mVideo.HasInternalSeekPending() &&
       ShouldSkip(aSkipToNextKeyframe, timeThreshold)) {
     RefPtr<MediaDataPromise> p = mVideo.EnsurePromise(__func__);
     SkipVideoDemuxToNextKeyFrame(timeThreshold);
     return p;
@@ -884,20 +880,16 @@ MediaFormatReader::RequestAudioData()
   MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking() || !IsSeeking(), "called mid-seek");
   LOGV("");
 
   if (!HasAudio()) {
     LOG("called with no audio track");
     return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
   }
 
-  if (IsSuspended()) {
-    return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
-  }
-
   if (IsSeeking()) {
     LOG("called mid-seek. Rejecting.");
     return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
   }
 
   if (mShutdown) {
     NS_WARNING("RequestAudioData on shutdown MediaFormatReader!");
     return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
@@ -1183,24 +1175,16 @@ MediaFormatReader::DecodeDemuxedSamples(
 }
 
 void
 MediaFormatReader::HandleDemuxedSamples(TrackType aTrack,
                                         AbstractMediaDecoder::AutoNotifyDecoded& aA)
 {
   MOZ_ASSERT(OnTaskQueue());
 
-  // Don't try to create or initialize decoders
-  // (which might allocate hardware resources) when suspended.
-  if (IsSuspended()) {
-    // Should've deleted decoders when suspended.
-    MOZ_DIAGNOSTIC_ASSERT(!mAudio.mDecoder && !mVideo.mDecoder);
-    return;
-  }
-
   auto& decoder = GetDecoderData(aTrack);
 
   if (decoder.mQueuedSamples.IsEmpty()) {
     return;
   }
 
   if (!decoder.mDecoder) {
     mDecoderFactory->CreateDecoder(aTrack);