Bug 1114885 - Allow media elements to be GC'd when their MediaSource is unreferenced. r=roc, a=sledru
authorKarl Tomlinson <karlt+@karlt.net>
Thu, 11 Dec 2014 16:08:20 +1300
changeset 242840 44e174f9d843
parent 242839 ad2cfe2a92a5
child 242841 08f30b223076
push id4320
push userryanvm@gmail.com
push date2015-01-14 14:48 +0000
treeherdermozilla-beta@06bb4d89e2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, sledru
bugs1114885
milestone36.0
Bug 1114885 - Allow media elements to be GC'd when their MediaSource is unreferenced. r=roc, a=sledru
dom/html/HTMLMediaElement.cpp
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -140,25 +140,32 @@ static const double THRESHOLD_LOW_PLAYBA
 // so we need to stay alive.
 // 2) If the element is not paused and playback has not ended, then
 // we will (or might) play, sending timeupdate and ended events and possibly
 // audio output, so we need to stay alive.
 // 3) if the element is seeking then we will fire seeking events and possibly
 // start playing afterward, so we need to stay alive.
 // 4) If autoplay could start playback in this element (if we got enough data),
 // then we need to stay alive.
-// 5) if the element is currently loading and not suspended,
-// script might be waiting for progress events or a 'suspend' event,
-// so we need to stay alive. If we're already suspended then (all other
-// conditions being met) it's OK to just disappear without firing any more
-// events, since we have the freedom to remain suspended indefinitely. Note
+// 5) if the element is currently loading, not suspended, and its source is
+// not a MediaSource, then script might be waiting for progress events or a
+// 'stalled' or 'suspend' event, so we need to stay alive.
+// If we're already suspended then (all other conditions being met),
+// it's OK to just disappear without firing any more events,
+// since we have the freedom to remain suspended indefinitely. Note
 // that we could use this 'suspended' loophole to garbage-collect a suspended
 // element in case 4 even if it had 'autoplay' set, but we choose not to.
 // If someone throws away all references to a loading 'autoplay' element
 // sound should still eventually play.
+// 6) If the source is a MediaSource, most loading events will not fire unless
+// appendBuffer() is called on a SourceBuffer, in which case something is
+// already referencing the SourceBuffer, which keeps the associated media
+// element alive. Further, a MediaSource will never time out the resource
+// fetch, and so should not keep the media element alive if it is
+// unreferenced. A pending 'stalled' event keeps the media element alive.
 //
 // Media elements owned by inactive documents (i.e. documents not contained in any
 // document viewer) should never hold a self-reference because none of the
 // above conditions are allowed: the element will stop loading and playing
 // and never resume loading or playing unless its owner document changes to
 // an active document (which can only happen if there is an external reference
 // to the element).
 // Media elements with no owner doc should be able to hold a self-reference.
@@ -3113,16 +3120,18 @@ void HTMLMediaElement::CheckProgress(boo
     DispatchAsyncEvent(NS_LITERAL_STRING("stalled"));
     ChangeDelayLoadStatus(false);
 
     NS_ASSERTION(mProgressTimer, "detected stalled without timer");
     // Stop timer events, which prevents repeated stalled events until there
     // is more progress.
     StopProgress();
   }
+
+  AddRemoveSelfReference();
 }
 
 /* static */
 void HTMLMediaElement::ProgressTimerCallback(nsITimer* aTimer, void* aClosure)
 {
   auto decoder = static_cast<HTMLMediaElement*>(aClosure);
   decoder->CheckProgress(false);
 }
@@ -3597,17 +3606,18 @@ void HTMLMediaElement::AddRemoveSelfRefe
   // boolean expression.
   bool needSelfReference = !mShuttingDown &&
     ownerDoc->IsActive() &&
     (mDelayingLoadEvent ||
      (!mPaused && mDecoder && !mDecoder->IsEnded()) ||
      (!mPaused && mSrcStream && !mSrcStream->IsFinished()) ||
      (mDecoder && mDecoder->IsSeeking()) ||
      CanActivateAutoplay() ||
-     mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING);
+     (mMediaSource ? mProgressTimer :
+      mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING));
 
   if (needSelfReference != mHasSelfReference) {
     mHasSelfReference = needSelfReference;
     if (needSelfReference) {
       // The observer service will hold a strong reference to us. This
       // will do to keep us alive. We need to know about shutdown so that
       // we can release our self-reference.
       nsContentUtils::RegisterShutdownObserver(this);