Bug 1137511 - Account for audio frames already pushed to audio hardware but not yet played when computing OutOfDecodedAudio. r=kinetik, a=lsblakk
authorBobby Holley <bobbyholley@gmail.com>
Thu, 26 Feb 2015 13:37:03 -0800
changeset 247880 f61a5c023ec1c203276fd3cef80464a1b6f97950
parent 247879 2f29031bfd403eab9046988511dcdcaa619c2d7d
child 247881 d2d54a52605d645040672f17f9506dd7c9a53f84
push id7706
push userryanvm@gmail.com
push dateWed, 04 Mar 2015 17:34:32 +0000
treeherdermozilla-aurora@f9bc1766be40 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik, lsblakk
bugs1137511
milestone38.0a2
Bug 1137511 - Account for audio frames already pushed to audio hardware but not yet played when computing OutOfDecodedAudio. r=kinetik, a=lsblakk
dom/media/AudioSink.cpp
dom/media/AudioSink.h
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
--- a/dom/media/AudioSink.cpp
+++ b/dom/media/AudioSink.cpp
@@ -80,16 +80,25 @@ AudioSink::GetPosition()
       (pos = mAudioStream->GetPosition()) >= 0) {
     // Update the last good position when we got a good one.
     mLastGoodPosition = pos;
   }
 
   return mLastGoodPosition;
 }
 
+bool
+AudioSink::HasUnplayedFrames()
+{
+  AssertCurrentThreadInMonitor();
+  // Experimentation suggests that GetPositionInFrames() is zero-indexed,
+  // so we need to add 1 here before comparing it to mWritten.
+  return mAudioStream && mAudioStream->GetPositionInFrames() + 1 < mWritten;
+}
+
 void
 AudioSink::PrepareToShutdown()
 {
   AssertCurrentThreadInMonitor();
   mStopAudioThread = true;
   if (mAudioStream) {
     mAudioStream->Cancel();
   }
--- a/dom/media/AudioSink.h
+++ b/dom/media/AudioSink.h
@@ -22,16 +22,20 @@ public:
 
   AudioSink(MediaDecoderStateMachine* aStateMachine,
             int64_t aStartTime, AudioInfo aInfo, dom::AudioChannel aChannel);
 
   nsresult Init();
 
   int64_t GetPosition();
 
+  // Check whether we've pushed more frames to the audio hardware than it has
+  // played.
+  bool HasUnplayedFrames();
+
   // Tell the AudioSink to stop processing and initiate shutdown.  Must be
   // called with the decoder monitor held.
   void PrepareToShutdown();
 
   // Shut down the AudioSink's resources.  The decoder monitor must not be
   // held during this call, as it may block processing thread event queues.
   void Shutdown();
 
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -2098,16 +2098,23 @@ bool MediaDecoderStateMachine::HasLowDec
   // provided we've not decoded to the end of the audio stream, or
   // if we're low on video frames, provided
   // we've not decoded to the end of the video stream.
   return ((IsAudioDecoding() && AudioDecodedUsecs() < aAudioUsecs) ||
          (IsVideoDecoding() &&
           static_cast<uint32_t>(VideoQueue().GetSize()) < LOW_VIDEO_FRAMES));
 }
 
+bool MediaDecoderStateMachine::OutOfDecodedAudio()
+{
+    return IsAudioDecoding() && !AudioQueue().IsFinished() &&
+           AudioQueue().GetSize() == 0 &&
+           (!mAudioSink || !mAudioSink->HasUnplayedFrames());
+}
+
 bool MediaDecoderStateMachine::HasLowUndecodedData()
 {
   return HasLowUndecodedData(mLowDataThresholdUsecs);
 }
 
 bool MediaDecoderStateMachine::HasLowUndecodedData(int64_t aUsecs)
 {
   AssertCurrentThreadInMonitor();
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -491,20 +491,17 @@ protected:
   bool NeedToDecodeVideo();
 
   // Returns true if we've got less than aAudioUsecs microseconds of decoded
   // and playable data. The decoder monitor must be held.
   //
   // May not be invoked when mReader->UseBufferingHeuristics() is false.
   bool HasLowDecodedData(int64_t aAudioUsecs);
 
-  bool OutOfDecodedAudio()
-  {
-    return IsAudioDecoding() && !AudioQueue().IsFinished() && AudioQueue().GetSize() == 0;
-  }
+  bool OutOfDecodedAudio();
 
   bool OutOfDecodedVideo()
   {
     // In buffering mode, we keep the last already-played frame in the queue.
     int emptyVideoSize = mState == DECODER_STATE_BUFFERING ? 1 : 0;
     return IsVideoDecoding() && !VideoQueue().IsFinished() && VideoQueue().GetSize() <= emptyVideoSize;
   }