Bug 1496281 - let AudioSinkWrapper decide whether we need to create AudioSink. r=jya
authoralwu <alwu@mozilla.com>
Fri, 19 Oct 2018 23:30:06 +0000
changeset 490674 f1aba3f856d0d40fd326b7238b1998c02fe8b308
parent 490673 2a0dfe99894b5e2173bd37ea01a1c7292b11e886
child 490675 cd0f7cc1cfe469231513a6fbedd263435be2f103
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersjya
bugs1496281
milestone64.0a1
Bug 1496281 - let AudioSinkWrapper decide whether we need to create AudioSink. r=jya Allow AudioSinkWrapper to access MDSM's audio queue in order to know whether the audio source ended. Differential Revision: https://phabricator.services.mozilla.com/D8031
dom/media/MediaDecoderStateMachine.cpp
dom/media/mediasink/AudioSinkWrapper.cpp
dom/media/mediasink/AudioSinkWrapper.h
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -2782,17 +2782,17 @@ MediaDecoderStateMachine::CreateAudioSin
       self->GetMediaTime(),
       self->Info().mAudio);
 
     self->mAudibleListener = audioSink->AudibleEvent().Connect(
       self->mTaskQueue, self.get(),
       &MediaDecoderStateMachine::AudioAudibleChanged);
     return audioSink;
   };
-  return new AudioSinkWrapper(mTaskQueue, audioSinkCreator);
+  return new AudioSinkWrapper(mTaskQueue, mAudioQueue, audioSinkCreator);
 }
 
 already_AddRefed<media::MediaSink>
 MediaDecoderStateMachine::CreateMediaSink(bool aAudioCaptured)
 {
   RefPtr<media::MediaSink> audioSink =
     aAudioCaptured
     ? new DecodedStream(mTaskQueue, mAbstractMainThread, mAudioQueue,
--- a/dom/media/mediasink/AudioSinkWrapper.cpp
+++ b/dom/media/mediasink/AudioSinkWrapper.cpp
@@ -81,16 +81,17 @@ AudioSinkWrapper::GetPosition(TimeStamp*
 {
   AssertOwnerThread();
   MOZ_ASSERT(mIsStarted, "Must be called after playback starts.");
 
   TimeUnit pos;
   TimeStamp t = TimeStamp::Now();
 
   if (!mAudioEnded) {
+    MOZ_ASSERT(mAudioSink);
     // Rely on the audio sink to report playback position when it is not ended.
     pos = mAudioSink->GetPosition();
   } else if (!mPlayStartTime.IsNull()) {
     // Calculate playback position using system clock if we are still playing.
     pos = GetVideoPosition(t);
   } else {
     // Return how long we've played if we are not playing.
     pos = mPlayDuration;
@@ -182,34 +183,44 @@ nsresult
 AudioSinkWrapper::Start(const TimeUnit& aStartTime, const MediaInfo& aInfo)
 {
   AssertOwnerThread();
   MOZ_ASSERT(!mIsStarted, "playback already started.");
 
   mIsStarted = true;
   mPlayDuration = aStartTime;
   mPlayStartTime = TimeStamp::Now();
-
-  // no audio is equivalent to audio ended before video starts.
-  mAudioEnded = !aInfo.HasAudio();
+  mAudioEnded = IsAudioSourceEnded(aInfo);
 
   nsresult rv = NS_OK;
-  if (aInfo.HasAudio()) {
+  if (!mAudioEnded) {
     mAudioSink.reset(mCreator->Create());
     rv = mAudioSink->Init(mParams, mEndPromise);
-
     mEndPromise->Then(
       mOwnerThread.get(), __func__, this,
       &AudioSinkWrapper::OnAudioEnded,
       &AudioSinkWrapper::OnAudioEnded
     )->Track(mAudioSinkPromise);
+  } else {
+    if (aInfo.HasAudio()) {
+      mEndPromise = GenericPromise::CreateAndResolve(true, __func__);
+    }
   }
   return rv;
 }
 
+bool
+AudioSinkWrapper::IsAudioSourceEnded(const MediaInfo& aInfo) const
+{
+  // no audio or empty audio queue which won't get data anymore is equivalent to
+  // audio ended
+  return !aInfo.HasAudio() ||
+         (mAudioQueue.IsFinished() && mAudioQueue.GetSize() == 0u);
+}
+
 void
 AudioSinkWrapper::Stop()
 {
   AssertOwnerThread();
   MOZ_ASSERT(mIsStarted, "playback not started.");
 
   mIsStarted = false;
   mAudioEnded = true;
--- a/dom/media/mediasink/AudioSinkWrapper.h
+++ b/dom/media/mediasink/AudioSinkWrapper.h
@@ -40,23 +40,26 @@ class AudioSinkWrapper : public MediaSin
     explicit CreatorImpl(const Function& aFunc) : mFunction(aFunc) {}
     AudioSink* Create() override { return mFunction(); }
   private:
     Function mFunction;
   };
 
 public:
   template <typename Function>
-  AudioSinkWrapper(AbstractThread* aOwnerThread, const Function& aFunc)
+  AudioSinkWrapper(AbstractThread* aOwnerThread,
+                   const MediaQueue<AudioData>& aAudioQueue,
+                   const Function& aFunc)
     : mOwnerThread(aOwnerThread)
     , mCreator(new CreatorImpl<Function>(aFunc))
     , mIsStarted(false)
     // Give an invalid value to facilitate debug if used before playback starts.
     , mPlayDuration(TimeUnit::Invalid())
     , mAudioEnded(true)
+    , mAudioQueue(aAudioQueue)
   {}
 
   const PlaybackParams& GetPlaybackParams() const override;
   void SetPlaybackParams(const PlaybackParams& aParams) override;
 
   RefPtr<GenericPromise> OnEnded(TrackType aType) override;
   TimeUnit GetEndTime(TrackType aType) const override;
   TimeUnit GetPosition(TimeStamp* aTimeStamp = nullptr) const override;
@@ -82,27 +85,31 @@ private:
   void AssertOwnerThread() const {
     MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
   }
 
   TimeUnit GetVideoPosition(TimeStamp aNow) const;
 
   void OnAudioEnded();
 
+  bool IsAudioSourceEnded(const MediaInfo& aInfo) const;
+
   const RefPtr<AbstractThread> mOwnerThread;
   UniquePtr<Creator> mCreator;
   UniquePtr<AudioSink> mAudioSink;
+  // Will only exist when media has an audio track.
   RefPtr<GenericPromise> mEndPromise;
 
   bool mIsStarted;
   PlaybackParams mParams;
 
   TimeStamp mPlayStartTime;
   TimeUnit mPlayDuration;
 
   bool mAudioEnded;
   MozPromiseRequestHolder<GenericPromise> mAudioSinkPromise;
+  const MediaQueue<AudioData>& mAudioQueue;
 };
 
 } // namespace media
 } // namespace mozilla
 
 #endif //AudioSinkWrapper_h_