--- a/dom/media/AccurateSeekTask.cpp
+++ b/dom/media/AccurateSeekTask.cpp
@@ -318,66 +318,64 @@ AccurateSeekTask::OnAudioDecoded(MediaDa
RequestAudioData();
return;
}
MaybeFinishSeek();
}
void
AccurateSeekTask::OnNotDecoded(MediaData::Type aType,
- MediaDecoderReader::NotDecodedReason aReason)
+ const MediaResult& aError)
{
AssertOwnerThread();
MOZ_ASSERT(!mSeekTaskPromise.IsEmpty(), "Seek shouldn't be finished");
- SAMPLE_LOG("OnNotDecoded type=%d reason=%u", aType, aReason);
+ SAMPLE_LOG("OnNotDecoded type=%d reason=%u", aType, aError.Code());
// Ignore pending requests from video-only seek.
if (aType == MediaData::AUDIO_DATA && mTarget.IsVideoOnly()) {
return;
}
- if (aReason == MediaDecoderReader::DECODE_ERROR) {
- // If this is a decode error, delegate to the generic error path.
- CancelCallbacks();
- RejectIfExist(__func__);
- 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) {
+ if (aError == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
mReader->WaitForData(aType);
return;
}
- if (aReason == MediaDecoderReader::CANCELED) {
+ if (aError == NS_ERROR_DOM_MEDIA_CANCELED) {
if (aType == MediaData::AUDIO_DATA) {
RequestAudioData();
} else {
RequestVideoData();
}
return;
}
- if (aReason == MediaDecoderReader::END_OF_STREAM) {
+ if (aError == NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
if (aType == MediaData::AUDIO_DATA) {
mIsAudioQueueFinished = true;
mDoneAudioSeeking = true;
} else {
mIsVideoQueueFinished = true;
mDoneVideoSeeking = true;
if (mFirstVideoFrameAfterSeek) {
// Hit the end of stream. Move mFirstVideoFrameAfterSeek into
// mSeekedVideoData so we have something to display after seeking.
mSeekedVideoData = mFirstVideoFrameAfterSeek.forget();
}
}
MaybeFinishSeek();
+ return;
}
+
+ // This is a decode error, delegate to the generic error path.
+ CancelCallbacks();
+ RejectIfExist(__func__);
}
void
AccurateSeekTask::OnVideoDecoded(MediaData* aVideoSample)
{
AssertOwnerThread();
MOZ_ASSERT(!mSeekTaskPromise.IsEmpty(), "Seek shouldn't be finished");
@@ -414,28 +412,28 @@ AccurateSeekTask::SetCallbacks()
AssertOwnerThread();
mAudioCallback = mReader->AudioCallback().Connect(
OwnerThread(), [this] (AudioCallbackData aData) {
if (aData.is<MediaData*>()) {
OnAudioDecoded(aData.as<MediaData*>());
} else {
OnNotDecoded(MediaData::AUDIO_DATA,
- aData.as<MediaDecoderReader::NotDecodedReason>());
+ aData.as<MediaResult>());
}
});
mVideoCallback = mReader->VideoCallback().Connect(
OwnerThread(), [this] (VideoCallbackData aData) {
typedef Tuple<MediaData*, TimeStamp> Type;
if (aData.is<Type>()) {
OnVideoDecoded(Get<0>(aData.as<Type>()));
} else {
OnNotDecoded(MediaData::VIDEO_DATA,
- aData.as<MediaDecoderReader::NotDecodedReason>());
+ aData.as<MediaResult>());
}
});
mAudioWaitCallback = mReader->AudioWaitCallback().Connect(
OwnerThread(), [this] (WaitCallbackData aData) {
// Ignore pending requests from video-only seek.
if (mTarget.IsVideoOnly()) {
return;
--- a/dom/media/AccurateSeekTask.h
+++ b/dom/media/AccurateSeekTask.h
@@ -45,17 +45,17 @@ private:
void OnSeekResolved(media::TimeUnit);
void OnSeekRejected(nsresult aResult);
void OnAudioDecoded(MediaData* aAudioSample);
void OnVideoDecoded(MediaData* aVideoSample);
- void OnNotDecoded(MediaData::Type, MediaDecoderReader::NotDecodedReason);
+ void OnNotDecoded(MediaData::Type, const MediaResult&);
void SetCallbacks();
void CancelCallbacks();
void AdjustFastSeekIfNeeded(MediaData* aSample);
/*
--- a/dom/media/MediaDecoderReader.cpp
+++ b/dom/media/MediaDecoderReader.cpp
@@ -284,22 +284,22 @@ size_t MediaDecoderReader::SizeOfAudioQu
{
return mAudioQueue.GetSize();
}
nsresult MediaDecoderReader::ResetDecode(TrackSet aTracks)
{
if (aTracks.contains(TrackInfo::kVideoTrack)) {
VideoQueue().Reset();
- mBaseVideoPromise.RejectIfExists(CANCELED, __func__);
+ mBaseVideoPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
}
if (aTracks.contains(TrackInfo::kAudioTrack)) {
AudioQueue().Reset();
- mBaseAudioPromise.RejectIfExists(CANCELED, __func__);
+ mBaseAudioPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
}
return NS_OK;
}
RefPtr<MediaDecoderReader::MediaDataPromise>
MediaDecoderReader::DecodeToFirstVideoData()
{
@@ -318,17 +318,17 @@ MediaDecoderReader::DecodeToFirstVideoDa
return true;
}, [self] () -> bool {
MOZ_ASSERT(self->OnTaskQueue());
return self->VideoQueue().GetSize();
})->Then(OwnerThread(), __func__, [self, p] () {
p->Resolve(self->VideoQueue().PeekFront(), __func__);
}, [p] () {
// We don't have a way to differentiate EOS, error, and shutdown here. :-(
- p->Reject(END_OF_STREAM, __func__);
+ p->Reject(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
});
return p.forget();
}
void
MediaDecoderReader::UpdateBuffered()
{
@@ -451,17 +451,17 @@ MediaDecoderReader::RequestVideoData(boo
mTaskQueue->Dispatch(task.forget());
return p;
}
}
if (VideoQueue().GetSize() > 0) {
RefPtr<VideoData> v = VideoQueue().PopFront();
mBaseVideoPromise.Resolve(v, __func__);
} else if (VideoQueue().IsFinished()) {
- mBaseVideoPromise.Reject(END_OF_STREAM, __func__);
+ mBaseVideoPromise.Reject(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
} else {
MOZ_ASSERT(false, "Dropping this promise on the floor");
}
return p;
}
RefPtr<MediaDecoderReader::MediaDataPromise>
@@ -483,33 +483,35 @@ MediaDecoderReader::RequestAudioData()
mTaskQueue->Dispatch(task.forget());
return p;
}
}
if (AudioQueue().GetSize() > 0) {
RefPtr<AudioData> a = AudioQueue().PopFront();
mBaseAudioPromise.Resolve(a, __func__);
} else if (AudioQueue().IsFinished()) {
- mBaseAudioPromise.Reject(mHitAudioDecodeError ? DECODE_ERROR : END_OF_STREAM, __func__);
+ mBaseAudioPromise.Reject(mHitAudioDecodeError
+ ? NS_ERROR_DOM_MEDIA_FATAL_ERR
+ : NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
mHitAudioDecodeError = false;
} else {
MOZ_ASSERT(false, "Dropping this promise on the floor");
}
return p;
}
RefPtr<ShutdownPromise>
MediaDecoderReader::Shutdown()
{
MOZ_ASSERT(OnTaskQueue());
mShutdown = true;
- mBaseAudioPromise.RejectIfExists(END_OF_STREAM, __func__);
- mBaseVideoPromise.RejectIfExists(END_OF_STREAM, __func__);
+ mBaseAudioPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
+ mBaseVideoPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
mDataArrivedListener.DisconnectIfExists();
ReleaseResources();
mDuration.DisconnectIfConnected();
mBuffered.DisconnectAll();
mIsSuspended.DisconnectAll();
--- a/dom/media/MediaDecoderReader.h
+++ b/dom/media/MediaDecoderReader.h
@@ -8,16 +8,17 @@
#include "mozilla/EnumSet.h"
#include "mozilla/MozPromise.h"
#include "nsAutoPtr.h"
#include "AbstractMediaDecoder.h"
#include "MediaInfo.h"
#include "MediaData.h"
+#include "MediaResult.h"
#include "MediaMetadataManager.h"
#include "MediaQueue.h"
#include "MediaTimer.h"
#include "AudioCompactor.h"
#include "Intervals.h"
#include "TimeUnits.h"
#include "SeekTarget.h"
@@ -63,29 +64,22 @@ enum class ReadMetadataFailureReason : i
// be accessed on the decode task queue.
class MediaDecoderReader {
friend class ReRequestVideoWithSkipTask;
friend class ReRequestAudioTask;
static const bool IsExclusive = true;
public:
- enum NotDecodedReason {
- END_OF_STREAM,
- DECODE_ERROR,
- WAITING_FOR_DATA,
- CANCELED
- };
-
using TrackSet = EnumSet<TrackInfo::TrackType>;
using MetadataPromise =
MozPromise<RefPtr<MetadataHolder>, ReadMetadataFailureReason, IsExclusive>;
using MediaDataPromise =
- MozPromise<RefPtr<MediaData>, NotDecodedReason, IsExclusive>;
+ MozPromise<RefPtr<MediaData>, MediaResult, IsExclusive>;
using SeekPromise = MozPromise<media::TimeUnit, nsresult, IsExclusive>;
// Note that, conceptually, WaitForData makes sense in a non-exclusive sense.
// But in the current architecture it's only ever used exclusively (by MDSM),
// so we mark it that way to verify our assumptions. If you have a use-case
// for multiple WaitForData consumers, feel free to flip the exclusivity here.
using WaitForDataPromise =
MozPromise<MediaData::Type, WaitForDataRejectValue, IsExclusive>;
--- a/dom/media/MediaDecoderReaderWrapper.cpp
+++ b/dom/media/MediaDecoderReaderWrapper.cpp
@@ -71,32 +71,32 @@ public:
RefPtr<StartTimeRendezvous> self = this;
AwaitStartTime()->Then(
mOwnerThread, __func__,
[p, data, self] () {
MOZ_ASSERT(self->mOwnerThread->IsCurrentThreadIn());
p->Resolve(data, __func__);
},
[p] () {
- p->Reject(MediaDecoderReader::CANCELED, __func__);
+ p->Reject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
});
return p.forget();
}
template<MediaData::Type SampleType>
- void FirstSampleRejected(MediaDecoderReader::NotDecodedReason aReason)
+ void FirstSampleRejected(const MediaResult& aError)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
- if (aReason == MediaDecoderReader::DECODE_ERROR) {
- mHaveStartTimePromise.RejectIfExists(false, __func__);
- } else if (aReason == MediaDecoderReader::END_OF_STREAM) {
+ if (aError == NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
LOG("StartTimeRendezvous=%p SampleType(%d) Has no samples.",
this, SampleType);
MaybeSetChannelStartTime<SampleType>(INT64_MAX);
+ } else if (aError != NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
+ mHaveStartTimePromise.RejectIfExists(false, __func__);
}
}
bool HaveStartTime() const
{
return mAudioStartTime.isSome() && mVideoStartTime.isSome();
}
@@ -195,19 +195,19 @@ MediaDecoderReaderWrapper::RequestAudioD
RefPtr<MediaDecoderReaderWrapper> self = this;
mAudioDataRequest.Begin(p->Then(mOwnerThread, __func__,
[self] (MediaData* aAudioSample) {
self->mAudioDataRequest.Complete();
aAudioSample->AdjustForStartTime(self->StartTime().ToMicroseconds());
self->mAudioCallback.Notify(AsVariant(aAudioSample));
},
- [self] (MediaDecoderReader::NotDecodedReason aReason) {
+ [self] (const MediaResult& aError) {
self->mAudioDataRequest.Complete();
- self->mAudioCallback.Notify(AsVariant(aReason));
+ self->mAudioCallback.Notify(AsVariant(aError));
}));
}
void
MediaDecoderReaderWrapper::RequestVideoData(bool aSkipToNextKeyframe,
media::TimeUnit aTimeThreshold)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
@@ -235,19 +235,19 @@ MediaDecoderReaderWrapper::RequestVideoD
RefPtr<MediaDecoderReaderWrapper> self = this;
mVideoDataRequest.Begin(p->Then(mOwnerThread, __func__,
[self, videoDecodeStartTime] (MediaData* aVideoSample) {
self->mVideoDataRequest.Complete();
aVideoSample->AdjustForStartTime(self->StartTime().ToMicroseconds());
self->mVideoCallback.Notify(AsVariant(MakeTuple(aVideoSample, videoDecodeStartTime)));
},
- [self] (MediaDecoderReader::NotDecodedReason aReason) {
+ [self] (const MediaResult& aError) {
self->mVideoDataRequest.Complete();
- self->mVideoCallback.Notify(AsVariant(aReason));
+ self->mVideoCallback.Notify(AsVariant(aError));
}));
}
bool
MediaDecoderReaderWrapper::IsRequestingAudioData() const
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
return mAudioDataRequest.Exists();
--- a/dom/media/MediaDecoderReaderWrapper.h
+++ b/dom/media/MediaDecoderReaderWrapper.h
@@ -16,18 +16,18 @@
#include "MediaEventSource.h"
namespace mozilla {
class StartTimeRendezvous;
typedef MozPromise<bool, bool, /* isExclusive = */ false> HaveStartTimePromise;
-typedef Variant<MediaData*, MediaDecoderReader::NotDecodedReason> AudioCallbackData;
-typedef Variant<Tuple<MediaData*, TimeStamp>, MediaDecoderReader::NotDecodedReason> VideoCallbackData;
+typedef Variant<MediaData*, MediaResult> AudioCallbackData;
+typedef Variant<Tuple<MediaData*, TimeStamp>, MediaResult> VideoCallbackData;
typedef Variant<MediaData::Type, WaitForDataRejectValue> WaitCallbackData;
/**
* A wrapper around MediaDecoderReader to offset the timestamps of Audio/Video
* samples by the start time to ensure MDSM can always assume zero start time.
* It also adjusts the seek target passed to Seek() to ensure correct seek time
* is passed to the underlying reader.
*/
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -974,66 +974,65 @@ MediaDecoderStateMachine::OnVideoPopped(
MOZ_ASSERT(OnTaskQueue());
mPlaybackOffset = std::max(mPlaybackOffset.Ref(), aSample->mOffset);
UpdateNextFrameStatus();
DispatchVideoDecodeTaskIfNeeded();
}
void
MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
- MediaDecoderReader::NotDecodedReason aReason)
+ const MediaResult& aError)
{
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(mState != DECODER_STATE_SEEKING);
- SAMPLE_LOG("OnNotDecoded (aType=%u, aReason=%u)", aType, aReason);
+ SAMPLE_LOG("OnNotDecoded (aType=%u, aError=%u)", aType, aError.Code());
bool isAudio = aType == MediaData::AUDIO_DATA;
MOZ_ASSERT_IF(!isAudio, aType == MediaData::VIDEO_DATA);
if (IsShutdown()) {
// Already shutdown;
return;
}
- // 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) {
+ if (aError == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
MOZ_ASSERT(mReader->IsWaitForDataSupported(),
"Readers that send WAITING_FOR_DATA need to implement WaitForData");
mReader->WaitForData(aType);
// We are out of data to decode and will enter buffering mode soon.
// We want to play the frames we have already decoded, so we stop pre-rolling
// and ensure that loadeddata is fired as required.
if (isAudio) {
StopPrerollingAudio();
} else {
StopPrerollingVideo();
}
return;
}
- if (aReason == MediaDecoderReader::CANCELED) {
+ if (aError == NS_ERROR_DOM_MEDIA_CANCELED) {
if (isAudio) {
EnsureAudioDecodeTaskQueued();
} else {
EnsureVideoDecodeTaskQueued();
}
return;
}
+ // If this is a decode error, delegate to the generic error path.
+ if (aError != NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
+ DecodeError();
+ return;
+ }
+
// This is an EOS. Finish off the queue, and then handle things based on our
// state.
- MOZ_ASSERT(aReason == MediaDecoderReader::END_OF_STREAM);
if (isAudio) {
AudioQueue().Finish();
StopPrerollingAudio();
} else {
VideoQueue().Finish();
StopPrerollingVideo();
}
switch (mState) {
@@ -1214,28 +1213,28 @@ MediaDecoderStateMachine::SetMediaDecode
{
MOZ_ASSERT(OnTaskQueue());
mAudioCallback = mReader->AudioCallback().Connect(
mTaskQueue, [this] (AudioCallbackData aData) {
if (aData.is<MediaData*>()) {
OnAudioDecoded(aData.as<MediaData*>());
} else {
- OnNotDecoded(MediaData::AUDIO_DATA, aData.as<MediaDecoderReader::NotDecodedReason>());
+ OnNotDecoded(MediaData::AUDIO_DATA, aData.as<MediaResult>());
}
});
mVideoCallback = mReader->VideoCallback().Connect(
mTaskQueue, [this] (VideoCallbackData aData) {
typedef Tuple<MediaData*, TimeStamp> Type;
if (aData.is<Type>()) {
auto&& v = aData.as<Type>();
OnVideoDecoded(Get<0>(v), Get<1>(v));
} else {
- OnNotDecoded(MediaData::VIDEO_DATA, aData.as<MediaDecoderReader::NotDecodedReason>());
+ OnNotDecoded(MediaData::VIDEO_DATA, aData.as<MediaResult>());
}
});
mAudioWaitCallback = mReader->AudioWaitCallback().Connect(
mTaskQueue, [this] (WaitCallbackData aData) {
if (aData.is<MediaData::Type>()) {
EnsureAudioDecodeTaskQueued();
}
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -339,17 +339,17 @@ private:
// Returns true if we're currently playing. The decoder monitor must
// be held.
bool IsPlaying() const;
// TODO: Those callback function may receive demuxed-only data.
// Need to figure out a suitable API name for this case.
void OnAudioDecoded(MediaData* aAudioSample);
void OnVideoDecoded(MediaData* aVideoSample, TimeStamp aDecodeStartTime);
- void OnNotDecoded(MediaData::Type aType, MediaDecoderReader::NotDecodedReason aReason);
+ void OnNotDecoded(MediaData::Type aType, const MediaResult& aError);
// Resets all state related to decoding and playback, emptying all buffers
// and aborting all pending operations on the decode task queue.
void Reset(TrackSet aTracks = TrackSet(TrackInfo::kAudioTrack,
TrackInfo::kVideoTrack));
protected:
virtual ~MediaDecoderStateMachine();
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -89,23 +89,23 @@ MediaFormatReader::~MediaFormatReader()
RefPtr<ShutdownPromise>
MediaFormatReader::Shutdown()
{
MOZ_ASSERT(OnTaskQueue());
mDemuxerInitRequest.DisconnectIfExists();
mMetadataPromise.RejectIfExists(ReadMetadataFailureReason::METADATA_ERROR, __func__);
- mSeekPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
+ mSeekPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
mSkipRequest.DisconnectIfExists();
if (mAudio.mDecoder) {
Reset(TrackInfo::kAudioTrack);
if (mAudio.HasPromise()) {
- mAudio.RejectPromise(CANCELED, __func__);
+ mAudio.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
}
mAudio.ShutdownDecoder();
}
if (mAudio.mTrackDemuxer) {
mAudio.ResetDemuxer();
mAudio.mTrackDemuxer->BreakCycles();
mAudio.mTrackDemuxer = nullptr;
}
@@ -114,17 +114,17 @@ MediaFormatReader::Shutdown()
mAudio.mTaskQueue->AwaitShutdownAndIdle();
mAudio.mTaskQueue = nullptr;
}
MOZ_ASSERT(!mAudio.HasPromise());
if (mVideo.mDecoder) {
Reset(TrackInfo::kVideoTrack);
if (mVideo.HasPromise()) {
- mVideo.RejectPromise(CANCELED, __func__);
+ mVideo.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
}
mVideo.ShutdownDecoder();
}
if (mVideo.mTrackDemuxer) {
mVideo.ResetDemuxer();
mVideo.mTrackDemuxer->BreakCycles();
mVideo.mTrackDemuxer = nullptr;
}
@@ -529,31 +529,31 @@ MediaFormatReader::RequestVideoData(bool
MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise(), "No duplicate sample requests");
MOZ_DIAGNOSTIC_ASSERT(!mVideo.mSeekRequest.Exists() ||
mVideo.mTimeThreshold.isSome());
MOZ_DIAGNOSTIC_ASSERT(!IsSeeking(), "called mid-seek");
LOGV("RequestVideoData(%d, %lld)", aSkipToNextKeyframe, aTimeThreshold);
if (!HasVideo()) {
LOG("called with no video track");
- return MediaDataPromise::CreateAndReject(DECODE_ERROR, __func__);
+ return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
}
if (IsSeeking()) {
LOG("called mid-seek. Rejecting.");
- return MediaDataPromise::CreateAndReject(CANCELED, __func__);
+ return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
}
if (mShutdown) {
NS_WARNING("RequestVideoData on shutdown MediaFormatReader!");
- return MediaDataPromise::CreateAndReject(CANCELED, __func__);
+ return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
}
if (IsSuspended()) {
- return MediaDataPromise::CreateAndReject(CANCELED, __func__);
+ return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
}
media::TimeUnit timeThreshold{media::TimeUnit::FromMicroseconds(aTimeThreshold)};
// Ensure we have no pending seek going as ShouldSkip could return out of date
// information.
if (!mVideo.HasInternalSeekPending() &&
ShouldSkip(aSkipToNextKeyframe, timeThreshold)) {
RefPtr<MediaDataPromise> p = mVideo.EnsurePromise(__func__);
@@ -589,17 +589,17 @@ MediaFormatReader::OnDemuxFailed(TrackTy
if (!decoder.mWaitingForData) {
decoder.mNeedDraining = true;
}
NotifyWaitingForData(aTrack);
break;
case DemuxerFailureReason::CANCELED: MOZ_FALLTHROUGH;
case DemuxerFailureReason::SHUTDOWN:
if (decoder.HasPromise()) {
- decoder.RejectPromise(CANCELED, __func__);
+ decoder.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
}
break;
default:
MOZ_ASSERT(false);
break;
}
}
@@ -633,31 +633,31 @@ MediaFormatReader::RequestAudioData()
MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking() ||
!mAudio.mSeekRequest.Exists() ||
mAudio.mTimeThreshold.isSome());
MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking() || !IsSeeking(), "called mid-seek");
LOGV("");
if (!HasAudio()) {
LOG("called with no audio track");
- return MediaDataPromise::CreateAndReject(DECODE_ERROR, __func__);
+ return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
}
if (IsSuspended()) {
- return MediaDataPromise::CreateAndReject(CANCELED, __func__);
+ return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
}
if (IsSeeking()) {
LOG("called mid-seek. Rejecting.");
- return MediaDataPromise::CreateAndReject(CANCELED, __func__);
+ return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
}
if (mShutdown) {
NS_WARNING("RequestAudioData on shutdown MediaFormatReader!");
- return MediaDataPromise::CreateAndReject(CANCELED, __func__);
+ return MediaDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
}
RefPtr<MediaDataPromise> p = mAudio.EnsurePromise(__func__);
ScheduleUpdate(TrackInfo::kAudioTrack);
return p;
}
@@ -1200,55 +1200,55 @@ MediaFormatReader::Update(TrackType aTra
mPreviousDecodedKeyframeTime_us = output->mTime;
}
nsCString error;
mVideo.mIsHardwareAccelerated =
mVideo.mDecoder && mVideo.mDecoder->IsHardwareAccelerated(error);
}
} else if (decoder.HasFatalError()) {
LOG("Rejecting %s promise: DECODE_ERROR", TrackTypeToStr(aTrack));
- decoder.RejectPromise(DECODE_ERROR, __func__);
+ decoder.RejectPromise(decoder.mError.ref(), __func__);
return;
} else if (decoder.mDrainComplete) {
bool wasDraining = decoder.mDraining;
decoder.mDrainComplete = false;
decoder.mDraining = false;
if (decoder.mDemuxEOS) {
LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
- decoder.RejectPromise(END_OF_STREAM, __func__);
+ decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
} else if (decoder.mWaitingForData) {
if (wasDraining && decoder.mLastSampleTime &&
!decoder.mNextStreamSourceID) {
// We have completed draining the decoder following WaitingForData.
// Set up the internal seek machinery to be able to resume from the
// last sample decoded.
LOG("Seeking to last sample time: %lld",
decoder.mLastSampleTime.ref().mStart.ToMicroseconds());
InternalSeek(aTrack, InternalSeekTarget(decoder.mLastSampleTime.ref(), true));
}
if (!decoder.mReceivedNewData) {
LOG("Rejecting %s promise: WAITING_FOR_DATA", TrackTypeToStr(aTrack));
- decoder.RejectPromise(WAITING_FOR_DATA, __func__);
+ decoder.RejectPromise(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
}
}
// Now that draining has completed, we check if we have received
// new data again as the result may now be different from the earlier
// run.
if (UpdateReceivedNewData(aTrack) || decoder.mSeekRequest.Exists()) {
LOGV("Nothing more to do");
return;
}
} else if (decoder.mDemuxEOS && !decoder.mNeedDraining &&
!decoder.HasPendingDrain() && decoder.mQueuedSamples.IsEmpty()) {
// It is possible to transition from WAITING_FOR_DATA directly to EOS
// state during the internal seek; in which case no draining would occur.
// There is no more samples left to be decoded and we are already in
// EOS state. We can immediately reject the data promise.
LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
- decoder.RejectPromise(END_OF_STREAM, __func__);
+ decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
}
}
if (decoder.mNeedDraining) {
DrainDecoder(aTrack);
return;
}
@@ -1392,25 +1392,25 @@ MediaFormatReader::ResetDecode(TrackSet
// Reset miscellaneous seeking state.
mPendingSeekTime.reset();
if (HasVideo() && aTracks.contains(TrackInfo::kVideoTrack)) {
mVideo.ResetDemuxer();
Reset(TrackInfo::kVideoTrack);
if (mVideo.HasPromise()) {
- mVideo.RejectPromise(CANCELED, __func__);
+ mVideo.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
}
}
if (HasAudio() && aTracks.contains(TrackInfo::kAudioTrack)) {
mAudio.ResetDemuxer();
Reset(TrackInfo::kAudioTrack);
if (mAudio.HasPromise()) {
- mAudio.RejectPromise(CANCELED, __func__);
+ mAudio.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
}
}
return MediaDecoderReader::ResetDecode(aTracks);
}
void
MediaFormatReader::Output(TrackType aTrack, MediaData* aSample)
@@ -1574,17 +1574,17 @@ MediaFormatReader::OnVideoSkipFailed(Med
DropDecodedSamples(TrackInfo::kVideoTrack);
// We can't complete the skip operation, will just service a video frame
// normally.
ScheduleUpdate(TrackInfo::kVideoTrack);
break;
case DemuxerFailureReason::CANCELED: MOZ_FALLTHROUGH;
case DemuxerFailureReason::SHUTDOWN:
if (mVideo.HasPromise()) {
- mVideo.RejectPromise(CANCELED, __func__);
+ mVideo.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
}
break;
default:
NotifyError(TrackType::kVideoTrack);
break;
}
}
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -350,17 +350,17 @@ private:
uint64_t mNumSamplesSkippedTotal;
// These get overridden in the templated concrete class.
// Indicate if we have a pending promise for decoded frame.
// Rejecting the promise will stop the reader from decoding ahead.
virtual bool HasPromise() const = 0;
virtual RefPtr<MediaDataPromise> EnsurePromise(const char* aMethodName) = 0;
virtual void ResolvePromise(MediaData* aData, const char* aMethodName) = 0;
- virtual void RejectPromise(MediaDecoderReader::NotDecodedReason aReason,
+ virtual void RejectPromise(const MediaResult& aError,
const char* aMethodName) = 0;
// Clear track demuxer related data.
void ResetDemuxer()
{
mDemuxRequest.DisconnectIfExists();
mSeekRequest.DisconnectIfExists();
mTrackDemuxer->Reset();
@@ -458,21 +458,21 @@ private:
void ResolvePromise(MediaData* aData, const char* aMethodName) override
{
MOZ_ASSERT(mOwner->OnTaskQueue());
mPromise.Resolve(aData, aMethodName);
mHasPromise = false;
}
- void RejectPromise(MediaDecoderReader::NotDecodedReason aReason,
+ void RejectPromise(const MediaResult& aError,
const char* aMethodName) override
{
MOZ_ASSERT(mOwner->OnTaskQueue());
- mPromise.Reject(aReason, aMethodName);
+ mPromise.Reject(aError, aMethodName);
mHasPromise = false;
}
private:
MozPromiseHolder<MediaDataPromise> mPromise;
Atomic<bool> mHasPromise;
};
--- a/dom/media/NextFrameSeekTask.cpp
+++ b/dom/media/NextFrameSeekTask.cpp
@@ -178,22 +178,22 @@ NextFrameSeekTask::OnAudioDecoded(MediaD
// We accept any audio data here.
mSeekedAudioData = aAudioSample;
MaybeFinishSeek();
}
void
-NextFrameSeekTask::OnAudioNotDecoded(MediaDecoderReader::NotDecodedReason aReason)
+NextFrameSeekTask::OnAudioNotDecoded(const MediaResult& aError)
{
AssertOwnerThread();
MOZ_ASSERT(!mSeekTaskPromise.IsEmpty(), "Seek shouldn't be finished");
- SAMPLE_LOG("OnAudioNotDecoded (aReason=%u)", aReason);
+ SAMPLE_LOG("OnAudioNotDecoded (aError=%u)", aError.Code());
// We don't really handle audio deocde error here. Let MDSM to trigger further
// audio decoding tasks if it needs to play audio, and MDSM will then receive
// the decoding state from MediaDecoderReader.
MaybeFinishSeek();
}
@@ -219,47 +219,47 @@ NextFrameSeekTask::OnVideoDecoded(MediaD
RequestVideoData();
return;
}
MaybeFinishSeek();
}
void
-NextFrameSeekTask::OnVideoNotDecoded(MediaDecoderReader::NotDecodedReason aReason)
+NextFrameSeekTask::OnVideoNotDecoded(const MediaResult& aError)
{
AssertOwnerThread();
MOZ_ASSERT(!mSeekTaskPromise.IsEmpty(), "Seek shouldn't be finished");
- SAMPLE_LOG("OnVideoNotDecoded (aReason=%u)", aReason);
+ SAMPLE_LOG("OnVideoNotDecoded (aError=%u)", aError.Code());
- if (aReason == MediaDecoderReader::END_OF_STREAM) {
+ if (aError == NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
mIsVideoQueueFinished = true;
}
// Video seek not finished.
if (NeedMoreVideo()) {
- switch (aReason) {
- case MediaDecoderReader::DECODE_ERROR:
+ switch (aError.Code()) {
+ case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
+ mReader->WaitForData(MediaData::VIDEO_DATA);
+ break;
+ case NS_ERROR_DOM_MEDIA_CANCELED:
+ RequestVideoData();
+ break;
+ case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
+ MOZ_ASSERT(false, "Shouldn't want more data for ended video.");
+ break;
+ default:
// We might lose the audio sample after canceling the callbacks.
// However it doesn't really matter because MDSM is gonna shut down
// when seek fails.
CancelCallbacks();
// Reject the promise since we can't finish video seek anyway.
RejectIfExist(__func__);
break;
- case MediaDecoderReader::WAITING_FOR_DATA:
- mReader->WaitForData(MediaData::VIDEO_DATA);
- break;
- case MediaDecoderReader::CANCELED:
- RequestVideoData();
- break;
- case MediaDecoderReader::END_OF_STREAM:
- MOZ_ASSERT(false, "Shouldn't want more data for ended video.");
- break;
}
return;
}
MaybeFinishSeek();
}
void
@@ -269,27 +269,27 @@ NextFrameSeekTask::SetCallbacks()
// Register dummy callbcak for audio decoding since we don't need to handle
// the decoded audio samples.
mAudioCallback = mReader->AudioCallback().Connect(
OwnerThread(), [this] (AudioCallbackData aData) {
if (aData.is<MediaData*>()) {
OnAudioDecoded(aData.as<MediaData*>());
} else {
- OnAudioNotDecoded(aData.as<MediaDecoderReader::NotDecodedReason>());
+ OnAudioNotDecoded(aData.as<MediaResult>());
}
});
mVideoCallback = mReader->VideoCallback().Connect(
OwnerThread(), [this] (VideoCallbackData aData) {
typedef Tuple<MediaData*, TimeStamp> Type;
if (aData.is<Type>()) {
OnVideoDecoded(Get<0>(aData.as<Type>()));
} else {
- OnVideoNotDecoded(aData.as<MediaDecoderReader::NotDecodedReason>());
+ OnVideoNotDecoded(aData.as<MediaResult>());
}
});
mAudioWaitCallback = mReader->AudioWaitCallback().Connect(
OwnerThread(), [this] (WaitCallbackData aData) {
// We don't make an audio decode request here, instead, let MDSM to
// trigger further audio decode tasks if MDSM itself needs to play audio.
MaybeFinishSeek();
--- a/dom/media/NextFrameSeekTask.h
+++ b/dom/media/NextFrameSeekTask.h
@@ -52,21 +52,21 @@ private:
bool IsAudioSeekComplete() const;
bool IsVideoSeekComplete() const;
void MaybeFinishSeek();
void OnAudioDecoded(MediaData* aAudioSample);
- void OnAudioNotDecoded(MediaDecoderReader::NotDecodedReason aReason);
+ void OnAudioNotDecoded(const MediaResult& aError);
void OnVideoDecoded(MediaData* aVideoSample);
- void OnVideoNotDecoded(MediaDecoderReader::NotDecodedReason aReason);
+ void OnVideoNotDecoded(const MediaResult& aError);
void SetCallbacks();
void CancelCallbacks();
// Update the seek target's time before resolving this seek task, the updated
// time will be used in the MDSM::SeekCompleted() to update the MDSM's position.
void UpdateSeekTargetTime();
--- a/dom/media/gtest/TestMediaFormatReader.cpp
+++ b/dom/media/gtest/TestMediaFormatReader.cpp
@@ -102,17 +102,17 @@ public:
void OnVideoRawDataDemuxed(MediaData* aVideoSample)
{
EXPECT_TRUE(aVideoSample);
EXPECT_EQ(MediaData::RAW_DATA, aVideoSample->mType);
ReaderShutdown();
}
- void OnNotDemuxed(MediaDecoderReader::NotDecodedReason aReason)
+ void OnNotDemuxed(const MediaResult& aReason)
{
EXPECT_TRUE(false);
ReaderShutdown();
}
void ReaderShutdown()
{
RefPtr<MediaFormatReaderBinding> self = this;
--- a/dom/media/webaudio/MediaBufferDecoder.cpp
+++ b/dom/media/webaudio/MediaBufferDecoder.cpp
@@ -130,17 +130,17 @@ private:
}
}
void Decode();
void OnMetadataRead(MetadataHolder* aMetadata);
void OnMetadataNotRead(ReadMetadataFailureReason aReason);
void RequestSample();
void SampleDecoded(MediaData* aData);
- void SampleNotDecoded(MediaDecoderReader::NotDecodedReason aReason);
+ void SampleNotDecoded(const MediaResult& aError);
void FinishDecode();
void AllocateBuffer();
void CallbackTheResult();
void Cleanup()
{
MOZ_ASSERT(NS_IsMainThread());
// MediaDecoderReader expects that BufferDecoder is alive.
@@ -332,25 +332,24 @@ MediaDecodeTask::SampleDecoded(MediaData
if (!mFirstFrameDecoded) {
mDecoderReader->ReadUpdatedMetadata(&mMediaInfo);
mFirstFrameDecoded = true;
}
RequestSample();
}
void
-MediaDecodeTask::SampleNotDecoded(MediaDecoderReader::NotDecodedReason aReason)
+MediaDecodeTask::SampleNotDecoded(const MediaResult& aError)
{
MOZ_ASSERT(!NS_IsMainThread());
- if (aReason == MediaDecoderReader::DECODE_ERROR) {
+ if (aError == NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
+ FinishDecode();
+ } else {
mDecoderReader->Shutdown();
ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
- } else {
- MOZ_ASSERT(aReason == MediaDecoderReader::END_OF_STREAM);
- FinishDecode();
}
}
void
MediaDecodeTask::FinishDecode()
{
mDecoderReader->Shutdown();