Bug 1423465. P4 - run GetStatistics() off the main thread. draft
authorJW Wang <jwwang@mozilla.com>
Tue, 05 Dec 2017 15:06:34 +0800
changeset 708108 03d4443f03a4479ff32dbc63897d84b0a2a3c1f6
parent 708107 e0bf93d7638b741c14bb8cf91af48d678e288cb7
child 708109 1ce503c3d9ef89c6250f9e6877dce3213ccb7427
push id92287
push userjwwang@mozilla.com
push dateWed, 06 Dec 2017 07:32:57 +0000
bugs1423465
milestone59.0a1
Bug 1423465. P4 - run GetStatistics() off the main thread. Note we cache the result of GetStatistics().CanPlayThrough() which is needed by CanPlayThroughImpl(). MozReview-Commit-ID: QYNqk1pUN5
dom/media/ChannelMediaDecoder.cpp
dom/media/ChannelMediaDecoder.h
--- a/dom/media/ChannelMediaDecoder.cpp
+++ b/dom/media/ChannelMediaDecoder.cpp
@@ -293,18 +293,17 @@ ChannelMediaDecoder::NotifyDownloadEnded
     NetworkError(MediaResult(aStatus, "Download aborted"));
   }
 }
 
 bool
 ChannelMediaDecoder::CanPlayThroughImpl()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  NS_ENSURE_TRUE(GetStateMachine(), false);
-  return GetStatistics(ComputePlaybackRate()).CanPlayThrough();
+  return mCanPlayThrough;
 }
 
 bool
 ChannelMediaDecoder::IsLiveStream()
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mResource->IsLiveStream();
 }
@@ -356,28 +355,40 @@ ChannelMediaDecoder::DurationChanged()
 void
 ChannelMediaDecoder::DownloadProgressed()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   AbstractThread::AutoEnter context(AbstractMainThread());
   GetOwner()->DownloadProgressed();
 
-  auto rate = ComputePlaybackRate();
-  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
-    "ChannelMediaDecoder::UpdatePlaybackRate",
-    [ rate, res = RefPtr<BaseMediaResource>(mResource) ]() {
-      UpdatePlaybackRate(rate, res);
-    });
-  nsresult rv = GetStateMachine()->OwnerThread()->Dispatch(r.forget());
-  MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
-
-  MediaStatistics stats = GetStatistics(rate);
-  GetStateMachine()->DispatchCanPlayThrough(stats.CanPlayThrough());
-  mResource->ThrottleReadahead(ShouldThrottleDownload(stats));
+  using StatsPromise = MozPromise<MediaStatistics, bool, true>;
+  InvokeAsync(GetStateMachine()->OwnerThread(),
+              __func__,
+              [
+                rate = ComputePlaybackRate(),
+                res = RefPtr<BaseMediaResource>(mResource),
+                pos = mPlaybackPosition
+              ]() {
+                UpdatePlaybackRate(rate, res);
+                MediaStatistics stats = GetStatistics(rate, res, pos);
+                return StatsPromise::CreateAndResolve(stats, __func__);
+              })
+    ->Then(
+      mAbstractMainThread,
+      __func__,
+      [ =, self = RefPtr<ChannelMediaDecoder>(this) ](MediaStatistics aStats) {
+        if (IsShutdown()) {
+          return;
+        }
+        mCanPlayThrough = aStats.CanPlayThrough();
+        GetStateMachine()->DispatchCanPlayThrough(mCanPlayThrough);
+        mResource->ThrottleReadahead(ShouldThrottleDownload(aStats));
+      },
+      []() { MOZ_ASSERT_UNREACHABLE("Promise not resolved"); });
 }
 
 ChannelMediaDecoder::PlaybackRateInfo
 ChannelMediaDecoder::ComputePlaybackRate()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mResource);
 
@@ -406,30 +417,30 @@ ChannelMediaDecoder::UpdatePlaybackRate(
     // Set a minimum rate of 10,000 bytes per second ... sometimes we just
     // don't have good data
     rate = std::max(rate, 10000u);
   }
 
   aResource->SetPlaybackRate(rate);
 }
 
-MediaStatistics
-ChannelMediaDecoder::GetStatistics(const PlaybackRateInfo& aInfo)
+/* static */ MediaStatistics
+ChannelMediaDecoder::GetStatistics(const PlaybackRateInfo& aInfo,
+                                   BaseMediaResource* aRes,
+                                   int64_t aPlaybackPosition)
 {
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mResource);
+  MOZ_ASSERT(!NS_IsMainThread());
 
   MediaStatistics result;
-  result.mDownloadRate =
-    mResource->GetDownloadRate(&result.mDownloadRateReliable);
-  result.mDownloadPosition = mResource->GetCachedDataEnd(mPlaybackPosition);
-  result.mTotalBytes = mResource->GetLength();
+  result.mDownloadRate = aRes->GetDownloadRate(&result.mDownloadRateReliable);
+  result.mDownloadPosition = aRes->GetCachedDataEnd(aPlaybackPosition);
+  result.mTotalBytes = aRes->GetLength();
   result.mPlaybackRate = aInfo.mRate;
   result.mPlaybackRateReliable = aInfo.mReliable;
-  result.mPlaybackPosition = mPlaybackPosition;
+  result.mPlaybackPosition = aPlaybackPosition;
   return result;
 }
 
 bool
 ChannelMediaDecoder::ShouldThrottleDownload(const MediaStatistics& aStats)
 {
   // We throttle the download if either the throttle override pref is set
   // (so that we can always throttle in Firefox on mobile) or if the download
--- a/dom/media/ChannelMediaDecoder.h
+++ b/dom/media/ChannelMediaDecoder.h
@@ -130,17 +130,19 @@ private:
   // so recompute it.
   static void UpdatePlaybackRate(const PlaybackRateInfo& aInfo,
                                  BaseMediaResource* aResource);
 
   // Return statistics. This is used for progress events and other things.
   // This can be called from any thread. It's only a snapshot of the
   // current state, since other threads might be changing the state
   // at any time.
-  MediaStatistics GetStatistics(const PlaybackRateInfo& aInfo);
+  static MediaStatistics GetStatistics(const PlaybackRateInfo& aInfo,
+                                       BaseMediaResource* aRes,
+                                       int64_t aPlaybackPosition);
 
   bool ShouldThrottleDownload(const MediaStatistics& aStats);
 
   // Data needed to estimate playback data rate. The timeline used for
   // this estimate is "decode time" (where the "current time" is the
   // time of the last decoded video frame).
   MediaChannelStatistics mPlaybackStatistics;
 
@@ -148,13 +150,15 @@ private:
   // while seeking.
   bool mPinnedForSeek = false;
 
   // Current playback position in the stream. This is (approximately)
   // where we're up to playing back the stream. This is not adjusted
   // during decoder seek operations, but it's updated at the end when we
   // start playing back again.
   int64_t mPlaybackPosition = 0;
+
+  bool mCanPlayThrough = false;
 };
 
 } // namespace mozilla
 
 #endif // ChannelMediaDecoder_h_