Bug 1427699. P2 - rewrite InitAsCloneInternal() to mimic the case where data is downloaded from a channel. r=gerald
authorJW Wang <jwwang@mozilla.com>
Fri, 05 Jan 2018 16:31:39 +0800
changeset 398175 8932f0853269bfdaf7cc043ae4b1167a1cf28ad0
parent 398174 15c31a08d6e3d530c0ed84bc162f5370d2e5ce29
child 398176 856a6df2766c7e70483cd8580a6d2e0551ead4db
push id57643
push userjwwang@mozilla.com
push dateMon, 08 Jan 2018 03:05:15 +0000
treeherderautoland@8932f0853269 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgerald
bugs1427699
milestone59.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 1427699. P2 - rewrite InitAsCloneInternal() to mimic the case where data is downloaded from a channel. r=gerald Note we add mClient->CacheClientSuspend() so the network state of the element is changed to IDLE because we have no channel to fetch data initially. MozReview-Commit-ID: DgJbMxvJBzH
dom/media/ChannelMediaResource.cpp
dom/media/ChannelMediaResource.h
dom/media/MediaCache.cpp
--- a/dom/media/ChannelMediaResource.cpp
+++ b/dom/media/ChannelMediaResource.cpp
@@ -25,17 +25,17 @@ mozilla::LazyLogModule gMediaResourceLog
 namespace mozilla {
 
 ChannelMediaResource::ChannelMediaResource(MediaResourceCallback* aCallback,
                                            nsIChannel* aChannel,
                                            nsIURI* aURI,
                                            bool aIsPrivateBrowsing)
   : BaseMediaResource(aCallback, aChannel, aURI)
   , mCacheStream(this, aIsPrivateBrowsing)
-  , mSuspendAgent(mCacheStream, !aChannel /*aSuspended*/)
+  , mSuspendAgent(mCacheStream)
 {
 }
 
 ChannelMediaResource::~ChannelMediaResource()
 {
   MOZ_ASSERT(mClosed);
   MOZ_ASSERT(!mChannel);
   MOZ_ASSERT(!mListener);
--- a/dom/media/ChannelMediaResource.h
+++ b/dom/media/ChannelMediaResource.h
@@ -18,19 +18,18 @@ namespace mozilla {
 
 /**
  * This class is responsible for managing the suspend count and report suspend
  * status of channel.
  **/
 class ChannelSuspendAgent
 {
 public:
-  ChannelSuspendAgent(MediaCacheStream& aCacheStream, bool aSuspended)
+  explicit ChannelSuspendAgent(MediaCacheStream& aCacheStream)
     : mCacheStream(aCacheStream)
-    , mSuspendCount(aSuspended ? 1 : 0)
   {
   }
 
   // True when the channel has been suspended or needs to be suspended.
   bool IsSuspended();
 
   // Return true when the channel is logically suspended, i.e. the suspend
   // count goes from 0 to 1.
@@ -45,17 +44,17 @@ public:
   void Revoke();
 
 private:
   // Only suspends channel but not changes the suspend count.
   void SuspendInternal();
 
   nsIChannel* mChannel = nullptr;
   MediaCacheStream& mCacheStream;
-  uint32_t mSuspendCount;
+  uint32_t mSuspendCount = 0;
   bool mIsChannelSuspended = false;
 };
 
 DDLoggedTypeDeclNameAndBase(ChannelMediaResource, BaseMediaResource);
 
 /**
  * This is the MediaResource implementation that wraps Necko channels.
  * Much of its functionality is actually delegated to MediaCache via
--- a/dom/media/MediaCache.cpp
+++ b/dom/media/MediaCache.cpp
@@ -2869,57 +2869,42 @@ MediaCacheStream::Init(int64_t aContentL
 void
 MediaCacheStream::InitAsClone(MediaCacheStream* aOriginal)
 {
   MOZ_ASSERT(!mMediaCache, "Has been initialized.");
   MOZ_ASSERT(aOriginal->mMediaCache, "Don't clone an uninitialized stream.");
 
   // Use the same MediaCache as our clone.
   mMediaCache = aOriginal->mMediaCache;
-  // This needs to be done before OpenStream() to avoid data race.
-  mClientSuspended = true;
-  // Cloned streams are initially suspended, since there is no channel open
-  // initially for a clone.
-  mCacheSuspended = true;
-  mChannelEnded = true;
-
   OwnerThread()->Dispatch(
     NS_NewRunnableFunction("MediaCacheStream::InitAsClone", [
       this,
       aOriginal,
       r1 = RefPtr<ChannelMediaResource>(mClient),
       r2 = RefPtr<ChannelMediaResource>(aOriginal->mClient)
     ]() { InitAsCloneInternal(aOriginal); }));
 }
 
 void
 MediaCacheStream::InitAsCloneInternal(MediaCacheStream* aOriginal)
 {
   MOZ_ASSERT(OwnerThread()->IsOnCurrentThread());
-  AutoLock lock(aOriginal->mMediaCache->Monitor());
+  AutoLock lock(mMediaCache->Monitor());
 
+  // Download data and notify events if necessary. Note the order is important
+  // in order to mimic the behavior of data being downloaded from the channel.
+
+  // Step 1: copy/download data from the original stream.
   mResourceID = aOriginal->mResourceID;
-
-  // Grab cache blocks from aOriginal as readahead blocks for our stream
   mStreamLength = aOriginal->mStreamLength;
   mIsTransportSeekable = aOriginal->mIsTransportSeekable;
   mDownloadStatistics = aOriginal->mDownloadStatistics;
   mDownloadStatistics.Stop();
 
-  // Notify the client that we have new data so the decoder has a chance to
-  // compute 'canplaythrough' and buffer ranges.
-  mClient->CacheClientNotifyDataReceived();
-
-  if (aOriginal->mDidNotifyDataEnded &&
-      NS_SUCCEEDED(aOriginal->mNotifyDataEndedStatus)) {
-    mNotifyDataEndedStatus = aOriginal->mNotifyDataEndedStatus;
-    mDidNotifyDataEnded = true;
-    mClient->CacheClientNotifyDataEnded(mNotifyDataEndedStatus);
-  }
-
+  // Grab cache blocks from aOriginal as readahead blocks for our stream
   for (uint32_t i = 0; i < aOriginal->mBlocks.Length(); ++i) {
     int32_t cacheBlockIndex = aOriginal->mBlocks[i];
     if (cacheBlockIndex < 0)
       continue;
 
     while (i >= mBlocks.Length()) {
       mBlocks.AppendElement(-1);
     }
@@ -2929,18 +2914,36 @@ MediaCacheStream::InitAsCloneInternal(Me
   }
 
   // Copy the partial block.
   mChannelOffset = aOriginal->mChannelOffset;
   memcpy(mPartialBlockBuffer.get(),
          aOriginal->mPartialBlockBuffer.get(),
          BLOCK_SIZE);
 
+  // Step 2: notify the client that we have new data so the decoder has a chance
+  // to compute 'canplaythrough' and buffer ranges.
+  mClient->CacheClientNotifyDataReceived();
+
+  // Step 3: notify download ended if necessary.
+  if (aOriginal->mDidNotifyDataEnded &&
+      NS_SUCCEEDED(aOriginal->mNotifyDataEndedStatus)) {
+    mNotifyDataEndedStatus = aOriginal->mNotifyDataEndedStatus;
+    mDidNotifyDataEnded = true;
+    mClient->CacheClientNotifyDataEnded(mNotifyDataEndedStatus);
+  }
+
+  // Step 4: notify download is suspended by the cache.
+  mClientSuspended = true;
+  mCacheSuspended = true;
+  mChannelEnded = true;
+  mClient->CacheClientSuspend();
+
+  // Step 5: add the stream to be managed by the cache.
   mMediaCache->OpenStream(lock, this, true /* aIsClone */);
-
   // Wake up the reader which is waiting for the cloned data.
   lock.NotifyAll();
 }
 
 nsIEventTarget*
 MediaCacheStream::OwnerThread() const
 {
   return mMediaCache->OwnerThread();