Bug 599089 - Remote Audio to parent process. r=kinetik a=blocking-fennec
authorDoug Turner <dougt@dougt.org>
Tue, 16 Nov 2010 20:14:19 -0800
changeset 57627 908443327ad31bd8cb22f5e6a8f44eab83b65db6
parent 57626 384f1f7127dfb7245c881eb2ce066ea0bbf59cd9
child 57628 6dd7e2f976395e1b863cf9da376c6e23bf424ebc
push idunknown
push userunknown
push dateunknown
reviewerskinetik, blocking-fennec
bugs599089
milestone2.0b8pre
Bug 599089 - Remote Audio to parent process. r=kinetik a=blocking-fennec
content/html/content/public/nsHTMLMediaElement.h
content/html/content/src/nsHTMLAudioElement.cpp
content/media/Makefile.in
content/media/nsAudioStream.cpp
content/media/nsAudioStream.h
content/media/nsBuiltinDecoderStateMachine.cpp
content/media/nsBuiltinDecoderStateMachine.h
content/media/wave/nsWaveDecoder.cpp
dom/ipc/AudioChild.cpp
dom/ipc/AudioChild.h
dom/ipc/AudioParent.cpp
dom/ipc/AudioParent.h
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/Makefile.in
dom/ipc/PAudio.ipdl
dom/ipc/PContent.ipdl
dom/ipc/ipdl.mk
--- a/content/html/content/public/nsHTMLMediaElement.h
+++ b/content/html/content/public/nsHTMLMediaElement.h
@@ -593,17 +593,17 @@ protected:
 
   nsRefPtr<gfxASurface> mPrintSurface;
 
   // 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;
 
   // An audio stream for writing audio directly from JS.
-  nsAutoPtr<nsAudioStream> mAudioStream;
+  nsRefPtr<nsAudioStream> mAudioStream;
 
   // PR_TRUE if MozAudioAvailable events can be safely dispatched, based on
   // a media and element same-origin check.
   PRBool mAllowAudioData;
 
   // If true then we have begun downloading the media content.
   // Set to false when completed, or not yet started.
   PRPackedBool mBegun;
--- a/content/html/content/src/nsHTMLAudioElement.cpp
+++ b/content/html/content/src/nsHTMLAudioElement.cpp
@@ -163,17 +163,17 @@ nsHTMLAudioElement::MozSetup(PRUint32 aC
   if (0 == aChannels) {
     return NS_ERROR_FAILURE;
   }
 
   if (mAudioStream) {
     mAudioStream->Shutdown();
   }
 
-  mAudioStream = new nsAudioStream();
+  mAudioStream = nsAudioStream::AllocateStream();
   nsresult rv = mAudioStream->Init(aChannels, aRate,
                                    nsAudioStream::FORMAT_FLOAT32);
   if (NS_FAILED(rv)) {
     mAudioStream->Shutdown();
     mAudioStream = nsnull;
     return rv;
   }
 
--- a/content/media/Makefile.in
+++ b/content/media/Makefile.in
@@ -93,14 +93,16 @@ PARALLEL_DIRS += webm
 endif
 
 ifdef ENABLE_TESTS
 PARALLEL_DIRS += test
 endif
 
 FORCE_STATIC_LIB = 1
 
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 INCLUDES += \
   -I$(srcdir)/../base/src \
   -I$(srcdir)/../html/content/src \
   $(NULL)
--- a/content/media/nsAudioStream.cpp
+++ b/content/media/nsAudioStream.cpp
@@ -30,107 +30,381 @@
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
+
+#ifdef MOZ_IPC
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/PAudioChild.h"
+#include "mozilla/dom/AudioChild.h"
+#include "nsXULAppAPI.h"
+using namespace mozilla::dom;
+#endif
+
 #include <stdio.h>
 #include <math.h>
 #include "prlog.h"
 #include "prmem.h"
 #include "nsAutoPtr.h"
 #include "nsAudioStream.h"
 #include "nsAlgorithm.h"
 extern "C" {
 #include "sydneyaudio/sydney_audio.h"
 }
 #include "mozilla/TimeStamp.h"
+#include "nsThreadUtils.h"
 
 #if defined(XP_MACOSX)
 #define SA_PER_STREAM_VOLUME 1
 #endif
 
 using mozilla::TimeStamp;
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* gAudioStreamLog = nsnull;
 #endif
 
+#ifdef MOZ_IPC
+static nsIThread *gAudioPlaybackThread = nsnull;
+#endif
+
 #define FAKE_BUFFER_SIZE 176400
 #define MILLISECONDS_PER_SECOND 1000
 
+class nsAudioStreamLocal : public nsAudioStream
+{
+ public:
+  NS_DECL_ISUPPORTS
+
+  ~nsAudioStreamLocal();
+  nsAudioStreamLocal();
+  
+  nsresult Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat);
+  void Shutdown();
+  nsresult Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking);
+  PRUint32 Available();
+  void SetVolume(float aVolume);
+  void Drain();
+  void Pause();
+  void Resume();
+  PRInt64 GetPosition();
+  PRInt64 GetSampleOffset();
+  PRBool IsPaused();
+
+ private:
+
+  double mVolume;
+  void* mAudioHandle;
+  int mRate;
+  int mChannels;
+
+  SampleFormat mFormat;
+
+  // When a Write() request is made, and the number of samples
+  // requested to be written exceeds the buffer size of the audio
+  // backend, the remaining samples are stored in this variable. They
+  // will be written on the next Write() request.
+  nsTArray<short> mBufferOverflow;
+
+  // PR_TRUE if this audio stream is paused.
+  PRPackedBool mPaused;
+
+  // PR_TRUE if this stream has encountered an error.
+  PRPackedBool mInError;
+
+};
+
+#ifdef MOZ_IPC
+class nsAudioStreamRemote : public nsAudioStream
+{
+ public:
+  NS_DECL_ISUPPORTS
+
+  nsAudioStreamRemote();
+  ~nsAudioStreamRemote();
+  
+  nsresult Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat);
+  void Shutdown();
+  nsresult Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking);
+  PRUint32 Available();
+  void SetVolume(float aVolume);
+  void Drain();
+  void Pause();
+  void Resume();
+  PRInt64 GetPosition();
+  PRInt64 GetSampleOffset();
+  PRBool IsPaused();
+
+  AudioChild* mAudioChild;
+
+  SampleFormat mFormat;
+  int mRate;
+  int mChannels;
+  // PR_TRUE if this audio stream is paused.
+  PRPackedBool mPaused;
+
+  PRInt32 mBytesPerSample;
+
+  friend class AudioInitEvent;
+  friend class AudioShutdownEvent;
+  friend class AudioWriteEvent;
+  friend class AudioSetVolumeEvent;
+  friend class AudioPauseEvent;
+  friend class AudioDrainEvent;
+  friend class AudioGetSampleEvent;
+};
+
+class AudioInitEvent : public nsRunnable
+{
+ public:
+  AudioInitEvent(nsAudioStreamRemote* owner)
+  {
+    mOwner = owner;
+  }
+
+  NS_IMETHOD Run()
+  {
+    ContentChild * cpc = ContentChild::GetSingleton();
+    NS_ASSERTION(cpc, "Content Protocol is NULL!");
+    mOwner->mAudioChild =  static_cast<AudioChild*> (cpc->SendPAudioConstructor(mOwner->mChannels,
+                                                                                mOwner->mRate,
+                                                                                mOwner->mFormat));
+    return NS_OK;
+  }
+  
+  nsRefPtr<nsAudioStreamRemote> mOwner;
+};
+
+class AudioShutdownEvent : public nsRunnable
+{
+ public:
+  AudioShutdownEvent(nsAudioStreamRemote* owner)
+  {
+    mOwner = owner;
+  }
+
+  NS_IMETHOD Run()
+  {
+    if (mOwner->mAudioChild) {
+      PAudioChild::Send__delete__(mOwner->mAudioChild);
+      mOwner->mAudioChild = nsnull;
+    }
+    mOwner = nsnull;
+    return NS_OK;
+  }
+  nsRefPtr<nsAudioStreamRemote> mOwner;
+};
+
+class AudioWriteEvent : public nsRunnable
+{
+ public:
+  AudioWriteEvent(nsAudioStreamRemote* owner,
+                  const void* aBuf,
+                  PRUint32 aNumberOfSamples,
+                  PRUint32 aBytesPerSample)
+  {    
+    mOwner = owner;
+    mBytesPerSample = aBytesPerSample;
+    mBuffer.Assign((const char*)aBuf, aNumberOfSamples*aBytesPerSample);
+  }
+
+  NS_IMETHOD Run()
+  {
+    if (!mOwner->mAudioChild)
+      return NS_OK;
+
+    mOwner->mAudioChild->SendWrite(mBuffer,
+                                   mBuffer.Length() / mBytesPerSample);
+    return NS_OK;
+  }
+
+  nsRefPtr<nsAudioStreamRemote> mOwner;
+  nsCString mBuffer;
+  PRUint32 mBytesPerSample;
+};
+
+class AudioSetVolumeEvent : public nsRunnable
+{
+ public:
+  AudioSetVolumeEvent(nsAudioStreamRemote* owner, float volume)
+  {
+    mOwner = owner;
+    mVolume = volume;
+  }
+
+  NS_IMETHOD Run()
+  {
+    if (!mOwner->mAudioChild)
+      return NS_OK;
+
+    mOwner->mAudioChild->SendSetVolume(mVolume);
+    return NS_OK;
+  }
+  
+  nsRefPtr<nsAudioStreamRemote> mOwner;
+  float mVolume;
+};
+
+class AudioDrainEvent : public nsRunnable
+{
+ public:
+  AudioDrainEvent(nsAudioStreamRemote* owner)
+  {
+    mOwner = owner;
+  }
+
+  NS_IMETHOD Run()
+  {
+    if (!mOwner->mAudioChild)
+      return NS_OK;
+
+    mOwner->mAudioChild->SendDrain();
+    return NS_OK;
+  }
+  
+  nsRefPtr<nsAudioStreamRemote> mOwner;
+};
+
+
+class AudioPauseEvent : public nsRunnable
+{
+ public:
+  AudioPauseEvent(nsAudioStreamRemote* owner, PRBool pause)
+  {
+    mOwner = owner;
+    mPause = pause;
+  }
+
+  NS_IMETHOD Run()
+  {
+    if (!mOwner->mAudioChild)
+      return NS_OK;
+
+    if (mPause)
+      mOwner->mAudioChild->SendPause();
+    else
+      mOwner->mAudioChild->SendResume();
+
+    return NS_OK;
+  }
+  
+  nsRefPtr<nsAudioStreamRemote> mOwner;
+  PRBool mPause;
+};
+
+
+#endif // MOZ_IPC
+
+
 void nsAudioStream::InitLibrary()
 {
 #ifdef PR_LOGGING
   gAudioStreamLog = PR_NewLogModule("nsAudioStream");
 #endif
+
+#ifdef MOZ_IPC
+  // We only need this thread in the main process.
+  if (XRE_GetProcessType() == GeckoProcessType_Default) {
+      NS_NewThread(&gAudioPlaybackThread);
+  }
+#endif
 }
 
 void nsAudioStream::ShutdownLibrary()
 {
+#ifdef MOZ_IPC
+  NS_IF_RELEASE(gAudioPlaybackThread);
+#endif
 }
 
-nsAudioStream::nsAudioStream() :
+
+nsIThread *
+nsAudioStream::GetGlobalThread()
+{
+#ifdef MOZ_IPC
+  NS_IF_ADDREF(gAudioPlaybackThread);
+  return gAudioPlaybackThread;
+#else
+  return nsnull;
+#endif
+}
+
+nsAudioStream* nsAudioStream::AllocateStream()
+{
+  nsAudioStream* result = nsnull;
+
+#ifdef MOZ_IPC
+  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+    return new nsAudioStreamRemote();
+  }
+#endif
+  return new nsAudioStreamLocal();
+}
+
+nsAudioStreamLocal::nsAudioStreamLocal() :
   mVolume(1.0),
   mAudioHandle(0),
   mRate(0),
   mChannels(0),
   mFormat(FORMAT_S16_LE),
   mPaused(PR_FALSE),
   mInError(PR_FALSE)
 {
 }
 
-nsAudioStream::~nsAudioStream()
-{
-  Shutdown();
-}
+nsAudioStreamLocal::~nsAudioStreamLocal(){}
 
-nsresult nsAudioStream::Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat)
+NS_IMPL_THREADSAFE_ISUPPORTS0(nsAudioStreamLocal)
+
+nsresult nsAudioStreamLocal::Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat)
 {
   mRate = aRate;
   mChannels = aNumChannels;
   mFormat = aFormat;
+
   if (sa_stream_create_pcm(reinterpret_cast<sa_stream_t**>(&mAudioHandle),
                            NULL, 
                            SA_MODE_WRONLY, 
                            SA_PCM_FORMAT_S16_NE,
                            aRate,
                            aNumChannels) != SA_SUCCESS) {
     mAudioHandle = nsnull;
     mInError = PR_TRUE;
-    PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_create_pcm error"));
+    PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStreamLocal: sa_stream_create_pcm error"));
     return NS_ERROR_FAILURE;
   }
   
   if (sa_stream_open(static_cast<sa_stream_t*>(mAudioHandle)) != SA_SUCCESS) {
     sa_stream_destroy(static_cast<sa_stream_t*>(mAudioHandle));
     mAudioHandle = nsnull;
     mInError = PR_TRUE;
-    PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_open error"));
+    PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStreamLocal: sa_stream_open error"));
     return NS_ERROR_FAILURE;
   }
   mInError = PR_FALSE;
+
   return NS_OK;
 }
 
-void nsAudioStream::Shutdown()
+void nsAudioStreamLocal::Shutdown()
 {
-  if (!mAudioHandle) 
+  if (!mAudioHandle)
     return;
 
   sa_stream_destroy(static_cast<sa_stream_t*>(mAudioHandle));
   mAudioHandle = nsnull;
   mInError = PR_TRUE;
 }
 
-nsresult nsAudioStream::Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking)
+nsresult nsAudioStreamLocal::Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking)
 {
   NS_ABORT_IF_FALSE(aCount % mChannels == 0,
                     "Buffer size must be divisible by channel count");
   NS_ASSERTION(!mPaused, "Don't write audio when paused, you'll block");
 
   if (mInError)
     return NS_ERROR_FAILURE;
 
@@ -194,100 +468,99 @@ nsresult nsAudioStream::Write(const void
         count = available;
       }
     }
 
     if (sa_stream_write(static_cast<sa_stream_t*>(mAudioHandle),
                         s_data.get(),
                         count * sizeof(short)) != SA_SUCCESS)
     {
-      PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_write error"));
+      PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStreamLocal: sa_stream_write error"));
       mInError = PR_TRUE;
       return NS_ERROR_FAILURE;
     }
   }
   return NS_OK;
 }
 
-PRUint32 nsAudioStream::Available()
+PRUint32 nsAudioStreamLocal::Available()
 {
   // If the audio backend failed to open, lie and say we'll accept some
   // data.
   if (mInError)
     return FAKE_BUFFER_SIZE;
 
   size_t s = 0; 
   if (sa_stream_get_write_size(static_cast<sa_stream_t*>(mAudioHandle), &s) != SA_SUCCESS)
     return 0;
 
   return s / sizeof(short);
 }
 
-void nsAudioStream::SetVolume(float aVolume)
+void nsAudioStreamLocal::SetVolume(float aVolume)
 {
   NS_ASSERTION(aVolume >= 0.0 && aVolume <= 1.0, "Invalid volume");
 #if defined(SA_PER_STREAM_VOLUME)
   if (sa_stream_set_volume_abs(static_cast<sa_stream_t*>(mAudioHandle), aVolume) != SA_SUCCESS) {
-    PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_set_volume_abs error"));
+    PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStreamLocal: sa_stream_set_volume_abs error"));
     mInError = PR_TRUE;
   }
 #else
   mVolume = aVolume;
 #endif
 }
 
-void nsAudioStream::Drain()
+void nsAudioStreamLocal::Drain()
 {
   if (mInError)
     return;
 
   // Write any remaining unwritten sound data in the overflow buffer
   if (!mBufferOverflow.IsEmpty()) {
     if (sa_stream_write(static_cast<sa_stream_t*>(mAudioHandle),
                         mBufferOverflow.Elements(),
                         mBufferOverflow.Length() * sizeof(short)) != SA_SUCCESS)
-      PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_write error"));
+      PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStreamLocal: sa_stream_write error"));
       mInError = PR_TRUE;
       return;
   }
 
   int r = sa_stream_drain(static_cast<sa_stream_t*>(mAudioHandle));
   if (r != SA_SUCCESS && r != SA_ERROR_INVALID) {
-    PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_drain error"));
+    PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStreamLocal: sa_stream_drain error"));
     mInError = PR_TRUE;
   }
 }
 
-void nsAudioStream::Pause()
+void nsAudioStreamLocal::Pause()
 {
   if (mInError)
     return;
   mPaused = PR_TRUE;
   sa_stream_pause(static_cast<sa_stream_t*>(mAudioHandle));
 }
 
-void nsAudioStream::Resume()
+void nsAudioStreamLocal::Resume()
 {
   if (mInError)
     return;
   mPaused = PR_FALSE;
   sa_stream_resume(static_cast<sa_stream_t*>(mAudioHandle));
 }
 
-PRInt64 nsAudioStream::GetPosition()
+PRInt64 nsAudioStreamLocal::GetPosition()
 {
   PRInt64 sampleOffset = GetSampleOffset();
   if (sampleOffset >= 0) {
     return ((MILLISECONDS_PER_SECOND * sampleOffset) / mRate / mChannels);
   }
-
   return -1;
 }
 
-PRInt64 nsAudioStream::GetSampleOffset()
+PRInt64 nsAudioStreamLocal::GetSampleOffset()
 {
   if (mInError) {
     return -1;
   }
  
   sa_position_t positionType = SA_POSITION_WRITE_SOFTWARE;
 #if defined(XP_WIN)
   positionType = SA_POSITION_WRITE_HARDWARE;
@@ -295,8 +568,146 @@ PRInt64 nsAudioStream::GetSampleOffset()
   PRInt64 position = 0;
   if (sa_stream_get_position(static_cast<sa_stream_t*>(mAudioHandle),
                              positionType, &position) == SA_SUCCESS) {
     return position / sizeof(short);
   }
 
   return -1;
 }
+
+PRBool nsAudioStreamLocal::IsPaused()
+{
+  return mPaused;
+}
+
+#ifdef MOZ_IPC
+
+nsAudioStreamRemote::nsAudioStreamRemote()
+ : mAudioChild(NULL),
+   mFormat(FORMAT_S16_LE),
+   mRate(0),
+   mChannels(0),
+   mPaused(PR_FALSE),
+   mBytesPerSample(1)
+{}
+
+nsAudioStreamRemote::~nsAudioStreamRemote()
+{}
+
+NS_IMPL_THREADSAFE_ISUPPORTS0(nsAudioStreamRemote)
+
+nsresult 
+nsAudioStreamRemote::Init(PRInt32 aNumChannels,
+                          PRInt32 aRate,
+                          SampleFormat aFormat)
+{
+  mRate = aRate;
+  mChannels = aNumChannels;
+  mFormat = aFormat;
+
+  switch (mFormat) {
+    case FORMAT_U8: {
+      mBytesPerSample = sizeof(PRUint8);
+      break;
+    }
+    case FORMAT_S16_LE: {
+      mBytesPerSample = sizeof(short);
+      break;
+    }
+    case FORMAT_FLOAT32: {
+      mBytesPerSample = sizeof(float);
+    }
+  }
+
+  nsCOMPtr<nsIRunnable> event = new AudioInitEvent(this);
+  NS_DispatchToMainThread(event);
+  return NS_OK;
+}
+
+void
+nsAudioStreamRemote::Shutdown()
+{
+  nsCOMPtr<nsIRunnable> event = new AudioShutdownEvent(this);
+  NS_DispatchToMainThread(event);
+}
+
+nsresult
+nsAudioStreamRemote::Write(const void* aBuf,
+                           PRUint32 aCount,
+                           PRBool aBlocking)
+{
+  nsCOMPtr<nsIRunnable> event = new AudioWriteEvent(this,
+                                                    aBuf,
+                                                    aCount,
+                                                    mBytesPerSample);
+  NS_DispatchToMainThread(event);
+  return NS_OK;
+}
+
+PRUint32
+nsAudioStreamRemote::Available()
+{
+  return FAKE_BUFFER_SIZE;
+}
+
+void
+nsAudioStreamRemote::SetVolume(float aVolume)
+{
+  nsCOMPtr<nsIRunnable> event = new AudioSetVolumeEvent(this, aVolume);
+  NS_DispatchToMainThread(event);
+}
+
+void
+nsAudioStreamRemote::Drain()
+{
+  nsCOMPtr<nsIRunnable> event = new AudioDrainEvent(this);
+  NS_DispatchToMainThread(event, NS_DISPATCH_SYNC);
+}
+ 
+void
+nsAudioStreamRemote::Pause()
+{
+  mPaused = PR_TRUE;
+  nsCOMPtr<nsIRunnable> event = new AudioPauseEvent(this, PR_TRUE);
+  NS_DispatchToMainThread(event);
+}
+
+void
+nsAudioStreamRemote::Resume()
+{
+  mPaused = PR_FALSE;
+  nsCOMPtr<nsIRunnable> event = new AudioPauseEvent(this, PR_FALSE);
+  NS_DispatchToMainThread(event);
+}
+
+PRInt64 nsAudioStreamRemote::GetPosition()
+{
+  PRInt64 sampleOffset = GetSampleOffset();
+  if (sampleOffset >= 0) {
+    return ((MILLISECONDS_PER_SECOND * sampleOffset) / mRate / mChannels);
+  }
+  return 0;
+}
+
+PRInt64
+nsAudioStreamRemote::GetSampleOffset()
+{
+  if(!mAudioChild)
+    return 0;
+
+  PRInt64 offset = mAudioChild->GetLastKnownSampleOffset();
+  if (offset == -1)
+    return 0;
+
+  PRInt64 time   = mAudioChild->GetLastKnownSampleOffsetTime();
+  PRInt64 result = offset + (mRate * mChannels * (PR_IntervalNow() - time) / MILLISECONDS_PER_SECOND);
+
+  return result;
+}
+
+PRBool
+nsAudioStreamRemote::IsPaused()
+{
+  return mPaused;
+}
+
+#endif // MOZ_IPC
--- a/content/media/nsAudioStream.h
+++ b/content/media/nsAudioStream.h
@@ -34,99 +34,86 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 #if !defined(nsAudioStream_h_)
 #define nsAudioStream_h_
 
 #include "nscore.h"
-#include "prlog.h"
-#include "nsTArray.h"
+#include "nsISupportsImpl.h"
+#include "nsIThread.h"
 
-extern PRLogModuleInfo* gAudioStreamLog;
+class nsAudioStream : public nsISupports
+{
+public:
 
-class nsAudioStream 
-{
- public:
   enum SampleFormat
   {
     FORMAT_U8,
     FORMAT_S16_LE,
     FORMAT_FLOAT32
   };
 
   // Initialize Audio Library. Some Audio backends require initializing the
   // library before using it. 
   static void InitLibrary();
 
   // Shutdown Audio Library. Some Audio backends require shutting down the
   // library after using it.
   static void ShutdownLibrary();
 
-  nsAudioStream();
-  ~nsAudioStream();
+  // Thread, usually for MOZ_IPC handling, that is shared between audio streams.
+  // This may return null in the child process
+  static nsIThread *GetGlobalThread();
+
+  // AllocateStream will return either a local stream or a remoted stream
+  // depending on where you call it from.  If MOZ_IPC is enabled, and you
+  // call this from a child process, you may recieve an implementation which
+  // forwards to a compositing process.
+  static nsAudioStream* AllocateStream();
 
   // Initialize the audio stream. aNumChannels is the number of audio channels 
   // (1 for mono, 2 for stereo, etc) and aRate is the frequency of the sound 
   // samples (22050, 44100, etc).
-  nsresult Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat);
+  virtual nsresult Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat) = 0;
 
   // Closes the stream. All future use of the stream is an error.
-  void Shutdown();
+  virtual void Shutdown() = 0;
 
   // Write sound data to the audio hardware.  aBuf is an array of samples in
   // the format specified by mFormat of length aCount.  aCount should be
   // evenly divisible by the number of channels in this audio stream.
   // When aBlocking is PR_TRUE, we'll block until the write has completed,
   // otherwise we'll buffer any data we can't write immediately, and write
   // it in a later call.
-  nsresult Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking);
+  virtual nsresult Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking) = 0;
 
   // Return the number of sound samples that can be written to the audio device
   // without blocking.
-  PRUint32 Available();
+  virtual PRUint32 Available() = 0;
 
   // Set the current volume of the audio playback. This is a value from
   // 0 (meaning muted) to 1 (meaning full volume).
-  void SetVolume(float aVolume);
+  virtual void SetVolume(float aVolume) = 0;
 
   // Block until buffered audio data has been consumed.
-  void Drain();
+  virtual void Drain() = 0;
 
   // Pause audio playback
-  void Pause();
+  virtual void Pause() = 0;
 
   // Resume audio playback
-  void Resume();
+  virtual void Resume() = 0;
 
   // Return the position in milliseconds of the sample being played by the
   // audio hardware.
-  PRInt64 GetPosition();
+  virtual PRInt64 GetPosition() = 0;
 
   // Return the position, measured in samples played since the start, by
   // the audio hardware.
-  PRInt64 GetSampleOffset();
+  virtual PRInt64 GetSampleOffset() = 0;
 
   // Returns PR_TRUE when the audio stream is paused.
-  PRBool IsPaused() { return mPaused; }
-
- private:
-  double mVolume;
-  void* mAudioHandle;
-  int mRate;
-  int mChannels;
-
-  SampleFormat mFormat;
+  virtual PRBool IsPaused() = 0;
+};
 
-  // When a Write() request is made, and the number of samples
-  // requested to be written exceeds the buffer size of the audio
-  // backend, the remaining samples are stored in this variable. They
-  // will be written on the next Write() request.
-  nsTArray<short> mBufferOverflow;
-
-  // PR_TRUE if this audio stream is paused.
-  PRPackedBool mPaused;
-
-  // PR_TRUE if this stream has encountered an error.
-  PRPackedBool mInError;
-};
 #endif
--- a/content/media/nsBuiltinDecoderStateMachine.cpp
+++ b/content/media/nsBuiltinDecoderStateMachine.cpp
@@ -156,16 +156,22 @@ nsBuiltinDecoderStateMachine::nsBuiltinD
   mEventManager(aDecoder)
 {
   MOZ_COUNT_CTOR(nsBuiltinDecoderStateMachine);
 }
 
 nsBuiltinDecoderStateMachine::~nsBuiltinDecoderStateMachine()
 {
   MOZ_COUNT_DTOR(nsBuiltinDecoderStateMachine);
+
+  if (mAudioStream) {
+    MonitorAutoEnter mon(mDecoder->GetMonitor());
+    mAudioStream->Shutdown();
+    mAudioStream = nsnull;
+  }
 }
 
 PRBool nsBuiltinDecoderStateMachine::HasFutureAudio() const {
   mDecoder->GetMonitor().AssertCurrentThreadIn();
   NS_ASSERTION(HasAudio(), "Should only call HasFutureAudio() when we have audio");
   // We've got audio ready to play if:
   // 1. We've not completed playback of audio, and
   // 2. we either have more than the threshold of decoded audio available, or
@@ -606,17 +612,17 @@ void nsBuiltinDecoderStateMachine::Start
     MonitorAutoEnter audioMon(mAudioMonitor);
     if (mAudioStream) {
       // We have an audiostream, so it must have been paused the last time
       // StopPlayback() was called.
       mAudioStream->Resume();
     } else {
       // No audiostream, create one.
       const nsVideoInfo& info = mReader->GetInfo();
-      mAudioStream = new nsAudioStream();
+      mAudioStream = nsAudioStream::AllocateStream();
       mAudioStream->Init(info.mAudioChannels,
                          info.mAudioRate,
                          MOZ_SOUND_DATA_FORMAT);
       mAudioStream->SetVolume(mVolume);
     }
   }
   mPlayStartTime = TimeStamp::Now();
   mDecoder->GetMonitor().NotifyAll();
--- a/content/media/nsBuiltinDecoderStateMachine.h
+++ b/content/media/nsBuiltinDecoderStateMachine.h
@@ -421,17 +421,17 @@ protected:
   // Position to seek to in milliseconds when the seek state transition occurs.
   // The decoder monitor lock must be obtained before reading or writing
   // this value. Accessed on main and state machine thread.
   PRInt64 mSeekTime;
 
   // The audio stream resource. Used on the state machine, audio, and main
   // threads. You must hold the mAudioMonitor, and must NOT hold the decoder
   // monitor when using the audio stream!
-  nsAutoPtr<nsAudioStream> mAudioStream;
+  nsRefPtr<nsAudioStream> mAudioStream;
 
   // The reader, don't call its methods with the decoder monitor held.
   // This is created in the play state machine's constructor, and destroyed
   // in the play state machine's destructor.
   nsAutoPtr<nsBuiltinDecoderReader> mReader;
 
   // The time of the current frame in milliseconds. This is referenced from
   // 0 which is the initial playback position. Set by the state machine
--- a/content/media/wave/nsWaveDecoder.cpp
+++ b/content/media/wave/nsWaveDecoder.cpp
@@ -290,17 +290,17 @@ private:
   // the state machine.  The stream is threadsafe, but is only used on the
   // playback thread except for create, open, and cancel, which are called
   // from the main thread.
   nsMediaStream* mStream;
 
   // Our audio stream.  Created on demand when entering playback state.  It
   // is destroyed when seeking begins and will not be reinitialized until
   // playback resumes, so it is possible for this to be null.
-  nsAutoPtr<nsAudioStream> mAudioStream;
+  nsRefPtr<nsAudioStream> mAudioStream;
 
   // Maximum time to spend waiting for data during buffering.
   TimeDuration mBufferingWait;
 
   // Machine time that buffering began, used with mBufferingWait to time out
   // buffering.
   TimeStamp mBufferingStart;
 
@@ -901,17 +901,17 @@ nsWaveStateMachine::ChangeState(State aS
 #endif
   mState = aState;
   monitor.NotifyAll();
 }
 
 void
 nsWaveStateMachine::OpenAudioStream()
 {
-  mAudioStream = new nsAudioStream();
+  mAudioStream = nsAudioStream::AllocateStream();
   if (!mAudioStream) {
     LOG(PR_LOG_ERROR, ("Could not create audio stream"));
   } else {
     NS_ABORT_IF_FALSE(mMetadataValid,
                       "Attempting to initialize audio stream with invalid metadata");
     mAudioStream->Init(mChannels, mSampleRate, mSampleFormat);
     mAudioStream->SetVolume(mInitialVolume);
   }
new file mode 100644
--- /dev/null
+++ b/dom/ipc/AudioChild.cpp
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Audio IPC
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Doug Turner <dougt@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "mozilla/dom/AudioChild.h"
+
+namespace mozilla {
+namespace dom {
+
+AudioChild::AudioChild()
+  : mLastSampleOffset(-1),
+    mLastSampleOffsetTime(0)
+{
+  MOZ_COUNT_CTOR(AudioChild);
+}
+
+AudioChild::~AudioChild()
+{
+  MOZ_COUNT_DTOR(AudioChild);
+}
+
+bool
+AudioChild::RecvSampleOffsetUpdate(const PRInt64& offset,
+                                   const PRInt64& time)
+{
+  mLastSampleOffset = offset;
+  mLastSampleOffsetTime = time;
+  return true;
+}
+
+PRInt64
+AudioChild::GetLastKnownSampleOffset()
+{
+  return mLastSampleOffset;
+}
+
+PRInt64
+AudioChild::GetLastKnownSampleOffsetTime()
+{
+  return mLastSampleOffsetTime;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/AudioChild.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Audio IPC
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Doug Turner <dougt@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_dom_AudioChild_h
+#define mozilla_dom_AudioChild_h
+
+#include "mozilla/dom/PAudioChild.h"
+
+namespace mozilla {
+namespace dom {
+
+class AudioChild : public PAudioChild
+{
+ public:
+    AudioChild();
+    virtual ~AudioChild();
+    virtual bool RecvSampleOffsetUpdate(const PRInt64&, const PRInt64&);
+    
+    PRInt64 GetLastKnownSampleOffset();
+    PRInt64 GetLastKnownSampleOffsetTime();
+ private:
+    PRInt64 mLastSampleOffset, mLastSampleOffsetTime;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/ipc/AudioParent.cpp
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Audio IPC
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Doug Turner <dougt@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "mozilla/dom/AudioParent.h"
+#include "nsThreadUtils.h"
+
+// C++ file contents
+namespace mozilla {
+namespace dom {
+
+class AudioWriteEvent : public nsRunnable
+{
+ public:
+  AudioWriteEvent(nsAudioStream* owner, nsCString data, PRUint32 count)
+  {
+    mOwner = owner;
+    mData  = data;
+    mCount = count;
+  }
+
+  NS_IMETHOD Run()
+  {
+    mOwner->Write(mData.get(), mCount, true);
+    return NS_OK;
+  }
+
+ private:
+    nsRefPtr<nsAudioStream> mOwner;
+    nsCString mData;
+    PRUint32  mCount;
+};
+
+NS_IMPL_THREADSAFE_ISUPPORTS1(AudioParent, nsITimerCallback)
+
+nsresult
+AudioParent::Notify(nsITimer* timer)
+{
+  if (!mStream) {
+    timer->Cancel();
+    return NS_ERROR_FAILURE;
+  }
+
+  PRInt64 offset = mStream->GetSampleOffset();
+  SendSampleOffsetUpdate(offset, PR_IntervalNow());
+  return NS_OK;
+}
+bool
+AudioParent::RecvWrite(
+        const nsCString& data,
+        const PRUint32& count)
+{
+  nsCOMPtr<nsIRunnable> event = new AudioWriteEvent(mStream, data, count);
+  nsCOMPtr<nsIThread> thread = nsAudioStream::GetGlobalThread();
+  thread->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL);
+  return true;
+}
+    
+bool
+AudioParent::RecvSetVolume(const float& aVolume)
+{
+  if (mStream)
+    mStream->SetVolume(aVolume);
+  return true;
+}
+
+bool
+AudioParent::RecvDrain()
+{
+  if (mStream)
+    mStream->Drain();
+  return true;
+}
+
+bool
+AudioParent::RecvPause()
+{
+  if (mStream)
+    mStream->Pause();
+  return true;
+}
+
+bool
+AudioParent::RecvResume()
+{
+  if (mStream)
+    mStream->Resume();
+  return true;
+}
+
+bool
+AudioParent::Recv__delete__()
+{
+  if (mStream) {
+    mStream->Shutdown();
+    mStream = nsnull;
+  }
+
+  if (mTimer) {
+    mTimer->Cancel();
+    mTimer = nsnull;
+  }
+  return true;
+}
+
+AudioParent::AudioParent(PRInt32 aNumChannels, PRInt32 aRate, PRInt32 aFormat)
+{
+  mStream = nsAudioStream::AllocateStream();
+  if (mStream)
+    mStream->Init(aNumChannels,
+                  aRate,
+                  (nsAudioStream::SampleFormat) aFormat);
+  if (!mStream)
+    return; 
+
+  mTimer = do_CreateInstance("@mozilla.org/timer;1");
+  mTimer->InitWithCallback(this, 1000, nsITimer::TYPE_REPEATING_SLACK);
+}
+
+AudioParent::~AudioParent()
+{
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/ipc/AudioParent.h
@@ -0,0 +1,86 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Audio IPC
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Doug Turner <dougt@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_dom_AudioParent_h
+#define mozilla_dom_AudioParent_h
+
+#include "mozilla/dom/PAudioParent.h"
+#include "nsAudioStream.h"
+#include "nsITimer.h"
+
+namespace mozilla {
+namespace dom {
+class AudioParent : public PAudioParent, public nsITimerCallback
+{
+ public:
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSITIMERCALLBACK
+
+    virtual bool
+    RecvWrite(
+            const nsCString& data,
+            const PRUint32& count);
+
+    virtual bool
+    RecvSetVolume(const float& aVolume);
+
+    virtual bool
+    RecvDrain();
+
+    virtual bool
+    RecvPause();
+
+    virtual bool
+    RecvResume();
+
+    virtual bool
+    Recv__delete__();
+
+    AudioParent(PRInt32 aNumChannels, PRInt32 aRate, PRInt32 aFormat);
+    virtual ~AudioParent();
+
+    nsRefPtr<nsAudioStream> mStream;
+    nsCOMPtr<nsITimer> mTimer;
+
+};
+} // namespace dom
+} // namespace mozilla
+
+#endif
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -42,23 +42,26 @@
 #endif
 
 #ifdef MOZ_WIDGET_QT
 #include "nsQAppInstance.h"
 #endif
 
 #include "ContentChild.h"
 #include "TabChild.h"
+#include "AudioChild.h"
 
 #include "mozilla/ipc/TestShellChild.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/ipc/XPCShellEnvironment.h"
 #include "mozilla/jsipc/PContextWrapperChild.h"
 #include "mozilla/dom/ExternalHelperAppChild.h"
 
+#include "nsAudioStream.h"
+
 #include "nsIObserverService.h"
 #include "nsTObserverArray.h"
 #include "nsIObserver.h"
 #include "nsIPrefService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsXULAppAPI.h"
 #include "nsWeakReference.h"
 #include "nsIScriptError.h"
@@ -282,16 +285,32 @@ ContentChild::DeallocPTestShell(PTestShe
 
 bool
 ContentChild::RecvPTestShellConstructor(PTestShellChild* actor)
 {
     actor->SendPContextWrapperConstructor()->SendPObjectWrapperConstructor(true);
     return true;
 }
 
+PAudioChild*
+ContentChild::AllocPAudio(const PRInt32& numChannels,
+                          const PRInt32& rate,
+                          const PRInt32& format)
+{
+    PAudioChild *child = new AudioChild();
+    return child;
+}
+
+bool
+ContentChild::DeallocPAudio(PAudioChild* doomed)
+{
+    delete doomed;
+    return true;
+}
+
 PNeckoChild* 
 ContentChild::AllocPNecko()
 {
     return new NeckoChild();
 }
 
 bool 
 ContentChild::DeallocPNecko(PNeckoChild* necko)
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -78,16 +78,21 @@ public:
 
     virtual PBrowserChild* AllocPBrowser(const PRUint32& aChromeFlags);
     virtual bool DeallocPBrowser(PBrowserChild*);
 
     virtual PTestShellChild* AllocPTestShell();
     virtual bool DeallocPTestShell(PTestShellChild*);
     virtual bool RecvPTestShellConstructor(PTestShellChild*);
 
+    virtual PAudioChild* AllocPAudio(const PRInt32&,
+                                     const PRInt32&,
+                                     const PRInt32&);
+    virtual bool DeallocPAudio(PAudioChild*);
+
     virtual PNeckoChild* AllocPNecko();
     virtual bool DeallocPNecko(PNeckoChild*);
 
     virtual PExternalHelperAppChild *AllocPExternalHelperApp(
             const IPC::URI& uri,
             const nsCString& aMimeContentType,
             const nsCString& aContentDisposition,
             const bool& aForceSave,
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -61,16 +61,17 @@
 #include "nsCExternalHandlerService.h"
 #include "nsFrameMessageManager.h"
 #include "nsIAlertsService.h"
 #include "nsToolkitCompsCID.h"
 #include "nsIDOMGeoGeolocation.h"
 #include "nsIConsoleService.h"
 #include "nsIScriptError.h"
 #include "nsConsoleMessage.h"
+#include "AudioParent.h"
 
 #ifdef MOZ_PERMISSIONS
 #include "nsPermissionManager.h"
 #endif
 
 #include "mozilla/dom/ExternalHelperAppParent.h"
 #include "nsAccelerometer.h"
 
@@ -356,16 +357,34 @@ ContentParent::AllocPTestShell()
 }
 
 bool
 ContentParent::DeallocPTestShell(PTestShellParent* shell)
 {
   delete shell;
   return true;
 }
+ 
+PAudioParent*
+ContentParent::AllocPAudio(const PRInt32& numChannels,
+                           const PRInt32& rate,
+                           const PRInt32& format)
+{
+    AudioParent *parent = new AudioParent(numChannels, rate, format);
+    parent->AddRef();
+    return parent;
+}
+
+bool
+ContentParent::DeallocPAudio(PAudioParent* doomed)
+{
+    AudioParent *parent = static_cast<AudioParent*>(doomed);
+    NS_RELEASE(parent);
+    return true;
+}
 
 PNeckoParent* 
 ContentParent::AllocPNecko()
 {
     return new NeckoParent();
 }
 
 bool 
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -112,16 +112,21 @@ private:
     virtual ~ContentParent();
 
     virtual PBrowserParent* AllocPBrowser(const PRUint32& aChromeFlags);
     virtual bool DeallocPBrowser(PBrowserParent* frame);
 
     virtual PTestShellParent* AllocPTestShell();
     virtual bool DeallocPTestShell(PTestShellParent* shell);
 
+    virtual PAudioParent* AllocPAudio(const PRInt32&,
+                                     const PRInt32&,
+                                     const PRInt32&);
+    virtual bool DeallocPAudio(PAudioParent*);
+
     virtual PNeckoParent* AllocPNecko();
     virtual bool DeallocPNecko(PNeckoParent* necko);
 
     virtual PExternalHelperAppParent* AllocPExternalHelperApp(
             const IPC::URI& uri,
             const nsCString& aMimeContentType,
             const nsCString& aContentDisposition,
             const bool& aForceSave,
--- a/dom/ipc/Makefile.in
+++ b/dom/ipc/Makefile.in
@@ -47,24 +47,28 @@ LIBXUL_LIBRARY = 1
 FORCE_STATIC_LIB = 1
 EXPORT_LIBRARY = 1
 
 EXPORTS = TabMessageUtils.h PCOMContentPermissionRequestChild.h
 
 EXPORTS_NAMESPACES = mozilla/dom
 
 EXPORTS_mozilla/dom = \
+  AudioChild.h \
+  AudioParent.h \
   ContentChild.h \
   ContentParent.h \
   ContentProcess.h \
   TabParent.h \
   TabChild.h \
   $(NULL)
 
 CPPSRCS = \
+  AudioChild.cpp \
+  AudioParent.cpp \
   ContentProcess.cpp \
   ContentParent.cpp \
   ContentChild.cpp \
   TabParent.cpp \
   TabChild.cpp \
   TabMessageUtils.cpp \
   $(NULL)
 
new file mode 100644
--- /dev/null
+++ b/dom/ipc/PAudio.ipdl
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Audio IPC
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Doug Turner <dougt@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+include protocol PContent;
+
+namespace mozilla {
+namespace dom {
+
+sync protocol PAudio
+{
+  manager PContent;
+
+parent:
+
+  __delete__();
+
+  Write(nsCString data, PRUint32 count);
+
+  SetVolume(float aVolume);
+
+  sync Drain();
+
+  Pause();
+  Resume();
+
+ child:
+
+  SampleOffsetUpdate(PRInt64 offset, PRInt64 time);
+
+
+};
+
+} // namespace dom
+} // namespace mozilla
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -31,16 +31,17 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
+include protocol PAudio;
 include protocol PBrowser;
 include protocol PTestShell;
 include protocol PNecko;
 include protocol PExternalHelperApp;
 
 include "mozilla/chrome/RegistryMessageUtils.h";
 include "mozilla/net/NeckoMessageUtils.h";
 
@@ -56,16 +57,17 @@ using OverrideMapping;
 using IPC::URI;
 using IPC::Permission;
 
 namespace mozilla {
 namespace dom {
 
 rpc protocol PContent
 {
+    manages PAudio;
     manages PBrowser;
     manages PTestShell;
     manages PNecko;
     manages PExternalHelperApp;
 
 child:
     PBrowser(PRUint32 chromeFlags);
 
@@ -87,16 +89,18 @@ child:
     // nsIPermissionManager messages
     AddPermission(Permission permission);
 
     AccelerationChanged(double x, double y, double z);
 
 parent:
     PNecko();
 
+    PAudio(PRInt32 aNumChannels, PRInt32 aRate, PRInt32 aFormat);
+
     // Services remoting
 
     async StartVisitedQuery(URI uri);
     async VisitURI(URI uri, URI referrer, PRUint32 flags);
     async SetURITitle(URI uri, nsString title);
     
     // filepicker remoting
     sync ShowFilePicker(PRInt16 mode, PRInt16 selectedType, 
--- a/dom/ipc/ipdl.mk
+++ b/dom/ipc/ipdl.mk
@@ -30,14 +30,15 @@
 # decision by deleting the provisions above and replace them with the notice
 # and other provisions required by the GPL or the LGPL. If you do not delete
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
 IPDLSRCS = \
+  PAudio.ipdl \
   PBrowser.ipdl \
   PContent.ipdl \
   PContentDialog.ipdl \
   PDocumentRenderer.ipdl \
   PContentPermissionRequest.ipdl \
   $(NULL)