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 250236 729cf69ef43f
parent 250235 70d3a14eab61
child 250237 003b419b893f
push id4523
push userryanvm@gmail.com
push date2015-03-04 17:35 +0000
treeherdermozilla-beta@729cf69ef43f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik, lsblakk
bugs1137511
milestone37.0
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
@@ -2067,16 +2067,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;
   }