Skip to content

Commit

Permalink
Bug 1144486 - Use state watching machinery for mReadyState updates. r…
Browse files Browse the repository at this point in the history
…=jww
  • Loading branch information
bholley committed Apr 23, 2015
1 parent 08da945 commit 0867953
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 25 deletions.
55 changes: 37 additions & 18 deletions dom/html/HTMLMediaElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ void HTMLMediaElement::ShutdownDecoder()
RemoveMediaElementFromURITable();
NS_ASSERTION(mDecoder, "Must have decoder to shut down");
mDecoder->Shutdown();
mDecoder = nullptr;
SetDecoder(nullptr);
}

void HTMLMediaElement::AbortExistingLoads()
Expand Down Expand Up @@ -700,7 +700,7 @@ void HTMLMediaElement::AbortExistingLoads()
mPendingEncryptedInitData.mInitDatas.Clear();
#endif // MOZ_EME
mSourcePointer = nullptr;
mLastNextFrameStatus = NEXT_FRAME_UNINITIALIZED;
mNextFrameStatus = NEXT_FRAME_UNINITIALIZED;

mTags = nullptr;

Expand Down Expand Up @@ -941,13 +941,13 @@ void HTMLMediaElement::NotifyMediaStreamTracksAvailable(DOMMediaStream* aStream)

bool videoHasChanged = IsVideo() && HasVideo() != !VideoTracks()->IsEmpty();

UpdateReadyStateForData(mLastNextFrameStatus);

if (videoHasChanged) {
// We are a video element and HasVideo() changed so update the screen
// wakelock
NotifyOwnerDocumentActivityChanged();
}

mReadyStateUpdater->Notify();
}

void HTMLMediaElement::LoadFromSourceChildren()
Expand Down Expand Up @@ -2045,8 +2045,9 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
: nsGenericHTMLElement(aNodeInfo),
mCurrentLoadID(0),
mNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY),
mReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING),
mLastNextFrameStatus(NEXT_FRAME_UNINITIALIZED),
mReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING, "HTMLMediaElement::mReadyState"),
mReadyStateUpdater("HTMLMediaElement::mReadyStateUpdater"),
mNextFrameStatus(NEXT_FRAME_UNINITIALIZED, "HTMLMediaElement::mNextFrameStatus"),
mLoadWaitStatus(NOT_WAITING),
mVolume(1.0),
mPreloadAction(PRELOAD_UNDEFINED),
Expand Down Expand Up @@ -2087,7 +2088,7 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
mMediaSecurityVerified(false),
mCORSMode(CORS_NONE),
mIsEncrypted(false),
mDownloadSuspendedByCache(false),
mDownloadSuspendedByCache(false, "HTMLMediaElement::mDownloadSuspendedByCache"),
mAudioChannelFaded(false),
mPlayingThroughTheAudioChannel(false),
mDisableVideo(false),
Expand All @@ -2100,6 +2101,7 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
if (!gMediaElementEventsLog) {
gMediaElementEventsLog = PR_NewLogModule("nsMediaElementEvents");
}
EnsureStateWatchingLog();
#endif

mAudioChannel = AudioChannelService::GetDefaultAudioChannel();
Expand All @@ -2108,6 +2110,14 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo

RegisterActivityObserver();
NotifyOwnerDocumentActivityChanged();

MOZ_ASSERT(NS_IsMainThread());
mReadyStateUpdater->AddWeakCallback(this, &HTMLMediaElement::UpdateReadyStateInternal);
mReadyStateUpdater->Watch(mNextFrameStatus);
mReadyStateUpdater->Watch(mDownloadSuspendedByCache);
// Paradoxically, there is a self-edge whereby UpdateReadyStateInternal refuses
// to run until mReadyState reaches at least HAVE_METADATA by some other means.
mReadyStateUpdater->Watch(mReadyState);
}

HTMLMediaElement::~HTMLMediaElement()
Expand Down Expand Up @@ -2604,8 +2614,8 @@ HTMLMediaElement::ReportMSETelemetry()
ErrorResult ignore;
stalled = index != TimeRanges::NoIndex &&
(ranges->End(index, ignore) - t) < errorMargin;
stalled |= mLastNextFrameStatus == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING &&
mReadyState == HTMLMediaElement::HAVE_CURRENT_DATA;
stalled |= mNextFrameStatus == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING &&
mReadyState == HTMLMediaElement::HAVE_CURRENT_DATA;
if (stalled) {
state = STALLED;
}
Expand Down Expand Up @@ -2751,7 +2761,7 @@ nsresult HTMLMediaElement::InitializeDecoderForChannel(nsIChannel* aChannel,
// RtspMediaResource.
if (DecoderTraits::DecoderWaitsForOnConnected(mimeType)) {
decoder->SetResource(resource);
mDecoder = decoder;
SetDecoder(decoder);
if (aListener) {
*aListener = nullptr;
}
Expand All @@ -2777,7 +2787,7 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
mPendingEvents.Clear();
// Set mDecoder now so if methods like GetCurrentSrc get called between
// here and Load(), they work.
mDecoder = aDecoder;
SetDecoder(aDecoder);

// Tell the decoder about its MediaResource now so things like principals are
// available immediately.
Expand All @@ -2802,7 +2812,7 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,

nsresult rv = aDecoder->Load(aListener, aCloneDonor);
if (NS_FAILED(rv)) {
mDecoder = nullptr;
SetDecoder(nullptr);
LOG(PR_LOG_DEBUG, ("%p Failed to load for decoder %p", this, aDecoder));
return rv;
}
Expand Down Expand Up @@ -3213,7 +3223,7 @@ void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo,
if (!aInfo->HasVideo()) {
ResetState();
} else {
UpdateReadyStateForData(mLastNextFrameStatus);
mReadyStateUpdater->Notify();
}

if (IsVideo() && aInfo->HasVideo()) {
Expand Down Expand Up @@ -3496,7 +3506,16 @@ bool HTMLMediaElement::IsCORSSameOrigin()

void HTMLMediaElement::UpdateReadyStateForData(MediaDecoderOwner::NextFrameStatus aNextFrame)
{
mLastNextFrameStatus = aNextFrame;
mNextFrameStatus = aNextFrame;
}

void
HTMLMediaElement::UpdateReadyStateInternal()
{
if (!mDecoder && !mSrcStream) {
// Not initialized - bail out.
return;
}

if (mDecoder && mReadyState < nsIDOMHTMLMediaElement::HAVE_METADATA) {
// aNextFrame might have a next frame because the decoder can advance
Expand All @@ -3520,7 +3539,7 @@ void HTMLMediaElement::UpdateReadyStateForData(MediaDecoderOwner::NextFrameStatu
MetadataLoaded(&mediaInfo, nsAutoPtr<const MetadataTags>(nullptr));
}

if (aNextFrame == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING) {
if (mNextFrameStatus == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING) {
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
return;
}
Expand Down Expand Up @@ -3549,9 +3568,9 @@ void HTMLMediaElement::UpdateReadyStateForData(MediaDecoderOwner::NextFrameStatu
return;
}

if (aNextFrame != MediaDecoderOwner::NEXT_FRAME_AVAILABLE) {
if (mNextFrameStatus != MediaDecoderOwner::NEXT_FRAME_AVAILABLE) {
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA);
if (!mWaitingFired && aNextFrame == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING) {
if (!mWaitingFired && mNextFrameStatus == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING) {
FireTimeUpdate(false);
DispatchAsyncEvent(NS_LITERAL_STRING("waiting"));
mWaitingFired = true;
Expand Down Expand Up @@ -3870,7 +3889,7 @@ void HTMLMediaElement::UpdateMediaSize(const nsIntSize& aSize)
}

mMediaInfo.mVideo.mDisplay = aSize;
UpdateReadyStateForData(mLastNextFrameStatus);
mReadyStateUpdater->Notify();
}

void HTMLMediaElement::UpdateInitialMediaSize(const nsIntSize& aSize)
Expand Down
23 changes: 20 additions & 3 deletions dom/html/HTMLMediaElement.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#ifdef MOZ_EME
#include "mozilla/dom/MediaKeys.h"
#endif
#include "StateWatching.h"
#include "nsGkAtoms.h"

// X.h on Linux #defines CurrentTime as 0L, so we have to #undef it here.
Expand Down Expand Up @@ -647,6 +648,17 @@ class HTMLMediaElement : public nsGenericHTMLElement,
class StreamListener;
class StreamSizeListener;

void SetDecoder(MediaDecoder* aDecoder)
{
if (mDecoder) {
mReadyStateUpdater->Unwatch(mDecoder->ReadyStateWatchTarget());
}
mDecoder = aDecoder;
if (mDecoder) {
mReadyStateUpdater->Watch(mDecoder->ReadyStateWatchTarget());
}
}

virtual void GetItemValueText(DOMString& text) override;
virtual void SetItemValueText(const nsAString& text) override;

Expand Down Expand Up @@ -1013,6 +1025,9 @@ class HTMLMediaElement : public nsGenericHTMLElement,
// MediaElement doesn't yet have one then it will create it.
TextTrackManager* GetOrCreateTextTrackManager();

// Recomputes ready state and fires events as necessary based on current state.
void UpdateReadyStateInternal();

class nsAsyncEventRunner;
using nsGenericHTMLElement::DispatchEvent;
// For nsAsyncEventRunner.
Expand Down Expand Up @@ -1090,10 +1105,12 @@ class HTMLMediaElement : public nsGenericHTMLElement,
// Media loading flags. See:
// http://www.whatwg.org/specs/web-apps/current-work/#video)
nsMediaNetworkState mNetworkState;
nsMediaReadyState mReadyState;
Watchable<nsMediaReadyState> mReadyState;

WatcherHolder mReadyStateUpdater;

// Last value passed from codec or stream source to UpdateReadyStateForData.
NextFrameStatus mLastNextFrameStatus;
Watchable<NextFrameStatus> mNextFrameStatus;

enum LoadAlgorithmState {
// No load algorithm instance is waiting for a source to be added to the
Expand Down Expand Up @@ -1328,7 +1345,7 @@ class HTMLMediaElement : public nsGenericHTMLElement,
#endif // MOZ_EME

// True if the media's channel's download has been suspended.
bool mDownloadSuspendedByCache;
Watchable<bool> mDownloadSuspendedByCache;

// Audio Channel.
AudioChannel mAudioChannel;
Expand Down
9 changes: 6 additions & 3 deletions dom/media/MediaDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,7 @@ bool MediaDecoder::IsInfinite()
}

MediaDecoder::MediaDecoder() :
mReadyStateWatchTarget("MediaDecoder::mReadyStateWatchTarget"),
mDecoderPosition(0),
mPlaybackPosition(0),
mCurrentTime(0.0),
Expand All @@ -595,7 +596,7 @@ MediaDecoder::MediaDecoder() :
mMediaSeekable(true),
mSameOriginMedia(false),
mReentrantMonitor("media.decoder"),
mPlayState(PLAY_STATE_LOADING),
mPlayState(PLAY_STATE_LOADING, "MediaDecoder::mPlayState"),
mNextState(PLAY_STATE_PAUSED),
mIgnoreProgressData(false),
mInfiniteStream(false),
Expand All @@ -622,8 +623,11 @@ MediaDecoder::MediaDecoder() :
if (!gMediaDecoderLog) {
gMediaDecoderLog = PR_NewLogModule("MediaDecoder");
}
EnsureStateWatchingLog();
#endif
mAudioChannel = AudioChannelService::GetDefaultAudioChannel();

mReadyStateWatchTarget->Watch(mPlayState);
}

bool MediaDecoder::Init(MediaDecoderOwner* aOwner)
Expand Down Expand Up @@ -1140,7 +1144,6 @@ void MediaDecoder::NotifySuspendedStatusChanged()
if (mResource && mOwner) {
bool suspended = mResource->IsSuspendedByCache();
mOwner->NotifySuspendedByCache(suspended);
UpdateReadyStateForData();
}
}

Expand Down Expand Up @@ -1704,8 +1707,8 @@ void MediaDecoder::UnpinForSeek()
bool MediaDecoder::CanPlayThrough()
{
Statistics stats = GetStatistics();
NS_ENSURE_TRUE(mDecoderStateMachine, false);

NS_ASSERTION(mDecoderStateMachine, "CanPlayThrough should have state machine!");
if (mDecoderStateMachine->IsRealTime() ||
(stats.mTotalBytes < 0 && stats.mDownloadRateReliable) ||
(stats.mTotalBytes >= 0 && stats.mTotalBytes == stats.mDownloadPosition)) {
Expand Down
7 changes: 6 additions & 1 deletion dom/media/MediaDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ destroying the MediaDecoder object.
#include "mozilla/ReentrantMonitor.h"
#include "MediaStreamGraph.h"
#include "AbstractMediaDecoder.h"
#include "StateWatching.h"
#include "necko-config.h"
#ifdef MOZ_EME
#include "mozilla/CDMProxy.h"
Expand Down Expand Up @@ -1040,6 +1041,8 @@ class MediaDecoder : public nsIObserver,
GetFrameStatistics().NotifyDecodedFrames(aParsed, aDecoded, aDropped);
}

WatchTarget& ReadyStateWatchTarget() { return *mReadyStateWatchTarget; }

protected:
virtual ~MediaDecoder();
void SetStateMachineParameters();
Expand All @@ -1055,6 +1058,8 @@ class MediaDecoder : public nsIObserver,
// Return true if the decoder has reached the end of playback
bool IsEnded() const;

WatcherHolder mReadyStateWatchTarget;

/******
* The following members should be accessed with the decoder lock held.
******/
Expand Down Expand Up @@ -1137,7 +1142,7 @@ class MediaDecoder : public nsIObserver,
// OR on the main thread.
// Any change to the state on the main thread must call NotifyAll on the
// monitor so the decode thread can wake up.
PlayState mPlayState;
Watchable<PlayState> mPlayState;

// The state to change to after a seek or load operation.
// This can only be changed on the main thread while holding the decoder
Expand Down

0 comments on commit 0867953

Please sign in to comment.