Bug 1191696. Part 2 - implementation in DecodedStream. r=roc.
authorJW Wang <jwwang@mozilla.com>
Mon, 17 Aug 2015 07:52:42 +0800
changeset 257975 e44c94a159dbf8d50b52a4e2d099498e64576c8b
parent 257974 6dd75dc65de38db09c04203f906733513a688213
child 257976 a30421f03bc51317050c3970e5120ee063532436
push id29238
push userryanvm@gmail.com
push dateMon, 17 Aug 2015 13:06:57 +0000
treeherdermozilla-central@a6eeb28458fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs1191696
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 1191696. Part 2 - implementation in DecodedStream. r=roc.
dom/media/DecodedStream.cpp
--- a/dom/media/DecodedStream.cpp
+++ b/dom/media/DecodedStream.cpp
@@ -13,21 +13,25 @@
 #include "VideoSegment.h"
 #include "VideoUtils.h"
 
 namespace mozilla {
 
 class DecodedStreamGraphListener : public MediaStreamListener {
   typedef MediaStreamListener::MediaStreamGraphEvent MediaStreamGraphEvent;
 public:
-  explicit DecodedStreamGraphListener(MediaStream* aStream)
+  DecodedStreamGraphListener(MediaStream* aStream,
+                             MozPromiseHolder<GenericPromise>&& aPromise)
     : mMutex("DecodedStreamGraphListener::mMutex")
     , mStream(aStream)
     , mLastOutputTime(aStream->StreamTimeToMicroseconds(aStream->GetCurrentTime()))
-    , mStreamFinishedOnMainThread(false) {}
+    , mStreamFinishedOnMainThread(false)
+  {
+    mFinishPromise = Move(aPromise);
+  }
 
   void NotifyOutput(MediaStreamGraph* aGraph, GraphTime aCurrentTime) override
   {
     MutexAutoLock lock(mMutex);
     if (mStream) {
       mLastOutputTime = mStream->StreamTimeToMicroseconds(mStream->GraphTimeToStreamTime(aCurrentTime));
     }
   }
@@ -38,45 +42,49 @@ public:
       nsCOMPtr<nsIRunnable> event =
         NS_NewRunnableMethod(this, &DecodedStreamGraphListener::DoNotifyFinished);
       aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
     }
   }
 
   void DoNotifyFinished()
   {
+    mFinishPromise.ResolveIfExists(true, __func__);
     MutexAutoLock lock(mMutex);
     mStreamFinishedOnMainThread = true;
   }
 
   int64_t GetLastOutputTime()
   {
     MutexAutoLock lock(mMutex);
     return mLastOutputTime;
   }
 
   void Forget()
   {
     MOZ_ASSERT(NS_IsMainThread());
+    mFinishPromise.ResolveIfExists(true, __func__);
     MutexAutoLock lock(mMutex);
     mStream = nullptr;
   }
 
   bool IsFinishedOnMainThread()
   {
     MutexAutoLock lock(mMutex);
     return mStreamFinishedOnMainThread;
   }
 
 private:
   Mutex mMutex;
   // Members below are protected by mMutex.
   nsRefPtr<MediaStream> mStream;
   int64_t mLastOutputTime; // microseconds
   bool mStreamFinishedOnMainThread;
+  // Main thread only.
+  MozPromiseHolder<GenericPromise> mFinishPromise;
 };
 
 static void
 UpdateStreamBlocking(MediaStream* aStream, bool aBlocking)
 {
   int32_t delta = aBlocking ? 1 : -1;
   if (NS_IsMainThread()) {
     aStream->ChangeExplicitBlockerCount(delta);
@@ -126,31 +134,36 @@ public:
 
   // The decoder is responsible for calling Destroy() on this stream.
   const nsRefPtr<SourceMediaStream> mStream;
   nsRefPtr<DecodedStreamGraphListener> mListener;
   bool mPlaying;
   // True if we need to send a compensation video frame to ensure the
   // StreamTime going forward.
   bool mEOSVideoCompensation;
+  // This promise will be resolved when the SourceMediaStream is finished.
+  nsRefPtr<GenericPromise> mFinishPromise;
 };
 
 DecodedStreamData::DecodedStreamData(SourceMediaStream* aStream, bool aPlaying)
   : mAudioFramesWritten(0)
   , mNextVideoTime(-1)
   , mNextAudioTime(-1)
   , mStreamInitialized(false)
   , mHaveSentFinish(false)
   , mHaveSentFinishAudio(false)
   , mHaveSentFinishVideo(false)
   , mStream(aStream)
   , mPlaying(aPlaying)
   , mEOSVideoCompensation(false)
 {
-  mListener = new DecodedStreamGraphListener(mStream);
+  MozPromiseHolder<GenericPromise> promise;
+  mFinishPromise = promise.Ensure(__func__);
+  // DecodedStreamGraphListener will resolve this promise.
+  mListener = new DecodedStreamGraphListener(mStream, Move(promise));
   mStream->AddListener(mListener);
 
   // Block the stream if we are not playing.
   if (!aPlaying) {
     UpdateStreamBlocking(mStream, true);
   }
 }
 
@@ -246,18 +259,22 @@ DecodedStream::~DecodedStream()
 
 nsRefPtr<GenericPromise>
 DecodedStream::StartPlayback(int64_t aStartTime, const MediaInfo& aInfo)
 {
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   MOZ_ASSERT(mStartTime.isNothing(), "playback already started.");
   mStartTime.emplace(aStartTime);
   mInfo = aInfo;
-  // TODO: fix me in next patches.
-  return nullptr;
+
+  // TODO: Unfortunately, current call flow of MDSM guarantees mData is non-null
+  // when StartPlayback() is called which imposes an obscure dependency on MDSM.
+  // We will align the life cycle of mData with {Start,Stop}Playback so that
+  // DecodedStream doesn't need to make assumptions about mData's life cycle.
+  return mData->mFinishPromise;
 }
 
 void DecodedStream::StopPlayback()
 {
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   mStartTime.reset();
 }