Bug 1393336 - Remove WaitForCDM state from MDSM.
MozReview-Commit-ID: 7XofvBZTerH
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -357,17 +357,16 @@ MediaDecoder::IsInfinite() const
name(mOwner->AbstractMainThread(), val, "MediaDecoder::" #name " (Mirror)")
#define INIT_CANONICAL(name, val) \
name(mOwner->AbstractMainThread(), val, "MediaDecoder::" #name " (Canonical)")
MediaDecoder::MediaDecoder(MediaDecoderInit& aInit)
: mWatchManager(this, aInit.mOwner->AbstractMainThread())
, mLogicalPosition(0.0)
, mDuration(std::numeric_limits<double>::quiet_NaN())
- , mCDMProxyPromise(mCDMProxyPromiseHolder.Ensure(__func__))
, mOwner(aInit.mOwner)
, mAbstractMainThread(aInit.mOwner->AbstractMainThread())
, mFrameStats(new FrameStatistics())
, mVideoFrameContainer(aInit.mOwner->GetVideoFrameContainer())
, mPinnedForSeek(false)
, mAudioChannel(aInit.mAudioChannel)
, mMinimizePreroll(aInit.mMinimizePreroll)
, mFiredMetadataLoaded(false)
@@ -435,18 +434,16 @@ MediaDecoder::Shutdown()
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
AbstractThread::AutoEnter context(AbstractMainThread());
UnpinForSeek();
// Unwatch all watch targets to prevent further notifications.
mWatchManager.Shutdown();
- mCDMProxyPromiseHolder.RejectIfExists(true, __func__);
-
DiscardOngoingSeekIfExists();
// 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();
@@ -1446,29 +1443,28 @@ MediaDecoder::CanPlayThrough()
bool val = CanPlayThroughImpl();
if (val != mCanPlayThrough) {
mCanPlayThrough = val;
mDecoderStateMachine->DispatchCanPlayThrough(val);
}
return val;
}
-RefPtr<MediaDecoder::CDMProxyPromise>
-MediaDecoder::RequestCDMProxy() const
-{
- return mCDMProxyPromise;
-}
-
void
MediaDecoder::SetCDMProxy(CDMProxy* aProxy)
{
MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aProxy);
-
- mCDMProxyPromiseHolder.ResolveIfExists(aProxy, __func__);
+ RefPtr<CDMProxy> proxy = aProxy;
+ RefPtr<MediaFormatReader> reader = mReader;
+ nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
+ "MediaFormatReader::SetCDMProxy",
+ [reader, proxy]() {
+ reader->SetCDMProxy(proxy);
+ });
+ mReader->OwnerThread()->Dispatch(r.forget());
}
bool
MediaDecoder::IsOpusEnabled()
{
return Preferences::GetBool("media.opus.enabled");
}
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -373,24 +373,16 @@ private:
MediaDecoderOwner* GetOwner() const;
AbstractThread* AbstractMainThread() const
{
return mAbstractMainThread;
}
- typedef MozPromise<RefPtr<CDMProxy>, bool /* aIgnored */,
- /* IsExclusive = */ true>
- CDMProxyPromise;
-
- // Resolved when a CDMProxy is available and the capabilities are known or
- // rejected when this decoder is about to shut down.
- RefPtr<CDMProxyPromise> RequestCDMProxy() const;
-
void SetCDMProxy(CDMProxy* aProxy);
void EnsureTelemetryReported();
static bool IsOggEnabled();
static bool IsOpusEnabled();
static bool IsWaveEnabled();
static bool IsWebMEnabled();
@@ -525,19 +517,16 @@ private:
// call methods of this object from other threads. Its internal data
// is synchronised on a monitor. The lifetime of this object is
// after mPlayState is LOADING and before mPlayState is SHUTDOWN. It
// is safe to access it during this period.
//
// Explicitly prievate to force access via accessors.
RefPtr<MediaDecoderStateMachine> mDecoderStateMachine;
- MozPromiseHolder<CDMProxyPromise> mCDMProxyPromiseHolder;
- RefPtr<CDMProxyPromise> mCDMProxyPromise;
-
protected:
void NotifyDataArrivedInternal();
void DiscardOngoingSeekIfExists();
virtual void CallSeek(const SeekTarget& aTarget);
// Called to notify fetching media data is in progress.
// Called on the main thread only.
virtual void DownloadProgressed();
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -174,17 +174,16 @@ class MediaDecoderStateMachine::StateObj
{
public:
virtual ~StateObject() { }
virtual void Exit() { } // Exit action.
virtual void Step() { } // Perform a 'cycle' of this state object.
virtual State GetState() const = 0;
// Event handlers for various events.
- virtual void HandleCDMProxyReady() { }
virtual void HandleAudioCaptured() { }
virtual void HandleAudioDecoded(AudioData* aAudio)
{
Crash("Unexpected event!", __func__);
}
virtual void HandleVideoDecoded(VideoData* aVideo, TimeStamp aDecodeStart)
{
Crash("Unexpected event!", __func__);
@@ -321,17 +320,16 @@ protected:
Master* mMaster;
};
/**
* Purpose: decode metadata like duration and dimensions of the media resource.
*
* Transition to other states when decoding metadata is done:
* SHUTDOWN if failing to decode metadata.
- * WAIT_FOR_CDM if the media is encrypted and CDM is not available.
* DECODING_FIRSTFRAME otherwise.
*/
class MediaDecoderStateMachine::DecodeMetadataState
: public MediaDecoderStateMachine::StateObject
{
public:
explicit DecodeMetadataState(Master* aPtr) : StateObject(aPtr) { }
@@ -387,68 +385,16 @@ private:
SLOGW("Decode metadata failed, shutting down decoder");
mMaster->DecodeError(aError);
}
MozPromiseRequestHolder<MediaFormatReader::MetadataPromise> mMetadataRequest;
};
/**
- * Purpose: wait for the CDM to start decoding.
- *
- * Transition to other states when CDM is ready:
- * SEEKING if any pending seek request.
- * DECODING_FIRSTFRAME otherwise.
- */
-class MediaDecoderStateMachine::WaitForCDMState
- : public MediaDecoderStateMachine::StateObject
-{
-public:
- explicit WaitForCDMState(Master* aPtr) : StateObject(aPtr) { }
-
- void Enter() { MOZ_ASSERT(!mMaster->mVideoDecodeSuspended); }
-
- void Exit() override
- {
- // mPendingSeek is either moved in HandleCDMProxyReady() or should be
- // rejected here before transition to SHUTDOWN.
- mPendingSeek.RejectIfExists(__func__);
- }
-
- State GetState() const override
- {
- return DECODER_STATE_WAIT_FOR_CDM;
- }
-
- void HandleCDMProxyReady() override;
-
- RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
- {
- SLOG("Not Enough Data to seek at this stage, queuing seek");
- mPendingSeek.RejectIfExists(__func__);
- mPendingSeek.mTarget.emplace(aTarget);
- return mPendingSeek.mPromise.Ensure(__func__);
- }
-
- void HandleVideoSuspendTimeout() override
- {
- // Do nothing since no decoders are created yet.
- }
-
- void HandleResumeVideoDecoding(const TimeUnit&) override
- {
- // We never suspend video decoding in this state.
- MOZ_ASSERT(false, "Shouldn't have suspended video decoding.");
- }
-
-private:
- SeekJob mPendingSeek;
-};
-
-/**
* Purpose: release decoder resources to save memory and hardware resources.
*
* Transition to:
* SEEKING if any seek request or play state changes to PLAYING.
*/
class MediaDecoderStateMachine::DormantState
: public MediaDecoderStateMachine::StateObject
{
@@ -2254,50 +2200,32 @@ DecodeMetadataState::OnMetadataRead(Meta
MOZ_ASSERT(mMaster->mDuration.Ref().isSome());
mMaster->mMetadataLoadedEvent.Notify(
Move(aMetadata.mInfo),
Move(aMetadata.mTags),
MediaDecoderEventVisibility::Observable);
- if (Info().IsEncrypted() && !mMaster->mCDMProxy) {
- // Metadata parsing was successful but we're still waiting for CDM caps
- // to become available so that we can build the correct decryptor/decoder.
- SetState<WaitForCDMState>();
- } else {
- SetState<DecodingFirstFrameState>();
- }
+ SetState<DecodingFirstFrameState>();
}
void
MediaDecoderStateMachine::
DormantState::HandlePlayStateChanged(MediaDecoder::PlayState aPlayState)
{
if (aPlayState == MediaDecoder::PLAY_STATE_PLAYING) {
// Exit dormant when the user wants to play.
- MOZ_ASSERT(!Info().IsEncrypted() || mMaster->mCDMProxy);
MOZ_ASSERT(mMaster->mSentFirstFrameLoadedEvent);
SetSeekingState(Move(mPendingSeek), EventVisibility::Suppressed);
}
}
void
MediaDecoderStateMachine::
-WaitForCDMState::HandleCDMProxyReady()
-{
- if (mPendingSeek.Exists()) {
- SetSeekingState(Move(mPendingSeek), EventVisibility::Observable);
- } else {
- SetState<DecodingFirstFrameState>();
- }
-}
-
-void
-MediaDecoderStateMachine::
DecodingFirstFrameState::Enter()
{
// Transition to DECODING if we've decoded first frames.
if (mMaster->mSentFirstFrameLoadedEvent) {
SetState<DecodingState>();
return;
}
@@ -2637,18 +2565,16 @@ ShutdownState::Enter()
auto master = mMaster;
master->mDelayedScheduler.Reset();
// Shutdown happens while decode timer is active, we need to disconnect and
// dispose of the timer.
master->CancelSuspendTimer();
- master->mCDMProxyPromise.DisconnectIfExists();
-
if (master->IsPlaying()) {
master->StopPlayback();
}
master->mAudioDataRequest.DisconnectIfExists();
master->mVideoDataRequest.DisconnectIfExists();
master->mAudioWaitRequest.DisconnectIfExists();
master->mVideoWaitRequest.DisconnectIfExists();
@@ -2930,22 +2856,16 @@ nsresult MediaDecoderStateMachine::Init(
mMetadataManager.Connect(mReader->TimedMetadataEvent(), OwnerThread());
mOnMediaNotSeekable = mReader->OnMediaNotSeekable().Connect(
OwnerThread(), this, &MediaDecoderStateMachine::SetMediaNotSeekable);
mMediaSink = CreateMediaSink(mAudioCaptured);
- aDecoder->RequestCDMProxy()->Then(
- OwnerThread(), __func__, this,
- &MediaDecoderStateMachine::OnCDMProxyReady,
- &MediaDecoderStateMachine::OnCDMProxyNotReady)
- ->Track(mCDMProxyPromise);
-
nsresult rv = mReader->Init();
NS_ENSURE_SUCCESS(rv, rv);
mReader->SetCanonicalDuration(&mDuration);
return NS_OK;
}
@@ -3036,17 +2956,16 @@ MediaDecoderStateMachine::UpdatePlayback
}
}
/* static */ const char*
MediaDecoderStateMachine::ToStateStr(State aState)
{
switch (aState) {
case DECODER_STATE_DECODING_METADATA: return "DECODING_METADATA";
- case DECODER_STATE_WAIT_FOR_CDM: return "WAIT_FOR_CDM";
case DECODER_STATE_DORMANT: return "DORMANT";
case DECODER_STATE_DECODING_FIRSTFRAME: return "DECODING_FIRSTFRAME";
case DECODER_STATE_DECODING: return "DECODING";
case DECODER_STATE_SEEKING: return "SEEKING";
case DECODER_STATE_BUFFERING: return "BUFFERING";
case DECODER_STATE_COMPLETED: return "COMPLETED";
case DECODER_STATE_SHUTDOWN: return "SHUTDOWN";
default: MOZ_ASSERT_UNREACHABLE("Invalid state.");
@@ -3780,33 +3699,16 @@ void MediaDecoderStateMachine::OnMediaSi
}
// 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__));
}
void
-MediaDecoderStateMachine::OnCDMProxyReady(RefPtr<CDMProxy> aProxy)
-{
- MOZ_ASSERT(OnTaskQueue());
- mCDMProxyPromise.Complete();
- mCDMProxy = aProxy;
- mReader->SetCDMProxy(aProxy);
- mStateObj->HandleCDMProxyReady();
-}
-
-void
-MediaDecoderStateMachine::OnCDMProxyNotReady()
-{
- MOZ_ASSERT(OnTaskQueue());
- mCDMProxyPromise.Complete();
-}
-
-void
MediaDecoderStateMachine::SetAudioCaptured(bool aCaptured)
{
MOZ_ASSERT(OnTaskQueue());
if (aCaptured == mAudioCaptured) {
return;
}
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -158,17 +158,16 @@ public:
MediaDecoderStateMachine(MediaDecoder* aDecoder, MediaFormatReader* aReader);
nsresult Init(MediaDecoder* aDecoder);
// Enumeration for the valid decoding states
enum State
{
DECODER_STATE_DECODING_METADATA,
- DECODER_STATE_WAIT_FOR_CDM,
DECODER_STATE_DORMANT,
DECODER_STATE_DECODING_FIRSTFRAME,
DECODER_STATE_DECODING,
DECODER_STATE_SEEKING,
DECODER_STATE_BUFFERING,
DECODER_STATE_COMPLETED,
DECODER_STATE_SHUTDOWN
};
@@ -253,17 +252,16 @@ public:
size_t SizeOfAudioQueue() const;
// Sets the video decode mode. Used by the suspend-video-decoder feature.
void SetVideoDecodeMode(VideoDecodeMode aMode);
private:
class StateObject;
class DecodeMetadataState;
- class WaitForCDMState;
class DormantState;
class DecodingFirstFrameState;
class DecodingState;
class SeekingState;
class AccurateSeekingState;
class NextFrameSeekingState;
class NextFrameSeekingFromDormantState;
class VideoOnlySeekingState;
@@ -655,21 +653,16 @@ private:
MediaEventProducerExc<nsAutoPtr<MediaInfo>,
MediaDecoderEventVisibility> mFirstFrameLoadedEvent;
MediaEventProducer<MediaEventType> mOnPlaybackEvent;
MediaEventProducer<MediaResult> mOnPlaybackErrorEvent;
MediaEventProducer<DecoderDoctorEvent> mOnDecoderDoctorEvent;
- void OnCDMProxyReady(RefPtr<CDMProxy> aProxy);
- void OnCDMProxyNotReady();
- RefPtr<CDMProxy> mCDMProxy;
- MozPromiseRequestHolder<MediaDecoder::CDMProxyPromise> mCDMProxyPromise;
-
const bool mIsMSE;
private:
// The buffered range. Mirrored from the decoder thread.
Mirror<media::TimeIntervals> mBuffered;
// The current play state, mirrored from the main thread.
Mirror<MediaDecoder::PlayState> mPlayState;
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -1233,16 +1233,22 @@ void
MediaFormatReader::SetCDMProxy(CDMProxy* aProxy)
{
RefPtr<CDMProxy> proxy = aProxy;
RefPtr<MediaFormatReader> self = this;
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableFunction("MediaFormatReader::SetCDMProxy", [=]() {
MOZ_ASSERT(self->OnTaskQueue());
self->mCDMProxy = proxy;
+ if (HasAudio()) {
+ self->ScheduleUpdate(TrackInfo::kAudioTrack);
+ }
+ if (HasVideo()) {
+ self->ScheduleUpdate(TrackInfo::kVideoTrack);
+ }
});
OwnerThread()->Dispatch(r.forget());
}
bool
MediaFormatReader::IsWaitingOnCDMResource()
{
MOZ_ASSERT(OnTaskQueue());
@@ -2337,16 +2343,22 @@ MediaFormatReader::Update(TrackType aTra
decoder.mFlushing,
decoder.mDescription,
uint32_t(decoder.mOutput.Length()),
decoder.mWaitingForData,
decoder.mDemuxEOS,
int32_t(decoder.mDrainState),
decoder.mLastStreamSourceID);
+ if (IsWaitingOnCDMResource()) {
+ // If the content is encrypted, MFR won't start to create decoder until
+ // CDMProxy is set.
+ return;
+ }
+
if ((decoder.mWaitingForData
&& (!decoder.mTimeThreshold || decoder.mTimeThreshold.ref().mWaiting))
|| (decoder.mWaitingForKey && decoder.mDecodeRequest.Exists())) {
// Nothing more we can do at present.
LOGV("Still waiting for data or key.");
return;
}