--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -223,18 +223,16 @@ MediaDecoderStateMachine::MediaDecoderSt
mPlaybackRate(1.0),
mPreservesPitch(true),
mAmpleVideoFrames(MIN_VIDEO_QUEUE_SIZE),
mLowAudioThresholdUsecs(detail::LOW_AUDIO_USECS),
mAmpleAudioThresholdUsecs(detail::AMPLE_AUDIO_USECS),
mQuickBufferingLowDataThresholdUsecs(detail::QUICK_BUFFERING_LOW_DATA_USECS),
mIsAudioPrerolling(false),
mIsVideoPrerolling(false),
- mAudioRequestStatus(RequestStatus::Idle),
- mVideoRequestStatus(RequestStatus::Idle),
mAudioCaptured(false),
mPositionChangeQueued(false),
mAudioCompleted(false),
mGotDurationFromMetaData(false),
mDispatchedEventToDecode(false),
mStopAudioThread(true),
mQuickBuffering(false),
mMinimizePreroll(false),
@@ -702,17 +700,17 @@ MediaDecoderStateMachine::IsVideoSeekCom
}
void
MediaDecoderStateMachine::OnAudioDecoded(AudioData* aAudioSample)
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
nsRefPtr<AudioData> audio(aAudioSample);
MOZ_ASSERT(audio);
- mAudioRequestStatus = RequestStatus::Idle;
+ mAudioDataRequest.Complete();
mDecodedAudioEndTime = audio->GetEndTime();
SAMPLE_LOG("OnAudioDecoded [%lld,%lld] disc=%d",
(audio ? audio->mTime : -1),
(audio ? audio->GetEndTime() : -1),
(audio ? audio->mDiscontinuity : 0));
switch (mState) {
@@ -819,39 +817,43 @@ MediaDecoderStateMachine::Push(VideoData
mDecoder->GetReentrantMonitor().NotifyAll();
}
}
void
MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
MediaDecoderReader::NotDecodedReason aReason)
{
+ MOZ_ASSERT(OnDecodeThread());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
SAMPLE_LOG("OnNotDecoded (aType=%u, aReason=%u)", aType, aReason);
bool isAudio = aType == MediaData::AUDIO_DATA;
MOZ_ASSERT_IF(!isAudio, aType == MediaData::VIDEO_DATA);
- // This callback means that the pending request is dead.
- RequestStatusRef(aType) = RequestStatus::Idle;
+ if (isAudio) {
+ mAudioDataRequest.Complete();
+ } else {
+ mVideoDataRequest.Complete();
+ }
// If this is a decode error, delegate to the generic error path.
if (aReason == MediaDecoderReader::DECODE_ERROR) {
DecodeError();
return;
}
// If the decoder is waiting for data, we tell it to call us back when the
// data arrives.
if (aReason == MediaDecoderReader::WAITING_FOR_DATA) {
MOZ_ASSERT(mReader->IsWaitForDataSupported(),
"Readers that send WAITING_FOR_DATA need to implement WaitForData");
- RequestStatusRef(aType) = RequestStatus::Waiting;
- mReader->WaitForData(aType)->Then(DecodeTaskQueue(), __func__, this,
- &MediaDecoderStateMachine::OnWaitForDataResolved,
- &MediaDecoderStateMachine::OnWaitForDataRejected);
+ WaitRequestRef(aType).Begin(mReader->WaitForData(aType)
+ ->RefableThen(DecodeTaskQueue(), __func__, this,
+ &MediaDecoderStateMachine::OnWaitForDataResolved,
+ &MediaDecoderStateMachine::OnWaitForDataRejected));
return;
}
if (aReason == MediaDecoderReader::CANCELED) {
DispatchDecodeTasksIfNeeded();
return;
}
@@ -935,17 +937,17 @@ MediaDecoderStateMachine::MaybeFinishDec
}
void
MediaDecoderStateMachine::OnVideoDecoded(VideoData* aVideoSample)
{
MOZ_ASSERT(OnDecodeThread());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
nsRefPtr<VideoData> video(aVideoSample);
- mVideoRequestStatus = RequestStatus::Idle;
+ mVideoDataRequest.Complete();
mDecodedVideoEndTime = video ? video->GetEndTime() : mDecodedVideoEndTime;
SAMPLE_LOG("OnVideoDecoded [%lld,%lld] disc=%d",
(video ? video->mTime : -1),
(video ? video->GetEndTime() : -1),
(video ? video->mDiscontinuity : 0));
switch (mState) {
@@ -1858,19 +1860,19 @@ MediaDecoderStateMachine::DispatchDecode
(!needToDecodeAudio && !needToDecodeVideo));
bool needIdle = !mDecoder->IsLogicallyPlaying() &&
mState != DECODER_STATE_SEEKING &&
!needToDecodeAudio &&
!needToDecodeVideo &&
!IsPlaying();
- SAMPLE_LOG("DispatchDecodeTasksIfNeeded needAudio=%d audioStatus=%d needVideo=%d videoStatus=%d needIdle=%d",
- needToDecodeAudio, mAudioRequestStatus,
- needToDecodeVideo, mVideoRequestStatus,
+ SAMPLE_LOG("DispatchDecodeTasksIfNeeded needAudio=%d audioStatus=%s needVideo=%d videoStatus=%s needIdle=%d",
+ needToDecodeAudio, AudioRequestStatus(),
+ needToDecodeVideo, VideoRequestStatus(),
needIdle);
if (needToDecodeAudio) {
EnsureAudioDecodeTaskQueued();
}
if (needToDecodeVideo) {
EnsureVideoDecodeTaskQueued();
}
@@ -1919,38 +1921,39 @@ MediaDecoderStateMachine::DispatchAudioD
nsresult
MediaDecoderStateMachine::EnsureAudioDecodeTaskQueued()
{
AssertCurrentThreadInMonitor();
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
"Should be on state machine or decode thread.");
- SAMPLE_LOG("EnsureAudioDecodeTaskQueued isDecoding=%d status=%d",
- IsAudioDecoding(), mAudioRequestStatus);
+ SAMPLE_LOG("EnsureAudioDecodeTaskQueued isDecoding=%d status=%s",
+ IsAudioDecoding(), AudioRequestStatus());
if (mState != DECODER_STATE_DECODING &&
mState != DECODER_STATE_DECODING_FIRSTFRAME &&
mState != DECODER_STATE_BUFFERING &&
mState != DECODER_STATE_SEEKING) {
return NS_OK;
}
- if (!IsAudioDecoding() || mAudioRequestStatus != RequestStatus::Idle || mWaitingForDecoderSeek) {
+ if (!IsAudioDecoding() || mAudioDataRequest.Exists() ||
+ mAudioWaitRequest.Exists() || mWaitingForDecoderSeek) {
return NS_OK;
}
SAMPLE_LOG("Queueing audio task - queued=%i, decoder-queued=%o",
AudioQueue().GetSize(), mReader->SizeOfAudioQueueInFrames());
- mAudioRequestStatus = RequestStatus::Pending;
- ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__, &MediaDecoderReader::RequestAudioData)
- ->Then(DecodeTaskQueue(), __func__, this,
- &MediaDecoderStateMachine::OnAudioDecoded,
- &MediaDecoderStateMachine::OnAudioNotDecoded);
+ mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
+ __func__, &MediaDecoderReader::RequestAudioData)
+ ->RefableThen(DecodeTaskQueue(), __func__, this,
+ &MediaDecoderStateMachine::OnAudioDecoded,
+ &MediaDecoderStateMachine::OnAudioNotDecoded));
return NS_OK;
}
nsresult
MediaDecoderStateMachine::DispatchVideoDecodeTaskIfNeeded()
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
@@ -1964,52 +1967,52 @@ MediaDecoderStateMachine::DispatchVideoD
return NS_OK;
}
nsresult
MediaDecoderStateMachine::EnsureVideoDecodeTaskQueued()
{
AssertCurrentThreadInMonitor();
- SAMPLE_LOG("EnsureVideoDecodeTaskQueued isDecoding=%d status=%d",
- IsVideoDecoding(), mVideoRequestStatus);
+ SAMPLE_LOG("EnsureVideoDecodeTaskQueued isDecoding=%d status=%s",
+ IsVideoDecoding(), VideoRequestStatus());
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
"Should be on state machine or decode thread.");
if (mState != DECODER_STATE_DECODING &&
mState != DECODER_STATE_DECODING_FIRSTFRAME &&
mState != DECODER_STATE_BUFFERING &&
mState != DECODER_STATE_SEEKING) {
return NS_OK;
}
- if (!IsVideoDecoding() || mVideoRequestStatus != RequestStatus::Idle || mWaitingForDecoderSeek) {
+ if (!IsVideoDecoding() || mVideoDataRequest.Exists() ||
+ mVideoWaitRequest.Exists() || mWaitingForDecoderSeek) {
return NS_OK;
}
bool skipToNextKeyFrame = NeedToSkipToNextKeyframe();
int64_t currentTime = mState == DECODER_STATE_SEEKING ? 0 : GetMediaTime();
// Time the video decode, so that if it's slow, we can increase our low
// audio threshold to reduce the chance of an audio underrun while we're
// waiting for a video decode to complete.
mVideoDecodeStartTime = TimeStamp::Now();
SAMPLE_LOG("Queueing video task - queued=%i, decoder-queued=%o, skip=%i, time=%lld",
VideoQueue().GetSize(), mReader->SizeOfVideoQueueInFrames(), skipToNextKeyFrame,
currentTime);
- mVideoRequestStatus = RequestStatus::Pending;
- ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
- &MediaDecoderReader::RequestVideoData, skipToNextKeyFrame, currentTime)
- ->Then(DecodeTaskQueue(), __func__, this,
- &MediaDecoderStateMachine::OnVideoDecoded,
- &MediaDecoderStateMachine::OnVideoNotDecoded);
-
+ mVideoDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
+ &MediaDecoderReader::RequestVideoData,
+ skipToNextKeyFrame, currentTime)
+ ->RefableThen(DecodeTaskQueue(), __func__, this,
+ &MediaDecoderStateMachine::OnVideoDecoded,
+ &MediaDecoderStateMachine::OnVideoNotDecoded));
return NS_OK;
}
nsresult
MediaDecoderStateMachine::StartAudioThread()
{
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
"Should be on state machine or decode thread.");
@@ -2289,31 +2292,32 @@ MediaDecoderStateMachine::DecodeFirstFra
} else if (mSentFirstFrameLoadedEvent) {
// We're resuming from dormant state, so we don't need to request
// the first samples in order to determine the media start time,
// we have the start time from last time we loaded.
SetStartTime(mStartTime);
nsresult res = FinishDecodeFirstFrame();
NS_ENSURE_SUCCESS(res, res);
} else {
+ // NB: We're already on the decode thread, but we proxy these anyway so that
+ // we don't need to worry about dropping locks.
if (HasAudio()) {
- mAudioRequestStatus = RequestStatus::Pending;
- ReentrantMonitorAutoExit unlock(mDecoder->GetReentrantMonitor());
- mReader->RequestAudioData()->Then(DecodeTaskQueue(), __func__, this,
- &MediaDecoderStateMachine::OnAudioDecoded,
- &MediaDecoderStateMachine::OnAudioNotDecoded);
+ mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
+ __func__, &MediaDecoderReader::RequestAudioData)
+ ->RefableThen(DecodeTaskQueue(), __func__, this,
+ &MediaDecoderStateMachine::OnAudioDecoded,
+ &MediaDecoderStateMachine::OnAudioNotDecoded));
}
if (HasVideo()) {
mVideoDecodeStartTime = TimeStamp::Now();
- mVideoRequestStatus = RequestStatus::Pending;
- ReentrantMonitorAutoExit unlock(mDecoder->GetReentrantMonitor());
- mReader->RequestVideoData(false, 0)
- ->Then(DecodeTaskQueue(), __func__, this,
- &MediaDecoderStateMachine::OnVideoDecoded,
- &MediaDecoderStateMachine::OnVideoNotDecoded);
+ mVideoDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
+ __func__, &MediaDecoderReader::RequestVideoData, false, int64_t(0))
+ ->RefableThen(DecodeTaskQueue(), __func__, this,
+ &MediaDecoderStateMachine::OnVideoDecoded,
+ &MediaDecoderStateMachine::OnVideoNotDecoded));
}
}
return NS_OK;
}
nsresult
MediaDecoderStateMachine::FinishDecodeFirstFrame()
@@ -2760,18 +2764,16 @@ nsresult MediaDecoderStateMachine::RunSt
StopAudioThread();
FlushDecoding();
// Now that those threads are stopped, there's no possibility of
// mPendingWakeDecoder being needed again. Revoke it.
mPendingWakeDecoder = nullptr;
DebugOnly<nsresult> rv = DecodeTaskQueue()->Dispatch(
NS_NewRunnableMethod(mReader, &MediaDecoderReader::ReleaseMediaResources));
MOZ_ASSERT(NS_SUCCEEDED(rv));
- mAudioRequestStatus = RequestStatus::Idle;
- mVideoRequestStatus = RequestStatus::Idle;
return NS_OK;
}
case DECODER_STATE_WAIT_FOR_RESOURCES: {
return NS_OK;
}
case DECODER_STATE_DECODING_NONE: {
@@ -2829,22 +2831,22 @@ nsresult MediaDecoderStateMachine::RunSt
(mQuickBuffering ? "(quick exit)" : ""));
ScheduleStateMachine(USECS_PER_S);
return NS_OK;
}
} 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(), mAudioRequestStatus != RequestStatus::Idle);
- MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedVideo(), mVideoRequestStatus != RequestStatus::Idle);
+ MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedAudio(), mAudioDataRequest.Exists() || mAudioWaitRequest.Exists());
+ MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedVideo(), mVideoDataRequest.Exists() || mVideoWaitRequest.Exists());
DECODER_LOG("In buffering mode, waiting to be notified: outOfAudio: %d, "
- "mAudioStatus: %d, outOfVideo: %d, mVideoStatus: %d",
- OutOfDecodedAudio(), mAudioRequestStatus,
- OutOfDecodedVideo(), mVideoRequestStatus);
+ "mAudioStatus: %s, outOfVideo: %d, mVideoStatus: %s",
+ OutOfDecodedAudio(), AudioRequestStatus(),
+ OutOfDecodedVideo(), VideoRequestStatus());
return NS_OK;
}
DECODER_LOG("Changed state from BUFFERING to DECODING");
DECODER_LOG("Buffered for %.3lfs", (now - mBufferingStart).ToSeconds());
StartDecoding();
// Notify to allow blocked decoder thread to continue
@@ -3098,18 +3100,18 @@ void MediaDecoderStateMachine::AdvanceFr
mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING &&
mDecoder->IsExpectingMoreData()) {
bool shouldBuffer;
if (mReader->UseBufferingHeuristics()) {
shouldBuffer = HasLowDecodedData(remainingTime + EXHAUSTED_DATA_MARGIN_USECS) &&
(JustExitedQuickBuffering() || HasLowUndecodedData());
} else {
MOZ_ASSERT(mReader->IsWaitForDataSupported());
- shouldBuffer = (OutOfDecodedAudio() && mAudioRequestStatus == RequestStatus::Waiting) ||
- (OutOfDecodedVideo() && mVideoRequestStatus == RequestStatus::Waiting);
+ shouldBuffer = (OutOfDecodedAudio() && mAudioWaitRequest.Exists()) ||
+ (OutOfDecodedVideo() && mVideoWaitRequest.Exists());
}
if (shouldBuffer) {
if (currentFrame) {
VideoQueue().PushFront(currentFrame);
}
StartBuffering();
// 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