diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index d682c35ecee0..5df1f793b494 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -205,11 +205,12 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder, mRealTime(aRealTime), mDispatchedStateMachine(false), mDelayedScheduler(this), - mState(DECODER_STATE_DECODING_NONE), + mState(DECODER_STATE_DECODING_NONE, "MediaDecoderStateMachine::mState"), mPlayDuration(0), mStartTime(-1), mEndTime(-1), mDurationSet(false), + mNextFrameStatusUpdater("MediaDecoderStateMachine::mNextFrameStatusUpdater"), mFragmentEndTime(-1), mReader(aReader), mCurrentFrameTime(0), @@ -228,7 +229,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder, mIsVideoPrerolling(false), mAudioCaptured(false), mPositionChangeQueued(false), - mAudioCompleted(false), + mAudioCompleted(false, "MediaDecoderStateMachine::mAudioCompleted"), mGotDurationFromMetaData(false), mDispatchedEventToDecode(false), mStopAudioThread(true), @@ -257,6 +258,12 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder, mNextFrameStatus.Init(mTaskQueue, MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED, "MediaDecoderStateMachine::mNextFrameStatus (Canonical)"); + // Skip the initial notification we get when we Watch the value, since we're + // not on the right thread yet. + mNextFrameStatusUpdater->Watch(mState, /* aSkipInitialNotify = */ true); + mNextFrameStatusUpdater->Watch(mAudioCompleted, /* aSkipInitialNotify = */ true); + mNextFrameStatusUpdater->AddWeakCallback(this, &MediaDecoderStateMachine::UpdateNextFrameStatus); + static bool sPrefCacheInit = false; if (!sPrefCacheInit) { sPrefCacheInit = true; @@ -1321,8 +1328,6 @@ void MediaDecoderStateMachine::SetState(State aState) mState = aState; - UpdateNextFrameStatus(); - // Clear state-scoped state. mSentPlaybackEndedEvent = false; } @@ -3182,7 +3187,7 @@ void MediaDecoderStateMachine::SetStartTime(int64_t aStartTimeUsecs) void MediaDecoderStateMachine::UpdateNextFrameStatus() { MOZ_ASSERT(OnTaskQueue()); - AssertCurrentThreadInMonitor(); + ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); MediaDecoderOwner::NextFrameStatus status; const char* statusString; @@ -3424,7 +3429,6 @@ void MediaDecoderStateMachine::OnAudioSinkComplete() } ResyncAudioClock(); mAudioCompleted = true; - UpdateNextFrameStatus(); // Kick the decode thread; it may be sleeping waiting for this to finish. mDecoder->GetReentrantMonitor().NotifyAll(); } diff --git a/dom/media/MediaDecoderStateMachine.h b/dom/media/MediaDecoderStateMachine.h index 521e09b0c59d..40fab5faaa08 100644 --- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -844,7 +844,7 @@ public: // NotifyAll on the monitor must be called when the state is changed so // that interested threads can wake up and alter behaviour if appropriate // Accessed on state machine, audio, main, and AV thread. - State mState; + Watchable mState; // The task queue in which we run decode tasks. This is referred to as // the "decode thread", though in practise tasks can run on a different @@ -887,6 +887,7 @@ public: // The status of our next frame. Mirrored on the main thread and used to // compute ready state. + WatcherHolder mNextFrameStatusUpdater; Canonical::Holder mNextFrameStatus; public: AbstractCanonical* CanonicalNextFrameStatus() { return &mNextFrameStatus; } @@ -1155,7 +1156,7 @@ protected: // the state machine thread. Synchronised via decoder monitor. // When data is being sent to a MediaStream, this is true when all data has // been written to the MediaStream. - bool mAudioCompleted; + Watchable mAudioCompleted; // True if mDuration has a value obtained from an HTTP header, or from // the media index/metadata. Accessed on the state machine thread. diff --git a/dom/media/StateWatching.h b/dom/media/StateWatching.h index ac8052d1d85a..bfef7488a0b1 100644 --- a/dom/media/StateWatching.h +++ b/dom/media/StateWatching.h @@ -70,7 +70,7 @@ void EnsureStateWatchingLog(); class AbstractWatcher { public: - NS_INLINE_DECL_REFCOUNTING(AbstractWatcher) + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AbstractWatcher) AbstractWatcher() : mDestroyed(false) {} bool IsDestroyed() { return mDestroyed; } virtual void Notify() = 0; @@ -104,11 +104,13 @@ class WatchTarget public: explicit WatchTarget(const char* aName) : mName(aName) {} - void AddWatcher(AbstractWatcher* aWatcher) + void AddWatcher(AbstractWatcher* aWatcher, bool aSkipInitialNotify) { MOZ_ASSERT(!mWatchers.Contains(aWatcher)); mWatchers.AppendElement(aWatcher); - aWatcher->Notify(); + if (!aSkipInitialNotify) { + aWatcher->Notify(); + } } void RemoveWatcher(AbstractWatcher* aWatcher) @@ -204,7 +206,7 @@ public: AbstractThread::GetCurrent()->TailDispatcher().AddDirectTask(r.forget()); } - void Watch(WatchTarget& aTarget) { aTarget.AddWatcher(this); } + void Watch(WatchTarget& aTarget, bool aSkipInitialNotify = false) { aTarget.AddWatcher(this, aSkipInitialNotify); } void Unwatch(WatchTarget& aTarget) { aTarget.RemoveWatcher(this); } template