Bug 1299072: P9. Pass decoding error details to MediaDecoder. r?jwwang
MozReview-Commit-ID: uXWHhTozon
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -193,17 +193,17 @@ MediaDecoder::ResourceCallback::NotifyNe
}
void
MediaDecoder::ResourceCallback::NotifyDecodeError()
{
RefPtr<ResourceCallback> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
if (self->mDecoder) {
- self->mDecoder->DecodeError();
+ self->mDecoder->DecodeError(NS_ERROR_DOM_MEDIA_FATAL_ERR);
}
});
AbstractThread::MainThread()->Dispatch(r.forget());
}
/* static */ void
MediaDecoder::ResourceCallback::TimerCallback(nsITimer* aTimer, void* aClosure)
{
@@ -602,16 +602,17 @@ MediaDecoder::Shutdown()
// This changes the decoder state to SHUTDOWN and does other things
// necessary to unblock the state machine thread if it's blocked, so
// the asynchronous shutdown in nsDestroyStateMachine won't deadlock.
if (mDecoderStateMachine) {
mTimedMetadataListener.Disconnect();
mMetadataLoadedListener.Disconnect();
mFirstFrameLoadedListener.Disconnect();
mOnPlaybackEvent.Disconnect();
+ mOnPlaybackErrorEvent.Disconnect();
mOnMediaNotSeekable.Disconnect();
mDecoderStateMachine->BeginShutdown()
->Then(AbstractThread::MainThread(), __func__, this,
&MediaDecoder::FinishShutdown,
&MediaDecoder::FinishShutdown);
} else {
// Ensure we always unregister asynchronously in order not to disrupt
@@ -656,32 +657,35 @@ MediaDecoder::OnPlaybackEvent(MediaEvent
ComputePlaybackRate();
break;
case MediaEventType::PlaybackEnded:
PlaybackEnded();
break;
case MediaEventType::SeekStarted:
SeekingStarted();
break;
- case MediaEventType::DecodeError:
- DecodeError();
- break;
case MediaEventType::Invalidate:
Invalidate();
break;
case MediaEventType::EnterVideoSuspend:
mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("mozentervideosuspend"));
break;
case MediaEventType::ExitVideoSuspend:
mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("mozexitvideosuspend"));
break;
}
}
void
+MediaDecoder::OnPlaybackErrorEvent(const MediaResult& aError)
+{
+ DecodeError(aError);
+}
+
+void
MediaDecoder::FinishShutdown()
{
MOZ_ASSERT(NS_IsMainThread());
mDecoderStateMachine->BreakCycles();
SetStateMachine(nullptr);
mVideoFrameContainer = nullptr;
MediaShutdownManager::Instance().Unregister(this);
}
@@ -744,16 +748,18 @@ MediaDecoder::SetStateMachineParameters(
AbstractThread::MainThread(), this, &MediaDecoder::OnMetadataUpdate);
mMetadataLoadedListener = mDecoderStateMachine->MetadataLoadedEvent().Connect(
AbstractThread::MainThread(), this, &MediaDecoder::MetadataLoaded);
mFirstFrameLoadedListener = mDecoderStateMachine->FirstFrameLoadedEvent().Connect(
AbstractThread::MainThread(), this, &MediaDecoder::FirstFrameLoaded);
mOnPlaybackEvent = mDecoderStateMachine->OnPlaybackEvent().Connect(
AbstractThread::MainThread(), this, &MediaDecoder::OnPlaybackEvent);
+ mOnPlaybackErrorEvent = mDecoderStateMachine->OnPlaybackErrorEvent().Connect(
+ AbstractThread::MainThread(), this, &MediaDecoder::OnPlaybackErrorEvent);
mOnMediaNotSeekable = mDecoderStateMachine->OnMediaNotSeekable().Connect(
AbstractThread::MainThread(), this, &MediaDecoder::OnMediaNotSeekable);
}
void
MediaDecoder::SetMinimizePrerollUntilPlaybackStarts()
{
MOZ_ASSERT(NS_IsMainThread());
@@ -1001,17 +1007,17 @@ MediaDecoder::NetworkError()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsShutdown());
mOwner->NetworkError();
MOZ_ASSERT(IsShutdown());
}
void
-MediaDecoder::DecodeError()
+MediaDecoder::DecodeError(const MediaResult& aError)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsShutdown());
mOwner->DecodeError();
MOZ_ASSERT(IsShutdown());
}
void
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -431,17 +431,17 @@ private:
UpdateLogicalPositionInternal(MediaDecoderEventVisibility::Observable);
}
// Find the end of the cached data starting at the current decoder
// position.
int64_t GetDownloadPosition();
// Notifies the element that decoding has failed.
- void DecodeError();
+ void DecodeError(const MediaResult& aError);
// Indicate whether the media is same-origin with the element.
void UpdateSameOriginStatus(bool aSameOrigin);
MediaDecoderOwner* GetOwner() const override;
#ifdef MOZ_EME
typedef MozPromise<RefPtr<CDMProxy>, bool /* aIgnored */, /* IsExclusive = */ true> CDMProxyPromise;
@@ -587,16 +587,17 @@ private:
void MetadataLoaded(nsAutoPtr<MediaInfo> aInfo,
nsAutoPtr<MetadataTags> aTags,
MediaDecoderEventVisibility aEventVisibility);
MediaEventSource<void>*
DataArrivedEvent() override { return &mDataArrivedEvent; }
void OnPlaybackEvent(MediaEventType aEvent);
+ void OnPlaybackErrorEvent(const MediaResult& aError);
void OnMediaNotSeekable()
{
SetMediaSeekable(false);
}
void FinishShutdown();
@@ -726,16 +727,17 @@ protected:
// A listener to receive metadata updates from MDSM.
MediaEventListener mTimedMetadataListener;
MediaEventListener mMetadataLoadedListener;
MediaEventListener mFirstFrameLoadedListener;
MediaEventListener mOnPlaybackEvent;
+ MediaEventListener mOnPlaybackErrorEvent;
MediaEventListener mOnMediaNotSeekable;
protected:
// Whether the state machine is shut down.
Mirror<bool> mStateMachineIsShutdown;
// Buffered range, mirrored from the reader.
Mirror<media::TimeIntervals> mBuffered;
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1017,17 +1017,17 @@ MediaDecoderStateMachine::OnNotDecoded(M
} 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();
+ DecodeError(aError);
return;
}
// This is an EOS. Finish off the queue, and then handle things based on our
// state.
if (isAudio) {
AudioQueue().Finish();
StopPrerollingAudio();
@@ -2077,17 +2077,17 @@ MediaDecoderStateMachine::OnSeekTaskReje
StopPrerollingAudio();
}
if (aValue.mIsVideoQueueFinished) {
VideoQueue().Finish();
StopPrerollingVideo();
}
- DecodeError();
+ DecodeError(aValue.mError);
DiscardSeekTaskIfExist();
}
void
MediaDecoderStateMachine::DiscardSeekTaskIfExist()
{
if (mSeekTask) {
@@ -2286,23 +2286,23 @@ bool MediaDecoderStateMachine::HasLowUnd
return false;
}
media::TimeInterval interval(media::TimeUnit::FromMicroseconds(endOfDecodedData),
media::TimeUnit::FromMicroseconds(std::min(endOfDecodedData + aUsecs, Duration().ToMicroseconds())));
return endOfDecodedData != INT64_MAX && !mBuffered.Ref().Contains(interval);
}
void
-MediaDecoderStateMachine::DecodeError()
+MediaDecoderStateMachine::DecodeError(const MediaResult& aError)
{
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(!IsShutdown());
DECODER_WARN("Decode error");
// Notify the decode error and MediaDecoder will shut down MDSM.
- mOnPlaybackEvent.Notify(MediaEventType::DecodeError);
+ mOnPlaybackErrorEvent.Notify(aError);
}
void
MediaDecoderStateMachine::EnqueueLoadedMetadataEvent()
{
MOZ_ASSERT(OnTaskQueue());
MediaDecoderEventVisibility visibility =
mSentLoadedMetadataEvent ? MediaDecoderEventVisibility::Suppressed
@@ -2913,17 +2913,17 @@ MediaDecoderStateMachine::OnMediaSinkVid
MOZ_ASSERT(mInfo.HasVideo());
VERBOSE_LOG("[%s]", __func__);
mMediaSinkVideoPromise.Complete();
mVideoCompleted = true;
if (HasAudio()) {
return;
}
- DecodeError();
+ DecodeError(MediaResult(NS_ERROR_DOM_MEDIA_MEDIASINK_ERR, __func__));
}
void MediaDecoderStateMachine::OnMediaSinkAudioComplete()
{
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(mInfo.HasAudio());
VERBOSE_LOG("[%s]", __func__);
@@ -2944,17 +2944,17 @@ void MediaDecoderStateMachine::OnMediaSi
// Make the best effort to continue playback when there is video.
if (HasVideo()) {
return;
}
// Otherwise notify media decoder/element about this error for it makes
// no sense to play an audio-only file without sound output.
- DecodeError();
+ DecodeError(MediaResult(NS_ERROR_DOM_MEDIA_MEDIASINK_ERR, __func__));
}
#ifdef MOZ_EME
void
MediaDecoderStateMachine::OnCDMProxyReady(RefPtr<CDMProxy> aProxy)
{
MOZ_ASSERT(OnTaskQueue());
mCDMProxyPromise.Complete();
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -114,17 +114,16 @@ class TaskQueue;
extern LazyLogModule gMediaDecoderLog;
extern LazyLogModule gMediaSampleLog;
enum class MediaEventType : int8_t {
PlaybackStarted,
PlaybackStopped,
PlaybackEnded,
SeekStarted,
- DecodeError,
Invalidate,
EnterVideoSuspend,
ExitVideoSuspend
};
/*
The state machine class. This manages the decoding and seeking in the
MediaDecoderReader on the decode task queue, and A/V sync on the shared
@@ -240,16 +239,18 @@ public:
MetadataLoadedEvent() { return mMetadataLoadedEvent; }
MediaEventSourceExc<nsAutoPtr<MediaInfo>,
MediaDecoderEventVisibility>&
FirstFrameLoadedEvent() { return mFirstFrameLoadedEvent; }
MediaEventSource<MediaEventType>&
OnPlaybackEvent() { return mOnPlaybackEvent; }
+ MediaEventSource<MediaResult>&
+ OnPlaybackErrorEvent() { return mOnPlaybackErrorEvent; }
size_t SizeOfVideoQueue() const;
size_t SizeOfAudioQueue() const;
private:
class StateObject;
class DecodeMetadataState;
@@ -476,17 +477,17 @@ protected:
// The entry action of DECODER_STATE_DECODING.
void StartDecoding();
// Moves the decoder into the shutdown state, and dispatches an error
// event to the media element. This begins shutting down the decoder.
// The decoder monitor must be held. This is only called on the
// decode thread.
- void DecodeError();
+ void DecodeError(const MediaResult& aError);
// Dispatches a LoadedMetadataEvent.
// This is threadsafe and can be called on any thread.
// The decoder monitor must be held.
void EnqueueLoadedMetadataEvent();
void EnqueueFirstFrameLoadedEvent();
@@ -887,16 +888,17 @@ private:
MediaEventProducerExc<nsAutoPtr<MediaInfo>,
nsAutoPtr<MetadataTags>,
MediaDecoderEventVisibility> mMetadataLoadedEvent;
MediaEventProducerExc<nsAutoPtr<MediaInfo>,
MediaDecoderEventVisibility> mFirstFrameLoadedEvent;
MediaEventProducer<MediaEventType> mOnPlaybackEvent;
+ MediaEventProducer<MediaResult> mOnPlaybackErrorEvent;
// True if audio is offloading.
// Playback will not start when audio is offloading.
bool mAudioOffloading;
#ifdef MOZ_EME
void OnCDMProxyReady(RefPtr<CDMProxy> aProxy);
void OnCDMProxyNotReady();