Bug 703379. Fire CacheClientNotifyDataEnded when we clone a decoder which has already reached the end of the download. r=doublec
authorRobert O'Callahan <robert@ocallahan.org>
Thu, 24 Nov 2011 12:05:12 +1300
changeset 82352 3ea9c865650099135c5af99107c5994bf48eae94
parent 82351 0e96c5b621152d9c0f1f662ffc42f01e0bdeeb77
child 82353 ea58921ed9eabd2fdffed87f66a0072a265f3b66
push idunknown
push userunknown
push dateunknown
reviewersdoublec
bugs703379
milestone11.0a1
Bug 703379. Fire CacheClientNotifyDataEnded when we clone a decoder which has already reached the end of the download. r=doublec
content/media/nsMediaCache.cpp
content/media/nsMediaCache.h
--- a/content/media/nsMediaCache.cpp
+++ b/content/media/nsMediaCache.cpp
@@ -1834,23 +1834,28 @@ nsMediaCacheStream::NotifyDataEnded(nsre
     memset(reinterpret_cast<char*>(mPartialBlockBuffer) + blockOffset, 0,
            BLOCK_SIZE - blockOffset);
     gMediaCache->AllocateAndWriteBlock(this, mPartialBlockBuffer,
         mMetadataInPartialBlockBuffer ? MODE_METADATA : MODE_PLAYBACK);
     // Wake up readers who may be waiting for this data
     mon.NotifyAll();
   }
 
-  nsMediaCache::ResourceStreamIterator iter(mResourceID);
-  while (nsMediaCacheStream* stream = iter.Next()) {
-    if (NS_SUCCEEDED(aStatus)) {
-      // We read the whole stream, so remember the true length
-      stream->mStreamLength = mChannelOffset;
+  if (!mDidNotifyDataEnded) {
+    nsMediaCache::ResourceStreamIterator iter(mResourceID);
+    while (nsMediaCacheStream* stream = iter.Next()) {
+      if (NS_SUCCEEDED(aStatus)) {
+        // We read the whole stream, so remember the true length
+        stream->mStreamLength = mChannelOffset;
+      }
+      NS_ASSERTION(!stream->mDidNotifyDataEnded, "Stream already ended!");
+      stream->mDidNotifyDataEnded = true;
+      stream->mNotifyDataEndedStatus = aStatus;
+      stream->mClient->CacheClientNotifyDataEnded(aStatus);
     }
-    stream->mClient->CacheClientNotifyDataEnded(aStatus);
   }
 }
 
 nsMediaCacheStream::~nsMediaCacheStream()
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
   NS_ASSERTION(!mPinCount, "Unbalanced Pin");
 
@@ -2281,16 +2286,22 @@ nsMediaCacheStream::InitAsClone(nsMediaC
   mPrincipal = aOriginal->mPrincipal;
   mStreamLength = aOriginal->mStreamLength;
   mIsSeekable = aOriginal->mIsSeekable;
 
   // Cloned streams are initially suspended, since there is no channel open
   // initially for a clone.
   mCacheSuspended = true;
 
+  if (aOriginal->mDidNotifyDataEnded) {
+    mNotifyDataEndedStatus = aOriginal->mNotifyDataEndedStatus;
+    mDidNotifyDataEnded = true;
+    mClient->CacheClientNotifyDataEnded(mNotifyDataEndedStatus);
+  }
+
   for (PRUint32 i = 0; i < aOriginal->mBlocks.Length(); ++i) {
     PRInt32 cacheBlockIndex = aOriginal->mBlocks[i];
     if (cacheBlockIndex < 0)
       continue;
 
     while (i >= mBlocks.Length()) {
       mBlocks.AppendElement(-1);
     }
--- a/content/media/nsMediaCache.h
+++ b/content/media/nsMediaCache.h
@@ -223,16 +223,17 @@ public:
     MODE_PLAYBACK
   };
 
   // aClient provides the underlying transport that cache will use to read
   // data for this stream.
   nsMediaCacheStream(nsMediaChannelStream* aClient)
     : mClient(aClient), mResourceID(0), mInitialized(false),
       mIsSeekable(false), mCacheSuspended(false),
+      mDidNotifyDataEnded(false),
       mUsingNullPrincipal(false),
       mChannelOffset(0), mStreamLength(-1),  
       mStreamOffset(0), mPlaybackBytesPerSecond(10000),
       mPinCount(0), mCurrentMode(MODE_PLAYBACK),
       mMetadataInPartialBlockBuffer(false),
       mClosed(false) {}
   ~nsMediaCacheStream();
 
@@ -451,16 +452,18 @@ private:
   // only written on the main thread. 
 
   // The last reported seekability state for the underlying channel
   bool mIsSeekable;
   // True if the cache has suspended our channel because the cache is
   // full and the priority of the data that would be received is lower
   // than the priority of the data already in the cache
   bool mCacheSuspended;
+  // True if CacheClientNotifyDataEnded has been called for this stream.
+  bool mDidNotifyDataEnded;
   // True if mPrincipal is a null principal because we saw data from
   // multiple origins
   bool mUsingNullPrincipal;
   // The offset where the next data from the channel will arrive
   PRInt64      mChannelOffset;
   // The reported or discovered length of the data, or -1 if nothing is
   // known
   PRInt64      mStreamLength;
@@ -481,16 +484,18 @@ private:
   BlockList         mMetadataBlocks;
   // The list of played-back blocks; the first block is the most recently used
   BlockList         mPlayedBlocks;
   // The last reported estimate of the decoder's playback rate
   PRUint32          mPlaybackBytesPerSecond;
   // The number of times this stream has been Pinned without a
   // corresponding Unpin
   PRUint32          mPinCount;
+  // The status used when we did CacheClientNotifyDataEnded
+  nsresult          mNotifyDataEndedStatus;
   // The last reported read mode
   ReadMode          mCurrentMode;
   // True if some data in mPartialBlockBuffer has been read as metadata
   bool              mMetadataInPartialBlockBuffer;
   // Set to true when the stream has been closed either explicitly or
   // due to an internal cache error
   bool              mClosed;