Bug 1311872. Part 1 - remove dormant code from MediaDecoder and its friends. We will let MDSM solely decide when to enter/exit dormant.
MozReview-Commit-ID: 4rRSGcruy7Z
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -36,19 +36,16 @@
#ifdef MOZ_ANDROID_OMX
#include "AndroidBridge.h"
#endif
using namespace mozilla::dom;
using namespace mozilla::layers;
using namespace mozilla::media;
-// Default timeout msecs until try to enter dormant state by heuristic.
-static const int DEFAULT_HEURISTIC_DORMANT_TIMEOUT_MSECS = 10000;
-
namespace mozilla {
// The amount of instability we tollerate in calls to
// MediaDecoder::UpdateEstimatedMediaDuration(); changes of duration
// less than this are ignored, as they're assumed to be the result of
// instability in the duration estimation.
static const uint64_t ESTIMATED_DURATION_FUZZ_FACTOR_USECS = USECS_PER_S / 2;
@@ -293,130 +290,17 @@ MediaDecoder::ResourceCallback::NotifyBy
AbstractThread::MainThread()->Dispatch(r.forget());
}
void
MediaDecoder::NotifyOwnerActivityChanged(bool aIsVisible)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsShutdown());
-
SetElementVisibility(aIsVisible);
-
- UpdateDormantState(false /* aDormantTimeout */, false /* aActivity */);
- // Start dormant timer if necessary
- StartDormantTimer();
-}
-
-bool
-MediaDecoder::IsHeuristicDormantSupported() const
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- // We disallow dormant for encrypted media until bug 1181864 is fixed.
- return mInfo &&
- !mInfo->IsEncrypted() &&
- mIsHeuristicDormantSupported;
-}
-
-void
-MediaDecoder::UpdateDormantState(bool aDormantTimeout, bool aActivity)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(!IsShutdown());
-
- if (!mDecoderStateMachine ||
- !mOwner->GetVideoFrameContainer() ||
- (mOwner->GetMediaElement() && mOwner->GetMediaElement()->IsBeingDestroyed()) ||
- !mDormantSupported)
- {
- return;
- }
-
- DECODER_LOG("UpdateDormantState aTimeout=%d aActivity=%d mIsDormant=%d "
- "ownerActive=%d mIsVisible=%d mIsHeuristicDormant=%d "
- "mPlayState=%s encrypted=%s",
- aDormantTimeout, aActivity, mIsDormant, mOwner->IsActive(),
- mIsVisible.Ref(), mIsHeuristicDormant, PlayStateStr(),
- (!mInfo ? "Unknown" : (mInfo->IsEncrypted() ? "1" : "0")));
-
- bool prevDormant = mIsDormant;
- mIsDormant = false;
-#ifdef MOZ_WIDGET_GONK
- if (mOwner->IsHidden()) {
- mIsDormant = true;
- }
-#endif
-
- // Try to enable dormant by idle heuristic, when the owner is hidden.
- bool prevHeuristicDormant = mIsHeuristicDormant;
- mIsHeuristicDormant = false;
- if (IsHeuristicDormantSupported() && !mIsVisible) {
- // Do not enter dormant when MediaDecoder is not paused nor ended.
- if ((aDormantTimeout || !mOwner->IsActive()) && !aActivity &&
- (mPlayState == PLAY_STATE_PAUSED || IsEnded())) {
- // Enable heuristic dormant
- mIsHeuristicDormant = true;
- } else if(prevHeuristicDormant && !aActivity) {
- // Continue heuristic dormant
- mIsHeuristicDormant = true;
- }
-
- if (mIsHeuristicDormant) {
- mIsDormant = true;
- }
- }
-
- if (prevDormant == mIsDormant) {
- // No update to dormant state
- return;
- }
-
- DECODER_LOG("UpdateDormantState() %s DORMANT state", mIsDormant ? "entering" : "exiting");
- mDecoderStateMachine->DispatchSetDormant(mIsDormant);
-}
-
-void
-MediaDecoder::DormantTimerExpired(nsITimer* aTimer, void* aClosure)
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(aClosure);
- MediaDecoder* decoder = static_cast<MediaDecoder*>(aClosure);
- decoder->UpdateDormantState(true /* aDormantTimeout */,
- false /* aActivity */);
-}
-
-void
-MediaDecoder::StartDormantTimer()
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- if (!IsHeuristicDormantSupported() ||
- mIsHeuristicDormant ||
- mIsVisible ||
- (mPlayState != PLAY_STATE_PAUSED && !IsEnded())) {
- return;
- }
-
- if (!mDormantTimer) {
- mDormantTimer = do_CreateInstance("@mozilla.org/timer;1");
- }
- mDormantTimer->InitWithFuncCallback(&MediaDecoder::DormantTimerExpired,
- this,
- mHeuristicDormantTimeout,
- nsITimer::TYPE_ONE_SHOT);
-}
-
-void
-MediaDecoder::CancelDormantTimer()
-{
- MOZ_ASSERT(NS_IsMainThread());
- if (mDormantTimer) {
- mDormantTimer->Cancel();
- }
}
void
MediaDecoder::Pause()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsShutdown());
if (mPlayState == PLAY_STATE_LOADING || IsEnded()) {
@@ -482,40 +366,32 @@ MediaDecoder::IsInfinite() const
#define INIT_MIRROR(name, val) \
name(AbstractThread::MainThread(), val, "MediaDecoder::" #name " (Mirror)")
#define INIT_CANONICAL(name, val) \
name(AbstractThread::MainThread(), val, "MediaDecoder::" #name " (Canonical)")
MediaDecoder::MediaDecoder(MediaDecoderOwner* aOwner)
: mWatchManager(this, AbstractThread::MainThread())
- , mDormantSupported(false)
, mLogicalPosition(0.0)
, mDuration(std::numeric_limits<double>::quiet_NaN())
, mResourceCallback(new ResourceCallback())
, mCDMProxyPromise(mCDMProxyPromiseHolder.Ensure(__func__))
, mIgnoreProgressData(false)
, mInfiniteStream(false)
, mOwner(aOwner)
, mFrameStats(new FrameStatistics())
, mVideoFrameContainer(aOwner->GetVideoFrameContainer())
, mPlaybackStatistics(new MediaChannelStatistics())
, mPinnedForSeek(false)
, mMinimizePreroll(false)
, mMediaTracksConstructed(false)
, mFiredMetadataLoaded(false)
, mElementVisible(!aOwner->IsHidden())
, mForcedHidden(false)
- , mIsDormant(false)
- , mIsHeuristicDormantSupported(
- Preferences::GetBool("media.decoder.heuristic.dormant.enabled", false))
- , mHeuristicDormantTimeout(
- Preferences::GetInt("media.decoder.heuristic.dormant.timeout",
- DEFAULT_HEURISTIC_DORMANT_TIMEOUT_MSECS))
- , mIsHeuristicDormant(false)
, INIT_MIRROR(mStateMachineIsShutdown, true)
, INIT_MIRROR(mBuffered, TimeIntervals())
, INIT_MIRROR(mNextFrameStatus, MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED)
, INIT_MIRROR(mCurrentPosition, 0)
, INIT_MIRROR(mStateMachineDuration, NullableTimeUnit())
, INIT_MIRROR(mPlaybackPosition, 0)
, INIT_MIRROR(mIsAudioDataAudible, false)
, INIT_CANONICAL(mVolume, 0.0)
@@ -618,18 +494,16 @@ MediaDecoder::Shutdown()
}
// Force any outstanding seek and byterange requests to complete
// to prevent shutdown from deadlocking.
if (mResource) {
mResource->Close();
}
- CancelDormantTimer();
-
ChangeState(PLAY_STATE_SHUTDOWN);
mOwner = nullptr;
}
MediaDecoder::~MediaDecoder()
{
MOZ_ASSERT(NS_IsMainThread());
MediaMemoryTracker::RemoveMediaDecoder(this);
@@ -785,17 +659,16 @@ MediaDecoder::SetMinimizePrerollUntilPla
// have no effect.
MOZ_DIAGNOSTIC_ASSERT(!mDecoderStateMachine);
}
nsresult
MediaDecoder::Play()
{
MOZ_ASSERT(NS_IsMainThread());
- UpdateDormantState(false /* aDormantTimeout */, true /* aActivity */);
NS_ASSERTION(mDecoderStateMachine != nullptr, "Should have state machine.");
if (mPlaybackRate == 0) {
return NS_OK;
}
if (IsEnded()) {
return Seek(0, SeekTarget::PrevSyncPoint);
@@ -809,19 +682,16 @@ MediaDecoder::Play()
}
nsresult
MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType, dom::Promise* aPromise /*=nullptr*/)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsShutdown());
- UpdateDormantState(false /* aDormantTimeout */, true /* aActivity */);
-
- MOZ_ASSERT(!mIsDormant, "should be out of dormant by now");
MOZ_ASSERT(aTime >= 0.0, "Cannot seek to a negative value.");
int64_t timeUsecs = TimeUnit::FromSeconds(aTime).ToMicroseconds();
mLogicalPosition = aTime;
mLogicallySeeking = true;
SeekTarget target = SeekTarget(timeUsecs, aSeekType);
@@ -985,32 +855,32 @@ MediaDecoder::PlayStateStr()
void
MediaDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
MediaDecoderEventVisibility aEventVisibility)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsShutdown());
- DECODER_LOG("FirstFrameLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d mPlayState=%s mIsDormant=%d",
+ DECODER_LOG("FirstFrameLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d mPlayState=%s",
aInfo->mAudio.mChannels, aInfo->mAudio.mRate,
- aInfo->HasAudio(), aInfo->HasVideo(), PlayStateStr(), mIsDormant);
+ aInfo->HasAudio(), aInfo->HasVideo(), PlayStateStr());
mInfo = aInfo.forget();
Invalidate();
// This can run cache callbacks.
mResource->EnsureCacheUpToDate();
// The element can run javascript via events
// before reaching here, so only change the
// state if we're still set to the original
// loading state.
- if (mPlayState == PLAY_STATE_LOADING && !mIsDormant) {
+ if (mPlayState == PLAY_STATE_LOADING) {
ChangeState(mNextState);
}
// Run NotifySuspendedStatusChanged now to give us a chance to notice
// that autoplay should run.
NotifySuspendedStatusChanged();
// mOwner->FirstFrameLoaded() might call us back. Put it at the bottom of
@@ -1313,20 +1183,16 @@ MediaDecoder::ChangeState(PlayState aSta
DECODER_LOG("ChangeState %s => %s", PlayStateStr(), ToPlayStateStr(aState));
mPlayState = aState;
if (mPlayState == PLAY_STATE_PLAYING) {
ConstructMediaTracks();
} else if (IsEnded()) {
RemoveMediaTracks();
}
-
- CancelDormantTimer();
- // Start dormant timer if necessary
- StartDormantTimer();
}
void
MediaDecoder::UpdateLogicalPositionInternal(MediaDecoderEventVisibility aEventVisibility)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsShutdown());
@@ -1885,20 +1751,20 @@ MediaDecoder::NextFrameBufferedStatus()
: MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
}
void
MediaDecoder::DumpDebugInfo()
{
MOZ_ASSERT(!IsShutdown());
DUMP_LOG("metadata: channels=%u rate=%u hasAudio=%d hasVideo=%d, "
- "state: mPlayState=%s mIsDormant=%d, mdsm=%p",
+ "state: mPlayState=%s mdsm=%p",
mInfo ? mInfo->mAudio.mChannels : 0, mInfo ? mInfo->mAudio.mRate : 0,
mInfo ? mInfo->HasAudio() : 0, mInfo ? mInfo->HasVideo() : 0,
- PlayStateStr(), mIsDormant, GetStateMachine());
+ PlayStateStr(), GetStateMachine());
nsString str;
GetMozDebugReaderData(str);
if (!str.IsEmpty()) {
DUMP_LOG("reader data:\n%s", NS_ConvertUTF16toUTF8(str).get());
}
if (GetStateMachine()) {
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -179,24 +179,18 @@ public:
// Initialize state machine and schedule it.
nsresult InitializeStateMachine();
// Start playback of a video. 'Load' must have previously been
// called.
virtual nsresult Play();
// Notify activity of the decoder owner is changed.
- // Based on the activity, dormant state is updated.
- // Dormant state is a state to free all scarce media resources
- // (like hw video codec), did not decoding and stay dormant.
- // It is used to share scarece media resources in system.
virtual void NotifyOwnerActivityChanged(bool aIsVisible);
- void UpdateDormantState(bool aDormantTimeout, bool aActivity);
-
// Pause video playback.
virtual void Pause();
// Adjust the speed of the playback, optionally with pitch correction,
virtual void SetVolume(double aVolume);
virtual void SetPlaybackRate(double aPlaybackRate);
void SetPreservesPitch(bool aPreservesPitch);
@@ -501,24 +495,16 @@ protected:
// Called when the first audio and/or video from the media file has been loaded
// by the state machine. Call on the main thread only.
virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
MediaDecoderEventVisibility aEventVisibility);
void SetStateMachineParameters();
- static void DormantTimerExpired(nsITimer *aTimer, void *aClosure);
-
- // Start a timer for heuristic dormant.
- void StartDormantTimer();
-
- // Cancel a timer for heuristic dormant.
- void CancelDormantTimer();
-
bool IsShutdown() const;
// Called by the state machine to notify the decoder that the duration
// has changed.
void DurationChanged();
// State-watching manager.
WatchManager<MediaDecoder> mWatchManager;
@@ -537,19 +523,16 @@ protected:
// that it takes effect immediately, rather than at the end of the current task.
DurationChanged();
}
/******
* The following members should be accessed with the decoder lock held.
******/
- // Whether the decoder implementation supports dormant mode.
- bool mDormantSupported;
-
// The logical playback position of the media resource in units of
// seconds. This corresponds to the "official position" in HTML5. Note that
// we need to store this as a double, rather than an int64_t (like
// mCurrentPosition), so that |v.currentTime = foo; v.currentTime == foo|
// returns true without being affected by rounding errors.
double mLogicalPosition;
// The current playback position of the underlying playback infrastructure.
@@ -623,19 +606,16 @@ protected:
// more task to file the promise resolving/rejection micro-tasks
// asynchronously to make sure that the micro-tasks are processed after the
// "seeking" event task.
void AsyncResolveSeekDOMPromiseIfExists();
void AsyncRejectSeekDOMPromiseIfExists();
void DiscardOngoingSeekIfExists();
virtual void CallSeek(const SeekTarget& aTarget, dom::Promise* aPromise);
- // Returns true if heuristic dormant is supported.
- bool IsHeuristicDormantSupported() const;
-
MozPromiseRequestHolder<SeekPromise> mSeekRequest;
RefPtr<dom::Promise> mSeekDOMPromise;
// True when seeking or otherwise moving the play position around in
// such a manner that progress event data is inaccurate. This is set
// during seek and duration operations to prevent the progress indicator
// from jumping around. Read/Write on the main thread only.
bool mIgnoreProgressData;
@@ -694,31 +674,16 @@ protected:
nsAutoPtr<MediaInfo> mInfo;
// Tracks the visiblity status from HTMLMediaElement
bool mElementVisible;
// If true, forces the decoder to be considered hidden.
bool mForcedHidden;
- // True if MediaDecoder is in dormant state.
- bool mIsDormant;
-
- // True if heuristic dormant is supported.
- const bool mIsHeuristicDormantSupported;
-
- // Timeout ms of heuristic dormant timer.
- const int mHeuristicDormantTimeout;
-
- // True if MediaDecoder is in dormant by heuristic.
- bool mIsHeuristicDormant;
-
- // Timer to schedule updating dormant state.
- nsCOMPtr<nsITimer> mDormantTimer;
-
// A listener to receive metadata updates from MDSM.
MediaEventListener mTimedMetadataListener;
MediaEventListener mMetadataLoadedListener;
MediaEventListener mFirstFrameLoadedListener;
MediaEventListener mOnPlaybackEvent;
MediaEventListener mOnPlaybackErrorEvent;
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -2451,24 +2451,16 @@ void MediaDecoderStateMachine::Recompute
duration = mObservedDuration;
}
MOZ_ASSERT(duration.ToMicroseconds() >= 0);
mDuration = Some(duration);
}
void
-MediaDecoderStateMachine::DispatchSetDormant(bool aDormant)
-{
- nsCOMPtr<nsIRunnable> r = NewRunnableMethod<bool>(
- this, &MediaDecoderStateMachine::SetDormant, aDormant);
- OwnerThread()->Dispatch(r.forget());
-}
-
-void
MediaDecoderStateMachine::SetDormant(bool aDormant)
{
MOZ_ASSERT(OnTaskQueue());
mStateObj->HandleDormant(aDormant);
}
RefPtr<ShutdownPromise>
MediaDecoderStateMachine::Shutdown()
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -175,19 +175,16 @@ public:
RefPtr<MediaDecoder::SeekPromise> InvokeSeek(SeekTarget aTarget);
void DispatchSetPlaybackRate(double aPlaybackRate)
{
OwnerThread()->DispatchStateChange(NewRunnableMethod<double>(
this, &MediaDecoderStateMachine::SetPlaybackRate, aPlaybackRate));
}
- // Set/Unset dormant state.
- void DispatchSetDormant(bool aDormant);
-
RefPtr<ShutdownPromise> BeginShutdown();
// Notifies the state machine that should minimize the number of samples
// decoded we preroll, until playback starts. The first time playback starts
// the state machine is free to return to prerolling normally. Note
// "prerolling" in this context refers to when we decode and buffer decoded
// samples in advance of when they're needed for playback.
void DispatchMinimizePrerollUntilPlaybackStarts()
--- a/dom/media/fmp4/MP4Decoder.cpp
+++ b/dom/media/fmp4/MP4Decoder.cpp
@@ -26,17 +26,16 @@
#include "PDMFactory.h"
namespace mozilla {
MP4Decoder::MP4Decoder(MediaDecoderOwner* aOwner)
: MediaDecoder(aOwner)
{
- mDormantSupported = Preferences::GetBool("media.decoder.heuristic.dormant.enabled", false);
}
MediaDecoderStateMachine* MP4Decoder::CreateStateMachine()
{
mReader =
new MediaFormatReader(this,
new MP4Demuxer(GetResource()),
GetVideoFrameContainer());
--- a/dom/media/mediasource/MediaSourceDecoder.h
+++ b/dom/media/mediasource/MediaSourceDecoder.h
@@ -38,24 +38,16 @@ public:
explicit MediaSourceDecoder(dom::HTMLMediaElement* aElement);
MediaDecoder* Clone(MediaDecoderOwner* aOwner) override;
MediaDecoderStateMachine* CreateStateMachine() override;
nsresult Load(nsIStreamListener**) override;
media::TimeIntervals GetSeekable() override;
media::TimeIntervals GetBuffered() override;
- // We can't do this in the constructor because we don't know what type of
- // media we're dealing with by that point.
- void NotifyDormantSupported(bool aSupported)
- {
- MOZ_ASSERT(NS_IsMainThread());
- mDormantSupported = aSupported;
- }
-
void Shutdown() override;
static already_AddRefed<MediaResource> CreateResource(nsIPrincipal* aPrincipal = nullptr);
void AttachMediaSource(dom::MediaSource* aMediaSource);
void DetachMediaSource();
void Ended(bool aEnded);
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -307,19 +307,16 @@ SourceBuffer::SourceBuffer(MediaSource*
, mType(aType)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aMediaSource);
mTrackBuffersManager =
new TrackBuffersManager(aMediaSource->GetDecoder(), aType);
- // Now that we know what type we're dealing with, enable dormant as needed.
- aMediaSource->GetDecoder()->NotifyDormantSupported(Preferences::GetBool("media.decoder.heuristic.dormant.enabled", false));
-
MSE_DEBUG("Create mTrackBuffersManager=%p",
mTrackBuffersManager.get());
ErrorResult dummy;
if (mCurrentAttributes.mGenerateTimestamps) {
SetMode(SourceBufferAppendMode::Sequence, dummy);
} else {
SetMode(SourceBufferAppendMode::Segments, dummy);
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -329,19 +329,16 @@ pref("media.wakelock_timeout", 2000);
// Whether we should play videos opened in a "video document", i.e. videos
// opened as top-level documents, as opposed to inside a media element.
pref("media.play-stand-alone", true);
pref("media.hardware-video-decoding.enabled", true);
pref("media.hardware-video-decoding.force-enabled", false);
-pref("media.decoder.heuristic.dormant.enabled", true);
-pref("media.decoder.heuristic.dormant.timeout", 10000);
-
#ifdef MOZ_DIRECTSHOW
pref("media.directshow.enabled", true);
#endif
#ifdef MOZ_FMP4
pref("media.mp4.enabled", true);
// Specifies whether the PDMFactory can create a test decoder that
#endif
// just outputs blank frames/audio instead of actually decoding. The blank
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -307,20 +307,16 @@ user_pref("browser.search.geoSpecificDef
// Make sure the self support tab doesn't hit the network.
user_pref("browser.selfsupport.url", "https://%(server)s/selfsupport-dummy/");
user_pref("media.eme.enabled", true);
user_pref("media.autoplay.enabled", true);
-#if defined(XP_WIN)
-user_pref("media.decoder.heuristic.dormant.timeout", 0);
-#endif
-
// Don't use auto-enabled e10s
user_pref("browser.tabs.remote.autostart.1", false);
user_pref("browser.tabs.remote.autostart.2", false);
// Don't show a delay when hiding the audio indicator during tests
user_pref("browser.tabs.delayHidingAudioPlayingIconMS", 0);
// Don't forceably kill content processes after a timeout
user_pref("dom.ipc.tabs.shutdownTimeoutSecs", 0);