Bug 1126465 - Introduce machinery to hold onto MediaPromise::Consumer references, and use it for MediaSourceReader subdecoders. r=mattwoodrow, a=sledru
authorBobby Holley <bobbyholley@gmail.com>
Thu, 29 Jan 2015 22:11:11 -0800
changeset 243643 54d7f88c8b75
parent 243642 6e44bfd1e0f8
child 243644 29c741d65b11
push id4421
push userryanvm@gmail.com
push date2015-02-02 19:52 +0000
treeherdermozilla-beta@08a02585bc60 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow, sledru
bugs1126465
milestone36.0
Bug 1126465 - Introduce machinery to hold onto MediaPromise::Consumer references, and use it for MediaSourceReader subdecoders. r=mattwoodrow, a=sledru
dom/media/MediaPromise.h
dom/media/mediasource/MediaSourceReader.cpp
dom/media/mediasource/MediaSourceReader.h
--- a/dom/media/MediaPromise.h
+++ b/dom/media/MediaPromise.h
@@ -248,31 +248,43 @@ protected:
     nsRefPtr<ThisType> mThisVal;
     ResolveMethodType mResolveMethod;
     RejectMethodType mRejectMethod;
   };
 public:
 
   template<typename TargetType, typename ThisType,
            typename ResolveMethodType, typename RejectMethodType>
-  void Then(TargetType* aResponseTarget, const char* aCallSite, ThisType* aThisVal,
-            ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod)
+  already_AddRefed<Consumer> RefableThen(TargetType* aResponseTarget, const char* aCallSite, ThisType* aThisVal,
+                                         ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod)
   {
     MutexAutoLock lock(mMutex);
     nsRefPtr<ThenValueBase> thenValue = new ThenValue<TargetType, ThisType, ResolveMethodType,
                                                       RejectMethodType>(aResponseTarget, aThisVal,
                                                                         aResolveMethod, aRejectMethod,
                                                                         aCallSite);
     PROMISE_LOG("%s invoking Then() [this=%p, thenValue=%p, aThisVal=%p, isPending=%d]",
                 aCallSite, this, thenValue.get(), aThisVal, (int) IsPending());
     if (!IsPending()) {
       thenValue->Dispatch(this);
     } else {
       mThenValues.AppendElement(thenValue);
     }
+
+    return thenValue.forget();
+  }
+
+  template<typename TargetType, typename ThisType,
+           typename ResolveMethodType, typename RejectMethodType>
+  void Then(TargetType* aResponseTarget, const char* aCallSite, ThisType* aThisVal,
+            ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod)
+  {
+    nsRefPtr<Consumer> c =
+      RefableThen(aResponseTarget, aCallSite, aThisVal, aResolveMethod, aRejectMethod);
+    return;
   }
 
   void ChainTo(already_AddRefed<MediaPromise> aChainedPromise, const char* aCallSite)
   {
     MutexAutoLock lock(mMutex);
     nsRefPtr<MediaPromise> chainedPromise = aChainedPromise;
     PROMISE_LOG("%s invoking Chain() [this=%p, chainedPromise=%p, isPending=%d]",
                 aCallSite, this, chainedPromise.get(), (int) IsPending());
@@ -427,13 +439,42 @@ public:
     }
   }
 
 private:
   Monitor* mMonitor;
   nsRefPtr<PromiseType> mPromise;
 };
 
+/*
+ * Class to encapsulate a MediaPromise::Consumer reference. Use this as the member
+ * variable for a class waiting on a media promise.
+ */
+template<typename PromiseType>
+class MediaPromiseConsumerHolder
+{
+public:
+  MediaPromiseConsumerHolder() {}
+  ~MediaPromiseConsumerHolder() { MOZ_ASSERT(!mConsumer); }
+
+  void Begin(already_AddRefed<typename PromiseType::Consumer> aConsumer)
+  {
+    MOZ_RELEASE_ASSERT(!Exists());
+    mConsumer = aConsumer;
+  }
+
+  void Complete()
+  {
+    MOZ_RELEASE_ASSERT(Exists());
+    mConsumer = nullptr;
+  }
+
+  bool Exists() { return !!mConsumer; }
+
+private:
+  nsRefPtr<typename PromiseType::Consumer> mConsumer;
+};
+
 #undef PROMISE_LOG
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/mediasource/MediaSourceReader.cpp
+++ b/dom/media/mediasource/MediaSourceReader.cpp
@@ -144,39 +144,43 @@ MediaSourceReader::RequestAudioData()
       break;
   }
   return p;
 }
 
 void
 MediaSourceReader::RequestAudioDataComplete(int64_t aTime)
 {
-  mAudioReader->RequestAudioData()->Then(GetTaskQueue(), __func__, this,
-                                         &MediaSourceReader::OnAudioDecoded,
-                                         &MediaSourceReader::OnAudioNotDecoded);
+  mAudioRequest.Begin(mAudioReader->RequestAudioData()
+                      ->RefableThen(GetTaskQueue(), __func__, this,
+                                    &MediaSourceReader::OnAudioDecoded,
+                                    &MediaSourceReader::OnAudioNotDecoded));
 }
 
 void
 MediaSourceReader::RequestAudioDataFailed(nsresult aResult)
 {
   mAudioPromise.Reject(DECODE_ERROR, __func__);
 }
 
 void
 MediaSourceReader::OnAudioDecoded(AudioData* aSample)
 {
+  mAudioRequest.Complete();
+
   MSE_DEBUGV("MediaSourceReader(%p)::OnAudioDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
              this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
   if (mDropAudioBeforeThreshold) {
     if (aSample->mTime < mTimeThreshold) {
       MSE_DEBUG("MediaSourceReader(%p)::OnAudioDecoded mTime=%lld < mTimeThreshold=%lld",
                 this, aSample->mTime, mTimeThreshold);
-      mAudioReader->RequestAudioData()->Then(GetTaskQueue(), __func__, this,
-                                             &MediaSourceReader::OnAudioDecoded,
-                                             &MediaSourceReader::OnAudioNotDecoded);
+      mAudioRequest.Begin(mAudioReader->RequestAudioData()
+                          ->RefableThen(GetTaskQueue(), __func__, this,
+                                        &MediaSourceReader::OnAudioDecoded,
+                                        &MediaSourceReader::OnAudioNotDecoded));
       return;
     }
     mDropAudioBeforeThreshold = false;
   }
 
   // Any OnAudioDecoded callbacks received while mAudioIsSeeking must be not
   // update our last used timestamp, as these are emitted by the reader we're
   // switching away from.
@@ -211,16 +215,18 @@ AdjustEndTime(int64_t* aEndTime, MediaDe
       *aEndTime = std::max(*aEndTime, end);
     }
   }
 }
 
 void
 MediaSourceReader::OnAudioNotDecoded(NotDecodedReason aReason)
 {
+  mAudioRequest.Complete();
+
   MSE_DEBUG("MediaSourceReader(%p)::OnAudioNotDecoded aReason=%u IsEnded: %d", this, aReason, IsEnded());
   if (aReason == DECODE_ERROR || aReason == CANCELED) {
     mAudioPromise.Reject(aReason, __func__);
     return;
   }
 
   // End of stream. Force switching past this stream to another reader by
   // switching to the end of the buffered range.
@@ -273,51 +279,56 @@ MediaSourceReader::RequestVideoData(bool
       break;
     case READER_ERROR:
       if (mLastVideoTime) {
         CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA, mLastVideoTime);
         break;
       }
       // Fallback to using current reader.
     default:
-      mVideoReader->RequestVideoData(aSkipToNextKeyframe, aTimeThreshold)
-                  ->Then(GetTaskQueue(), __func__, this,
-                         &MediaSourceReader::OnVideoDecoded, &MediaSourceReader::OnVideoNotDecoded);
+      mVideoRequest.Begin(mVideoReader->RequestVideoData(aSkipToNextKeyframe, aTimeThreshold)
+                          ->RefableThen(GetTaskQueue(), __func__, this,
+                                        &MediaSourceReader::OnVideoDecoded,
+                                        &MediaSourceReader::OnVideoNotDecoded));
       break;
   }
 
   return p;
 }
 
 void
 MediaSourceReader::RequestVideoDataComplete(int64_t aTime)
 {
-  mVideoReader->RequestVideoData(false, 0)
-              ->Then(GetTaskQueue(), __func__, this,
-                     &MediaSourceReader::OnVideoDecoded, &MediaSourceReader::OnVideoNotDecoded);
+  mVideoRequest.Begin(mVideoReader->RequestVideoData(false, 0)
+                      ->RefableThen(GetTaskQueue(), __func__, this,
+                                    &MediaSourceReader::OnVideoDecoded,
+                                    &MediaSourceReader::OnVideoNotDecoded));
 }
 
 void
 MediaSourceReader::RequestVideoDataFailed(nsresult aResult)
 {
   mVideoPromise.Reject(DECODE_ERROR, __func__);
 }
 
 void
 MediaSourceReader::OnVideoDecoded(VideoData* aSample)
 {
+  mVideoRequest.Complete();
+
   MSE_DEBUGV("MediaSourceReader(%p)::OnVideoDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
              this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
   if (mDropVideoBeforeThreshold) {
     if (aSample->mTime < mTimeThreshold) {
       MSE_DEBUG("MediaSourceReader(%p)::OnVideoDecoded mTime=%lld < mTimeThreshold=%lld",
                 this, aSample->mTime, mTimeThreshold);
-      mVideoReader->RequestVideoData(false, 0)->Then(GetTaskQueue(), __func__, this,
-                                                     &MediaSourceReader::OnVideoDecoded,
-                                                     &MediaSourceReader::OnVideoNotDecoded);
+      mVideoRequest.Begin(mVideoReader->RequestVideoData(false, 0)
+                          ->RefableThen(GetTaskQueue(), __func__, this,
+                                        &MediaSourceReader::OnVideoDecoded,
+                                        &MediaSourceReader::OnVideoNotDecoded));
       return;
     }
     mDropVideoBeforeThreshold = false;
   }
 
   // Any OnVideoDecoded callbacks received while mVideoIsSeeking must be not
   // update our last used timestamp, as these are emitted by the reader we're
   // switching away from.
@@ -326,16 +337,18 @@ MediaSourceReader::OnVideoDecoded(VideoD
   }
 
   mVideoPromise.Resolve(aSample, __func__);
 }
 
 void
 MediaSourceReader::OnVideoNotDecoded(NotDecodedReason aReason)
 {
+  mVideoRequest.Complete();
+
   MSE_DEBUG("MediaSourceReader(%p)::OnVideoNotDecoded aReason=%u IsEnded: %d", this, aReason, IsEnded());
   if (aReason == DECODE_ERROR || aReason == CANCELED) {
     mVideoPromise.Reject(aReason, __func__);
     return;
   }
 
   // End of stream. Force switching past this stream to another reader by
   // switching to the end of the buffered range.
--- a/dom/media/mediasource/MediaSourceReader.h
+++ b/dom/media/mediasource/MediaSourceReader.h
@@ -181,16 +181,19 @@ private:
   nsRefPtr<MediaDecoderReader> mVideoReader;
 
   nsTArray<nsRefPtr<TrackBuffer>> mTrackBuffers;
   nsTArray<nsRefPtr<TrackBuffer>> mShutdownTrackBuffers;
   nsTArray<nsRefPtr<TrackBuffer>> mEssentialTrackBuffers;
   nsRefPtr<TrackBuffer> mAudioTrack;
   nsRefPtr<TrackBuffer> mVideoTrack;
 
+  MediaPromiseConsumerHolder<AudioDataPromise> mAudioRequest;
+  MediaPromiseConsumerHolder<VideoDataPromise> mVideoRequest;
+
   MediaPromiseHolder<AudioDataPromise> mAudioPromise;
   MediaPromiseHolder<VideoDataPromise> mVideoPromise;
 
   MediaPromiseHolder<WaitForDataPromise> mAudioWaitPromise;
   MediaPromiseHolder<WaitForDataPromise> mVideoWaitPromise;
   MediaPromiseHolder<WaitForDataPromise>& WaitPromise(MediaData::Type aType)
   {
     return aType == MediaData::AUDIO_DATA ? mAudioWaitPromise : mVideoWaitPromise;