Bug 1108960 - notify all steams for the resource ID when any stream get closed/suspended/resumed. r=roc.
authorJW Wang <jwwang@mozilla.com>
Thu, 18 Dec 2014 23:48:00 +0100
changeset 220511 cf81114dbc71e09c531b25ee7b50029e70ec1e15
parent 220510 3233b239e61d238c50f28e2949791de63ffffb9f
child 220512 c89fec9c8b5595576107737f6702e14ce41f8ff9
push id53121
push usercbook@mozilla.com
push dateFri, 19 Dec 2014 09:13:31 +0000
treeherdermozilla-inbound@cf81114dbc71 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs1108960
milestone37.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 1108960 - notify all steams for the resource ID when any stream get closed/suspended/resumed. r=roc.
dom/media/MediaCache.cpp
dom/media/MediaResource.cpp
dom/media/MediaResource.h
--- a/dom/media/MediaCache.cpp
+++ b/dom/media/MediaCache.cpp
@@ -189,16 +189,20 @@ public:
                       MediaCacheStream::ReadMode aMode, TimeStamp aNow);
   // Mark aStream as having the block, adding it as an owner.
   void AddBlockOwnerAsReadahead(int32_t aBlockIndex, MediaCacheStream* aStream,
                                 int32_t aStreamBlockIndex);
 
   // This queues a call to Update() on the main thread.
   void QueueUpdate();
 
+  // Notify all streams for the resource ID that the suspended status changed
+  // at the end of MediaCache::Update.
+  void QueueSuspendedStatusUpdate(int64_t aResourceID);
+
   // Updates the cache state asynchronously on the main thread:
   // -- try to trim the cache back to its desired size, if necessary
   // -- suspend channels that are going to read data that's lower priority
   // than anything currently cached
   // -- resume channels that are going to read data that's higher priority
   // than something currently cached
   // -- seek channels that need to seek to a new location
   void Update();
@@ -342,16 +346,18 @@ protected:
   nsRefPtr<FileBlockCache> mFileCache;
   // The list of free blocks; they are not ordered.
   BlockList       mFreeBlocks;
   // True if an event to run Update() has been queued but not processed
   bool            mUpdateQueued;
 #ifdef DEBUG
   bool            mInUpdate;
 #endif
+  // A list of resource IDs to notify about the change in suspended status.
+  nsTArray<int64_t> mSuspendedStatusToNotify;
 };
 
 NS_IMETHODIMP
 MediaCacheFlusher::Observe(nsISupports *aSubject, char const *aTopic, char16_t const *aData)
 {
   if (strcmp(aTopic, "last-pb-context-exited") == 0) {
     MediaCache::Flush();
   }
@@ -1346,34 +1352,45 @@ MediaCache::Update()
       CACHE_LOG(PR_LOG_DEBUG, ("Stream %p CacheSeek to %lld (resume=%d)", stream,
                 (long long)stream->mChannelOffset, actions[i] == SEEK_AND_RESUME));
       rv = stream->mClient->CacheClientSeek(stream->mChannelOffset,
                                             actions[i] == SEEK_AND_RESUME);
       break;
     case RESUME:
       CACHE_LOG(PR_LOG_DEBUG, ("Stream %p Resumed", stream));
       rv = stream->mClient->CacheClientResume();
+      QueueSuspendedStatusUpdate(stream->mResourceID);
       break;
     case SUSPEND:
       CACHE_LOG(PR_LOG_DEBUG, ("Stream %p Suspended", stream));
       rv = stream->mClient->CacheClientSuspend();
+      QueueSuspendedStatusUpdate(stream->mResourceID);
       break;
     default:
       rv = NS_OK;
       break;
     }
 
     if (NS_FAILED(rv)) {
       // Close the streams that failed due to error. This will cause all
       // client Read and Seek operations on those streams to fail. Blocked
       // Reads will also be woken up.
       ReentrantMonitorAutoEnter mon(mReentrantMonitor);
       stream->CloseInternal(mon);
     }
   }
+
+  // Notify streams about the suspended status changes.
+  for (uint32_t i = 0; i < mSuspendedStatusToNotify.Length(); ++i) {
+    MediaCache::ResourceStreamIterator iter(mSuspendedStatusToNotify[i]);
+    while (MediaCacheStream* stream = iter.Next()) {
+      stream->mClient->CacheClientNotifySuspendedStatusChanged();
+    }
+  }
+  mSuspendedStatusToNotify.Clear();
 }
 
 class UpdateEvent : public nsRunnable
 {
 public:
   NS_IMETHOD Run()
   {
     if (gMediaCache) {
@@ -1394,16 +1411,25 @@ MediaCache::QueueUpdate()
                "Queuing an update while we're in an update");
   if (mUpdateQueued)
     return;
   mUpdateQueued = true;
   nsCOMPtr<nsIRunnable> event = new UpdateEvent();
   NS_DispatchToMainThread(event);
 }
 
+void
+MediaCache::QueueSuspendedStatusUpdate(int64_t aResourceID)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
+  if (!mSuspendedStatusToNotify.Contains(aResourceID)) {
+    mSuspendedStatusToNotify.AppendElement(aResourceID);
+  }
+}
+
 #ifdef DEBUG_VERIFY_CACHE
 void
 MediaCache::Verify()
 {
   mReentrantMonitor.AssertCurrentThreadIn();
 
   mFreeBlocks.Verify();
   for (uint32_t i = 0; i < mStreams.Length(); ++i) {
@@ -1975,16 +2001,20 @@ MediaCacheStream::EnsureCacheUpdate()
 void
 MediaCacheStream::CloseInternal(ReentrantMonitorAutoEnter& aReentrantMonitor)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   if (mClosed)
     return;
   mClosed = true;
+  // Closing a stream will change the return value of
+  // MediaCacheStream::AreAllStreamsForResourceSuspended as well as
+  // ChannelMediaResource::IsSuspendedByCache. Let's notify it.
+  gMediaCache->QueueSuspendedStatusUpdate(mResourceID);
   gMediaCache->ReleaseStreamBlocks(this);
   // Wake up any blocked readers
   aReentrantMonitor.NotifyAll();
 }
 
 void
 MediaCacheStream::Pin()
 {
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -1004,16 +1004,23 @@ ChannelMediaResource::CacheClientNotifyD
 void
 ChannelMediaResource::CacheClientNotifyPrincipalChanged()
 {
   NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
 
   mDecoder->NotifyPrincipalChanged();
 }
 
+void
+ChannelMediaResource::CacheClientNotifySuspendedStatusChanged()
+{
+  NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
+  mDecoder->NotifySuspendedStatusChanged();
+}
+
 nsresult
 ChannelMediaResource::CacheClientSeek(int64_t aOffset, bool aResume)
 {
   NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
 
   CMLOG("CacheClientSeek requested for aOffset [%lld] for decoder [%p]",
         aOffset, mDecoder);
 
@@ -1062,27 +1069,23 @@ ChannelMediaResource::NotifyLastByteRang
   mCacheStream.NotifyDataEnded(NS_OK);
 
 }
 
 nsresult
 ChannelMediaResource::CacheClientSuspend()
 {
   Suspend(false);
-
-  mDecoder->NotifySuspendedStatusChanged();
   return NS_OK;
 }
 
 nsresult
 ChannelMediaResource::CacheClientResume()
 {
   Resume();
-
-  mDecoder->NotifySuspendedStatusChanged();
   return NS_OK;
 }
 
 int64_t
 ChannelMediaResource::GetNextCachedData(int64_t aOffset)
 {
   return mCacheStream.GetNextCachedData(aOffset);
 }
--- a/dom/media/MediaResource.h
+++ b/dom/media/MediaResource.h
@@ -533,16 +533,18 @@ public:
   // received data for the same resource.
   void CacheClientNotifyDataReceived();
   // Notify that we reached the end of the stream. This can happen even
   // if this stream didn't read any data, since another stream might have
   // received data for the same resource.
   void CacheClientNotifyDataEnded(nsresult aStatus);
   // Notify that the principal for the cached resource changed.
   void CacheClientNotifyPrincipalChanged();
+  // Notify the decoder that the cache suspended status changed.
+  void CacheClientNotifySuspendedStatusChanged();
 
   // These are called on the main thread by MediaCache. These shouldn't block,
   // but they may grab locks --- the media cache is not holding its lock
   // when these are called.
   // Start a new load at the given aOffset. The old load is cancelled
   // and no more data from the old load will be notified via
   // MediaCacheStream::NotifyDataReceived/Ended.
   // This can fail.