Bug 996465 - Extract code running state machine cycles into a class. r=cpearce

This commit is contained in:
JW Wang 2014-07-11 03:11:00 -04:00
parent e854923edc
commit 80b90738fb
5 changed files with 313 additions and 146 deletions

View File

@ -13,6 +13,7 @@
#include <stdint.h>
#include "MediaDecoderStateMachine.h"
#include "MediaDecoderStateMachineScheduler.h"
#include "AudioSink.h"
#include "nsTArray.h"
#include "MediaDecoder.h"
@ -168,8 +169,11 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
MediaDecoderReader* aReader,
bool aRealTime) :
mDecoder(aDecoder),
mScheduler(new MediaDecoderStateMachineScheduler(
aDecoder->GetReentrantMonitor(),
&MediaDecoderStateMachine::TimeoutExpired,
MOZ_THIS_IN_INITIALIZER_LIST(), aRealTime)),
mState(DECODER_STATE_DECODING_METADATA),
mInRunningStateMachine(false),
mSyncPointInMediaStream(-1),
mSyncPointInDecodedStream(-1),
mPlayDuration(0),
@ -198,30 +202,24 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mQuickBuffering(false),
mMinimizePreroll(false),
mDecodeThreadWaiting(false),
mRealTime(aRealTime),
mDispatchedDecodeMetadataTask(false),
mDropAudioUntilNextDiscontinuity(false),
mDropVideoUntilNextDiscontinuity(false),
mDecodeToSeekTarget(false),
mCurrentTimeBeforeSeek(0),
mLastFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED),
mTimerId(0)
mLastFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED)
{
MOZ_COUNT_CTOR(MediaDecoderStateMachine);
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
// Only enable realtime mode when "media.realtime_decoder.enabled" is true.
if (Preferences::GetBool("media.realtime_decoder.enabled", false) == false)
mRealTime = false;
mAmpleVideoFrames =
std::max<uint32_t>(Preferences::GetUint("media.video-queue.default-size", 10), 3);
mBufferingWait = mRealTime ? 0 : BUFFERING_WAIT_S;
mLowDataThresholdUsecs = mRealTime ? 0 : LOW_DATA_THRESHOLD_USECS;
mBufferingWait = mScheduler->IsRealTime() ? 0 : BUFFERING_WAIT_S;
mLowDataThresholdUsecs = mScheduler->IsRealTime() ? 0 : LOW_DATA_THRESHOLD_USECS;
mVideoPrerollFrames = mRealTime ? 0 : mAmpleVideoFrames / 2;
mAudioPrerollUsecs = mRealTime ? 0 : LOW_AUDIO_USECS * 2;
mVideoPrerollFrames = mScheduler->IsRealTime() ? 0 : mAmpleVideoFrames / 2;
mAudioPrerollUsecs = mScheduler->IsRealTime() ? 0 : LOW_AUDIO_USECS * 2;
#ifdef XP_WIN
// Ensure high precision timers are enabled on Windows, otherwise the state
@ -241,8 +239,6 @@ MediaDecoderStateMachine::~MediaDecoderStateMachine()
"WakeDecoder should have been revoked already");
MOZ_ASSERT(!mDecodeTaskQueue, "Should be released in SHUTDOWN");
// No need to cancel the timer here for we've done that in SHUTDOWN.
MOZ_ASSERT(!mTimer, "Should be released in SHUTDOWN");
mReader = nullptr;
#ifdef XP_WIN
@ -1063,10 +1059,6 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoderStateMachine* aCloneDonor)
RefPtr<SharedThreadPool> decodePool(GetMediaDecodeThreadPool());
NS_ENSURE_TRUE(decodePool, NS_ERROR_FAILURE);
RefPtr<SharedThreadPool> stateMachinePool(
SharedThreadPool::Get(NS_LITERAL_CSTRING("Media State Machine"), 1));
NS_ENSURE_TRUE(stateMachinePool, NS_ERROR_FAILURE);
mDecodeTaskQueue = new MediaTaskQueue(decodePool.forget());
NS_ENSURE_TRUE(mDecodeTaskQueue, NS_ERROR_FAILURE);
@ -1075,12 +1067,7 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoderStateMachine* aCloneDonor)
cloneReader = aCloneDonor->mReader;
}
mStateMachineThreadPool = stateMachinePool;
nsresult rv;
mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = mTimer->SetTarget(GetStateMachineThread());
nsresult rv = mScheduler->Init();
NS_ENSURE_SUCCESS(rv, rv);
// Note: This creates a cycle, broken in shutdown.
@ -1342,8 +1329,8 @@ void MediaDecoderStateMachine::Shutdown()
// Change state before issuing shutdown request to threads so those
// threads can start exiting cleanly during the Shutdown call.
DECODER_LOG(PR_LOG_DEBUG, "Changed state to SHUTDOWN");
ScheduleStateMachine();
mState = DECODER_STATE_SHUTDOWN;
mScheduler->ScheduleAndShutdown();
if (mAudioSink) {
mAudioSink->PrepareToShutdown();
}
@ -1753,6 +1740,7 @@ MediaDecoderStateMachine::StartAudioThread()
if (NS_FAILED(rv)) {
DECODER_LOG(PR_LOG_WARNING, "Changed state to SHUTDOWN because audio sink initialization failed");
mState = DECODER_STATE_SHUTDOWN;
mScheduler->ScheduleAndShutdown();
return rv;
}
@ -1830,8 +1818,8 @@ MediaDecoderStateMachine::DecodeError()
// and the HTMLMediaElement, so that our pipeline can start exiting
// cleanly during the sync dispatch below.
DECODER_LOG(PR_LOG_WARNING, "Decode error, changed state to SHUTDOWN due to error");
ScheduleStateMachine();
mState = DECODER_STATE_SHUTDOWN;
mScheduler->ScheduleAndShutdown();
mDecoder->GetReentrantMonitor().NotifyAll();
// Dispatch the event to call DecodeError synchronously. This ensures
@ -1911,7 +1899,7 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
VideoQueue().AddPopListener(decodeTask, mDecodeTaskQueue);
}
if (mRealTime) {
if (mScheduler->IsRealTime()) {
SetStartTime(0);
res = FinishDecodeMetadata();
NS_ENSURE_SUCCESS(res, res);
@ -1940,7 +1928,7 @@ MediaDecoderStateMachine::FinishDecodeMetadata()
return NS_ERROR_FAILURE;
}
if (!mRealTime) {
if (!mScheduler->IsRealTime()) {
const VideoData* v = VideoQueue().PeekFront();
const AudioData* a = AudioQueue().PeekFront();
@ -2292,8 +2280,6 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
GetStateMachineThread()->Dispatch(
new nsDispatchDisposeEvent(mDecoder, this), NS_DISPATCH_NORMAL);
mTimer->Cancel();
mTimer = nullptr;
return NS_OK;
}
@ -2589,7 +2575,7 @@ void MediaDecoderStateMachine::AdvanceFrame()
#endif
if (VideoQueue().GetSize() > 0) {
VideoData* frame = VideoQueue().PeekFront();
while (mRealTime || clock_time >= frame->mTime) {
while (mScheduler->IsRealTime() || clock_time >= frame->mTime) {
mVideoFrameEndTime = frame->GetEndTime();
currentFrame = frame;
#ifdef PR_LOGGING
@ -2929,24 +2915,13 @@ nsresult MediaDecoderStateMachine::CallRunStateMachine()
StopAudioThread();
}
MOZ_ASSERT(!mInRunningStateMachine, "State machine cycles must run in sequence!");
mTimeout = TimeStamp();
mInRunningStateMachine = true;
nsresult res = RunStateMachine();
mInRunningStateMachine = false;
return res;
return RunStateMachine();
}
nsresult MediaDecoderStateMachine::TimeoutExpired(int aTimerId)
nsresult MediaDecoderStateMachine::TimeoutExpired(void* aClosure)
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
NS_ASSERTION(OnStateMachineThread(), "Must be on state machine thread");
mTimer->Cancel();
if (mTimerId == aTimerId) {
return CallRunStateMachine();
} else {
return NS_OK;
}
MediaDecoderStateMachine* p = static_cast<MediaDecoderStateMachine*>(aClosure);
return p->CallRunStateMachine();
}
void MediaDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder() {
@ -2955,75 +2930,8 @@ void MediaDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder() {
DispatchVideoDecodeTaskIfNeeded();
}
class TimerEvent : public nsITimerCallback, public nsRunnable {
NS_DECL_THREADSAFE_ISUPPORTS
public:
TimerEvent(MediaDecoderStateMachine* aStateMachine, int aTimerId)
: mStateMachine(aStateMachine), mTimerId(aTimerId) {}
NS_IMETHOD Run() MOZ_OVERRIDE {
return mStateMachine->TimeoutExpired(mTimerId);
}
NS_IMETHOD Notify(nsITimer* aTimer) {
return mStateMachine->TimeoutExpired(mTimerId);
}
private:
~TimerEvent() {}
const nsRefPtr<MediaDecoderStateMachine> mStateMachine;
int mTimerId;
};
NS_IMPL_ISUPPORTS(TimerEvent, nsITimerCallback, nsIRunnable);
nsresult MediaDecoderStateMachine::ScheduleStateMachine(int64_t aUsecs) {
AssertCurrentThreadInMonitor();
NS_ABORT_IF_FALSE(GetStateMachineThread(),
"Must have a state machine thread to schedule");
if (mState == DECODER_STATE_SHUTDOWN) {
return NS_ERROR_FAILURE;
}
aUsecs = std::max<int64_t>(aUsecs, 0);
TimeStamp timeout = TimeStamp::Now() + UsecsToDuration(aUsecs);
if (!mTimeout.IsNull() && timeout >= mTimeout) {
// We've already scheduled a timer set to expire at or before this time,
// or have an event dispatched to run the state machine.
return NS_OK;
}
uint32_t ms = static_cast<uint32_t>((aUsecs / USECS_PER_MS) & 0xFFFFFFFF);
if (mRealTime && ms > 40) {
ms = 40;
}
// Don't cancel the timer here for this function will be called from
// different threads.
nsresult rv = NS_ERROR_FAILURE;
nsRefPtr<TimerEvent> event = new TimerEvent(this, mTimerId+1);
if (ms == 0) {
// Dispatch a runnable to the state machine thread when delay is 0.
// It will has less latency than dispatching a runnable to the state
// machine thread which will then schedule a zero-delay timer.
rv = GetStateMachineThread()->Dispatch(event, NS_DISPATCH_NORMAL);
} else if (OnStateMachineThread()) {
rv = mTimer->InitWithCallback(event, ms, nsITimer::TYPE_ONE_SHOT);
} else {
MOZ_ASSERT(false, "non-zero delay timer should be only scheduled in state machine thread");
}
if (NS_SUCCEEDED(rv)) {
mTimeout = timeout;
++mTimerId;
} else {
NS_WARNING("Failed to schedule state machine");
}
return rv;
return mScheduler->Schedule(aUsecs);
}
bool MediaDecoderStateMachine::OnDecodeThread() const
@ -3033,14 +2941,17 @@ bool MediaDecoderStateMachine::OnDecodeThread() const
bool MediaDecoderStateMachine::OnStateMachineThread() const
{
bool rv = false;
mStateMachineThreadPool->IsOnCurrentThread(&rv);
return rv;
return mScheduler->OnStateMachineThread();
}
nsIEventTarget* MediaDecoderStateMachine::GetStateMachineThread()
nsIEventTarget* MediaDecoderStateMachine::GetStateMachineThread() const
{
return mStateMachineThreadPool->GetEventTarget();
return mScheduler->GetStateMachineThread();
}
bool MediaDecoderStateMachine::IsStateMachineScheduled() const
{
return mScheduler->IsScheduled();
}
void MediaDecoderStateMachine::SetPlaybackRate(double aPlaybackRate)

View File

@ -100,6 +100,7 @@ class VideoSegment;
class MediaTaskQueue;
class SharedThreadPool;
class AudioSink;
class MediaDecoderStateMachineScheduler;
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
// GetTickCount() and conflicts with MediaDecoderStateMachine::GetCurrentTime
@ -279,7 +280,7 @@ public:
}
// Returns the shared state machine thread.
nsIEventTarget* GetStateMachineThread();
nsIEventTarget* GetStateMachineThread() const;
// Calls ScheduleStateMachine() after taking the decoder lock. Also
// notifies the decoder thread in case it's waiting on the decoder lock.
@ -290,8 +291,9 @@ public:
// earlier, in which case the request is discarded.
nsresult ScheduleStateMachine(int64_t aUsecs = 0);
// Timer function to implement ScheduleStateMachine(aUsecs).
nsresult TimeoutExpired(int aGeneration);
// Callback function registered with MediaDecoderStateMachineScheduler
// to run state machine cycles.
static nsresult TimeoutExpired(void* aClosure);
// Set the media fragment end time. aEndTime is in microseconds.
void SetFragmentEndTime(int64_t aEndTime);
@ -447,7 +449,7 @@ protected:
// Orders the Reader to stop decoding, and blocks until the Reader
// has stopped decoding and finished delivering samples, then calls
// ResetPlayback() to discard all enqueued data.
// ResetPlayback() to discard all enqueued data.
void FlushDecoding();
// Returns the audio clock, if we have audio, or -1 if we don't.
@ -610,10 +612,7 @@ protected:
// periodically via timer to ensure the video stays in sync.
nsresult RunStateMachine();
bool IsStateMachineScheduled() const {
AssertCurrentThreadInMonitor();
return !mTimeout.IsNull();
}
bool IsStateMachineScheduled() const;
// Returns true if we're not playing and the decode thread has filled its
// decode buffers and is waiting. We can shut the decode thread down in this
@ -650,6 +649,10 @@ protected:
// state machine, audio and main threads.
nsRefPtr<MediaDecoder> mDecoder;
// Used to schedule state machine cycles. This should never outlive
// the life cycle of the state machine.
const nsAutoPtr<MediaDecoderStateMachineScheduler> mScheduler;
// Time at which the last video sample was requested. If it takes too long
// before the sample arrives, we will increase the amount of audio we buffer.
// This is necessary for legacy synchronous decoders to prevent underruns.
@ -674,19 +677,6 @@ protected:
// thread every time they're called.
RefPtr<MediaTaskQueue> mDecodeTaskQueue;
RefPtr<SharedThreadPool> mStateMachineThreadPool;
// Timer to run the state machine cycles. Used by
// ScheduleStateMachine(). Access protected by decoder monitor.
nsCOMPtr<nsITimer> mTimer;
// Timestamp at which the next state machine cycle will run.
// Access protected by decoder monitor.
TimeStamp mTimeout;
// Used to check if there are state machine cycles are running in sequence.
DebugOnly<bool> mInRunningStateMachine;
// The time that playback started from the system clock. This is used for
// timing the presentation of video frames when there's no audio.
// Accessed only via the state machine thread. Must be set via SetPlayStartTime.
@ -911,9 +901,6 @@ protected:
// by the decoder monitor.
bool mDecodeThreadWaiting;
// True is we are decoding a realtime stream, like a camera stream
bool mRealTime;
// True if we've dispatched a task to the decode task queue to call
// ReadMetadata on the reader. We maintain a flag to ensure that we don't
// dispatch multiple tasks to re-do the metadata loading.
@ -942,9 +929,6 @@ protected:
mozilla::MediaMetadataManager mMetadataManager;
MediaDecoderOwner::NextFrameStatus mLastFrameStatus;
// The id of timer tasks, used to ignore tasks that are scheduled previously.
int mTimerId;
};
} // namespace mozilla;

View File

@ -0,0 +1,194 @@
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "MediaDecoderStateMachineScheduler.h"
#include "SharedThreadPool.h"
#include "mozilla/Preferences.h"
#include "mozilla/ReentrantMonitor.h"
#include "nsITimer.h"
#include "nsComponentManagerUtils.h"
#include "VideoUtils.h"
namespace {
class TimerEvent : public nsITimerCallback, public nsRunnable {
typedef mozilla::MediaDecoderStateMachineScheduler Scheduler;
NS_DECL_THREADSAFE_ISUPPORTS
public:
TimerEvent(Scheduler* aScheduler, int aTimerId)
: mScheduler(aScheduler), mTimerId(aTimerId) {}
NS_IMETHOD Run() MOZ_OVERRIDE {
return mScheduler->TimeoutExpired(mTimerId);
}
NS_IMETHOD Notify(nsITimer* aTimer) MOZ_OVERRIDE {
return mScheduler->TimeoutExpired(mTimerId);
}
private:
~TimerEvent() {}
Scheduler* const mScheduler;
const int mTimerId;
};
NS_IMPL_ISUPPORTS(TimerEvent, nsITimerCallback, nsIRunnable);
} // anonymous namespace
static already_AddRefed<nsIEventTarget>
CreateStateMachineThread()
{
using mozilla::SharedThreadPool;
using mozilla::RefPtr;
RefPtr<SharedThreadPool> threadPool(
SharedThreadPool::Get(NS_LITERAL_CSTRING("Media State Machine"), 1));
nsCOMPtr<nsIEventTarget> rv = threadPool.get();
return rv.forget();
}
namespace mozilla {
MediaDecoderStateMachineScheduler::MediaDecoderStateMachineScheduler(
ReentrantMonitor& aMonitor,
nsresult (*aTimeoutCallback)(void*),
void* aClosure, bool aRealTime)
: mTimeoutCallback(aTimeoutCallback)
, mClosure(aClosure)
// Only enable realtime mode when "media.realtime_decoder.enabled" is true.
, mRealTime(aRealTime &&
Preferences::GetBool("media.realtime_decoder.enabled", false))
, mMonitor(aMonitor)
, mEventTarget(CreateStateMachineThread())
, mTimer(do_CreateInstance("@mozilla.org/timer;1"))
, mTimerId(0)
, mState(SCHEDULER_STATE_NONE)
, mInRunningStateMachine(false)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_COUNT_CTOR(MediaDecoderStateMachineScheduler);
}
MediaDecoderStateMachineScheduler::~MediaDecoderStateMachineScheduler()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_COUNT_DTOR(MediaDecoderStateMachineScheduler);
}
nsresult
MediaDecoderStateMachineScheduler::Init()
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE(mEventTarget, NS_ERROR_FAILURE);
nsresult rv = mTimer->SetTarget(mEventTarget);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
MediaDecoderStateMachineScheduler::Schedule(int64_t aUsecs)
{
mMonitor.AssertCurrentThreadIn();
if (mState == SCHEDULER_STATE_SHUTDOWN) {
return NS_ERROR_FAILURE;
}
aUsecs = std::max<int64_t>(aUsecs, 0);
TimeStamp timeout = TimeStamp::Now() +
TimeDuration::FromMilliseconds(static_cast<double>(aUsecs) / USECS_PER_MS);
if (!mTimeout.IsNull() && timeout >= mTimeout) {
// We've already scheduled a timer set to expire at or before this time,
// or have an event dispatched to run the state machine.
return NS_OK;
}
uint32_t ms = static_cast<uint32_t>((aUsecs / USECS_PER_MS) & 0xFFFFFFFF);
if (IsRealTime() && ms > 40) {
ms = 40;
}
// Don't cancel the timer here for this function will be called from
// different threads.
nsresult rv = NS_ERROR_FAILURE;
nsRefPtr<TimerEvent> event = new TimerEvent(this, mTimerId+1);
if (ms == 0) {
// Dispatch a runnable to the state machine thread when delay is 0.
// It will has less latency than dispatching a runnable to the state
// machine thread which will then schedule a zero-delay timer.
rv = mEventTarget->Dispatch(event, NS_DISPATCH_NORMAL);
} else if (OnStateMachineThread()) {
rv = mTimer->InitWithCallback(event, ms, nsITimer::TYPE_ONE_SHOT);
} else {
MOZ_ASSERT(false, "non-zero delay timer should be only "
"scheduled in state machine thread");
}
if (NS_SUCCEEDED(rv)) {
mTimeout = timeout;
++mTimerId;
} else {
NS_WARNING("Failed to schedule state machine");
}
return rv;
}
nsresult
MediaDecoderStateMachineScheduler::TimeoutExpired(int aTimerId)
{
ReentrantMonitorAutoEnter mon(mMonitor);
MOZ_ASSERT(OnStateMachineThread());
MOZ_ASSERT(!mInRunningStateMachine,
"State machine cycles must run in sequence!");
mInRunningStateMachine = true;
// Only run state machine cycles when id matches.
nsresult rv = NS_OK;
if (mTimerId == aTimerId) {
ResetTimer();
rv = mTimeoutCallback(mClosure);
}
mInRunningStateMachine = false;
return rv;
}
void
MediaDecoderStateMachineScheduler::ScheduleAndShutdown()
{
mMonitor.AssertCurrentThreadIn();
// Schedule next cycle to handle SHUTDOWN in state machine thread.
Schedule();
// This must be set after calling Schedule()
// which does nothing in shutdown state.
mState = SCHEDULER_STATE_SHUTDOWN;
}
bool
MediaDecoderStateMachineScheduler::OnStateMachineThread() const
{
bool rv = false;
mEventTarget->IsOnCurrentThread(&rv);
return rv;
}
bool
MediaDecoderStateMachineScheduler::IsScheduled() const
{
mMonitor.AssertCurrentThreadIn();
return !mTimeout.IsNull();
}
void
MediaDecoderStateMachineScheduler::ResetTimer()
{
mMonitor.AssertCurrentThreadIn();
mTimer->Cancel();
mTimeout = TimeStamp();
}
} // namespace mozilla

View File

@ -0,0 +1,77 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MediaDecoderStateMachineScheduler_h__
#define MediaDecoderStateMachineScheduler_h__
#include "nsCOMPtr.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/DebugOnly.h"
class nsITimer;
class nsIEventTarget;
namespace mozilla {
class ReentrantMonitor;
class MediaDecoderStateMachineScheduler {
enum State {
SCHEDULER_STATE_NONE,
SCHEDULER_STATE_SHUTDOWN
};
public:
MediaDecoderStateMachineScheduler(ReentrantMonitor& aMonitor,
nsresult (*aTimeoutCallback)(void*),
void* aClosure, bool aRealTime);
~MediaDecoderStateMachineScheduler();
nsresult Init();
nsresult Schedule(int64_t aUsecs = 0);
void ScheduleAndShutdown();
nsresult TimeoutExpired(int aTimerId);
bool OnStateMachineThread() const;
bool IsScheduled() const;
bool IsRealTime() const {
return mRealTime;
}
nsIEventTarget* GetStateMachineThread() const {
return mEventTarget;
}
private:
void ResetTimer();
// Callback function provided by MediaDecoderStateMachine to run
// state machine cycles.
nsresult (*const mTimeoutCallback)(void*);
// Since StateMachineScheduler will never outlive the state machine,
// it is safe to keep a raw pointer only to avoid reference cycles.
void* const mClosure;
// True is we are decoding a realtime stream, like a camera stream
const bool mRealTime;
// Monitor of the decoder
ReentrantMonitor& mMonitor;
// State machine thread
const nsCOMPtr<nsIEventTarget> mEventTarget;
// Timer to schedule callbacks to run the state machine cycles.
nsCOMPtr<nsITimer> mTimer;
// Timestamp at which the next state machine cycle will run.
TimeStamp mTimeout;
// The id of timer tasks, timer callback will only run if id matches.
int mTimerId;
// No more state machine cycles in shutdown state.
State mState;
// Used to check if state machine cycles are running in sequence.
DebugOnly<bool> mInRunningStateMachine;
};
} // namespace mozilla
#endif // MediaDecoderStateMachineScheduler_h__

View File

@ -144,6 +144,7 @@ UNIFIED_SOURCES += [
'MediaDecoder.cpp',
'MediaDecoderReader.cpp',
'MediaDecoderStateMachine.cpp',
'MediaDecoderStateMachineScheduler.cpp',
'MediaRecorder.cpp',
'MediaResource.cpp',
'MediaShutdownManager.cpp',