Bug 654787 - part2: Teach ReaderProxy about audio looping; r=jwwang
MozReview-Commit-ID: FK0FRffDzjJ
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -2192,16 +2192,23 @@ DecodeMetadataState::OnMetadataRead(Meta
MOZ_ASSERT(mMaster->mDuration.Ref().isSome());
mMaster->mMetadataLoadedEvent.Notify(
Move(aMetadata.mInfo),
Move(aMetadata.mTags),
MediaDecoderEventVisibility::Observable);
+ // Check whether the media satisfies the requirement of seamless looing.
+ // (Before checking the media is audio only, we need to get metadata first.)
+ mMaster->mSeamlessLoopingAllowed = MediaPrefs::SeamlessLooping() &&
+ mMaster->HasAudio() &&
+ !mMaster->HasVideo();
+ mMaster->LoopingChanged();
+
SetState<DecodingFirstFrameState>();
}
void
MediaDecoderStateMachine::
DormantState::HandlePlayStateChanged(MediaDecoder::PlayState aPlayState)
{
if (aPlayState == MediaDecoder::PLAY_STATE_PLAYING) {
@@ -2615,16 +2622,17 @@ MediaDecoderStateMachine::MediaDecoderSt
mAudioCaptured(false),
mMinimizePreroll(aDecoder->GetMinimizePreroll()),
mSentFirstFrameLoadedEvent(false),
mVideoDecodeSuspended(false),
mVideoDecodeSuspendTimer(mTaskQueue),
mOutputStreamManager(new OutputStreamManager()),
mVideoDecodeMode(VideoDecodeMode::Normal),
mIsMSE(aDecoder->IsMSE()),
+ mSeamlessLoopingAllowed(false),
INIT_MIRROR(mBuffered, TimeIntervals()),
INIT_MIRROR(mPlayState, MediaDecoder::PLAY_STATE_LOADING),
INIT_MIRROR(mVolume, 1.0),
INIT_MIRROR(mPreservesPitch, true),
INIT_MIRROR(mLooping, false),
INIT_MIRROR(mSameOriginMedia, false),
INIT_MIRROR(mMediaPrincipalHandle, PRINCIPAL_HANDLE_NONE),
INIT_CANONICAL(mDuration, NullableTimeUnit()),
@@ -2671,16 +2679,17 @@ MediaDecoderStateMachine::Initialization
// Initialize watchers.
mWatchManager.Watch(mBuffered,
&MediaDecoderStateMachine::BufferedRangeUpdated);
mWatchManager.Watch(mVolume, &MediaDecoderStateMachine::VolumeChanged);
mWatchManager.Watch(mPreservesPitch,
&MediaDecoderStateMachine::PreservesPitchChanged);
mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::PlayStateChanged);
+ mWatchManager.Watch(mLooping, &MediaDecoderStateMachine::LoopingChanged);
MOZ_ASSERT(!mStateObj);
auto* s = new DecodeMetadataState(this);
mStateObj.reset(s);
s->Enter();
}
void
@@ -3552,16 +3561,25 @@ MediaDecoderStateMachine::SetPlaybackRat
}
void MediaDecoderStateMachine::PreservesPitchChanged()
{
MOZ_ASSERT(OnTaskQueue());
mMediaSink->SetPreservesPitch(mPreservesPitch);
}
+void
+MediaDecoderStateMachine::LoopingChanged()
+{
+ MOZ_ASSERT(OnTaskQueue());
+ if (mSeamlessLoopingAllowed) {
+ mReader->SetSeamlessLoopingEnabled(mLooping);
+ }
+}
+
TimeUnit
MediaDecoderStateMachine::AudioEndTime() const
{
MOZ_ASSERT(OnTaskQueue());
if (mMediaSink->IsStarted()) {
return mMediaSink->GetEndTime(TrackInfo::kAudioTrack);
}
return GetMediaTime();
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -353,16 +353,17 @@ protected:
void OnAudioPopped(const RefPtr<AudioData>& aSample);
void OnVideoPopped(const RefPtr<VideoData>& aSample);
void AudioAudibleChanged(bool aAudible);
void VolumeChanged();
void SetPlaybackRate(double aPlaybackRate);
void PreservesPitchChanged();
+ void LoopingChanged();
MediaQueue<AudioData>& AudioQueue() { return mAudioQueue; }
MediaQueue<VideoData>& VideoQueue() { return mVideoQueue; }
// True if we are low in decoded audio/video data.
// May not be invoked when mReader->UseBufferingHeuristics() is false.
bool HasLowDecodedData();
@@ -660,16 +661,18 @@ private:
MediaEventProducer<MediaResult> mOnPlaybackErrorEvent;
MediaEventProducer<DecoderDoctorEvent> mOnDecoderDoctorEvent;
MediaEventProducer<NextFrameStatus> mOnNextFrameStatus;
const bool mIsMSE;
+ bool mSeamlessLoopingAllowed;
+
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;
// Volume of playback. 0.0 = muted. 1.0 = full volume.
--- a/dom/media/ReaderProxy.cpp
+++ b/dom/media/ReaderProxy.cpp
@@ -14,16 +14,17 @@ namespace mozilla {
ReaderProxy::ReaderProxy(AbstractThread* aOwnerThread,
MediaFormatReader* aReader)
: mOwnerThread(aOwnerThread)
, mReader(aReader)
, mWatchManager(this, aReader->OwnerThread())
, mDuration(aReader->OwnerThread(),
media::NullableTimeUnit(),
"ReaderProxy::mDuration (Mirror)")
+ , mSeamlessLoopingEnabled(false)
{
// Must support either heuristic buffering or WaitForData().
MOZ_ASSERT(mReader->UseBufferingHeuristics() ||
mReader->IsWaitForDataSupported());
}
ReaderProxy::~ReaderProxy()
{}
@@ -213,9 +214,16 @@ ReaderProxy::SetCanonicalDuration(
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
"ReaderProxy::SetCanonicalDuration", [this, self, canonical]() {
mDuration.Connect(canonical);
mWatchManager.Watch(mDuration, &ReaderProxy::UpdateDuration);
});
mReader->OwnerThread()->Dispatch(r.forget());
}
+void
+ReaderProxy::SetSeamlessLoopingEnabled(bool aEnabled)
+{
+ MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+ mSeamlessLoopingEnabled = aEnabled;
+}
+
} // namespace mozilla
--- a/dom/media/ReaderProxy.h
+++ b/dom/media/ReaderProxy.h
@@ -79,16 +79,18 @@ public:
void SetCDMProxy(CDMProxy* aProxy) { mReader->SetCDMProxy(aProxy); }
void SetVideoBlankDecode(bool aIsBlankDecode);
void SetCanonicalDuration(
AbstractCanonical<media::NullableTimeUnit>* aCanonical);
+ void SetSeamlessLoopingEnabled(bool aEnabled);
+
private:
~ReaderProxy();
RefPtr<MetadataPromise> OnMetadataRead(MetadataHolder&& aMetadata);
RefPtr<MetadataPromise> OnMetadataNotRead(const MediaResult& aError);
void UpdateDuration();
const RefPtr<AbstractThread> mOwnerThread;
const RefPtr<MediaFormatReader> mReader;
@@ -96,13 +98,16 @@ private:
bool mShutdown = false;
Maybe<media::TimeUnit> mStartTime;
// State-watching manager.
WatchManager<ReaderProxy> mWatchManager;
// Duration, mirrored from the state machine task queue.
Mirror<media::NullableTimeUnit> mDuration;
+
+ // Indicates whether we should loop the media.
+ bool mSeamlessLoopingEnabled;
};
} // namespace mozilla
#endif // ReaderProxy_h_