Bug 1371882 - MediaCacheStream::Init forwards the known content length to the MediaCache factory - r=cpearce draft
authorGerald Squelart <gsquelart@mozilla.com>
Thu, 08 Jun 2017 15:59:43 +1200
changeset 595154 09c1f126c7da491ed7db18c76fb397f7673e431c
parent 595153 b567a13c9621a8a2e3302e1844fe9be21dbf193e
child 595155 cad3880119afe6dee6e2478a1cdc8c8998815ea4
push id64265
push usergsquelart@mozilla.com
push dateFri, 16 Jun 2017 03:37:56 +0000
reviewerscpearce
bugs1371882
milestone56.0a1
Bug 1371882 - MediaCacheStream::Init forwards the known content length to the MediaCache factory - r=cpearce This will give enough information (for now) for GetMediaCache to decide whether to use the (one global shared) file-backed MediaCache, or a discrete memory- backed MediaCache. (Note that GetMediaCache doesn't use this length yet in this patch.) MozReview-Commit-ID: 5B2E3sIsc4k
dom/media/MediaCache.cpp
dom/media/MediaCache.h
dom/media/MediaResource.cpp
--- a/dom/media/MediaCache.cpp
+++ b/dom/media/MediaCache.cpp
@@ -123,19 +123,25 @@ MediaCacheFlusher::UnregisterMediaCache(
 }
 
 class MediaCache {
 public:
   friend class MediaCacheStream::BlockList;
   typedef MediaCacheStream::BlockList BlockList;
   static const int64_t BLOCK_SIZE = MediaCacheStream::BLOCK_SIZE;
 
-  // Get an instance of the file-backed MediaCache.
-  // Returns nullptr if initialization failed.
-  static MediaCache* GetMediaCache();
+  // Get an instance of a MediaCache (or nullptr if initialization failed).
+  // aContentLength is the content length if known already, otherwise -1.
+  // If the length is known and considered small enough, a discrete MediaCache
+  // with memory backing will be given. Otherwise the one MediaCache with
+  // file backing will be provided.
+  // The caller adds a reference to the MediaCache object by calling
+  // OpenStream(); and later must release it by calling ReleaseStream() and
+  // then MaybeShutdown().
+  static MediaCache* GetMediaCache(int64_t aContentLength);
 
   // Shut down the cache if it's no longer needed. We shut down
   // the cache as soon as there are no streams. This means that during
   // normal operation we are likely to start up the cache and shut it down
   // many times, but that's OK since starting it up is cheap and
   // shutting it down cleans things up and releases disk space.
   void MaybeShutdown();
 
@@ -728,17 +734,17 @@ MediaCache::ShutdownAndDestroyThis()
     mShutdownInsteadOfUpdating = true;
     return;
   }
 
   delete this;
 }
 
 /* static */ MediaCache*
-MediaCache::GetMediaCache()
+MediaCache::GetMediaCache(int64_t aContentLength)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
   if (gMediaCache) {
     return gMediaCache;
   }
 
   gMediaCache = new MediaCache();
   nsresult rv = gMediaCache->Init();
@@ -2533,25 +2539,29 @@ MediaCacheStream::ReadFromCache(char* aB
     streamOffset += bytes;
     count += bytes;
   }
 
   return NS_OK;
 }
 
 nsresult
-MediaCacheStream::Init()
+MediaCacheStream::Init(int64_t aContentLength)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   if (mMediaCache) {
     return NS_OK;
   }
 
-  mMediaCache = MediaCache::GetMediaCache();
+  if (aContentLength > 0) {
+    mStreamLength = aContentLength;
+  }
+
+  mMediaCache = MediaCache::GetMediaCache(aContentLength);
   if (!mMediaCache) {
     return NS_ERROR_FAILURE;
   }
   mMediaCache->OpenStream(this);
   return NS_OK;
 }
 
 nsresult
@@ -2559,19 +2569,22 @@ MediaCacheStream::InitAsClone(MediaCache
 {
   if (!aOriginal->IsAvailableForSharing())
     return NS_ERROR_FAILURE;
 
   if (mMediaCache) {
     return NS_OK;
   }
 
-  nsresult rv = Init();
-  if (NS_FAILED(rv))
-    return rv;
+  NS_ASSERTION(aOriginal->mMediaCache, "Don't clone an uninitialized stream");
+  // Use the same MediaCache as our clone.
+  mMediaCache = aOriginal->mMediaCache;
+
+  mMediaCache->OpenStream(this);
+
   mResourceID = aOriginal->mResourceID;
 
   // Grab cache blocks from aOriginal as readahead blocks for our stream
   ReentrantMonitorAutoEnter mon(mMediaCache->GetReentrantMonitor());
 
   mPrincipal = aOriginal->mPrincipal;
   mStreamLength = aOriginal->mStreamLength;
   mIsTransportSeekable = aOriginal->mIsTransportSeekable;
--- a/dom/media/MediaCache.h
+++ b/dom/media/MediaCache.h
@@ -193,25 +193,26 @@ public:
     MODE_PLAYBACK
   };
 
   // aClient provides the underlying transport that cache will use to read
   // data for this stream.
   MediaCacheStream(ChannelMediaResource* aClient, bool aIsPrivateBrowsing);
   ~MediaCacheStream();
 
-  // Set up this stream with the cache. Can fail on OOM. One
-  // of InitAsClone or Init must be called before any other method on
-  // this class. Does nothing if already initialized.
-  nsresult Init();
+  // Set up this stream with the cache. Can fail on OOM.
+  // aContentLength is the content length if known, otherwise -1.
+  // Exactly one of InitAsClone or Init must be called before any other method
+  // on this class. Does nothing if already initialized.
+  nsresult Init(int64_t aContentLength);
 
   // Set up this stream with the cache, assuming it's for the same data
-  // as the aOriginal stream. Can fail on OOM. Exactly one
-  // of InitAsClone or Init must be called before any other method on
-  // this class. Does nothing if already initialized.
+  // as the aOriginal stream. Can fail on OOM.
+  // Exactly one of InitAsClone or Init must be called before any other method
+  // on this class. Does nothing if already initialized.
   nsresult InitAsClone(MediaCacheStream* aOriginal);
 
   // These are called on the main thread.
   // Tell us whether the stream is seekable or not. Non-seekable streams
   // will always pass 0 for aOffset to CacheClientSeek. This should only
   // be called while the stream is at channel offset 0. Seekability can
   // change during the lifetime of the MediaCacheStream --- every time
   // we do an HTTP load the seekability may be different (and sometimes
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -527,17 +527,27 @@ ChannelMediaResource::OnDataAvailable(ns
 
   return NS_OK;
 }
 
 nsresult ChannelMediaResource::Open(nsIStreamListener **aStreamListener)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
-  nsresult rv = mCacheStream.Init();
+  int64_t cl = -1;
+  if (mChannel) {
+    nsCOMPtr<nsIHttpChannel> hc = do_QueryInterface(mChannel);
+    if (hc) {
+      if (NS_FAILED(hc->GetContentLength(&cl))) {
+        cl = -1;
+      }
+    }
+  }
+
+  nsresult rv = mCacheStream.Init(cl);
   if (NS_FAILED(rv))
     return rv;
   NS_ASSERTION(mOffset == 0, "Who set mOffset already?");
 
   if (!mChannel) {
     // When we're a clone, the decoder might ask us to Open even though
     // we haven't established an mChannel (because we might not need one)
     NS_ASSERTION(!aStreamListener,