Bug 654787 - part2: Teach ReaderProxy about audio looping; r=jwwang draft
authorChun-Min Chang <chun.m.chang@gmail.com>
Fri, 10 Nov 2017 12:06:12 +0800
changeset 700494 585b059edf909fbb63c5476a55e6521b310cdc47
parent 700493 529978ef39fe46f1e95fbcb78c56027aaa33e9de
child 700495 7626916ad223574ea757a9c87d6e31950e07ef8f
push id89865
push userbmo:cchang@mozilla.com
push dateMon, 20 Nov 2017 09:20:49 +0000
reviewersjwwang
bugs654787
milestone59.0a1
Bug 654787 - part2: Teach ReaderProxy about audio looping; r=jwwang MozReview-Commit-ID: FK0FRffDzjJ
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
dom/media/ReaderProxy.cpp
dom/media/ReaderProxy.h
--- 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_