Bug 1312337. Part 4 - remove ReaderQueue and its friends.
MozReview-Commit-ID: Gg4IOPdjEeS
--- 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);