Bug 883731 - Progress update should be associated with network state transitions. Also centralize network state transition code. r=cpearce

This commit is contained in:
JW Wang 2014-09-24 19:26:00 +12:00
parent 3714d8b91e
commit d21e0abb6e
7 changed files with 106 additions and 41 deletions

View File

@ -204,6 +204,9 @@ public:
// ongoing. // ongoing.
virtual void DownloadResumed(bool aForceNetworkLoading = false) MOZ_FINAL MOZ_OVERRIDE; virtual void DownloadResumed(bool aForceNetworkLoading = false) MOZ_FINAL MOZ_OVERRIDE;
// Called to indicate the download is progressing.
virtual void DownloadProgressed() MOZ_FINAL MOZ_OVERRIDE;
// Called by the media decoder to indicate that the download has stalled // Called by the media decoder to indicate that the download has stalled
// (no data has arrived for a while). // (no data has arrived for a while).
virtual void DownloadStalled() MOZ_FINAL MOZ_OVERRIDE; virtual void DownloadStalled() MOZ_FINAL MOZ_OVERRIDE;
@ -643,6 +646,12 @@ protected:
*/ */
void ChangeReadyState(nsMediaReadyState aState); void ChangeReadyState(nsMediaReadyState aState);
/**
* Use this method to change the mNetworkState member, so required
* actions will be taken during the transition.
*/
void ChangeNetworkState(nsMediaNetworkState aState);
/** /**
* These two methods are called by the WakeLockBoolWrapper when the wakelock * These two methods are called by the WakeLockBoolWrapper when the wakelock
* has to be created or released. * has to be created or released.

View File

@ -618,6 +618,11 @@ void HTMLMediaElement::ShutdownDecoder()
{ {
RemoveMediaElementFromURITable(); RemoveMediaElementFromURITable();
NS_ASSERTION(mDecoder, "Must have decoder to shut down"); NS_ASSERTION(mDecoder, "Must have decoder to shut down");
// TODO: This should be handled by ChangeNetworkState() so we have only one
// place to call StopProgress().
if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
mDecoder->StopProgress();
}
mDecoder->Shutdown(); mDecoder->Shutdown();
mDecoder = nullptr; mDecoder = nullptr;
} }
@ -661,7 +666,6 @@ void HTMLMediaElement::AbortExistingLoads()
} }
mError = nullptr; mError = nullptr;
mBegun = false;
mLoadedDataFired = false; mLoadedDataFired = false;
mAutoplaying = true; mAutoplaying = true;
mIsLoadingFromSourceChildren = false; mIsLoadingFromSourceChildren = false;
@ -675,8 +679,8 @@ void HTMLMediaElement::AbortExistingLoads()
mTags = nullptr; mTags = nullptr;
if (mNetworkState != nsIDOMHTMLMediaElement::NETWORK_EMPTY) { if (mNetworkState != nsIDOMHTMLMediaElement::NETWORK_EMPTY) {
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY;
NS_ASSERTION(!mDecoder && !mSrcStream, "How did someone setup a new stream/decoder already?"); NS_ASSERTION(!mDecoder && !mSrcStream, "How did someone setup a new stream/decoder already?");
ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY);
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING); ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING);
mPaused = true; mPaused = true;
@ -702,7 +706,7 @@ void HTMLMediaElement::NoSupportedMediaSourceError()
NS_ASSERTION(mDelayingLoadEvent, "Load event not delayed during source selection?"); NS_ASSERTION(mDelayingLoadEvent, "Load event not delayed during source selection?");
mError = new MediaError(this, nsIDOMMediaError::MEDIA_ERR_SRC_NOT_SUPPORTED); mError = new MediaError(this, nsIDOMMediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE; ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE);
DispatchAsyncEvent(NS_LITERAL_STRING("error")); DispatchAsyncEvent(NS_LITERAL_STRING("error"));
// This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called // This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called
ChangeDelayLoadStatus(false); ChangeDelayLoadStatus(false);
@ -746,7 +750,7 @@ void HTMLMediaElement::RunInStableState(nsIRunnable* aRunnable)
void HTMLMediaElement::QueueLoadFromSourceTask() void HTMLMediaElement::QueueLoadFromSourceTask()
{ {
ChangeDelayLoadStatus(true); ChangeDelayLoadStatus(true);
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING; ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_LOADING);
RunInStableState( RunInStableState(
NS_NewRunnableMethod(this, &HTMLMediaElement::LoadFromSourceChildren)); NS_NewRunnableMethod(this, &HTMLMediaElement::LoadFromSourceChildren));
} }
@ -757,7 +761,7 @@ void HTMLMediaElement::QueueSelectResourceTask()
if (mHaveQueuedSelectResource) if (mHaveQueuedSelectResource)
return; return;
mHaveQueuedSelectResource = true; mHaveQueuedSelectResource = true;
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE; ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE);
RunInStableState( RunInStableState(
NS_NewRunnableMethod(this, &HTMLMediaElement::SelectResourceWrapper)); NS_NewRunnableMethod(this, &HTMLMediaElement::SelectResourceWrapper));
} }
@ -818,7 +822,7 @@ void HTMLMediaElement::SelectResource()
!HasSourceChildren(this)) { !HasSourceChildren(this)) {
// The media element has neither a src attribute nor any source // The media element has neither a src attribute nor any source
// element children, abort the load. // element children, abort the load.
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY; ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY);
// This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called // This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called
ChangeDelayLoadStatus(false); ChangeDelayLoadStatus(false);
return; return;
@ -826,7 +830,7 @@ void HTMLMediaElement::SelectResource()
ChangeDelayLoadStatus(true); ChangeDelayLoadStatus(true);
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING; ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_LOADING);
// Load event was delayed, and still is, so no need to call // Load event was delayed, and still is, so no need to call
// AddRemoveSelfReference, since it must still be held // AddRemoveSelfReference, since it must still be held
DispatchAsyncEvent(NS_LITERAL_STRING("loadstart")); DispatchAsyncEvent(NS_LITERAL_STRING("loadstart"));
@ -922,7 +926,7 @@ void HTMLMediaElement::LoadFromSourceChildren()
// Exhausted candidates, wait for more candidates to be appended to // Exhausted candidates, wait for more candidates to be appended to
// the media element. // the media element.
mLoadWaitStatus = WAITING_FOR_SOURCE; mLoadWaitStatus = WAITING_FOR_SOURCE;
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE; ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE);
ChangeDelayLoadStatus(false); ChangeDelayLoadStatus(false);
ReportLoadError("MediaLoadExhaustedCandidates"); ReportLoadError("MediaLoadExhaustedCandidates");
return; return;
@ -991,8 +995,7 @@ void HTMLMediaElement::LoadFromSourceChildren()
void HTMLMediaElement::SuspendLoad() void HTMLMediaElement::SuspendLoad()
{ {
mSuspendedForPreloadNone = true; mSuspendedForPreloadNone = true;
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE; ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
ChangeDelayLoadStatus(false); ChangeDelayLoadStatus(false);
} }
@ -1003,7 +1006,7 @@ void HTMLMediaElement::ResumeLoad(PreloadAction aAction)
mSuspendedForPreloadNone = false; mSuspendedForPreloadNone = false;
mPreloadAction = aAction; mPreloadAction = aAction;
ChangeDelayLoadStatus(true); ChangeDelayLoadStatus(true);
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING; ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_LOADING);
if (!mIsLoadingFromSourceChildren) { if (!mIsLoadingFromSourceChildren) {
// We were loading from the element's src attribute. // We were loading from the element's src attribute.
if (NS_FAILED(LoadResource())) { if (NS_FAILED(LoadResource())) {
@ -2155,11 +2158,10 @@ void HTMLMediaElement::SetPlayedOrSeeked(bool aValue)
void void
HTMLMediaElement::ResetConnectionState() HTMLMediaElement::ResetConnectionState()
{ {
mBegun = false;
SetCurrentTime(0); SetCurrentTime(0);
FireTimeUpdate(false); FireTimeUpdate(false);
DispatchAsyncEvent(NS_LITERAL_STRING("ended")); DispatchAsyncEvent(NS_LITERAL_STRING("ended"));
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY; ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY);
AddRemoveSelfReference(); AddRemoveSelfReference();
ChangeDelayLoadStatus(false); ChangeDelayLoadStatus(false);
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING); ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING);
@ -2647,7 +2649,7 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
nsIStreamListener** aListener, nsIStreamListener** aListener,
MediaDecoder* aCloneDonor) MediaDecoder* aCloneDonor)
{ {
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING; ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_LOADING);
// Force a same-origin check before allowing events for this media resource. // Force a same-origin check before allowing events for this media resource.
mMediaSecurityVerified = false; mMediaSecurityVerified = false;
@ -2668,6 +2670,8 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
mDecoder->SetVolume(mMuted ? 0.0 : mVolume); mDecoder->SetVolume(mMuted ? 0.0 : mVolume);
mDecoder->SetPreservesPitch(mPreservesPitch); mDecoder->SetPreservesPitch(mPreservesPitch);
mDecoder->SetPlaybackRate(mPlaybackRate); mDecoder->SetPlaybackRate(mPlaybackRate);
// Start progress timer for we are in NETWORK_LOADING.
mDecoder->StartProgress();
#ifdef MOZ_EME #ifdef MOZ_EME
if (mMediaKeys) { if (mMediaKeys) {
@ -2719,7 +2723,6 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
NS_ASSERTION(NS_SUCCEEDED(rv) == (MediaElementTableCount(this, mLoadingSrc) == 1), NS_ASSERTION(NS_SUCCEEDED(rv) == (MediaElementTableCount(this, mLoadingSrc) == 1),
"Media element should have single table entry if decode initialized"); "Media element should have single table entry if decode initialized");
mBegun = true;
return rv; return rv;
} }
@ -2868,8 +2871,7 @@ void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream)
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA); ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
DispatchAsyncEvent(NS_LITERAL_STRING("durationchange")); DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
DispatchAsyncEvent(NS_LITERAL_STRING("loadedmetadata")); DispatchAsyncEvent(NS_LITERAL_STRING("loadedmetadata"));
DispatchAsyncEvent(NS_LITERAL_STRING("suspend")); ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
AddRemoveSelfReference(); AddRemoveSelfReference();
// FirstFrameLoaded() will be called when the stream has current data. // FirstFrameLoaded() will be called when the stream has current data.
} }
@ -2996,13 +2998,12 @@ void HTMLMediaElement::Error(uint16_t aErrorCode)
aErrorCode == nsIDOMMediaError::MEDIA_ERR_ABORTED, aErrorCode == nsIDOMMediaError::MEDIA_ERR_ABORTED,
"Only use nsIDOMMediaError codes!"); "Only use nsIDOMMediaError codes!");
mError = new MediaError(this, aErrorCode); mError = new MediaError(this, aErrorCode);
mBegun = false;
DispatchAsyncEvent(NS_LITERAL_STRING("error")); DispatchAsyncEvent(NS_LITERAL_STRING("error"));
if (mReadyState == nsIDOMHTMLMediaElement::HAVE_NOTHING) { if (mReadyState == nsIDOMHTMLMediaElement::HAVE_NOTHING) {
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY; ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY);
DispatchAsyncEvent(NS_LITERAL_STRING("emptied")); DispatchAsyncEvent(NS_LITERAL_STRING("emptied"));
} else { } else {
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE; ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
} }
AddRemoveSelfReference(); AddRemoveSelfReference();
ChangeDelayLoadStatus(false); ChangeDelayLoadStatus(false);
@ -3076,22 +3077,28 @@ void HTMLMediaElement::NotifySuspendedByCache(bool aIsSuspended)
void HTMLMediaElement::DownloadSuspended() void HTMLMediaElement::DownloadSuspended()
{ {
DispatchAsyncEvent(NS_LITERAL_STRING("progress")); DownloadProgressed();
if (mBegun) { if (mBegun) {
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE; ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
AddRemoveSelfReference(); AddRemoveSelfReference();
DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
} }
} }
void HTMLMediaElement::DownloadResumed(bool aForceNetworkLoading) void HTMLMediaElement::DownloadResumed(bool aForceNetworkLoading)
{ {
if (mBegun || aForceNetworkLoading) { if (mBegun || aForceNetworkLoading) {
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING; ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_LOADING);
AddRemoveSelfReference(); AddRemoveSelfReference();
} }
} }
void HTMLMediaElement::DownloadProgressed()
{
if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
}
}
void HTMLMediaElement::DownloadStalled() void HTMLMediaElement::DownloadStalled()
{ {
if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) { if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
@ -3175,7 +3182,7 @@ void HTMLMediaElement::UpdateReadyStateForData(MediaDecoderOwner::NextFrameStatu
} }
#ifdef PR_LOGGING #ifdef PR_LOGGING
static const char* gReadyStateToString[] = { static const char* const gReadyStateToString[] = {
"HAVE_NOTHING", "HAVE_NOTHING",
"HAVE_METADATA", "HAVE_METADATA",
"HAVE_CURRENT_DATA", "HAVE_CURRENT_DATA",
@ -3234,6 +3241,50 @@ void HTMLMediaElement::ChangeReadyState(nsMediaReadyState aState)
} }
} }
#ifdef PR_LOGGING
static const char* const gNetworkStateToString[] = {
"EMPTY",
"IDLE",
"LOADING",
"NO_SOURCE"
};
#endif
void HTMLMediaElement::ChangeNetworkState(nsMediaNetworkState aState)
{
if (mNetworkState == aState) {
return;
}
nsMediaNetworkState oldState = mNetworkState;
mNetworkState = aState;
LOG(PR_LOG_DEBUG, ("%p Network state changed to %s", this, gNetworkStateToString[aState]));
// TODO: |mBegun| reflects the download status. We should be able to remove
// it and check |mNetworkState| only.
if (oldState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
// Reset |mBegun| since we're not downloading anymore.
mBegun = false;
if (mDecoder) {
// Stop progress notification when exiting NETWORK_LOADING.
mDecoder->StopProgress();
}
}
if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
// Download is begun.
mBegun = true;
if (mDecoder) {
// Start progress notification when entering NETWORK_LOADING.
mDecoder->StartProgress();
}
} else if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_IDLE && !mError) {
// Fire 'suspend' event when entering NETWORK_IDLE and no error presented.
DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
}
}
bool HTMLMediaElement::CanActivateAutoplay() bool HTMLMediaElement::CanActivateAutoplay()
{ {
// For stream inputs, we activate autoplay on HAVE_CURRENT_DATA because // For stream inputs, we activate autoplay on HAVE_CURRENT_DATA because
@ -3362,7 +3413,7 @@ bool HTMLMediaElement::IsPlaybackEnded() const
// TODO: // TODO:
// the current playback position is equal to the effective end of the media resource. // the current playback position is equal to the effective end of the media resource.
// See bug 449157. // See bug 449157.
return mNetworkState >= nsIDOMHTMLMediaElement::HAVE_METADATA && return mReadyState >= nsIDOMHTMLMediaElement::HAVE_METADATA &&
mDecoder ? mDecoder->IsEnded() : false; mDecoder ? mDecoder->IsEnded() : false;
} }

View File

@ -139,7 +139,6 @@ void MediaDecoder::SetDormantIfNecessary(bool aDormant)
if(aDormant) { if(aDormant) {
// enter dormant state // enter dormant state
StopProgress();
DestroyDecodedStream(); DestroyDecodedStream();
mDecoderStateMachine->SetDormant(true); mDecoderStateMachine->SetDormant(true);
@ -500,7 +499,8 @@ void MediaDecoder::Shutdown()
ChangeState(PLAY_STATE_SHUTDOWN); ChangeState(PLAY_STATE_SHUTDOWN);
StopProgress(); // If we hit this assertion, there might be a bug in network state transition.
NS_ASSERTION(!mProgressTimer, "Progress timer should've been stopped.");
mOwner = nullptr; mOwner = nullptr;
MediaShutdownManager::Instance().Unregister(this); MediaShutdownManager::Instance().Unregister(this);
@ -1517,6 +1517,7 @@ static void ProgressCallback(nsITimer* aTimer, void* aClosure)
void MediaDecoder::Progress(bool aTimer) void MediaDecoder::Progress(bool aTimer)
{ {
MOZ_ASSERT(NS_IsMainThread());
if (!mOwner) if (!mOwner)
return; return;
@ -1532,7 +1533,7 @@ void MediaDecoder::Progress(bool aTimer)
now - mProgressTime >= TimeDuration::FromMilliseconds(PROGRESS_MS)) && now - mProgressTime >= TimeDuration::FromMilliseconds(PROGRESS_MS)) &&
!mDataTime.IsNull() && !mDataTime.IsNull() &&
now - mDataTime <= TimeDuration::FromMilliseconds(PROGRESS_MS)) { now - mDataTime <= TimeDuration::FromMilliseconds(PROGRESS_MS)) {
mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("progress")); mOwner->DownloadProgressed();
mProgressTime = now; mProgressTime = now;
} }
@ -1546,8 +1547,8 @@ void MediaDecoder::Progress(bool aTimer)
nsresult MediaDecoder::StartProgress() nsresult MediaDecoder::StartProgress()
{ {
if (mProgressTimer) MOZ_ASSERT(NS_IsMainThread());
return NS_OK; NS_ASSERTION(!mProgressTimer, "Already started progress timer.");
mProgressTimer = do_CreateInstance("@mozilla.org/timer;1"); mProgressTimer = do_CreateInstance("@mozilla.org/timer;1");
return mProgressTimer->InitWithFuncCallback(ProgressCallback, return mProgressTimer->InitWithFuncCallback(ProgressCallback,
@ -1558,8 +1559,8 @@ nsresult MediaDecoder::StartProgress()
nsresult MediaDecoder::StopProgress() nsresult MediaDecoder::StopProgress()
{ {
if (!mProgressTimer) MOZ_ASSERT(NS_IsMainThread());
return NS_OK; NS_ASSERTION(mProgressTimer, "Already stopped progress timer.");
nsresult rv = mProgressTimer->Cancel(); nsresult rv = mProgressTimer->Cancel();
mProgressTimer = nullptr; mProgressTimer = nullptr;

View File

@ -689,6 +689,12 @@ public:
return mPlayState; return mPlayState;
} }
// Called by the media element to start timer to update download progress.
nsresult StartProgress();
// Called by the media element to stop progress information timer.
nsresult StopProgress();
// Fire progress events if needed according to the time and byte // Fire progress events if needed according to the time and byte
// constraints outlined in the specification. aTimer is true // constraints outlined in the specification. aTimer is true
// if the method is called as a result of the progress timer rather // if the method is called as a result of the progress timer rather
@ -1166,12 +1172,6 @@ protected:
// True if the stream is infinite (e.g. a webradio). // True if the stream is infinite (e.g. a webradio).
bool mInfiniteStream; bool mInfiniteStream;
// Start timer to update download progress information.
nsresult StartProgress();
// Stop progress information timer.
nsresult StopProgress();
// Ensures our media stream has been pinned. // Ensures our media stream has been pinned.
void PinForSeek(); void PinForSeek();

View File

@ -18,6 +18,8 @@ class HTMLMediaElement;
class MediaDecoderOwner class MediaDecoderOwner
{ {
public: public:
// Called by the media decoder to indicate that the download is progressing.
virtual void DownloadProgressed() = 0;
// Called by the media decoder to indicate that the download has stalled // Called by the media decoder to indicate that the download has stalled
// (no data has arrived for a while). // (no data has arrived for a while).
virtual void DownloadStalled() = 0; virtual void DownloadStalled() = 0;

View File

@ -905,8 +905,11 @@ void ChannelMediaResource::Resume()
// There is (or may be) data to read at mOffset, so start reading it. // There is (or may be) data to read at mOffset, so start reading it.
// Need to recreate the channel. // Need to recreate the channel.
CacheClientSeek(mOffset, false); CacheClientSeek(mOffset, false);
element->DownloadResumed();
} else {
// The channel remains dead. Do not notify DownloadResumed() which
// will leave the media element in NETWORK_LOADING state.
} }
element->DownloadResumed();
} }
} }
} }

View File

@ -101,7 +101,6 @@ MediaOmxCommonDecoder::PauseStateMachine()
if (!mDecoderStateMachine) { if (!mDecoderStateMachine) {
return; return;
} }
StopProgress();
mDecoderStateMachine->SetDormant(true); mDecoderStateMachine->SetDormant(true);
} }