Bug 1423465. P5 - run ComputePlaybackRate() off the main thread. draft
authorJW Wang <jwwang@mozilla.com>
Tue, 05 Dec 2017 15:21:45 +0800
changeset 708109 1ce503c3d9ef89c6250f9e6877dce3213ccb7427
parent 708108 03d4443f03a4479ff32dbc63897d84b0a2a3c1f6
child 708110 b30eea4d6dac1972a4f9cc0a6ee2275fc23965f1
push id92287
push userjwwang@mozilla.com
push dateWed, 06 Dec 2017 07:32:57 +0000
bugs1423465
milestone59.0a1
Bug 1423465. P5 - run ComputePlaybackRate() off the main thread. MozReview-Commit-ID: DhaZUVcHhiy
dom/media/ChannelMediaDecoder.cpp
dom/media/ChannelMediaDecoder.h
dom/media/MediaChannelStatistics.h
--- a/dom/media/ChannelMediaDecoder.cpp
+++ b/dom/media/ChannelMediaDecoder.cpp
@@ -271,19 +271,23 @@ ChannelMediaDecoder::NotifyDownloadEnded
   AbstractThread::AutoEnter context(AbstractMainThread());
 
   LOG("NotifyDownloadEnded, status=%" PRIx32, static_cast<uint32_t>(aStatus));
 
   MediaDecoderOwner* owner = GetOwner();
   if (NS_SUCCEEDED(aStatus) || aStatus == NS_BASE_STREAM_CLOSED) {
     nsCOMPtr<nsIRunnable> r =
       NS_NewRunnableFunction("ChannelMediaDecoder::UpdatePlaybackRate", [
-        rate = ComputePlaybackRate(),
-        res = RefPtr<BaseMediaResource>(mResource)
-      ]() { UpdatePlaybackRate(rate, res); });
+        stats = mPlaybackStatistics,
+        res = RefPtr<BaseMediaResource>(mResource),
+        duration = mDuration
+      ]() {
+        auto rate = ComputePlaybackRate(stats, res, duration);
+        UpdatePlaybackRate(rate, res);
+      });
     nsresult rv = GetStateMachine()->OwnerThread()->Dispatch(r.forget());
     MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
     owner->DownloadSuspended();
     // NotifySuspendedStatusChanged will tell the element that download
     // has been suspended "by the cache", which is true since we never
     // download anything. The element can then transition to HAVE_ENOUGH_DATA.
     owner->NotifySuspendedByCache(true);
   } else if (aStatus == NS_BINDING_ABORTED) {
@@ -340,39 +344,45 @@ void
 ChannelMediaDecoder::DurationChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
   AbstractThread::AutoEnter context(AbstractMainThread());
   MediaDecoder::DurationChanged();
   // Duration has changed so we should recompute playback rate
   nsCOMPtr<nsIRunnable> r =
     NS_NewRunnableFunction("ChannelMediaDecoder::UpdatePlaybackRate", [
-      rate = ComputePlaybackRate(),
-      res = RefPtr<BaseMediaResource>(mResource)
-    ]() { UpdatePlaybackRate(rate, res); });
+      stats = mPlaybackStatistics,
+      res = RefPtr<BaseMediaResource>(mResource),
+      duration = mDuration
+    ]() {
+      auto rate = ComputePlaybackRate(stats, res, duration);
+      UpdatePlaybackRate(rate, res);
+    });
   nsresult rv = GetStateMachine()->OwnerThread()->Dispatch(r.forget());
   MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
 }
 
 void
 ChannelMediaDecoder::DownloadProgressed()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
   AbstractThread::AutoEnter context(AbstractMainThread());
   GetOwner()->DownloadProgressed();
 
   using StatsPromise = MozPromise<MediaStatistics, bool, true>;
   InvokeAsync(GetStateMachine()->OwnerThread(),
               __func__,
               [
-                rate = ComputePlaybackRate(),
+                playbackStats = mPlaybackStatistics,
                 res = RefPtr<BaseMediaResource>(mResource),
+                duration = mDuration,
                 pos = mPlaybackPosition
               ]() {
+                auto rate = ComputePlaybackRate(playbackStats, res, duration);
                 UpdatePlaybackRate(rate, res);
                 MediaStatistics stats = GetStatistics(rate, res, pos);
                 return StatsPromise::CreateAndResolve(stats, __func__);
               })
     ->Then(
       mAbstractMainThread,
       __func__,
       [ =, self = RefPtr<ChannelMediaDecoder>(this) ](MediaStatistics aStats) {
@@ -381,29 +391,30 @@ ChannelMediaDecoder::DownloadProgressed(
         }
         mCanPlayThrough = aStats.CanPlayThrough();
         GetStateMachine()->DispatchCanPlayThrough(mCanPlayThrough);
         mResource->ThrottleReadahead(ShouldThrottleDownload(aStats));
       },
       []() { MOZ_ASSERT_UNREACHABLE("Promise not resolved"); });
 }
 
-ChannelMediaDecoder::PlaybackRateInfo
-ChannelMediaDecoder::ComputePlaybackRate()
+/* static */ ChannelMediaDecoder::PlaybackRateInfo
+ChannelMediaDecoder::ComputePlaybackRate(const MediaChannelStatistics& aStats,
+                                         BaseMediaResource* aResource,
+                                         double aDuration)
 {
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mResource);
+  MOZ_ASSERT(!NS_IsMainThread());
 
-  int64_t length = mResource->GetLength();
-  if (mozilla::IsFinite<double>(mDuration) && mDuration > 0 && length >= 0) {
-    return { uint32_t(length / mDuration), true };
+  int64_t length = aResource->GetLength();
+  if (mozilla::IsFinite<double>(aDuration) && aDuration > 0 && length >= 0) {
+    return { uint32_t(length / aDuration), true };
   }
 
   bool reliable = false;
-  uint32_t rate = mPlaybackStatistics.GetRate(&reliable);
+  uint32_t rate = aStats.GetRate(&reliable);
   return { rate, reliable };
 }
 
 /* static */ void
 ChannelMediaDecoder::UpdatePlaybackRate(const PlaybackRateInfo& aInfo,
                                         BaseMediaResource* aResource)
 {
   MOZ_ASSERT(!NS_IsMainThread());
--- a/dom/media/ChannelMediaDecoder.h
+++ b/dom/media/ChannelMediaDecoder.h
@@ -119,17 +119,20 @@ private:
   bool IsLiveStream() override final;
 
   struct PlaybackRateInfo
   {
     uint32_t mRate; // Estimate of the current playback rate (bytes/second).
     bool mReliable; // True if mRate is a reliable estimate.
   };
   // The actual playback rate computation.
-  PlaybackRateInfo ComputePlaybackRate();
+  static PlaybackRateInfo ComputePlaybackRate(
+    const MediaChannelStatistics& aStats,
+    BaseMediaResource* aResource,
+    double aDuration);
 
   // Something has changed that could affect the computed playback rate,
   // 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
--- a/dom/media/MediaChannelStatistics.h
+++ b/dom/media/MediaChannelStatistics.h
@@ -53,25 +53,27 @@ public:
   void AddBytes(int64_t aBytes) {
     if (!mIsStarted) {
       // ignore this data, it may be related to seeking or some other
       // operation we don't care about
       return;
     }
     mAccumulatedBytes += aBytes;
   }
-  double GetRateAtLastStop(bool* aReliable) {
+  double GetRateAtLastStop(bool* aReliable) const
+  {
     double seconds = mAccumulatedTime.ToSeconds();
     *aReliable = (seconds >= 1.0) ||
                  (mAccumulatedBytes >= RELIABLE_DATA_THRESHOLD);
     if (seconds <= 0.0)
       return 0.0;
     return static_cast<double>(mAccumulatedBytes)/seconds;
   }
-  double GetRate(bool* aReliable) {
+  double GetRate(bool* aReliable) const
+  {
     TimeDuration time = mAccumulatedTime;
     if (mIsStarted) {
       time += TimeStamp::Now() - mLastStartTime;
     }
     double seconds = time.ToSeconds();
     *aReliable = (seconds >= 3.0) ||
                  (mAccumulatedBytes >= RELIABLE_DATA_THRESHOLD);
     if (seconds <= 0.0)