Bug 1345403 part 4 - Clean up suspend timer canceling; r?jwwang
MozReview-Commit-ID: LuNmrtDl4BR
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -572,16 +572,21 @@ MediaDecoder::OnPlaybackEvent(MediaEvent
Invalidate();
break;
case MediaEventType::EnterVideoSuspend:
GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozentervideosuspend"));
break;
case MediaEventType::ExitVideoSuspend:
GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozexitvideosuspend"));
break;
+ case MediaEventType::StartVideoSuspendTimer:
+ GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozstartvideosuspendtimer"));
+ break;
+ case MediaEventType::CancelVideoSuspendTimer:
+ GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozcancelvideosuspendtimer"));
}
}
void
MediaDecoder::OnPlaybackErrorEvent(const MediaResult& aError)
{
DecodeError(aError);
}
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -2515,17 +2515,17 @@ ShutdownState::Enter()
{
auto master = mMaster;
master->mIsShutdown = true;
master->mDelayedScheduler.Reset();
// Shutdown happens while decode timer is active, we need to disconnect and
// dispose of the timer.
- master->mVideoDecodeSuspendTimer.Reset();
+ master->CancelSuspendTimer();
master->mCDMProxyPromise.DisconnectIfExists();
if (master->IsPlaying()) {
master->StopPlayback();
}
master->mAudioDataRequest.DisconnectIfExists();
@@ -2695,16 +2695,18 @@ MediaDecoderStateMachine::Initialization
&MediaDecoderStateMachine::RecomputeDuration);
mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::PlayStateChanged);
if (MediaPrefs::MDSMSuspendBackgroundVideoEnabled()) {
mIsVisible.Connect(aDecoder->CanonicalIsVisible());
mHasSuspendTaint.Connect(aDecoder->CanonicalHasSuspendTaint());
mWatchManager.Watch(mIsVisible,
&MediaDecoderStateMachine::VisibilityChanged);
+ mWatchManager.Watch(mHasSuspendTaint,
+ &MediaDecoderStateMachine::SuspendTaintChanged);
}
MOZ_ASSERT(!mStateObj);
auto* s = new DecodeMetadataState(this);
mStateObj.reset(s);
s->Enter();
}
@@ -3009,17 +3011,17 @@ MediaDecoderStateMachine::Shutdown()
return mStateObj->HandleShutdown();
}
void MediaDecoderStateMachine::PlayStateChanged()
{
MOZ_ASSERT(OnTaskQueue());
if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING) {
- mVideoDecodeSuspendTimer.Reset();
+ CancelSuspendTimer();
} else if (mMinimizePreroll) {
// Once we start playing, we don't want to minimize our prerolling, as we
// assume the user is likely to want to keep playing in future. This needs
// to happen before we invoke StartDecoding().
mMinimizePreroll = false;
}
mStateObj->HandlePlayStateChanged(mPlayState);
@@ -3033,25 +3035,39 @@ void MediaDecoderStateMachine::Visibilit
// 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(); },
- [=]() { self->OnSuspendTimerRejected(); });
+ [] () { MOZ_DIAGNOSTIC_ASSERT(false); });
+ mOnPlaybackEvent.Notify(MediaEventType::StartVideoSuspendTimer);
return;
}
// Resuming from suspended decoding
// If suspend timer exists, destroy it.
- mVideoDecodeSuspendTimer.Reset();
-
+ CancelSuspendTimer();
+
+ if (mVideoDecodeSuspended) {
+ mStateObj->HandleResumeVideoDecoding();
+ }
+}
+
+void MediaDecoderStateMachine::SuspendTaintChanged()
+{
+ MOZ_ASSERT(OnTaskQueue());
+ MOZ_ASSERT(mHasSuspendTaint); // Suspend taint is only ever set.
+
+ CancelSuspendTimer();
+
+ // Resume from suspended decoding.
if (mVideoDecodeSuspended) {
mStateObj->HandleResumeVideoDecoding();
}
}
void MediaDecoderStateMachine::BufferedRangeUpdated()
{
MOZ_ASSERT(OnTaskQueue());
@@ -3904,19 +3920,23 @@ void
MediaDecoderStateMachine::OnSuspendTimerResolved()
{
DECODER_LOG("OnSuspendTimerResolved");
mVideoDecodeSuspendTimer.CompleteRequest();
mStateObj->HandleVideoSuspendTimeout();
}
void
-MediaDecoderStateMachine::OnSuspendTimerRejected()
+MediaDecoderStateMachine::CancelSuspendTimer()
{
- DECODER_LOG("OnSuspendTimerRejected");
+ DECODER_LOG("CancelSuspendTimer: State: %s, Timer.IsScheduled: %c",
+ ToStateStr(mStateObj->GetState()),
+ mVideoDecodeSuspendTimer.IsScheduled() ? 'T' : 'F');
MOZ_ASSERT(OnTaskQueue());
- MOZ_ASSERT(!mVideoDecodeSuspended);
- mVideoDecodeSuspendTimer.CompleteRequest();
+ if (mVideoDecodeSuspendTimer.IsScheduled()) {
+ mOnPlaybackEvent.Notify(MediaEventType::CancelVideoSuspendTimer);
+ }
+ mVideoDecodeSuspendTimer.Reset();
}
} // namespace mozilla
#undef NS_DispatchToMainThread
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -117,17 +117,19 @@ extern LazyLogModule gMediaSampleLog;
enum class MediaEventType : int8_t
{
PlaybackStarted,
PlaybackStopped,
PlaybackEnded,
SeekStarted,
Invalidate,
EnterVideoSuspend,
- ExitVideoSuspend
+ ExitVideoSuspend,
+ StartVideoSuspendTimer,
+ CancelVideoSuspendTimer
};
/*
The state machine class. This manages the decoding and seeking in the
MediaDecoderReader on the decode task queue, and A/V sync on the shared
state machine thread, and controls the audio "push" thread.
All internal state is synchronised via the decoder monitor. State changes
@@ -389,16 +391,19 @@ protected:
void StartMediaSink();
// Notification method invoked when mPlayState changes.
void PlayStateChanged();
// Notification method invoked when mIsVisible changes.
void VisibilityChanged();
+ // Notification method invoked when mHasSuspendTaint changes.
+ void SuspendTaintChanged();
+
// Sets internal state which causes playback of media to pause.
// The decoder monitor must be held.
void StopPlayback();
// If the conditions are right, sets internal state which causes playback
// of media to begin or resume.
// Must be called with the decode monitor held.
void MaybeStartPlayback();
@@ -606,17 +611,17 @@ private:
MozPromiseRequestHolder<MediaDataPromise> mVideoDataRequest;
MozPromiseRequestHolder<WaitForDataPromise> mAudioWaitRequest;
MozPromiseRequestHolder<WaitForDataPromise> mVideoWaitRequest;
const char* AudioRequestStatus() const;
const char* VideoRequestStatus() const;
void OnSuspendTimerResolved();
- void OnSuspendTimerRejected();
+ void CancelSuspendTimer();
// True if we shouldn't play our audio (but still write it to any capturing
// streams). When this is true, the audio thread will never start again after
// it has stopped.
bool mAudioCaptured;
// True if all audio frames are already rendered.
bool mAudioCompleted = false;