--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -2270,127 +2270,140 @@ MediaDecoderStateMachine::FinishShutdown
void
MediaDecoderStateMachine::RunStateMachine()
{
MOZ_ASSERT(OnTaskQueue());
mDelayedScheduler.Reset(); // Must happen on state machine task queue.
mDispatchedStateMachine = false;
- MediaResource* resource = mResource;
- NS_ENSURE_TRUE_VOID(resource);
-
switch (mState) {
- case DECODER_STATE_DECODING: {
- if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING && IsPlaying())
- {
- // We're playing, but the element/decoder is in paused state. Stop
- // playing!
- StopPlayback();
- }
-
- // Start playback if necessary so that the clock can be properly queried.
- MaybeStartPlayback();
-
- UpdatePlaybackPositionPeriodically();
- NS_ASSERTION(!IsPlaying() ||
- IsStateMachineScheduled(),
- "Must have timer scheduled");
- MaybeStartBuffering();
+ case DECODER_STATE_DECODING:
+ StepDecoding();
+ return;
+ case DECODER_STATE_BUFFERING:
+ StepBuffering();
+ return;
+ case DECODER_STATE_COMPLETED:
+ StepCompleted();
+ return;
+ default:
+ return;
+ }
+}
+
+void
+MediaDecoderStateMachine::StepDecoding()
+{
+ MOZ_ASSERT(OnTaskQueue());
+
+ if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING && IsPlaying()) {
+ // We're playing, but the element/decoder is in paused state. Stop
+ // playing!
+ StopPlayback();
+ }
+
+ // Start playback if necessary so that the clock can be properly queried.
+ MaybeStartPlayback();
+
+ UpdatePlaybackPositionPeriodically();
+
+ NS_ASSERTION(!IsPlaying() ||
+ IsStateMachineScheduled(),
+ "Must have timer scheduled");
+
+ MaybeStartBuffering();
+}
+
+void
+MediaDecoderStateMachine::StepBuffering()
+{
+ MOZ_ASSERT(OnTaskQueue());
+
+ TimeStamp now = TimeStamp::Now();
+ NS_ASSERTION(!mBufferingStart.IsNull(), "Must know buffering start time.");
+
+ // With buffering heuristics we will remain in the buffering state if
+ // we've not decoded enough data to begin playback, or if we've not
+ // downloaded a reasonable amount of data inside our buffering time.
+ if (mReader->UseBufferingHeuristics()) {
+ TimeDuration elapsed = now - mBufferingStart;
+ bool isLiveStream = mResource->IsLiveStream();
+ if ((isLiveStream || !CanPlayThrough()) &&
+ elapsed < TimeDuration::FromSeconds(mBufferingWait * mPlaybackRate) &&
+ (mQuickBuffering ? HasLowDecodedData(mQuickBufferingLowDataThresholdUsecs)
+ : HasLowUndecodedData(mBufferingWait * USECS_PER_S)) &&
+ mResource->IsExpectingMoreData()) {
+ DECODER_LOG("Buffering: wait %ds, timeout in %.3lfs %s",
+ mBufferingWait, mBufferingWait - elapsed.ToSeconds(),
+ (mQuickBuffering ? "(quick exit)" : ""));
+ ScheduleStateMachineIn(USECS_PER_S);
return;
}
-
- case DECODER_STATE_BUFFERING: {
- TimeStamp now = TimeStamp::Now();
- NS_ASSERTION(!mBufferingStart.IsNull(), "Must know buffering start time.");
-
- // With buffering heuristics we will remain in the buffering state if
- // we've not decoded enough data to begin playback, or if we've not
- // downloaded a reasonable amount of data inside our buffering time.
- if (mReader->UseBufferingHeuristics()) {
- TimeDuration elapsed = now - mBufferingStart;
- bool isLiveStream = resource->IsLiveStream();
- if ((isLiveStream || !CanPlayThrough()) &&
- elapsed < TimeDuration::FromSeconds(mBufferingWait * mPlaybackRate) &&
- (mQuickBuffering ? HasLowDecodedData(mQuickBufferingLowDataThresholdUsecs)
- : HasLowUndecodedData(mBufferingWait * USECS_PER_S)) &&
- mResource->IsExpectingMoreData())
- {
- DECODER_LOG("Buffering: wait %ds, timeout in %.3lfs %s",
- mBufferingWait, mBufferingWait - elapsed.ToSeconds(),
- (mQuickBuffering ? "(quick exit)" : ""));
- ScheduleStateMachineIn(USECS_PER_S);
- return;
- }
- } else if (OutOfDecodedAudio() || OutOfDecodedVideo()) {
- MOZ_ASSERT(mReader->IsWaitForDataSupported(),
- "Don't yet have a strategy for non-heuristic + non-WaitForData");
- DispatchDecodeTasksIfNeeded();
- MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedAudio(), mReader->IsRequestingAudioData() || mReader->IsWaitingAudioData());
- MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedVideo(), mReader->IsRequestingVideoData() || mReader->IsWaitingVideoData());
- DECODER_LOG("In buffering mode, waiting to be notified: outOfAudio: %d, "
- "mAudioStatus: %s, outOfVideo: %d, mVideoStatus: %s",
- OutOfDecodedAudio(), AudioRequestStatus(),
- OutOfDecodedVideo(), VideoRequestStatus());
- return;
- }
-
- DECODER_LOG("Changed state from BUFFERING to DECODING");
- DECODER_LOG("Buffered for %.3lfs", (now - mBufferingStart).ToSeconds());
- SetState(DECODER_STATE_DECODING);
-
- NS_ASSERTION(IsStateMachineScheduled(), "Must have timer scheduled");
- return;
- }
-
- case DECODER_STATE_COMPLETED: {
- if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING && IsPlaying()) {
- StopPlayback();
- }
- // Play the remaining media. We want to run AdvanceFrame() at least
- // once to ensure the current playback position is advanced to the
- // end of the media, and so that we update the readyState.
- if ((HasVideo() && !mVideoCompleted) ||
- (HasAudio() && !mAudioCompleted)) {
- // Start playback if necessary to play the remaining media.
- MaybeStartPlayback();
- UpdatePlaybackPositionPeriodically();
- NS_ASSERTION(!IsPlaying() ||
- IsStateMachineScheduled(),
- "Must have timer scheduled");
- return;
- }
-
- // StopPlayback in order to reset the IsPlaying() state so audio
- // is restarted correctly.
- StopPlayback();
-
- if (mPlayState == MediaDecoder::PLAY_STATE_PLAYING &&
- !mSentPlaybackEndedEvent)
- {
- int64_t clockTime = std::max(AudioEndTime(), VideoEndTime());
- clockTime = std::max(int64_t(0), std::max(clockTime, Duration().ToMicroseconds()));
- UpdatePlaybackPosition(clockTime);
-
- // Ensure readyState is updated before firing the 'ended' event.
- UpdateNextFrameStatus();
-
- mOnPlaybackEvent.Notify(MediaEventType::PlaybackEnded);
-
- mSentPlaybackEndedEvent = true;
-
- // MediaSink::GetEndTime() must be called before stopping playback.
- StopMediaSink();
- }
-
- return;
- }
-
- default:
- return;
+ } else if (OutOfDecodedAudio() || OutOfDecodedVideo()) {
+ MOZ_ASSERT(mReader->IsWaitForDataSupported(),
+ "Don't yet have a strategy for non-heuristic + non-WaitForData");
+ DispatchDecodeTasksIfNeeded();
+ MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedAudio(), mReader->IsRequestingAudioData() || mReader->IsWaitingAudioData());
+ MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedVideo(), mReader->IsRequestingVideoData() || mReader->IsWaitingVideoData());
+ DECODER_LOG("In buffering mode, waiting to be notified: outOfAudio: %d, "
+ "mAudioStatus: %s, outOfVideo: %d, mVideoStatus: %s",
+ OutOfDecodedAudio(), AudioRequestStatus(),
+ OutOfDecodedVideo(), VideoRequestStatus());
+ return;
+ }
+
+ DECODER_LOG("Changed state from BUFFERING to DECODING");
+ DECODER_LOG("Buffered for %.3lfs", (now - mBufferingStart).ToSeconds());
+ SetState(DECODER_STATE_DECODING);
+ NS_ASSERTION(IsStateMachineScheduled(), "Must have timer scheduled");
+}
+
+void
+MediaDecoderStateMachine::StepCompleted()
+{
+ MOZ_ASSERT(OnTaskQueue());
+
+ if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING && IsPlaying()) {
+ StopPlayback();
+ }
+
+ // Play the remaining media. We want to run AdvanceFrame() at least
+ // once to ensure the current playback position is advanced to the
+ // end of the media, and so that we update the readyState.
+ if ((HasVideo() && !mVideoCompleted) ||
+ (HasAudio() && !mAudioCompleted)) {
+ // Start playback if necessary to play the remaining media.
+ MaybeStartPlayback();
+ UpdatePlaybackPositionPeriodically();
+ NS_ASSERTION(!IsPlaying() ||
+ IsStateMachineScheduled(),
+ "Must have timer scheduled");
+ return;
+ }
+
+ // StopPlayback in order to reset the IsPlaying() state so audio
+ // is restarted correctly.
+ StopPlayback();
+
+ if (mPlayState == MediaDecoder::PLAY_STATE_PLAYING &&
+ !mSentPlaybackEndedEvent) {
+ int64_t clockTime = std::max(AudioEndTime(), VideoEndTime());
+ clockTime = std::max(int64_t(0), std::max(clockTime, Duration().ToMicroseconds()));
+ UpdatePlaybackPosition(clockTime);
+
+ // Ensure readyState is updated before firing the 'ended' event.
+ UpdateNextFrameStatus();
+
+ mOnPlaybackEvent.Notify(MediaEventType::PlaybackEnded);
+
+ mSentPlaybackEndedEvent = true;
+
+ // MediaSink::GetEndTime() must be called before stopping playback.
+ StopMediaSink();
}
}
void
MediaDecoderStateMachine::Reset(TrackSet aTracks)
{
MOZ_ASSERT(OnTaskQueue());
DECODER_LOG("MediaDecoderStateMachine::Reset");
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -551,16 +551,22 @@ protected:
// Completes the seek operation, moves onto the next appropriate state.
void SeekCompleted();
// Queries our state to see whether the decode has finished for all streams.
bool CheckIfDecodeComplete();
// Performs one "cycle" of the state machine.
void RunStateMachine();
+ // Perform one cycle of the DECODING state.
+ void StepDecoding();
+ // Perform one cycle of the BUFFERING state.
+ void StepBuffering();
+ // Perform one cycle of the COMPLETED state.
+ void StepCompleted();
bool IsStateMachineScheduled() const;
// These return true if the respective stream's decode has not yet reached
// the end of stream.
bool IsAudioDecoding();
bool IsVideoDecoding();