Bug 1108838 - Move stalled/progress timing from MediaDecoder to HTMLMediaElement. r=cpearce, a=sledru
authorKarl Tomlinson <karlt+@karlt.net>
Wed, 14 Jan 2015 00:35:00 -0500
changeset 242830 15e3be526862
parent 242825 93587eeda731
child 242831 b07f9144d190
push id4319
push userryanvm@gmail.com
push date2015-01-14 14:36 +0000
treeherdermozilla-beta@f6d5f2303fea [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce, sledru
bugs1108838
milestone36.0
Bug 1108838 - Move stalled/progress timing from MediaDecoder to HTMLMediaElement. r=cpearce, a=sledru This provides that mNetworkState is available for determining whether progress notification from the resource/MediaCache after stalled should resume progress events. The timer will be stopped while stalled in a subsequent patch, and should not be restarted unless NETWORK_LOADING. --HG-- extra : rebase_source : e335555de404f6a899762be3c05b8f5444c357e3 Conflicts in dom/media/MediaDecoder.cpp resolved manually.
dom/html/HTMLMediaElement.cpp
dom/html/HTMLMediaElement.h
dom/media/MediaDecoder.cpp
dom/media/MediaDecoder.h
dom/media/MediaDecoderOwner.h
dom/media/MediaResource.cpp
dom/media/RtspMediaResource.cpp
dom/media/gtest/MockMediaDecoderOwner.h
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -106,16 +106,22 @@ static PRLogModuleInfo* gMediaElementEve
 #include "nsContentTypeParser.h"
 
 using namespace mozilla::layers;
 using mozilla::net::nsMediaFragmentURIParser;
 
 namespace mozilla {
 namespace dom {
 
+// Number of milliseconds between progress events as defined by spec
+static const uint32_t PROGRESS_MS = 350;
+
+// Number of milliseconds of no data before a stall event is fired as defined by spec
+static const uint32_t STALL_MS = 3000;
+
 // Used by AudioChannel for suppresssing the volume to this ratio.
 #define FADED_VOLUME_RATIO 0.25
 
 // These constants are arbitrary
 // Minimum playbackRate for a media
 static const double MIN_PLAYBACKRATE = 0.25;
 // Maximum playbackRate for a media
 static const double MAX_PLAYBACKRATE = 5.0;
@@ -2048,16 +2054,19 @@ HTMLMediaElement::~HTMLMediaElement()
 
   if (mVideoFrameContainer) {
     mVideoFrameContainer->ForgetElement();
   }
   UnregisterActivityObserver();
   if (mDecoder) {
     ShutdownDecoder();
   }
+  if (mProgressTimer) {
+    StopProgress();
+  }
   if (mSrcStream) {
     EndSrcMediaStreamPlayback();
   }
   if (mMediaSource) {
     mMediaSource->Detach();
     mMediaSource = nullptr;
   }
 
@@ -2639,18 +2648,16 @@ nsresult HTMLMediaElement::FinishDecoder
   // Tell the decoder about its MediaResource now so things like principals are
   // available immediately.
   mDecoder->SetResource(aStream);
   mDecoder->SetAudioChannel(mAudioChannel);
   mDecoder->SetAudioCaptured(mAudioCaptured);
   mDecoder->SetVolume(mMuted ? 0.0 : mVolume);
   mDecoder->SetPreservesPitch(mPreservesPitch);
   mDecoder->SetPlaybackRate(mPlaybackRate);
-  // Start progress timer for we are in NETWORK_LOADING.
-  mDecoder->StartProgress();
 
 #ifdef MOZ_EME
   if (mMediaKeys) {
     mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
   }
 #endif
   if (mPreloadAction == HTMLMediaElement::PRELOAD_METADATA) {
     mDecoder->SetMinimizePrerollUntilPlaybackStarts();
@@ -3048,43 +3055,107 @@ void HTMLMediaElement::SeekCompleted()
 
 void HTMLMediaElement::NotifySuspendedByCache(bool aIsSuspended)
 {
   mDownloadSuspendedByCache = aIsSuspended;
 }
 
 void HTMLMediaElement::DownloadSuspended()
 {
-  DownloadProgressed();
+  if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
+    DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
+  }
   if (mBegun) {
     ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
     AddRemoveSelfReference();
   }
 }
 
 void HTMLMediaElement::DownloadResumed(bool aForceNetworkLoading)
 {
   if (mBegun || aForceNetworkLoading) {
     ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_LOADING);
     AddRemoveSelfReference();
   }
 }
 
-void HTMLMediaElement::DownloadProgressed()
+void HTMLMediaElement::CheckProgress(bool aHaveNewProgress)
 {
-  if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING);
+
+  TimeStamp now = TimeStamp::NowLoRes();
+
+  if (aHaveNewProgress) {
+    mDataTime = now;
+  }
+
+  // If this is the first progress, or PROGRESS_MS has passed since the last
+  // progress event fired and more data has arrived since then, fire a
+  // progress event.
+  if (!mDataTime.IsNull() &&
+      (mProgressTime.IsNull() ||
+       (now - mProgressTime >= TimeDuration::FromMilliseconds(PROGRESS_MS) &&
+        mDataTime > mProgressTime))) {
     DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
+    // Resolution() ensures that future data will have now > mProgressTime,
+    // and so will trigger another event.  mDataTime is not reset because it
+    // is still required to detect stalled; it is similarly offset by
+    // resolution to indicate the new data has not yet arrived.
+    mProgressTime = now - TimeDuration::Resolution();
+    if (mDataTime > mProgressTime) {
+      mDataTime = mProgressTime;
+    }
+  }
+
+  if (!mDataTime.IsNull() &&
+      now - mDataTime >= TimeDuration::FromMilliseconds(STALL_MS)) {
+    DispatchAsyncEvent(NS_LITERAL_STRING("stalled"));
+    // Null it out
+    mDataTime = TimeStamp();
   }
 }
 
-void HTMLMediaElement::DownloadStalled()
+/* static */
+void HTMLMediaElement::ProgressTimerCallback(nsITimer* aTimer, void* aClosure)
+{
+  auto decoder = static_cast<HTMLMediaElement*>(aClosure);
+  decoder->CheckProgress(false);
+}
+
+nsresult HTMLMediaElement::StartProgress()
 {
-  if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
-    DispatchAsyncEvent(NS_LITERAL_STRING("stalled"));
-  }
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING);
+  NS_ASSERTION(!mProgressTimer, "Already started progress timer.");
+
+  mProgressTimer = do_CreateInstance("@mozilla.org/timer;1");
+  return mProgressTimer->InitWithFuncCallback(ProgressTimerCallback,
+                                              this,
+                                              PROGRESS_MS,
+                                              nsITimer::TYPE_REPEATING_SLACK);
+}
+
+nsresult HTMLMediaElement::StopProgress()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  NS_ASSERTION(mProgressTimer, "Already stopped progress timer.");
+
+  nsresult rv = mProgressTimer->Cancel();
+  mProgressTimer = nullptr;
+
+  return rv;
+}
+
+void HTMLMediaElement::DownloadProgressed()
+{
+  if (mNetworkState != nsIDOMHTMLMediaElement::NETWORK_LOADING) {
+    return;
+  }
+  CheckProgress(true);
 }
 
 bool HTMLMediaElement::ShouldCheckAllowOrigin()
 {
   return mCORSMode != CORS_NONE;
 }
 
 void HTMLMediaElement::UpdateReadyStateForData(MediaDecoderOwner::NextFrameStatus aNextFrame)
@@ -3226,29 +3297,25 @@ void HTMLMediaElement::ChangeNetworkStat
   LOG(PR_LOG_DEBUG, ("%p Network state changed to %s", this, gNetworkStateToString[aState]));
 
   // TODO: |mBegun| reflects the download status. We should be able to remove
   // it and check |mNetworkState| only.
 
   if (oldState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
     // Reset |mBegun| since we're not downloading anymore.
     mBegun = false;
-    if (mDecoder) {
-      // Stop progress notification when exiting NETWORK_LOADING.
-      mDecoder->StopProgress();
-    }
+    // Stop progress notification when exiting NETWORK_LOADING.
+    StopProgress();
   }
 
   if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
     // Download is begun.
     mBegun = true;
-    if (mDecoder) {
-      // Start progress notification when entering NETWORK_LOADING.
-      mDecoder->StartProgress();
-    }
+    // Start progress notification when entering NETWORK_LOADING.
+    StartProgress();
   } else if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_IDLE && !mError) {
     // Fire 'suspend' event when entering NETWORK_IDLE and no error presented.
     DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
   }
 }
 
 bool HTMLMediaElement::CanActivateAutoplay()
 {
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -202,20 +202,16 @@ public:
   // previously finished. We are downloading the middle of the media after
   // having downloaded the end, we need to notify the element a download in
   // ongoing.
   virtual void DownloadResumed(bool aForceNetworkLoading = false) MOZ_FINAL MOZ_OVERRIDE;
 
   // Called to indicate the download is progressing.
   virtual void DownloadProgressed() MOZ_FINAL MOZ_OVERRIDE;
 
-  // Called by the media decoder to indicate that the download has stalled
-  // (no data has arrived for a while).
-  virtual void DownloadStalled() MOZ_FINAL MOZ_OVERRIDE;
-
   // Called by the media decoder to indicate whether the media cache has
   // suspended the channel.
   virtual void NotifySuspendedByCache(bool aIsSuspended) MOZ_FINAL MOZ_OVERRIDE;
 
   // Called by the media decoder and the video frame to get the
   // ImageContainer containing the video data.
   virtual VideoFrameContainer* GetVideoFrameContainer() MOZ_FINAL MOZ_OVERRIDE;
   layers::ImageContainer* GetImageContainer();
@@ -876,16 +872,33 @@ protected:
    * value (or presence) of the preload attribute changes. The change in
    * attribute value may cause a change in the mPreloadAction of this
    * element. If there is a change then this method will initiate any
    * behaviour that is necessary to implement the action.
    */
   void UpdatePreloadAction();
 
   /**
+   * Fire progress events if needed according to the time and byte constraints
+   * outlined in the specification. aHaveNewProgress is true if progress has
+   * just been detected.  Otherwise the method is called as a result of the
+   * progress timer.
+   */
+  void CheckProgress(bool aHaveNewProgress);
+  static void ProgressTimerCallback(nsITimer* aTimer, void* aClosure);
+  /**
+   * Start timer to update download progress.
+   */
+  nsresult StartProgress();
+  /**
+   * Stop progress information timer.
+   */
+  nsresult StopProgress();
+
+  /**
    * Dispatches an error event to a child source element.
    */
   void DispatchAsyncSourceError(nsIContent* aSourceElement);
 
   /**
    * Resets the media element for an error condition as per aErrorCode.
    * aErrorCode must be one of nsIDOMHTMLMediaError codes.
    */
@@ -1063,16 +1076,27 @@ protected:
   // VideoFrameContainer so that it doesn't change unexpectedly under us
   // due to decoder activity.
   nsIntSize mMediaSize;
 
   // Time that the last timeupdate event was fired. Read/Write from the
   // main thread only.
   TimeStamp mTimeUpdateTime;
 
+  // Time that the last progress event was fired. Read/Write from the
+  // main thread only.
+  TimeStamp mProgressTime;
+
+  // Time that data was last read from the media resource. Used for
+  // computing if the download has stalled and to rate limit progress events
+  // when data is arriving slower than PROGRESS_MS. A value of null indicates
+  // that a stall event has already fired and not to fire another one until
+  // more data is received. Read/Write from the main thread only.
+  TimeStamp mDataTime;
+
   // Media 'currentTime' value when the last timeupdate event occurred.
   // Read/Write from the main thread only.
   double mLastCurrentTime;
 
   // Logical start time of the media resource in seconds as obtained
   // from any media fragments. A negative value indicates that no
   // fragment time has been set. Read/Write from the main thread only.
   double mFragmentStart;
@@ -1098,16 +1122,19 @@ protected:
 
   // Reference to the source element last returned by GetNextSource().
   // This is the child source element which we're trying to load from.
   nsCOMPtr<nsIContent> mSourceLoadCandidate;
 
   // Range of time played.
   nsRefPtr<TimeRanges> mPlayed;
 
+  // Timer used for updating progress events
+  nsCOMPtr<nsITimer> mProgressTimer;
+
 #ifdef MOZ_EME
   // Encrypted Media Extension media keys.
   nsRefPtr<MediaKeys> mMediaKeys;
 #endif
 
   // Stores the time at the start of the current 'played' range.
   double mCurrentPlayRangeStart;
 
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -15,17 +15,16 @@
 #include "mozilla/dom/TimeRanges.h"
 #include "ImageContainer.h"
 #include "MediaResource.h"
 #include "nsError.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/StaticPtr.h"
 #include "nsIMemoryReporter.h"
 #include "nsComponentManagerUtils.h"
-#include "nsITimer.h"
 #include <algorithm>
 #include "MediaShutdownManager.h"
 #include "AudioChannelService.h"
 #include "mozilla/dom/AudioTrack.h"
 #include "mozilla/dom/AudioTrackList.h"
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/dom/VideoTrack.h"
 #include "mozilla/dom/VideoTrackList.h"
@@ -34,22 +33,16 @@
 #include "WMFDecoder.h"
 #endif
 
 using namespace mozilla::layers;
 using namespace mozilla::dom;
 
 namespace mozilla {
 
-// Number of milliseconds between progress events as defined by spec
-static const uint32_t PROGRESS_MS = 350;
-
-// Number of milliseconds of no data before a stall event is fired as defined by spec
-static const uint32_t STALL_MS = 3000;
-
 // Number of estimated seconds worth of data we need to have buffered
 // ahead of the current playback position before we allow the media decoder
 // to report that it can play through the entire media without the decode
 // catching up with the download. Having this margin make the
 // MediaDecoder::CanPlayThrough() calculation more stable in the case of
 // fluctuating bitrates.
 static const int64_t CAN_PLAY_THROUGH_MARGIN = 1;
 
@@ -493,19 +486,16 @@ void MediaDecoder::Shutdown()
   // Force any outstanding seek and byterange requests to complete
   // to prevent shutdown from deadlocking.
   if (mResource) {
     mResource->Close();
   }
 
   ChangeState(PLAY_STATE_SHUTDOWN);
 
-  if (mProgressTimer) {
-    StopProgress();
-  }
   mOwner = nullptr;
 
   MediaShutdownManager::Instance().Unregister(this);
 }
 
 MediaDecoder::~MediaDecoder()
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -981,17 +971,19 @@ void MediaDecoder::NotifySuspendedStatus
 
 void MediaDecoder::NotifyBytesDownloaded()
 {
   MOZ_ASSERT(NS_IsMainThread());
   {
     ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
     UpdatePlaybackRate();
   }
-  Progress(false);
+  if (mOwner) {
+    mOwner->DownloadProgressed();
+  }
 }
 
 void MediaDecoder::NotifyDownloadEnded(nsresult aStatus)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   DECODER_LOG("NotifyDownloadEnded, status=%x", aStatus);
 
@@ -1535,75 +1527,16 @@ void MediaDecoder::BreakCycles() {
   mDecoderStateMachine = nullptr;
 }
 
 MediaDecoderOwner* MediaDecoder::GetMediaOwner() const
 {
   return mOwner;
 }
 
-static void ProgressCallback(nsITimer* aTimer, void* aClosure)
-{
-  MediaDecoder* decoder = static_cast<MediaDecoder*>(aClosure);
-  decoder->Progress(true);
-}
-
-void MediaDecoder::Progress(bool aTimer)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  if (!mOwner)
-    return;
-
-  TimeStamp now = TimeStamp::Now();
-
-  if (!aTimer) {
-    mDataTime = now;
-  }
-
-  // If PROGRESS_MS has passed since the last progress event fired and more
-  // data has arrived since then, fire another progress event.
-  if ((mProgressTime.IsNull() ||
-       now - mProgressTime >= TimeDuration::FromMilliseconds(PROGRESS_MS)) &&
-      !mDataTime.IsNull() &&
-      now - mDataTime <= TimeDuration::FromMilliseconds(PROGRESS_MS)) {
-    mOwner->DownloadProgressed();
-    mProgressTime = now;
-  }
-
-  if (!mDataTime.IsNull() &&
-      now - mDataTime >= TimeDuration::FromMilliseconds(STALL_MS)) {
-    mOwner->DownloadStalled();
-    // Null it out
-    mDataTime = TimeStamp();
-  }
-}
-
-nsresult MediaDecoder::StartProgress()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  NS_ASSERTION(!mProgressTimer, "Already started progress timer.");
-
-  mProgressTimer = do_CreateInstance("@mozilla.org/timer;1");
-  return mProgressTimer->InitWithFuncCallback(ProgressCallback,
-                                              this,
-                                              PROGRESS_MS,
-                                              nsITimer::TYPE_REPEATING_SLACK);
-}
-
-nsresult MediaDecoder::StopProgress()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  NS_ASSERTION(mProgressTimer, "Already stopped progress timer.");
-
-  nsresult rv = mProgressTimer->Cancel();
-  mProgressTimer = nullptr;
-
-  return rv;
-}
-
 void MediaDecoder::FireTimeUpdate()
 {
   if (!mOwner)
     return;
   mOwner->FireTimeUpdate(true);
 }
 
 void MediaDecoder::PinForSeek()
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -187,27 +187,25 @@ destroying the MediaDecoder object.
 #include "nsISupports.h"
 #include "nsCOMPtr.h"
 #include "nsIObserver.h"
 #include "nsAutoPtr.h"
 #include "MediaResource.h"
 #include "mozilla/dom/AudioChannelBinding.h"
 #include "mozilla/gfx/Rect.h"
 #include "mozilla/ReentrantMonitor.h"
-#include "mozilla/TimeStamp.h"
 #include "MediaStreamGraph.h"
 #include "AbstractMediaDecoder.h"
 #include "necko-config.h"
 #ifdef MOZ_EME
 #include "mozilla/CDMProxy.h"
 #endif
 
 class nsIStreamListener;
 class nsIPrincipal;
-class nsITimer;
 
 namespace mozilla {
 namespace dom {
 class TimeRanges;
 }
 }
 
 namespace mozilla {
@@ -690,28 +688,16 @@ public:
   layers::ImageContainer* GetImageContainer() MOZ_OVERRIDE;
 
   // Return the current state. Can be called on any thread. If called from
   // a non-main thread, the decoder monitor must be held.
   PlayState GetState() {
     return mPlayState;
   }
 
-  // Called by the media element to start timer to update download progress.
-  nsresult StartProgress();
-
-  // Called by the media element to stop progress information timer.
-  nsresult StopProgress();
-
-  // Fire progress events if needed according to the time and byte
-  // constraints outlined in the specification. aTimer is true
-  // if the method is called as a result of the progress timer rather
-  // than the result of downloaded data.
-  void Progress(bool aTimer);
-
   // Fire timeupdate events if needed according to the time constraints
   // outlined in the specification.
   void FireTimeUpdate();
 
   // Stop updating the bytes downloaded for progress notifications. Called
   // when seeking to prevent wild changes to the progress notification.
   // Must be called with the decoder monitor held.
   virtual void StopProgressUpdates();
@@ -1182,40 +1168,26 @@ protected:
   bool mInfiniteStream;
 
   // Ensures our media stream has been pinned.
   void PinForSeek();
 
   // Ensures our media stream has been unpinned.
   void UnpinForSeek();
 
-  // Timer used for updating progress events
-  nsCOMPtr<nsITimer> mProgressTimer;
-
   // This should only ever be accessed from the main thread.
   // It is set in Init and cleared in Shutdown when the element goes away.
   // The decoder does not add a reference the element.
   MediaDecoderOwner* mOwner;
 
   // Counters related to decode and presentation of frames.
   FrameStatistics mFrameStats;
 
   nsRefPtr<VideoFrameContainer> mVideoFrameContainer;
 
-  // Time that the last progress event was fired. Read/Write from the
-  // main thread only.
-  TimeStamp mProgressTime;
-
-  // Time that data was last read from the media resource. Used for
-  // computing if the download has stalled and to rate limit progress events
-  // when data is arriving slower than PROGRESS_MS. A value of null indicates
-  // that a stall event has already fired and not to fire another one until
-  // more data is received. Read/Write from the main thread only.
-  TimeStamp mDataTime;
-
   // Data needed to estimate playback data rate. The timeline used for
   // this estimate is "decode time" (where the "current time" is the
   // time of the last decoded video frame).
   nsRefPtr<MediaChannelStatistics> mPlaybackStatistics;
 
   // True when our media stream has been pinned. We pin the stream
   // while seeking.
   bool mPinnedForSeek;
--- a/dom/media/MediaDecoderOwner.h
+++ b/dom/media/MediaDecoderOwner.h
@@ -15,19 +15,16 @@ namespace dom {
 class HTMLMediaElement;
 }
 
 class MediaDecoderOwner
 {
 public:
   // Called by the media decoder to indicate that the download is progressing.
   virtual void DownloadProgressed() = 0;
-  // Called by the media decoder to indicate that the download has stalled
-  // (no data has arrived for a while).
-  virtual void DownloadStalled() = 0;
 
   // Dispatch a synchronous event to the decoder owner
   virtual nsresult DispatchEvent(const nsAString& aName) = 0;
 
   // Dispatch an asynchronous event to the decoder owner
   virtual nsresult DispatchAsyncEvent(const nsAString& aName) = 0;
 
   /**
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -364,17 +364,17 @@ ChannelMediaResource::OnStartRequest(nsI
     // No need to call PossiblySuspend here since the channel is
     // definitely in the right state for us in OnStartRequest.
     mChannel->Suspend();
     mIgnoreResume = false;
   }
 
   // Fires an initial progress event and sets up the stall counter so stall events
   // fire if no download occurs within the required time frame.
-  mDecoder->Progress(false);
+  owner->DownloadProgressed();
 
   return NS_OK;
 }
 
 bool
 ChannelMediaResource::IsTransportSeekable()
 {
   MutexAutoLock lock(mLock);
--- a/dom/media/RtspMediaResource.cpp
+++ b/dom/media/RtspMediaResource.cpp
@@ -733,22 +733,22 @@ RtspMediaResource::OnConnected(uint8_t a
       return NS_ERROR_FAILURE;
     } else {
       mRealTime = true;
       bool seekable = false;
       mDecoder->SetInfinite(true);
       mDecoder->SetMediaSeekable(seekable);
     }
   }
+  MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
+  NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE);
   // Fires an initial progress event and sets up the stall counter so stall events
   // fire if no download occurs within the required time frame.
-  mDecoder->Progress(false);
+  owner->DownloadProgressed();
 
-  MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
-  NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE);
   dom::HTMLMediaElement* element = owner->GetMediaElement();
   NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
 
   element->FinishDecoderSetup(mDecoder, this);
   mIsConnected = true;
 
   return NS_OK;
 }
--- a/dom/media/gtest/MockMediaDecoderOwner.h
+++ b/dom/media/gtest/MockMediaDecoderOwner.h
@@ -8,17 +8,16 @@
 #include "MediaDecoderOwner.h"
 
 namespace mozilla
 {
 
 class MockMediaDecoderOwner : public MediaDecoderOwner
 {
 public:
-  virtual void DownloadStalled() MOZ_OVERRIDE {}
   virtual nsresult DispatchEvent(const nsAString& aName) MOZ_OVERRIDE
   {
     return NS_OK;
   }
   virtual nsresult DispatchAsyncEvent(const nsAString& aName) MOZ_OVERRIDE
   {
     return NS_OK;
   }