Bug 1247056 - Notify MediaDecoder about Decoder Doctor events from MDSM - r=jwwang
MozReview-Commit-ID: Jgt5a2yJugu
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -602,16 +602,17 @@ MediaDecoder::Shutdown()
// 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();
+ mOnDecoderDoctorEvent.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
@@ -675,16 +676,34 @@ MediaDecoder::OnPlaybackEvent(MediaEvent
void
MediaDecoder::OnPlaybackErrorEvent(const MediaResult& aError)
{
DecodeError(aError);
}
void
+MediaDecoder::OnDecoderDoctorEvent(DecoderDoctorEvent aEvent)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ // OnDecoderDoctorEvent is disconnected at shutdown time.
+ MOZ_ASSERT(!IsShutdown());
+ HTMLMediaElement* element = mOwner->GetMediaElement();
+ if (!element) {
+ return;
+ }
+ nsIDocument* doc = element->OwnerDoc();
+ if (!doc) {
+ return;
+ }
+ DecoderDoctorDiagnostics diags;
+ diags.StoreEvent(doc, aEvent, __func__);
+}
+
+void
MediaDecoder::FinishShutdown()
{
MOZ_ASSERT(NS_IsMainThread());
mDecoderStateMachine->BreakCycles();
SetStateMachine(nullptr);
mVideoFrameContainer = nullptr;
MediaShutdownManager::Instance().Unregister(this);
}
@@ -752,16 +771,18 @@ MediaDecoder::SetStateMachineParameters(
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);
+ mOnDecoderDoctorEvent = mDecoderStateMachine->OnDecoderDoctorEvent().Connect(
+ AbstractThread::MainThread(), this, &MediaDecoder::OnDecoderDoctorEvent);
mOnMediaNotSeekable = mDecoderStateMachine->OnMediaNotSeekable().Connect(
AbstractThread::MainThread(), this, &MediaDecoder::OnMediaNotSeekable);
}
void
MediaDecoder::SetMinimizePrerollUntilPlaybackStarts()
{
MOZ_ASSERT(NS_IsMainThread());
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -22,16 +22,17 @@
#include "necko-config.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsIObserver.h"
#include "nsISupports.h"
#include "nsITimer.h"
#include "AbstractMediaDecoder.h"
+#include "DecoderDoctorDiagnostics.h"
#include "MediaDecoderOwner.h"
#include "MediaEventSource.h"
#include "MediaMetadataManager.h"
#include "MediaResource.h"
#include "MediaResourceCallback.h"
#include "MediaStatistics.h"
#include "MediaStreamGraph.h"
#include "TimeUnits.h"
@@ -589,16 +590,18 @@ private:
MediaDecoderEventVisibility aEventVisibility);
MediaEventSource<void>*
DataArrivedEvent() override { return &mDataArrivedEvent; }
void OnPlaybackEvent(MediaEventType aEvent);
void OnPlaybackErrorEvent(const MediaResult& aError);
+ void OnDecoderDoctorEvent(DecoderDoctorEvent aEvent);
+
void OnMediaNotSeekable()
{
SetMediaSeekable(false);
}
void FinishShutdown();
void ConnectMirrors(MediaDecoderStateMachine* aObject);
@@ -728,16 +731,17 @@ protected:
// A listener to receive metadata updates from MDSM.
MediaEventListener mTimedMetadataListener;
MediaEventListener mMetadataLoadedListener;
MediaEventListener mFirstFrameLoadedListener;
MediaEventListener mOnPlaybackEvent;
MediaEventListener mOnPlaybackErrorEvent;
+ MediaEventListener mOnDecoderDoctorEvent;
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
@@ -2872,27 +2872,36 @@ void MediaDecoderStateMachine::OnMediaSi
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(mInfo.HasAudio());
VERBOSE_LOG("[%s]", __func__);
mMediaSinkAudioPromise.Complete();
mAudioCompleted = true;
// To notify PlaybackEnded as soon as possible.
ScheduleStateMachine();
+
+ // Report OK to Decoder Doctor (to know if issue may have been resolved).
+ mOnDecoderDoctorEvent.Notify(
+ DecoderDoctorEvent{DecoderDoctorEvent::eAudioSinkStartup, NS_OK});
}
-void MediaDecoderStateMachine::OnMediaSinkAudioError()
+void MediaDecoderStateMachine::OnMediaSinkAudioError(nsresult aResult)
{
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(mInfo.HasAudio());
VERBOSE_LOG("[%s]", __func__);
mMediaSinkAudioPromise.Complete();
mAudioCompleted = true;
+ // Result should never be NS_OK in this *error* handler. Report to Dec-Doc.
+ MOZ_ASSERT(NS_FAILED(aResult));
+ mOnDecoderDoctorEvent.Notify(
+ DecoderDoctorEvent{DecoderDoctorEvent::eAudioSinkStartup, aResult});
+
// 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(MediaResult(NS_ERROR_DOM_MEDIA_MEDIASINK_ERR, __func__));
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -248,16 +248,19 @@ public:
MediaDecoderEventVisibility>&
FirstFrameLoadedEvent() { return mFirstFrameLoadedEvent; }
MediaEventSource<MediaEventType>&
OnPlaybackEvent() { return mOnPlaybackEvent; }
MediaEventSource<MediaResult>&
OnPlaybackErrorEvent() { return mOnPlaybackErrorEvent; }
+ MediaEventSource<DecoderDoctorEvent>&
+ OnDecoderDoctorEvent() { return mOnDecoderDoctorEvent; }
+
size_t SizeOfVideoQueue() const;
size_t SizeOfAudioQueue() const;
private:
class StateObject;
class DecodeMetadataState;
class WaitForCDMState;
@@ -556,17 +559,17 @@ protected:
private:
// Resolved by the MediaSink to signal that all audio/video outstanding
// work is complete and identify which part(a/v) of the sink is shutting down.
void OnMediaSinkAudioComplete();
void OnMediaSinkVideoComplete();
// Rejected by the MediaSink to signal errors for audio/video.
- void OnMediaSinkAudioError();
+ void OnMediaSinkAudioError(nsresult aResult);
void OnMediaSinkVideoError();
// Return true if the video decoder's decode speed can not catch up the
// play time.
bool NeedToSkipToNextKeyframe();
void* const mDecoderID;
const RefPtr<FrameStatistics> mFrameStats;
@@ -859,16 +862,18 @@ private:
nsAutoPtr<MetadataTags>,
MediaDecoderEventVisibility> mMetadataLoadedEvent;
MediaEventProducerExc<nsAutoPtr<MediaInfo>,
MediaDecoderEventVisibility> mFirstFrameLoadedEvent;
MediaEventProducer<MediaEventType> mOnPlaybackEvent;
MediaEventProducer<MediaResult> mOnPlaybackErrorEvent;
+ MediaEventProducer<DecoderDoctorEvent> mOnDecoderDoctorEvent;
+
// 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();
RefPtr<CDMProxy> mCDMProxy;