Bug 1135424 - Switch the MDSM to a task queue. r=mattwoodrow

This commit is contained in:
Bobby Holley
2015-03-10 09:59:30 -07:00
parent 11c2d00c68
commit 70a43b602e
11 changed files with 201 additions and 394 deletions

View File

@@ -191,12 +191,12 @@ void MediaDecoder::UpdateDormantState(bool aDormantTimeout, bool aActivity)
if (mIsDormant) { if (mIsDormant) {
DECODER_LOG("UpdateDormantState() entering DORMANT state"); DECODER_LOG("UpdateDormantState() entering DORMANT state");
// enter dormant state // enter dormant state
nsCOMPtr<nsIRunnable> event = RefPtr<nsRunnable> event =
NS_NewRunnableMethodWithArg<bool>( NS_NewRunnableMethodWithArg<bool>(
mDecoderStateMachine, mDecoderStateMachine,
&MediaDecoderStateMachine::SetDormant, &MediaDecoderStateMachine::SetDormant,
true); true);
mDecoderStateMachine->GetStateMachineThread()->Dispatch(event, NS_DISPATCH_NORMAL); mDecoderStateMachine->TaskQueue()->Dispatch(event);
if (IsEnded()) { if (IsEnded()) {
mWasEndedWhenEnteredDormant = true; mWasEndedWhenEnteredDormant = true;
@@ -207,12 +207,12 @@ void MediaDecoder::UpdateDormantState(bool aDormantTimeout, bool aActivity)
DECODER_LOG("UpdateDormantState() leaving DORMANT state"); DECODER_LOG("UpdateDormantState() leaving DORMANT state");
// exit dormant state // exit dormant state
// trigger to state machine. // trigger to state machine.
nsCOMPtr<nsIRunnable> event = RefPtr<nsRunnable> event =
NS_NewRunnableMethodWithArg<bool>( NS_NewRunnableMethodWithArg<bool>(
mDecoderStateMachine, mDecoderStateMachine,
&MediaDecoderStateMachine::SetDormant, &MediaDecoderStateMachine::SetDormant,
false); false);
mDecoderStateMachine->GetStateMachineThread()->Dispatch(event, NS_DISPATCH_NORMAL); mDecoderStateMachine->TaskQueue()->Dispatch(event);
} }
} }
@@ -750,7 +750,8 @@ nsresult MediaDecoder::ScheduleStateMachineThread()
if (mShuttingDown) if (mShuttingDown)
return NS_OK; return NS_OK;
ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
return mDecoderStateMachine->ScheduleStateMachine(); mDecoderStateMachine->ScheduleStateMachine();
return NS_OK;
} }
nsresult MediaDecoder::Play() nsresult MediaDecoder::Play()
@@ -763,8 +764,7 @@ nsresult MediaDecoder::Play()
if (mPausedForPlaybackRateNull) { if (mPausedForPlaybackRateNull) {
return NS_OK; return NS_OK;
} }
nsresult res = ScheduleStateMachineThread(); ScheduleStateMachineThread();
NS_ENSURE_SUCCESS(res,res);
if (IsEnded()) { if (IsEnded()) {
return Seek(0, SeekTarget::PrevSyncPoint); return Seek(0, SeekTarget::PrevSyncPoint);
} else if (mPlayState == PLAY_STATE_LOADING || mPlayState == PLAY_STATE_SEEKING) { } else if (mPlayState == PLAY_STATE_LOADING || mPlayState == PLAY_STATE_SEEKING) {
@@ -1317,7 +1317,7 @@ void MediaDecoder::ApplyStateToStateMachine(PlayState aState)
mDecoderStateMachine->Play(); mDecoderStateMachine->Play();
break; break;
case PLAY_STATE_SEEKING: case PLAY_STATE_SEEKING:
mSeekRequest.Begin(ProxyMediaCall(mDecoderStateMachine->GetStateMachineThread(), mSeekRequest.Begin(ProxyMediaCall(mDecoderStateMachine->TaskQueue(),
mDecoderStateMachine.get(), __func__, mDecoderStateMachine.get(), __func__,
&MediaDecoderStateMachine::Seek, mRequestedSeekTarget) &MediaDecoderStateMachine::Seek, mRequestedSeekTarget)
->RefableThen(NS_GetCurrentThread(), __func__, this, ->RefableThen(NS_GetCurrentThread(), __func__, this,

View File

@@ -13,7 +13,7 @@
#include <stdint.h> #include <stdint.h>
#include "MediaDecoderStateMachine.h" #include "MediaDecoderStateMachine.h"
#include "MediaDecoderStateMachineScheduler.h" #include "MediaTimer.h"
#include "AudioSink.h" #include "AudioSink.h"
#include "nsTArray.h" #include "nsTArray.h"
#include "MediaDecoder.h" #include "MediaDecoder.h"
@@ -201,9 +201,9 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
MediaDecoderReader* aReader, MediaDecoderReader* aReader,
bool aRealTime) : bool aRealTime) :
mDecoder(aDecoder), mDecoder(aDecoder),
mScheduler(new MediaDecoderStateMachineScheduler( mRealTime(aRealTime),
aDecoder->GetReentrantMonitor(), mDispatchedStateMachine(false),
&MediaDecoderStateMachine::TimeoutExpired, this, aRealTime)), mDelayedScheduler(this),
mState(DECODER_STATE_DECODING_NONE), mState(DECODER_STATE_DECODING_NONE),
mPlayDuration(0), mPlayDuration(0),
mStartTime(-1), mStartTime(-1),
@@ -248,6 +248,11 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
MOZ_COUNT_CTOR(MediaDecoderStateMachine); MOZ_COUNT_CTOR(MediaDecoderStateMachine);
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
// Set up our task queue.
RefPtr<SharedThreadPool> threadPool(
SharedThreadPool::Get(NS_LITERAL_CSTRING("Media State Machine"), 1));
mTaskQueue = new MediaTaskQueue(threadPool.forget());
static bool sPrefCacheInit = false; static bool sPrefCacheInit = false;
if (!sPrefCacheInit) { if (!sPrefCacheInit) {
sPrefCacheInit = true; sPrefCacheInit = true;
@@ -387,7 +392,7 @@ void MediaDecoderStateMachine::SendStreamData()
{ {
MOZ_ASSERT(OnStateMachineThread(), "Should be on state machine thread"); MOZ_ASSERT(OnStateMachineThread(), "Should be on state machine thread");
AssertCurrentThreadInMonitor(); AssertCurrentThreadInMonitor();
MOZ_ASSERT(!mAudioSink, "Should've been stopped in CallRunStateMachine()"); MOZ_ASSERT(!mAudioSink, "Should've been stopped in RunStateMachine()");
DecodedStreamData* stream = mDecoder->GetDecodedStream(); DecodedStreamData* stream = mDecoder->GetDecodedStream();
@@ -405,7 +410,7 @@ void MediaDecoderStateMachine::SendStreamData()
mediaStream->AddAudioTrack(audioTrackId, mInfo.mAudio.mRate, 0, audio, mediaStream->AddAudioTrack(audioTrackId, mInfo.mAudio.mRate, 0, audio,
SourceMediaStream::ADDTRACK_QUEUED); SourceMediaStream::ADDTRACK_QUEUED);
stream->mStream->DispatchWhenNotEnoughBuffered(audioTrackId, stream->mStream->DispatchWhenNotEnoughBuffered(audioTrackId,
GetStateMachineThread(), GetWakeDecoderRunnable()); TaskQueue(), GetWakeDecoderRunnable());
stream->mNextAudioTime = mStartTime + stream->mInitialTime; stream->mNextAudioTime = mStartTime + stream->mInitialTime;
} }
if (mInfo.HasVideo()) { if (mInfo.HasVideo()) {
@@ -414,7 +419,7 @@ void MediaDecoderStateMachine::SendStreamData()
mediaStream->AddTrack(videoTrackId, 0, video, mediaStream->AddTrack(videoTrackId, 0, video,
SourceMediaStream::ADDTRACK_QUEUED); SourceMediaStream::ADDTRACK_QUEUED);
stream->mStream->DispatchWhenNotEnoughBuffered(videoTrackId, stream->mStream->DispatchWhenNotEnoughBuffered(videoTrackId,
GetStateMachineThread(), GetWakeDecoderRunnable()); TaskQueue(), GetWakeDecoderRunnable());
// TODO: We can't initialize |mNextVideoTime| until |mStartTime| // TODO: We can't initialize |mNextVideoTime| until |mStartTime|
// is set. This is a good indication that DecodedStreamData is in // is set. This is a good indication that DecodedStreamData is in
@@ -570,7 +575,7 @@ bool MediaDecoderStateMachine::HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs)
return false; return false;
} }
stream->mStream->DispatchWhenNotEnoughBuffered(audioTrackId, stream->mStream->DispatchWhenNotEnoughBuffered(audioTrackId,
GetStateMachineThread(), GetWakeDecoderRunnable()); TaskQueue(), GetWakeDecoderRunnable());
} }
return true; return true;
@@ -593,7 +598,7 @@ bool MediaDecoderStateMachine::HaveEnoughDecodedVideo()
return false; return false;
} }
stream->mStream->DispatchWhenNotEnoughBuffered(videoTrackId, stream->mStream->DispatchWhenNotEnoughBuffered(videoTrackId,
GetStateMachineThread(), GetWakeDecoderRunnable()); TaskQueue(), GetWakeDecoderRunnable());
} }
return true; return true;
@@ -855,7 +860,7 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
"Readers that send WAITING_FOR_DATA need to implement WaitForData"); "Readers that send WAITING_FOR_DATA need to implement WaitForData");
WaitRequestRef(aType).Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__, WaitRequestRef(aType).Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::WaitForData, aType) &MediaDecoderReader::WaitForData, aType)
->RefableThen(mScheduler.get(), __func__, this, ->RefableThen(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnWaitForDataResolved, &MediaDecoderStateMachine::OnWaitForDataResolved,
&MediaDecoderStateMachine::OnWaitForDataRejected)); &MediaDecoderStateMachine::OnWaitForDataRejected));
return; return;
@@ -1084,7 +1089,7 @@ MediaDecoderStateMachine::CheckIfSeekComplete()
mDecodeToSeekTarget = false; mDecodeToSeekTarget = false;
RefPtr<nsIRunnable> task( RefPtr<nsIRunnable> task(
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::SeekCompleted)); NS_NewRunnableMethod(this, &MediaDecoderStateMachine::SeekCompleted));
nsresult rv = GetStateMachineThread()->Dispatch(task, NS_DISPATCH_NORMAL); nsresult rv = TaskQueue()->Dispatch(task);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
DecodeError(); DecodeError();
} }
@@ -1146,10 +1151,7 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoderStateMachine* aCloneDonor)
cloneReader = aCloneDonor->mReader; cloneReader = aCloneDonor->mReader;
} }
nsresult rv = mScheduler->Init(); nsresult rv = mReader->Init(cloneReader);
NS_ENSURE_SUCCESS(rv, rv);
rv = mReader->Init(cloneReader);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
return NS_OK; return NS_OK;
@@ -1343,7 +1345,7 @@ int64_t MediaDecoderStateMachine::GetCurrentTimeUs() const
} }
bool MediaDecoderStateMachine::IsRealTime() const { bool MediaDecoderStateMachine::IsRealTime() const {
return mScheduler->IsRealTime(); return mRealTime;
} }
int64_t MediaDecoderStateMachine::GetDuration() int64_t MediaDecoderStateMachine::GetDuration()
@@ -1523,9 +1525,8 @@ void MediaDecoderStateMachine::Shutdown()
// Change state before issuing shutdown request to threads so those // Change state before issuing shutdown request to threads so those
// threads can start exiting cleanly during the Shutdown call. // threads can start exiting cleanly during the Shutdown call.
DECODER_LOG("Changed state to SHUTDOWN"); ScheduleStateMachine();
SetState(DECODER_STATE_SHUTDOWN); SetState(DECODER_STATE_SHUTDOWN);
mScheduler->ScheduleAndShutdown();
if (mAudioSink) { if (mAudioSink) {
mAudioSink->PrepareToShutdown(); mAudioSink->PrepareToShutdown();
} }
@@ -1784,7 +1785,7 @@ MediaDecoderStateMachine::EnqueueDecodeFirstFrameTask()
RefPtr<nsIRunnable> task( RefPtr<nsIRunnable> task(
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::CallDecodeFirstFrame)); NS_NewRunnableMethod(this, &MediaDecoderStateMachine::CallDecodeFirstFrame));
nsresult rv = GetStateMachineThread()->Dispatch(task, NS_DISPATCH_NORMAL); nsresult rv = TaskQueue()->Dispatch(task);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
return NS_OK; return NS_OK;
} }
@@ -1931,7 +1932,7 @@ MediaDecoderStateMachine::InitiateSeek()
mSeekRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__, mSeekRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::Seek, mCurrentSeek.mTarget.mTime, &MediaDecoderReader::Seek, mCurrentSeek.mTarget.mTime,
GetEndTime()) GetEndTime())
->RefableThen(mScheduler.get(), __func__, this, ->RefableThen(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnSeekCompleted, &MediaDecoderStateMachine::OnSeekCompleted,
&MediaDecoderStateMachine::OnSeekFailed)); &MediaDecoderStateMachine::OnSeekFailed));
} }
@@ -1979,7 +1980,7 @@ MediaDecoderStateMachine::EnsureAudioDecodeTaskQueued()
mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
__func__, &MediaDecoderReader::RequestAudioData) __func__, &MediaDecoderReader::RequestAudioData)
->RefableThen(mScheduler.get(), __func__, this, ->RefableThen(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnAudioDecoded, &MediaDecoderStateMachine::OnAudioDecoded,
&MediaDecoderStateMachine::OnAudioNotDecoded)); &MediaDecoderStateMachine::OnAudioNotDecoded));
@@ -2039,7 +2040,7 @@ MediaDecoderStateMachine::EnsureVideoDecodeTaskQueued()
mVideoDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__, mVideoDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::RequestVideoData, &MediaDecoderReader::RequestVideoData,
skipToNextKeyFrame, currentTime) skipToNextKeyFrame, currentTime)
->RefableThen(mScheduler.get(), __func__, this, ->RefableThen(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnVideoDecoded, &MediaDecoderStateMachine::OnVideoDecoded,
&MediaDecoderStateMachine::OnVideoNotDecoded)); &MediaDecoderStateMachine::OnVideoNotDecoded));
return NS_OK; return NS_OK;
@@ -2177,9 +2178,9 @@ MediaDecoderStateMachine::DecodeError()
// Change state to shutdown before sending error report to MediaDecoder // Change state to shutdown before sending error report to MediaDecoder
// and the HTMLMediaElement, so that our pipeline can start exiting // and the HTMLMediaElement, so that our pipeline can start exiting
// cleanly during the sync dispatch below. // cleanly during the sync dispatch below.
DECODER_WARN("Decode error, changed state to SHUTDOWN due to error"); ScheduleStateMachine();
SetState(DECODER_STATE_SHUTDOWN); SetState(DECODER_STATE_SHUTDOWN);
mScheduler->ScheduleAndShutdown(); DECODER_WARN("Decode error, changed state to SHUTDOWN due to error");
mDecoder->GetReentrantMonitor().NotifyAll(); mDecoder->GetReentrantMonitor().NotifyAll();
// Dispatch the event to call DecodeError synchronously. This ensures // Dispatch the event to call DecodeError synchronously. This ensures
@@ -2332,12 +2333,12 @@ MediaDecoderStateMachine::DecodeFirstFrame()
if (HasAudio()) { if (HasAudio()) {
RefPtr<nsIRunnable> decodeTask( RefPtr<nsIRunnable> decodeTask(
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DispatchAudioDecodeTaskIfNeeded)); NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DispatchAudioDecodeTaskIfNeeded));
AudioQueue().AddPopListener(decodeTask, GetStateMachineThread()); AudioQueue().AddPopListener(decodeTask, TaskQueue());
} }
if (HasVideo()) { if (HasVideo()) {
RefPtr<nsIRunnable> decodeTask( RefPtr<nsIRunnable> decodeTask(
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DispatchVideoDecodeTaskIfNeeded)); NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DispatchVideoDecodeTaskIfNeeded));
VideoQueue().AddPopListener(decodeTask, GetStateMachineThread()); VideoQueue().AddPopListener(decodeTask, TaskQueue());
} }
if (IsRealTime()) { if (IsRealTime()) {
@@ -2355,7 +2356,7 @@ MediaDecoderStateMachine::DecodeFirstFrame()
if (HasAudio()) { if (HasAudio()) {
mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
__func__, &MediaDecoderReader::RequestAudioData) __func__, &MediaDecoderReader::RequestAudioData)
->RefableThen(mScheduler.get(), __func__, this, ->RefableThen(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnAudioDecoded, &MediaDecoderStateMachine::OnAudioDecoded,
&MediaDecoderStateMachine::OnAudioNotDecoded)); &MediaDecoderStateMachine::OnAudioNotDecoded));
} }
@@ -2363,7 +2364,7 @@ MediaDecoderStateMachine::DecodeFirstFrame()
mVideoDecodeStartTime = TimeStamp::Now(); mVideoDecodeStartTime = TimeStamp::Now();
mVideoDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), mVideoDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
__func__, &MediaDecoderReader::RequestVideoData, false, int64_t(0)) __func__, &MediaDecoderReader::RequestVideoData, false, int64_t(0))
->RefableThen(mScheduler.get(), __func__, this, ->RefableThen(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::OnVideoDecoded, &MediaDecoderStateMachine::OnVideoDecoded,
&MediaDecoderStateMachine::OnVideoNotDecoded)); &MediaDecoderStateMachine::OnVideoNotDecoded));
} }
@@ -2570,6 +2571,8 @@ public:
NS_ASSERTION(NS_IsMainThread(), "Must be on main thread."); NS_ASSERTION(NS_IsMainThread(), "Must be on main thread.");
MOZ_ASSERT(mStateMachine); MOZ_ASSERT(mStateMachine);
MOZ_ASSERT(mDecoder); MOZ_ASSERT(mDecoder);
mStateMachine->TaskQueue()->BeginShutdown();
mStateMachine->TaskQueue()->AwaitShutdownAndIdle();
mStateMachine->BreakCycles(); mStateMachine->BreakCycles();
mDecoder->BreakCycles(); mDecoder->BreakCycles();
mStateMachine = nullptr; mStateMachine = nullptr;
@@ -2604,7 +2607,7 @@ void
MediaDecoderStateMachine::ShutdownReader() MediaDecoderStateMachine::ShutdownReader()
{ {
MOZ_ASSERT(OnDecodeThread()); MOZ_ASSERT(OnDecodeThread());
mReader->Shutdown()->Then(mScheduler.get(), __func__, this, mReader->Shutdown()->Then(TaskQueue(), __func__, this,
&MediaDecoderStateMachine::FinishShutdown, &MediaDecoderStateMachine::FinishShutdown,
&MediaDecoderStateMachine::FinishShutdown); &MediaDecoderStateMachine::FinishShutdown);
} }
@@ -2640,15 +2643,24 @@ MediaDecoderStateMachine::FinishShutdown()
// finished and released its monitor/references. That event then will // finished and released its monitor/references. That event then will
// dispatch an event to the main thread to release the decoder and // dispatch an event to the main thread to release the decoder and
// state machine. // state machine.
GetStateMachineThread()->Dispatch( RefPtr<nsIRunnable> task = new nsDispatchDisposeEvent(mDecoder, this);
new nsDispatchDisposeEvent(mDecoder, this), NS_DISPATCH_NORMAL); TaskQueue()->Dispatch(task);
DECODER_LOG("Dispose Event Dispatched"); DECODER_LOG("Dispose Event Dispatched");
} }
nsresult MediaDecoderStateMachine::RunStateMachine() nsresult MediaDecoderStateMachine::RunStateMachine()
{ {
AssertCurrentThreadInMonitor(); MOZ_ASSERT(OnStateMachineThread());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mDelayedScheduler.Reset(); // Must happen on state machine thread.
mDispatchedStateMachine = false;
// If audio is being captured, stop the audio sink if it's running
if (mAudioCaptured) {
StopAudioThread();
}
MediaResource* resource = mDecoder->GetResource(); MediaResource* resource = mDecoder->GetResource();
NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER);
@@ -2738,7 +2750,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
DECODER_LOG("Buffering: wait %ds, timeout in %.3lfs %s", DECODER_LOG("Buffering: wait %ds, timeout in %.3lfs %s",
mBufferingWait, mBufferingWait - elapsed.ToSeconds(), mBufferingWait, mBufferingWait - elapsed.ToSeconds(),
(mQuickBuffering ? "(quick exit)" : "")); (mQuickBuffering ? "(quick exit)" : ""));
ScheduleStateMachine(USECS_PER_S); ScheduleStateMachineIn(USECS_PER_S);
return NS_OK; return NS_OK;
} }
} else if (OutOfDecodedAudio() || OutOfDecodedVideo()) { } else if (OutOfDecodedAudio() || OutOfDecodedVideo()) {
@@ -3062,7 +3074,7 @@ void MediaDecoderStateMachine::AdvanceFrame()
// Don't go straight back to the state machine loop since that might // Don't go straight back to the state machine loop since that might
// cause us to start decoding again and we could flip-flop between // cause us to start decoding again and we could flip-flop between
// decoding and quick-buffering. // decoding and quick-buffering.
ScheduleStateMachine(USECS_PER_S); ScheduleStateMachineIn(USECS_PER_S);
return; return;
} }
} }
@@ -3124,7 +3136,12 @@ void MediaDecoderStateMachine::AdvanceFrame()
// ready state. Post an update to do so. // ready state. Post an update to do so.
UpdateReadyState(); UpdateReadyState();
ScheduleStateMachine(remainingTime / mPlaybackRate); int64_t delay = remainingTime / mPlaybackRate;
if (delay > 0) {
ScheduleStateMachineIn(delay);
} else {
ScheduleStateMachine();
}
} }
nsresult nsresult
@@ -3370,33 +3387,59 @@ void MediaDecoderStateMachine::SetPlayStartTime(const TimeStamp& aTimeStamp)
} }
} }
nsresult MediaDecoderStateMachine::CallRunStateMachine()
{
AssertCurrentThreadInMonitor();
NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
// If audio is being captured, stop the audio sink if it's running
if (mAudioCaptured) {
StopAudioThread();
}
return RunStateMachine();
}
nsresult MediaDecoderStateMachine::TimeoutExpired(void* aClosure)
{
MediaDecoderStateMachine* p = static_cast<MediaDecoderStateMachine*>(aClosure);
return p->CallRunStateMachine();
}
void MediaDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder() { void MediaDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder() {
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
DispatchAudioDecodeTaskIfNeeded(); DispatchAudioDecodeTaskIfNeeded();
DispatchVideoDecodeTaskIfNeeded(); DispatchVideoDecodeTaskIfNeeded();
} }
nsresult MediaDecoderStateMachine::ScheduleStateMachine(int64_t aUsecs) { void
return mScheduler->Schedule(aUsecs); MediaDecoderStateMachine::ScheduleStateMachine() {
AssertCurrentThreadInMonitor();
if (mState == DECODER_STATE_SHUTDOWN) {
NS_WARNING("Refusing to schedule shutdown state machine");
return;
}
if (mDispatchedStateMachine) {
return;
}
mDispatchedStateMachine = true;
RefPtr<nsIRunnable> task =
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::RunStateMachine);
nsresult rv = TaskQueue()->Dispatch(task);
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
(void) rv;
}
void
MediaDecoderStateMachine::ScheduleStateMachineIn(int64_t aMicroseconds)
{
AssertCurrentThreadInMonitor();
MOZ_ASSERT(OnStateMachineThread()); // mDelayedScheduler.Ensure() may Disconnect()
// the promise, which must happen on the state
// machine thread.
MOZ_ASSERT(aMicroseconds > 0);
if (mState == DECODER_STATE_SHUTDOWN) {
NS_WARNING("Refusing to schedule shutdown state machine");
return;
}
if (mDispatchedStateMachine) {
return;
}
// Real-time weirdness.
if (IsRealTime()) {
aMicroseconds = std::min(aMicroseconds, int64_t(40000));
}
TimeStamp now = TimeStamp::Now();
TimeStamp target = now + TimeDuration::FromMicroseconds(aMicroseconds);
SAMPLE_LOG("Scheduling state machine for %lf ms from now", (target - now).ToMilliseconds());
mDelayedScheduler.Ensure(target);
} }
bool MediaDecoderStateMachine::OnDecodeThread() const bool MediaDecoderStateMachine::OnDecodeThread() const
@@ -3406,17 +3449,12 @@ bool MediaDecoderStateMachine::OnDecodeThread() const
bool MediaDecoderStateMachine::OnStateMachineThread() const bool MediaDecoderStateMachine::OnStateMachineThread() const
{ {
return mScheduler->OnStateMachineThread(); return TaskQueue()->IsCurrentThreadIn();
}
nsIEventTarget* MediaDecoderStateMachine::GetStateMachineThread() const
{
return mScheduler->GetStateMachineThread();
} }
bool MediaDecoderStateMachine::IsStateMachineScheduled() const bool MediaDecoderStateMachine::IsStateMachineScheduled() const
{ {
return mScheduler->IsScheduled(); return mDispatchedStateMachine || mDelayedScheduler.IsScheduled();
} }
void MediaDecoderStateMachine::SetPlaybackRate(double aPlaybackRate) void MediaDecoderStateMachine::SetPlaybackRate(double aPlaybackRate)

View File

@@ -89,8 +89,8 @@ hardware (via AudioStream).
#include "MediaDecoderReader.h" #include "MediaDecoderReader.h"
#include "MediaDecoderOwner.h" #include "MediaDecoderOwner.h"
#include "MediaMetadataManager.h" #include "MediaMetadataManager.h"
#include "MediaDecoderStateMachineScheduler.h"
#include "mozilla/RollingMean.h" #include "mozilla/RollingMean.h"
#include "MediaTimer.h"
class nsITimer; class nsITimer;
@@ -211,8 +211,8 @@ public:
void Play() void Play()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<nsRunnable> r = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::PlayInternal); RefPtr<nsRunnable> r = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::PlayInternal);
GetStateMachineThread()->Dispatch(r, NS_DISPATCH_NORMAL); TaskQueue()->Dispatch(r);
} }
private: private:
@@ -311,21 +311,30 @@ public:
void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset); void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
// Returns the shared state machine thread. // Returns the state machine task queue.
nsIEventTarget* GetStateMachineThread() const; MediaTaskQueue* TaskQueue() const { return mTaskQueue; }
// Calls ScheduleStateMachine() after taking the decoder lock. Also // Calls ScheduleStateMachine() after taking the decoder lock. Also
// notifies the decoder thread in case it's waiting on the decoder lock. // notifies the decoder thread in case it's waiting on the decoder lock.
void ScheduleStateMachineWithLockAndWakeDecoder(); void ScheduleStateMachineWithLockAndWakeDecoder();
// Schedules the shared state machine thread to run the state machine // Schedules the shared state machine thread to run the state machine.
// in aUsecs microseconds from now, if it's not already scheduled to run void ScheduleStateMachine();
// earlier, in which case the request is discarded.
nsresult ScheduleStateMachine(int64_t aUsecs = 0);
// Callback function registered with MediaDecoderStateMachineScheduler // Invokes ScheduleStateMachine to run in |aMicroseconds| microseconds,
// to run state machine cycles. // unless it's already scheduled to run earlier, in which case the
static nsresult TimeoutExpired(void* aClosure); // request is discarded.
void ScheduleStateMachineIn(int64_t aMicroseconds);
void OnDelayedSchedule()
{
MOZ_ASSERT(OnStateMachineThread());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mDelayedScheduler.CompleteRequest();
ScheduleStateMachine();
}
void NotReached() { MOZ_DIAGNOSTIC_ASSERT(false); }
// Set the media fragment end time. aEndTime is in microseconds. // Set the media fragment end time. aEndTime is in microseconds.
void SetFragmentEndTime(int64_t aEndTime); void SetFragmentEndTime(int64_t aEndTime);
@@ -689,9 +698,6 @@ protected:
void SendStreamAudio(AudioData* aAudio, DecodedStreamData* aStream, void SendStreamAudio(AudioData* aAudio, DecodedStreamData* aStream,
AudioSegment* aOutput); AudioSegment* aOutput);
// State machine thread run function. Defers to RunStateMachine().
nsresult CallRunStateMachine();
// Performs one "cycle" of the state machine. Polls the state, and may send // Performs one "cycle" of the state machine. Polls the state, and may send
// a video frame to be displayed, and generally manages the decode. Called // a video frame to be displayed, and generally manages the decode. Called
// periodically via timer to ensure the video stays in sync. // periodically via timer to ensure the video stays in sync.
@@ -745,9 +751,60 @@ protected:
// state machine, audio and main threads. // state machine, audio and main threads.
nsRefPtr<MediaDecoder> mDecoder; nsRefPtr<MediaDecoder> mDecoder;
// Used to schedule state machine cycles. This should never outlive // Task queue for running the state machine.
// the life cycle of the state machine. nsRefPtr<MediaTaskQueue> mTaskQueue;
const nsRefPtr<MediaDecoderStateMachineScheduler> mScheduler;
// True is we are decoding a realtime stream, like a camera stream.
bool mRealTime;
// True if we've dispatched a task to run the state machine but the task has
// yet to run.
bool mDispatchedStateMachine;
// Class for managing delayed dispatches of the state machine.
class DelayedScheduler {
public:
explicit DelayedScheduler(MediaDecoderStateMachine* aSelf)
: mSelf(aSelf), mMediaTimer(new MediaTimer()) {}
bool IsScheduled() const { return !mTarget.IsNull(); }
void Reset()
{
MOZ_ASSERT(mSelf->OnStateMachineThread(),
"Must be on state machine queue to disconnect");
if (IsScheduled()) {
mRequest.Disconnect();
mTarget = TimeStamp();
}
}
void Ensure(mozilla::TimeStamp& aTarget)
{
if (IsScheduled() && mTarget <= aTarget) {
return;
}
Reset();
mTarget = aTarget;
mRequest.Begin(mMediaTimer->WaitUntil(mTarget, __func__)->RefableThen(
mSelf->TaskQueue(), __func__, mSelf,
&MediaDecoderStateMachine::OnDelayedSchedule,
&MediaDecoderStateMachine::NotReached));
}
void CompleteRequest()
{
mRequest.Complete();
mTarget = TimeStamp();
}
private:
MediaDecoderStateMachine* mSelf;
nsRefPtr<MediaTimer> mMediaTimer;
MediaPromiseConsumerHolder<mozilla::MediaTimerPromise> mRequest;
TimeStamp mTarget;
} mDelayedScheduler;
// Time at which the last video sample was requested. If it takes too long // 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. // before the sample arrives, we will increase the amount of audio we buffer.
@@ -955,7 +1012,7 @@ protected:
// samples we must consume before are considered to be finished prerolling. // samples we must consume before are considered to be finished prerolling.
uint32_t AudioPrerollUsecs() const uint32_t AudioPrerollUsecs() const
{ {
if (mScheduler->IsRealTime()) { if (IsRealTime()) {
return 0; return 0;
} }
@@ -966,7 +1023,7 @@ protected:
uint32_t VideoPrerollFrames() const uint32_t VideoPrerollFrames() const
{ {
return mScheduler->IsRealTime() ? 0 : GetAmpleVideoFrames() / 2; return IsRealTime() ? 0 : GetAmpleVideoFrames() / 2;
} }
bool DonePrerollingAudio() bool DonePrerollingAudio()

View File

@@ -1,194 +0,0 @@
/* 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_ISUPPORTS_INHERITED
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_INHERITED(TimerEvent, nsRunnable, nsITimerCallback);
} // 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 (NS_WARN_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

@@ -1,78 +0,0 @@
/* -*- 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:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderStateMachineScheduler)
MediaDecoderStateMachineScheduler(ReentrantMonitor& aMonitor,
nsresult (*aTimeoutCallback)(void*),
void* aClosure, bool aRealTime);
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:
~MediaDecoderStateMachineScheduler();
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

@@ -6,7 +6,6 @@
#include "MediaPromise.h" #include "MediaPromise.h"
#include "MediaDecoderStateMachineScheduler.h"
#include "MediaTaskQueue.h" #include "MediaTaskQueue.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
@@ -25,12 +24,6 @@ DispatchMediaPromiseRunnable(nsIEventTarget* aEventTarget, nsIRunnable* aRunnabl
return aEventTarget->Dispatch(aRunnable, NS_DISPATCH_NORMAL); return aEventTarget->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
} }
nsresult
DispatchMediaPromiseRunnable(MediaDecoderStateMachineScheduler* aScheduler, nsIRunnable* aRunnable)
{
return aScheduler->GetStateMachineThread()->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
}
void void
AssertOnThread(MediaTaskQueue* aQueue) AssertOnThread(MediaTaskQueue* aQueue)
{ {
@@ -44,11 +37,5 @@ void AssertOnThread(nsIEventTarget* aTarget)
MOZ_ASSERT(NS_GetCurrentThread() == targetThread); MOZ_ASSERT(NS_GetCurrentThread() == targetThread);
} }
void
AssertOnThread(MediaDecoderStateMachineScheduler* aScheduler)
{
MOZ_ASSERT(aScheduler->OnStateMachineThread());
}
} }
} // namespace mozilla } // namespace mozilla

View File

@@ -33,17 +33,14 @@ extern PRLogModuleInfo* gMediaPromiseLog;
PR_LOG(gMediaPromiseLog, PR_LOG_DEBUG, (x, ##__VA_ARGS__)) PR_LOG(gMediaPromiseLog, PR_LOG_DEBUG, (x, ##__VA_ARGS__))
class MediaTaskQueue; class MediaTaskQueue;
class MediaDecoderStateMachineScheduler;
namespace detail { namespace detail {
nsresult DispatchMediaPromiseRunnable(MediaTaskQueue* aQueue, nsIRunnable* aRunnable); nsresult DispatchMediaPromiseRunnable(MediaTaskQueue* aQueue, nsIRunnable* aRunnable);
nsresult DispatchMediaPromiseRunnable(nsIEventTarget* aTarget, nsIRunnable* aRunnable); nsresult DispatchMediaPromiseRunnable(nsIEventTarget* aTarget, nsIRunnable* aRunnable);
nsresult DispatchMediaPromiseRunnable(MediaDecoderStateMachineScheduler* aScheduler, nsIRunnable* aRunnable);
#ifdef DEBUG #ifdef DEBUG
void AssertOnThread(MediaTaskQueue* aQueue); void AssertOnThread(MediaTaskQueue* aQueue);
void AssertOnThread(nsIEventTarget* aTarget); void AssertOnThread(nsIEventTarget* aTarget);
void AssertOnThread(MediaDecoderStateMachineScheduler* aScheduler);
#endif #endif
} // namespace detail } // namespace detail

View File

@@ -157,7 +157,7 @@ template <class T> class MediaQueue : private nsDeque {
mPopListeners.Clear(); mPopListeners.Clear();
} }
void AddPopListener(nsIRunnable* aRunnable, nsIEventTarget* aTarget) { void AddPopListener(nsIRunnable* aRunnable, MediaTaskQueue* aTarget) {
ReentrantMonitorAutoEnter mon(mReentrantMonitor); ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mPopListeners.AppendElement(Listener(aRunnable, aTarget)); mPopListeners.AppendElement(Listener(aRunnable, aTarget));
} }
@@ -166,7 +166,7 @@ private:
mutable ReentrantMonitor mReentrantMonitor; mutable ReentrantMonitor mReentrantMonitor;
struct Listener { struct Listener {
Listener(nsIRunnable* aRunnable, nsIEventTarget* aTarget) Listener(nsIRunnable* aRunnable, MediaTaskQueue* aTarget)
: mRunnable(aRunnable) : mRunnable(aRunnable)
, mTarget(aTarget) , mTarget(aTarget)
{ {
@@ -177,7 +177,7 @@ private:
{ {
} }
RefPtr<nsIRunnable> mRunnable; RefPtr<nsIRunnable> mRunnable;
RefPtr<nsIEventTarget> mTarget; RefPtr<MediaTaskQueue> mTarget;
}; };
nsTArray<Listener> mPopListeners; nsTArray<Listener> mPopListeners;
@@ -185,7 +185,7 @@ private:
void NotifyPopListeners() { void NotifyPopListeners() {
for (uint32_t i = 0; i < mPopListeners.Length(); i++) { for (uint32_t i = 0; i < mPopListeners.Length(); i++) {
Listener& l = mPopListeners[i]; Listener& l = mPopListeners[i];
l.mTarget->Dispatch(l.mRunnable, NS_DISPATCH_NORMAL); l.mTarget->Dispatch(l.mRunnable);
} }
} }

View File

@@ -278,7 +278,7 @@ MediaStreamGraphImpl::UpdateBufferSufficiencyState(SourceMediaStream* aStream)
} }
for (uint32_t i = 0; i < runnables.Length(); ++i) { for (uint32_t i = 0; i < runnables.Length(); ++i) {
runnables[i].mTarget->Dispatch(runnables[i].mRunnable, 0); runnables[i].mTarget->Dispatch(runnables[i].mRunnable);
} }
} }
@@ -2493,21 +2493,21 @@ SourceMediaStream::GetEndOfAppendedData(TrackID aID)
void void
SourceMediaStream::DispatchWhenNotEnoughBuffered(TrackID aID, SourceMediaStream::DispatchWhenNotEnoughBuffered(TrackID aID,
nsIEventTarget* aSignalThread, nsIRunnable* aSignalRunnable) MediaTaskQueue* aSignalQueue, nsIRunnable* aSignalRunnable)
{ {
MutexAutoLock lock(mMutex); MutexAutoLock lock(mMutex);
TrackData* data = FindDataForTrack(aID); TrackData* data = FindDataForTrack(aID);
if (!data) { if (!data) {
aSignalThread->Dispatch(aSignalRunnable, 0); aSignalQueue->Dispatch(aSignalRunnable);
return; return;
} }
if (data->mHaveEnough) { if (data->mHaveEnough) {
if (data->mDispatchWhenNotEnough.IsEmpty()) { if (data->mDispatchWhenNotEnough.IsEmpty()) {
data->mDispatchWhenNotEnough.AppendElement()->Init(aSignalThread, aSignalRunnable); data->mDispatchWhenNotEnough.AppendElement()->Init(aSignalQueue, aSignalRunnable);
} }
} else { } else {
aSignalThread->Dispatch(aSignalRunnable, 0); aSignalQueue->Dispatch(aSignalRunnable);
} }
} }

View File

@@ -16,6 +16,7 @@
#include "VideoFrameContainer.h" #include "VideoFrameContainer.h"
#include "VideoSegment.h" #include "VideoSegment.h"
#include "MainThreadUtils.h" #include "MainThreadUtils.h"
#include "MediaTaskQueue.h"
#include "nsAutoRef.h" #include "nsAutoRef.h"
#include "GraphDriver.h" #include "GraphDriver.h"
#include <speex/speex_resampler.h> #include <speex/speex_resampler.h>
@@ -783,7 +784,7 @@ public:
* does not exist. No op if a runnable is already present for this track. * does not exist. No op if a runnable is already present for this track.
*/ */
void DispatchWhenNotEnoughBuffered(TrackID aID, void DispatchWhenNotEnoughBuffered(TrackID aID,
nsIEventTarget* aSignalThread, nsIRunnable* aSignalRunnable); MediaTaskQueue* aSignalQueue, nsIRunnable* aSignalRunnable);
/** /**
* Indicate that a track has ended. Do not do any more API calls * Indicate that a track has ended. Do not do any more API calls
* affecting this track. * affecting this track.
@@ -847,14 +848,14 @@ public:
protected: protected:
struct ThreadAndRunnable { struct ThreadAndRunnable {
void Init(nsIEventTarget* aTarget, nsIRunnable* aRunnable) void Init(MediaTaskQueue* aTarget, nsIRunnable* aRunnable)
{ {
mTarget = aTarget; mTarget = aTarget;
mRunnable = aRunnable; mRunnable = aRunnable;
} }
nsCOMPtr<nsIEventTarget> mTarget; nsRefPtr<MediaTaskQueue> mTarget;
nsCOMPtr<nsIRunnable> mRunnable; RefPtr<nsIRunnable> mRunnable;
}; };
enum TrackCommands { enum TrackCommands {
TRACK_CREATE = MediaStreamListener::TRACK_EVENT_CREATED, TRACK_CREATE = MediaStreamListener::TRACK_EVENT_CREATED,

View File

@@ -102,7 +102,6 @@ EXPORTS += [
'MediaDecoderOwner.h', 'MediaDecoderOwner.h',
'MediaDecoderReader.h', 'MediaDecoderReader.h',
'MediaDecoderStateMachine.h', 'MediaDecoderStateMachine.h',
'MediaDecoderStateMachineScheduler.h',
'MediaInfo.h', 'MediaInfo.h',
'MediaMetadataManager.h', 'MediaMetadataManager.h',
'MediaPromise.h', 'MediaPromise.h',
@@ -112,6 +111,7 @@ EXPORTS += [
'MediaSegment.h', 'MediaSegment.h',
'MediaStreamGraph.h', 'MediaStreamGraph.h',
'MediaTaskQueue.h', 'MediaTaskQueue.h',
'MediaTimer.h',
'MediaTrack.h', 'MediaTrack.h',
'MediaTrackList.h', 'MediaTrackList.h',
'MP3FrameParser.h', 'MP3FrameParser.h',
@@ -181,7 +181,6 @@ UNIFIED_SOURCES += [
'MediaDecoder.cpp', 'MediaDecoder.cpp',
'MediaDecoderReader.cpp', 'MediaDecoderReader.cpp',
'MediaDecoderStateMachine.cpp', 'MediaDecoderStateMachine.cpp',
'MediaDecoderStateMachineScheduler.cpp',
'MediaDevices.cpp', 'MediaDevices.cpp',
'MediaManager.cpp', 'MediaManager.cpp',
'MediaPromise.cpp', 'MediaPromise.cpp',