Bug 1224973 - Part 3: Plumb element visibility into MDSM. r?jya, jwwang
change MediaDecoder::mIsVisible to be a Canonical<bool> and plumb through to
the MediaDecoderStateMachine. This will be used to trigger suspending the
decoding of video frames.
MozReview-Commit-ID: F3Dpf0ogE7c
--- a/dom/media/AbstractMediaDecoder.h
+++ b/dom/media/AbstractMediaDecoder.h
@@ -57,17 +57,17 @@ public:
// Can be called on any thread.
virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded,
uint32_t aDropped) = 0;
virtual AbstractCanonical<media::NullableTimeUnit>* CanonicalDurationOrNull() { return nullptr; };
// Return an event that will be notified when data arrives in MediaResource.
// MediaDecoderReader will register with this event to receive notifications
- // in order to udpate buffer ranges.
+ // in order to update buffer ranges.
// Return null if this decoder doesn't support the event.
virtual MediaEventSource<void>* DataArrivedEvent()
{
return nullptr;
}
protected:
virtual void UpdateEstimatedMediaDuration(int64_t aDuration) {};
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -330,17 +330,17 @@ MediaDecoder::UpdateDormantState(bool aD
{
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, mIsHeuristicDormant, PlayStateStr(),
+ mIsVisible.Ref(), mIsHeuristicDormant, PlayStateStr(),
(!mInfo ? "Unknown" : (mInfo->IsEncrypted() ? "1" : "0")));
bool prevDormant = mIsDormant;
mIsDormant = false;
if (!mOwner->IsActive()) {
mIsDormant = true;
}
#ifdef MOZ_WIDGET_GONK
@@ -569,17 +569,18 @@ MediaDecoder::MediaDecoder(MediaDecoderO
, mPlaybackRateReliable(AbstractThread::MainThread(), true,
"MediaDecoder::mPlaybackRateReliable (Canonical)")
, mDecoderPosition(AbstractThread::MainThread(), 0,
"MediaDecoder::mDecoderPosition (Canonical)")
, mMediaSeekable(AbstractThread::MainThread(), true,
"MediaDecoder::mMediaSeekable (Canonical)")
, mMediaSeekableOnlyInBufferedRanges(AbstractThread::MainThread(), false,
"MediaDecoder::mMediaSeekableOnlyInBufferedRanges (Canonical)")
- , mIsVisible(!mOwner->IsHidden())
+ , mIsVisible(AbstractThread::MainThread(), !mOwner->IsHidden(),
+ "MediaDecoder::mIsVisible (Canonical)")
, mTelemetryReported(false)
{
MOZ_COUNT_CTOR(MediaDecoder);
MOZ_ASSERT(NS_IsMainThread());
MediaMemoryTracker::AddMediaDecoder(this);
mAudioChannel = AudioChannelService::GetDefaultAudioChannel();
mResourceCallback->Connect(this);
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -739,17 +739,17 @@ protected:
Mirror<media::NullableTimeUnit> mStateMachineDuration;
// Current playback position in the stream. This is (approximately)
// where we're up to playing back the stream. This is not adjusted
// during decoder seek operations, but it's updated at the end when we
// start playing back again.
Mirror<int64_t> mPlaybackPosition;
- // Used to distiguish whether the audio is producing sound.
+ // Used to distinguish whether the audio is producing sound.
Mirror<bool> mIsAudioDataAudible;
// Volume of playback. 0.0 = muted. 1.0 = full volume.
Canonical<double> mVolume;
// PlaybackRate and pitch preservation status we should start at.
Canonical<double> mPlaybackRate;
@@ -801,17 +801,18 @@ protected:
Canonical<int64_t> mDecoderPosition;
// True if the media is seekable (i.e. supports random access).
Canonical<bool> mMediaSeekable;
// True if the media is only seekable within its buffered ranges.
Canonical<bool> mMediaSeekableOnlyInBufferedRanges;
- bool mIsVisible;
+ // True if the decoder is visible.
+ Canonical<bool> mIsVisible;
public:
AbstractCanonical<media::NullableTimeUnit>* CanonicalDurationOrNull() override;
AbstractCanonical<double>* CanonicalVolume() {
return &mVolume;
}
AbstractCanonical<double>* CanonicalPlaybackRate() {
return &mPlaybackRate;
@@ -850,16 +851,19 @@ public:
return &mDecoderPosition;
}
AbstractCanonical<bool>* CanonicalMediaSeekable() {
return &mMediaSeekable;
}
AbstractCanonical<bool>* CanonicalMediaSeekableOnlyInBufferedRanges() {
return &mMediaSeekableOnlyInBufferedRanges;
}
+ AbstractCanonical<bool>* CanonicalIsVisible() {
+ return &mIsVisible;
+ }
private:
// Notify owner when the audible state changed
void NotifyAudibleStateChanged();
/* Functions called by ResourceCallback */
// A media stream is assumed to be infinite if the metadata doesn't
--- a/dom/media/MediaDecoderReader.cpp
+++ b/dom/media/MediaDecoderReader.cpp
@@ -179,16 +179,20 @@ MediaDecoderReader::DecodeToFirstVideoDa
void
MediaDecoderReader::UpdateBuffered()
{
MOZ_ASSERT(OnTaskQueue());
NS_ENSURE_TRUE_VOID(!mShutdown);
mBuffered = GetBuffered();
}
+void
+MediaDecoderReader::VisibilityChanged()
+{}
+
media::TimeIntervals
MediaDecoderReader::GetBuffered()
{
MOZ_ASSERT(OnTaskQueue());
if (!HaveStartTime()) {
return media::TimeIntervals();
}
AutoPinned<MediaResource> stream(mDecoder->GetResource());
--- a/dom/media/MediaDecoderReader.h
+++ b/dom/media/MediaDecoderReader.h
@@ -390,16 +390,18 @@ private:
virtual nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
{
MOZ_CRASH();
}
// Recomputes mBuffered.
virtual void UpdateBuffered();
+ virtual void VisibilityChanged();
+
virtual void NotifyDataArrivedInternal() {}
// Overrides of this function should decodes an unspecified amount of
// audio data, enqueuing the audio data in mAudioQueue. Returns true
// when there's more audio to decode, false if the audio is finished,
// end of file has been reached, or an un-recoverable read error has
// occured. This function blocks until the decode is complete.
virtual bool DecodeAudioData()
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -272,16 +272,17 @@ MediaDecoderStateMachine::MediaDecoderSt
mPlaybackRateReliable(mTaskQueue, true,
"MediaDecoderStateMachine::mPlaybackRateReliable (Mirror)"),
mDecoderPosition(mTaskQueue, 0,
"MediaDecoderStateMachine::mDecoderPosition (Mirror)"),
mMediaSeekable(mTaskQueue, true,
"MediaDecoderStateMachine::mMediaSeekable (Mirror)"),
mMediaSeekableOnlyInBufferedRanges(mTaskQueue, false,
"MediaDecoderStateMachine::mMediaSeekableOnlyInBufferedRanges (Mirror)"),
+ mIsVisible(mTaskQueue, true, "MediaDecoderStateMachine::mIsVisible (Mirror)"),
mDuration(mTaskQueue, NullableTimeUnit(),
"MediaDecoderStateMachine::mDuration (Canonical"),
mIsShutdown(mTaskQueue, false,
"MediaDecoderStateMachine::mIsShutdown (Canonical)"),
mNextFrameStatus(mTaskQueue, MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED,
"MediaDecoderStateMachine::mNextFrameStatus (Canonical)"),
mCurrentPosition(mTaskQueue, 0,
"MediaDecoderStateMachine::mCurrentPosition (Canonical)"),
@@ -334,29 +335,31 @@ MediaDecoderStateMachine::Initialization
mPreservesPitch.Connect(aDecoder->CanonicalPreservesPitch());
mSameOriginMedia.Connect(aDecoder->CanonicalSameOriginMedia());
mMediaPrincipalHandle.Connect(aDecoder->CanonicalMediaPrincipalHandle());
mPlaybackBytesPerSecond.Connect(aDecoder->CanonicalPlaybackBytesPerSecond());
mPlaybackRateReliable.Connect(aDecoder->CanonicalPlaybackRateReliable());
mDecoderPosition.Connect(aDecoder->CanonicalDecoderPosition());
mMediaSeekable.Connect(aDecoder->CanonicalMediaSeekable());
mMediaSeekableOnlyInBufferedRanges.Connect(aDecoder->CanonicalMediaSeekableOnlyInBufferedRanges());
+ mIsVisible.Connect(aDecoder->CanonicalIsVisible());
// Initialize watchers.
mWatchManager.Watch(mBuffered, &MediaDecoderStateMachine::BufferedRangeUpdated);
mWatchManager.Watch(mState, &MediaDecoderStateMachine::UpdateNextFrameStatus);
mWatchManager.Watch(mAudioCompleted, &MediaDecoderStateMachine::UpdateNextFrameStatus);
mWatchManager.Watch(mVideoCompleted, &MediaDecoderStateMachine::UpdateNextFrameStatus);
mWatchManager.Watch(mVolume, &MediaDecoderStateMachine::VolumeChanged);
mWatchManager.Watch(mLogicalPlaybackRate, &MediaDecoderStateMachine::LogicalPlaybackRateChanged);
mWatchManager.Watch(mPreservesPitch, &MediaDecoderStateMachine::PreservesPitchChanged);
mWatchManager.Watch(mEstimatedDuration, &MediaDecoderStateMachine::RecomputeDuration);
mWatchManager.Watch(mExplicitDuration, &MediaDecoderStateMachine::RecomputeDuration);
mWatchManager.Watch(mObservedDuration, &MediaDecoderStateMachine::RecomputeDuration);
mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::PlayStateChanged);
+ mWatchManager.Watch(mIsVisible, &MediaDecoderStateMachine::VisibilityChanged);
// Configure MediaDecoderReaderWrapper.
SetMediaDecoderReaderWrapperCallback();
}
media::MediaSink*
MediaDecoderStateMachine::CreateAudioSink()
{
@@ -1321,16 +1324,21 @@ void MediaDecoderStateMachine::PlayState
// when the state machine notices the decoder's state change to PLAYING.
if (mState == DECODER_STATE_BUFFERING) {
StartDecoding();
}
ScheduleStateMachine();
}
+void MediaDecoderStateMachine::VisibilityChanged()
+{
+ DECODER_LOG("VisibilityChanged: is visible = %c", mIsVisible ? 'T' : 'F');
+}
+
void MediaDecoderStateMachine::BufferedRangeUpdated()
{
MOZ_ASSERT(OnTaskQueue());
// While playing an unseekable stream of unknown duration, mObservedDuration
// is updated (in AdvanceFrame()) as we play. But if data is being downloaded
// faster than played, mObserved won't reflect the end of playable data
// since we haven't played the frame at the end of buffered data. So update
@@ -2094,16 +2102,17 @@ MediaDecoderStateMachine::FinishShutdown
mPreservesPitch.DisconnectIfConnected();
mSameOriginMedia.DisconnectIfConnected();
mMediaPrincipalHandle.DisconnectIfConnected();
mPlaybackBytesPerSecond.DisconnectIfConnected();
mPlaybackRateReliable.DisconnectIfConnected();
mDecoderPosition.DisconnectIfConnected();
mMediaSeekable.DisconnectIfConnected();
mMediaSeekableOnlyInBufferedRanges.DisconnectIfConnected();
+ mIsVisible.DisconnectIfConnected();
mDuration.DisconnectAll();
mIsShutdown.DisconnectAll();
mNextFrameStatus.DisconnectAll();
mCurrentPosition.DisconnectAll();
mPlaybackOffset.DisconnectAll();
mIsAudioDataAudible.DisconnectAll();
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -466,16 +466,19 @@ protected:
// Create and start the media sink.
// The decoder monitor must be held with exactly one lock count.
// Called on the state machine thread.
void StartMediaSink();
// Notification method invoked when mPlayState changes.
void PlayStateChanged();
+ // Notification method invoked when mIsVisible changes.
+ void VisibilityChanged();
+
// Sets internal state which causes playback of media to pause.
// The decoder monitor must be held.
void StopPlayback();
// If the conditions are right, sets internal state which causes playback
// of media to begin or resume.
// Must be called with the decode monitor held.
void MaybeStartPlayback();
@@ -995,16 +998,19 @@ private:
Mirror<int64_t> mDecoderPosition;
// True if the media is seekable (i.e. supports random access).
Mirror<bool> mMediaSeekable;
// True if the media is seekable only in buffered ranges.
Mirror<bool> mMediaSeekableOnlyInBufferedRanges;
+ // IsVisible, mirrored from the media decoder.
+ Mirror<bool> mIsVisible;
+
// Duration of the media. This is guaranteed to be non-null after we finish
// decoding the first frame.
Canonical<media::NullableTimeUnit> mDuration;
// Whether we're currently in or transitioning to shutdown state.
Canonical<bool> mIsShutdown;
// The status of our next frame. Mirrored on the main thread and used to
@@ -1014,17 +1020,17 @@ private:
// The time of the current frame in microseconds, corresponding to the "current
// playback position" in HTML5. This is referenced from 0, which is the initial
// playback position.
Canonical<int64_t> mCurrentPosition;
// Current playback position in the stream in bytes.
Canonical<int64_t> mPlaybackOffset;
- // Used to distiguish whether the audio is producing sound.
+ // Used to distinguish whether the audio is producing sound.
Canonical<bool> mIsAudioDataAudible;
public:
AbstractCanonical<media::TimeIntervals>* CanonicalBuffered() const;
AbstractCanonical<media::NullableTimeUnit>* CanonicalDuration() {
return &mDuration;
}