--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -208,17 +208,17 @@ MediaDecoderStateMachine::MediaDecoderSt
mVideoFrameContainer(aDecoder->GetVideoFrameContainer()),
mAudioChannel(aDecoder->GetAudioChannel()),
mTaskQueue(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
/* aSupportsTailDispatch = */ true)),
mWatchManager(this, mTaskQueue),
mRealTime(aRealTime),
mDispatchedStateMachine(false),
mDelayedScheduler(mTaskQueue),
- mState(DECODER_STATE_DECODING_NONE, "MediaDecoderStateMachine::mState"),
+ mState(DECODER_STATE_DECODING_METADATA, "MediaDecoderStateMachine::mState"),
mCurrentFrameID(0),
mObservedDuration(TimeUnit(), "MediaDecoderStateMachine::mObservedDuration"),
mFragmentEndTime(-1),
mReader(aReader),
mDecodedAudioEndTime(0),
mDecodedVideoEndTime(0),
mPlaybackRate(1.0),
mLowAudioThresholdUsecs(detail::LOW_AUDIO_USECS),
@@ -1060,17 +1060,21 @@ bool MediaDecoderStateMachine::IsPlaying
return mMediaSink->IsPlaying();
}
nsresult MediaDecoderStateMachine::Init()
{
MOZ_ASSERT(NS_IsMainThread());
nsresult rv = mReader->Init();
NS_ENSURE_SUCCESS(rv, rv);
- ScheduleStateMachineCrossThread();
+
+ nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
+ this, &MediaDecoderStateMachine::ReadMetadata);
+ OwnerThread()->Dispatch(r.forget());
+
return NS_OK;
}
void MediaDecoderStateMachine::StopPlayback()
{
MOZ_ASSERT(OnTaskQueue());
DECODER_LOG("StopPlayback()");
@@ -1165,17 +1169,16 @@ void MediaDecoderStateMachine::UpdatePla
mMetadataManager.DispatchMetadataIfNeeded(TimeUnit::FromMicroseconds(aTime));
if (fragmentEnded) {
StopPlayback();
}
}
static const char* const gMachineStateStr[] = {
- "NONE",
"DECODING_METADATA",
"WAIT_FOR_CDM",
"DORMANT",
"DECODING",
"SEEKING",
"BUFFERING",
"COMPLETED",
"SHUTDOWN",
@@ -1305,19 +1308,19 @@ MediaDecoderStateMachine::SetDormant(boo
// queuing the ReleaseMediaResources task - instead, we disconnect promises,
// reset state, and put a ResetDecode in the decode task queue. Any tasks
// that run after ResetDecode are supposed to run with a clean slate. We rely
// on that in other places (i.e. seeking), so it seems reasonable to rely on
// it here as well.
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(mReader, &MediaDecoderReader::ReleaseMediaResources);
DecodeTaskQueue()->Dispatch(r.forget());
} else if ((aDormant != true) && (mState == DECODER_STATE_DORMANT)) {
- ScheduleStateMachine();
mDecodingFirstFrame = true;
- SetState(DECODER_STATE_DECODING_NONE);
+ SetState(DECODER_STATE_DECODING_METADATA);
+ ReadMetadata();
}
}
RefPtr<ShutdownPromise>
MediaDecoderStateMachine::Shutdown()
{
MOZ_ASSERT(OnTaskQueue());
@@ -1468,16 +1471,34 @@ void MediaDecoderStateMachine::BufferedR
bool exists;
media::TimeUnit end{mBuffered.Ref().GetEnd(&exists)};
if (exists) {
mObservedDuration = std::max(mObservedDuration.Ref(), end);
}
}
}
+void
+MediaDecoderStateMachine::ReadMetadata()
+{
+ MOZ_ASSERT(OnTaskQueue());
+ MOZ_ASSERT(!IsShutdown());
+ MOZ_ASSERT(mState == DECODER_STATE_DECODING_METADATA);
+ MOZ_ASSERT(!mMetadataRequest.Exists());
+
+ DECODER_LOG("Dispatching AsyncReadMetadata");
+ // Set mode to METADATA since we are about to read metadata.
+ mResource->SetReadMode(MediaCacheStream::MODE_METADATA);
+ mMetadataRequest.Begin(InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
+ &MediaDecoderReader::AsyncReadMetadata)
+ ->Then(OwnerThread(), __func__, this,
+ &MediaDecoderStateMachine::OnMetadataRead,
+ &MediaDecoderStateMachine::OnMetadataNotRead));
+}
+
RefPtr<MediaDecoder::SeekPromise>
MediaDecoderStateMachine::Seek(SeekTarget aTarget)
{
MOZ_ASSERT(OnTaskQueue());
if (IsShutdown()) {
return MediaDecoder::SeekPromise::CreateAndReject(/* aIgnored = */ true, __func__);
}
@@ -2227,38 +2248,18 @@ nsresult MediaDecoderStateMachine::RunSt
MediaResource* resource = mResource;
NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER);
switch (mState) {
case DECODER_STATE_ERROR:
case DECODER_STATE_SHUTDOWN:
case DECODER_STATE_DORMANT:
case DECODER_STATE_WAIT_FOR_CDM:
- return NS_OK;
-
- case DECODER_STATE_DECODING_NONE: {
- SetState(DECODER_STATE_DECODING_METADATA);
- ScheduleStateMachine();
+ case DECODER_STATE_DECODING_METADATA:
return NS_OK;
- }
-
- case DECODER_STATE_DECODING_METADATA: {
- if (!mMetadataRequest.Exists()) {
- DECODER_LOG("Dispatching AsyncReadMetadata");
- // Set mode to METADATA since we are about to read metadata.
- mResource->SetReadMode(MediaCacheStream::MODE_METADATA);
- mMetadataRequest.Begin(InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
- &MediaDecoderReader::AsyncReadMetadata)
- ->Then(OwnerThread(), __func__, this,
- &MediaDecoderStateMachine::OnMetadataRead,
- &MediaDecoderStateMachine::OnMetadataNotRead));
-
- }
- return NS_OK;
- }
case DECODER_STATE_DECODING: {
if (IsDecodingFirstFrame()) {
// We haven't completed decoding our first frames, we can't start
// playback yet.
return NS_OK;
}
if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING && IsPlaying())
@@ -2381,18 +2382,17 @@ MediaDecoderStateMachine::Reset()
DECODER_LOG("MediaDecoderStateMachine::Reset");
// We should be resetting because we're seeking, shutting down, or entering
// dormant state. We could also be in the process of going dormant, and have
// just switched to exiting dormant before we finished entering dormant,
// hence the DECODING_NONE case below.
MOZ_ASSERT(IsShutdown() ||
mState == DECODER_STATE_SEEKING ||
- mState == DECODER_STATE_DORMANT ||
- mState == DECODER_STATE_DECODING_NONE);
+ mState == DECODER_STATE_DORMANT);
// Stop the audio thread. Otherwise, MediaSink might be accessing AudioQueue
// outside of the decoder monitor while we are clearing the queue and causes
// crash for no samples to be popped.
StopMediaSink();
mDecodedVideoEndTime = 0;
mDecodedAudioEndTime = 0;
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -141,17 +141,16 @@ public:
MediaDecoderStateMachine(MediaDecoder* aDecoder,
MediaDecoderReader* aReader,
bool aRealTime = false);
nsresult Init();
// Enumeration for the valid decoding states
enum State {
- DECODER_STATE_DECODING_NONE,
DECODER_STATE_DECODING_METADATA,
DECODER_STATE_WAIT_FOR_CDM,
DECODER_STATE_DORMANT,
DECODER_STATE_DECODING,
DECODER_STATE_SEEKING,
DECODER_STATE_BUFFERING,
DECODER_STATE_COMPLETED,
DECODER_STATE_SHUTDOWN,
@@ -262,16 +261,18 @@ private:
// task that gets run on the task queue, and is dispatched from the MDSM
// constructor immediately after the task queue is created.
void InitializationTask(MediaDecoder* aDecoder);
void SetDormant(bool aDormant);
void SetAudioCaptured(bool aCaptured);
+ void ReadMetadata();
+
RefPtr<MediaDecoder::SeekPromise> Seek(SeekTarget aTarget);
RefPtr<ShutdownPromise> Shutdown();
RefPtr<ShutdownPromise> FinishShutdown();
// Update the playback position. This can result in a timeupdate event
// and an invalidate of the frame being dispatched asynchronously if
@@ -317,27 +318,17 @@ private:
MOZ_ASSERT(OnTaskQueue());
return mState == DECODER_STATE_SEEKING;
}
// Returns the state machine task queue.
TaskQueue* OwnerThread() const { return mTaskQueue; }
// Schedules the shared state machine thread to run the state machine.
- //
- // The first variant coalesces multiple calls into a single state machine
- // cycle, the second variant does not. The second variant must be used when
- // not already on the state machine task queue.
void ScheduleStateMachine();
- void ScheduleStateMachineCrossThread()
- {
- nsCOMPtr<nsIRunnable> task =
- NS_NewRunnableMethod(this, &MediaDecoderStateMachine::RunStateMachine);
- OwnerThread()->Dispatch(task.forget());
- }
// Invokes ScheduleStateMachine to run in |aMicroseconds| microseconds,
// unless it's already scheduled to run earlier, in which case the
// request is discarded.
void ScheduleStateMachineIn(int64_t aMicroseconds);
void OnDelayedSchedule()
{