Bug 1199121. Part 2 - handle the case where audio ends before video and switch to system clock for calculating playback position. r=kinetik.
authorJW Wang <jwwang@mozilla.com>
Mon, 07 Sep 2015 11:58:11 +0800
changeset 293809 11b926fd7b6b50df2b83adee427a86471c8c71b6
parent 293808 d71e93b86d1fc8e4ed23b2de65b7a3c5af1bec6f
child 293810 6af5de32b89b9d247aa2b30475ab782240053565
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik
bugs1199121
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1199121. Part 2 - handle the case where audio ends before video and switch to system clock for calculating playback position. r=kinetik.
dom/media/mediasink/AudioSinkWrapper.cpp
dom/media/mediasink/AudioSinkWrapper.h
--- a/dom/media/mediasink/AudioSinkWrapper.cpp
+++ b/dom/media/mediasink/AudioSinkWrapper.cpp
@@ -78,18 +78,18 @@ int64_t
 AudioSinkWrapper::GetPosition(TimeStamp* aTimeStamp) const
 {
   AssertOwnerThread();
   MOZ_ASSERT(mIsStarted, "Must be called after playback starts.");
 
   int64_t pos = -1;
   TimeStamp t = TimeStamp::Now();
 
-  if (mAudioSink) {
-    // Rely on the audio sink to report playback position when we have one.
+  if (!mAudioEnded) {
+    // 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;
   }
@@ -118,17 +118,17 @@ AudioSinkWrapper::SetVolume(double aVolu
   }
 }
 
 void
 AudioSinkWrapper::SetPlaybackRate(double aPlaybackRate)
 {
   AssertOwnerThread();
   mParams.playbackRate = aPlaybackRate;
-  if (mAudioSink) {
+  if (!mAudioEnded) {
     // Pass the playback rate to the audio sink. The underlying AudioStream
     // will handle playback rate changes and report correct audio position.
     mAudioSink->SetPlaybackRate(aPlaybackRate);
   } else if (!mPlayStartTime.IsNull()) {
     // Adjust playback duration and start time when we are still playing.
     TimeStamp now = TimeStamp::Now();
     mPlayDuration = GetVideoPosition(now);
     mPlayStartTime = now;
@@ -178,40 +178,62 @@ AudioSinkWrapper::Start(int64_t aStartTi
 {
   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();
+
   if (aInfo.HasAudio()) {
     mAudioSink = mCreator->Create();
     mEndPromise = mAudioSink->Init();
     SetPlaybackParams(mParams);
+
+    mAudioSinkPromise.Begin(mEndPromise->Then(
+      mOwnerThread.get(), __func__, this,
+      &AudioSinkWrapper::OnAudioEnded,
+      &AudioSinkWrapper::OnAudioEnded));
   }
 }
 
 void
 AudioSinkWrapper::Stop()
 {
   AssertOwnerThread();
   MOZ_ASSERT(mIsStarted, "playback not started.");
 
   mIsStarted = false;
+  mAudioEnded = true;
 
   if (mAudioSink) {
+    mAudioSinkPromise.DisconnectIfExists();
     mAudioSink->Shutdown();
     mAudioSink = nullptr;
     mEndPromise = nullptr;
   }
 }
 
 bool
 AudioSinkWrapper::IsStarted() const
 {
   AssertOwnerThread();
   return mIsStarted;
 }
 
+void
+AudioSinkWrapper::OnAudioEnded()
+{
+  AssertOwnerThread();
+  mAudioSinkPromise.Complete();
+  mPlayDuration = GetPosition();
+  if (!mPlayStartTime.IsNull()) {
+    mPlayStartTime = TimeStamp::Now();
+  }
+  mAudioEnded = true;
+}
+
 } // namespace media
 } // namespace mozilla
 
--- a/dom/media/mediasink/AudioSinkWrapper.h
+++ b/dom/media/mediasink/AudioSinkWrapper.h
@@ -48,16 +48,17 @@ class AudioSinkWrapper : public MediaSin
 public:
   template <typename Function>
   AudioSinkWrapper(AbstractThread* aOwnerThread, const Function& aFunc)
     : mOwnerThread(aOwnerThread)
     , mCreator(new CreatorImpl<Function>(aFunc))
     , mIsStarted(false)
     // Give an insane value to facilitate debug if used before playback starts.
     , mPlayDuration(INT64_MAX)
+    , mAudioEnded(true)
   {}
 
   const PlaybackParams& GetPlaybackParams() const override;
   void SetPlaybackParams(const PlaybackParams& aParams) override;
 
   nsRefPtr<GenericPromise> OnEnded(TrackType aType) override;
   int64_t GetEndTime(TrackType aType) const override;
   int64_t GetPosition(TimeStamp* aTimeStamp = nullptr) const override;
@@ -78,24 +79,29 @@ private:
   virtual ~AudioSinkWrapper();
 
   void AssertOwnerThread() const {
     MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
   }
 
   int64_t GetVideoPosition(TimeStamp aNow) const;
 
+  void OnAudioEnded();
+
   const nsRefPtr<AbstractThread> mOwnerThread;
   UniquePtr<Creator> mCreator;
   nsRefPtr<AudioSink> mAudioSink;
   nsRefPtr<GenericPromise> mEndPromise;
 
   bool mIsStarted;
   PlaybackParams mParams;
 
   TimeStamp mPlayStartTime;
   int64_t mPlayDuration;
+
+  bool mAudioEnded;
+  MozPromiseRequestHolder<GenericPromise> mAudioSinkPromise;
 };
 
 } // namespace media
 } // namespace mozilla
 
 #endif //AudioSinkWrapper_h_