Bug 693095 - Fix audio stream position estimation for remoted streams. Also resurrect audio thread wait removed in bug 669556 when using remoted audio streams. r=cpearce
authorMatthew Gregan <kinetik@flim.org>
Wed, 19 Oct 2011 18:29:08 +1300
changeset 79634 959ff7fea1e8130affc569b617dac85967db20df
parent 79633 9fd182788cd777ae019d823d4f34e332700c7948
child 79635 7a5a2d0857bdc39f54013d712747652d85e4a5fe
push id506
push userclegnitto@mozilla.com
push dateWed, 09 Nov 2011 02:03:18 +0000
treeherdermozilla-aurora@63587fc7bb93 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs693095, 669556
milestone10.0a1
Bug 693095 - Fix audio stream position estimation for remoted streams. Also resurrect audio thread wait removed in bug 669556 when using remoted audio streams. r=cpearce
content/media/VideoUtils.h
content/media/nsAudioStream.cpp
content/media/nsBuiltinDecoderStateMachine.cpp
--- a/content/media/VideoUtils.h
+++ b/content/media/VideoUtils.h
@@ -161,9 +161,15 @@ void ScaleDisplayByAspectRatio(nsIntSize
 // The amount of virtual memory reserved for thread stacks.
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(LINUX)
 #define MEDIA_THREAD_STACK_SIZE (128 * 1024)
 #else
 // All other platforms use their system defaults.
 #define MEDIA_THREAD_STACK_SIZE nsIThreadManager::DEFAULT_STACK_SIZE
 #endif
 
+// Android's audio backend is not available in content processes, so audio must
+// be remoted to the parent chrome process.
+#if defined(ANDROID)
+#define REMOTE_AUDIO 1
 #endif
+
+#endif
--- a/content/media/nsAudioStream.cpp
+++ b/content/media/nsAudioStream.cpp
@@ -61,30 +61,27 @@ extern "C" {
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
 
 #if defined(XP_MACOSX)
 #define SA_PER_STREAM_VOLUME 1
 #endif
 
-// Android's audio backend is not available in content processes, so audio must
-// be remoted to the parent chrome process.
-#if defined(ANDROID)
-#define REMOTE_AUDIO 1
-#endif
-
 using mozilla::TimeStamp;
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* gAudioStreamLog = nsnull;
 #endif
 
 static const PRUint32 FAKE_BUFFER_SIZE = 176400;
 
+// Number of milliseconds per second.
+static const PRInt64 MS_PER_S = 1000;
+
 class nsNativeAudioStream : public nsAudioStream
 {
  public:
   NS_DECL_ISUPPORTS
 
   ~nsNativeAudioStream();
   nsNativeAudioStream();
 
@@ -747,18 +744,18 @@ nsRemotedAudioStream::GetPositionInFrame
   if(!mAudioChild)
     return 0;
 
   PRInt64 position = mAudioChild->GetLastKnownPosition();
   if (position == -1)
     return 0;
 
   PRInt64 time = mAudioChild->GetLastKnownPositionTimestamp();
-  PRInt64 result = position + (mRate * (PR_IntervalNow() - time) / USECS_PER_S);
+  PRInt64 dt = PR_IntervalToMilliseconds(PR_IntervalNow() - time);
 
-  return result;
+  return position + (mRate * dt / MS_PER_S);
 }
 
 bool
 nsRemotedAudioStream::IsPaused()
 {
   return mPaused;
 }
--- a/content/media/nsBuiltinDecoderStateMachine.cpp
+++ b/content/media/nsBuiltinDecoderStateMachine.cpp
@@ -630,16 +630,39 @@ void nsBuiltinDecoderStateMachine::Audio
       if (!FramesToUsecs(audioDuration, rate, playedUsecs)) {
         NS_WARNING("Int overflow calculating playedUsecs");
         break;
       }
       if (!AddOverflow(audioStartTime, playedUsecs, mAudioEndTime)) {
         NS_WARNING("Int overflow calculating audio end time");
         break;
       }
+
+// The remoted audio stream does not block writes when the other end's buffers
+// are full, so this sleep is necessary to stop the audio thread spinning its
+// wheels.  When bug 695612 is fixed, this block of code can be removed.
+#if defined(REMOTE_AUDIO)
+      PRInt64 audioAhead = mAudioEndTime - GetMediaTime();
+      if (audioAhead > AMPLE_AUDIO_USECS &&
+          framesWritten > minWriteFrames)
+      {
+        // We've pushed enough audio onto the hardware that we've queued up a
+        // significant amount ahead of the playback position. The decode
+        // thread will be going to sleep, so we won't get any new audio
+        // anyway, so sleep until we need to push to the hardware again.
+        Wait(AMPLE_AUDIO_USECS / 2);
+        // Kick the decode thread; since above we only do a NotifyAll when
+        // we pop an audio chunk of the queue, the decoder won't wake up if
+        // we've got no more decoded chunks to push to the hardware. We can
+        // hit this condition if the last frame in the stream doesn't have
+        // it's EOS flag set, and the decode thread sleeps just after decoding
+        // that packet, but before realising there's no more packets.
+        mon.NotifyAll();
+      }
+#endif
     }
   }
   if (mReader->mAudioQueue.AtEndOfStream() &&
       mState != DECODER_STATE_SHUTDOWN &&
       !mStopAudioThread)
   {
     // Last frame pushed to audio hardware, wait for the audio to finish,
     // before the audio thread terminates.