Bug 612798 - Remoting Audio - Thread per stream to avoid problems with blocking drain/write calls. r=dougt. a=blocking-fennec

--HG--
extra : rebase_source : a2efdcf562d3da08e9676fe174d0cdc3e317fa82
This commit is contained in:
Matthew Gregan 2010-11-30 18:37:32 +13:00
parent d96f71fdba
commit 461a2eb686
6 changed files with 95 additions and 34 deletions

View File

@ -40,6 +40,7 @@
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/PAudioChild.h"
#include "mozilla/dom/AudioChild.h"
#include "mozilla/Monitor.h"
#include "nsXULAppAPI.h"
using namespace mozilla::dom;
#endif
@ -67,10 +68,6 @@ using mozilla::TimeStamp;
PRLogModuleInfo* gAudioStreamLog = nsnull;
#endif
#ifdef MOZ_IPC
static nsIThread *gAudioPlaybackThread = nsnull;
#endif
#define FAKE_BUFFER_SIZE 176400
#define MILLISECONDS_PER_SECOND 1000
@ -143,11 +140,12 @@ class nsAudioStreamRemote : public nsAudioStream
SampleFormat mFormat;
int mRate;
int mChannels;
// PR_TRUE if this audio stream is paused.
PRPackedBool mPaused;
PRInt32 mBytesPerSample;
// PR_TRUE if this audio stream is paused.
PRPackedBool mPaused;
friend class AudioInitEvent;
};
@ -295,32 +293,17 @@ 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
}
nsIThread *
nsAudioStream::GetGlobalThread()
nsAudioStream::GetThread()
{
#ifdef MOZ_IPC
NS_IF_ADDREF(gAudioPlaybackThread);
return gAudioPlaybackThread;
#else
return nsnull;
#endif
return mAudioPlaybackThread;
}
nsAudioStream* nsAudioStream::AllocateStream()
@ -342,6 +325,12 @@ nsAudioStreamLocal::nsAudioStreamLocal() :
mPaused(PR_FALSE),
mInError(PR_FALSE)
{
#ifdef MOZ_IPC
// We only need this thread in the main process.
if (XRE_GetProcessType() == GeckoProcessType_Default) {
NS_NewThread(getter_AddRefs(mAudioPlaybackThread));
}
#endif
}
nsAudioStreamLocal::~nsAudioStreamLocal()
@ -663,7 +652,8 @@ nsAudioStreamRemote::Drain()
if (!mAudioChild)
return;
nsCOMPtr<nsIRunnable> event = new AudioDrainEvent(mAudioChild);
NS_DispatchToMainThread(event, NS_DISPATCH_SYNC);
NS_DispatchToMainThread(event);
mAudioChild->WaitForDrain();
}
void

View File

@ -41,6 +41,7 @@
#include "nscore.h"
#include "nsISupportsImpl.h"
#include "nsIThread.h"
#include "nsAutoPtr.h"
class nsAudioStream : public nsISupports
{
@ -63,7 +64,7 @@ public:
// Thread, usually for MOZ_IPC handling, that is shared between audio streams.
// This may return null in the child process
static nsIThread *GetGlobalThread();
virtual nsIThread *GetThread();
// 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
@ -114,6 +115,9 @@ public:
// Returns PR_TRUE when the audio stream is paused.
virtual PRBool IsPaused() = 0;
protected:
nsCOMPtr<nsIThread> mAudioPlaybackThread;
};
#endif

View File

@ -48,7 +48,9 @@ NS_IMPL_THREADSAFE_RELEASE(AudioChild);
AudioChild::AudioChild()
: mLastSampleOffset(-1),
mLastSampleOffsetTime(0),
mIPCOpen(PR_TRUE)
mAudioMonitor("media.audiochild.monitor"),
mIPCOpen(PR_TRUE),
mDrained(PR_FALSE)
{
MOZ_COUNT_CTOR(AudioChild);
}
@ -73,6 +75,24 @@ AudioChild::RecvSampleOffsetUpdate(const PRInt64& offset,
return true;
}
bool
AudioChild::RecvDrainDone()
{
mozilla::MonitorAutoEnter mon(mAudioMonitor);
mDrained = PR_TRUE;
mAudioMonitor.NotifyAll();
return true;
}
void
AudioChild::WaitForDrain()
{
mozilla::MonitorAutoEnter mon(mAudioMonitor);
while (!mDrained && mIPCOpen) {
mAudioMonitor.Wait();
}
}
PRInt64
AudioChild::GetLastKnownSampleOffset()
{

View File

@ -41,6 +41,7 @@
#define mozilla_dom_AudioChild_h
#include "mozilla/dom/PAudioChild.h"
#include "mozilla/Monitor.h"
namespace mozilla {
namespace dom {
@ -54,6 +55,8 @@ class AudioChild : public PAudioChild
AudioChild();
virtual ~AudioChild();
virtual bool RecvSampleOffsetUpdate(const PRInt64&, const PRInt64&);
virtual bool RecvDrainDone();
virtual void WaitForDrain();
virtual void ActorDestroy(ActorDestroyReason);
PRInt64 GetLastKnownSampleOffset();
@ -64,7 +67,9 @@ class AudioChild : public PAudioChild
nsAutoRefCnt mRefCnt;
NS_DECL_OWNINGTHREAD
PRInt64 mLastSampleOffset, mLastSampleOffsetTime;
mozilla::Monitor mAudioMonitor;
PRPackedBool mIPCOpen;
PRPackedBool mDrained;
};
} // namespace dom

View File

@ -89,6 +89,46 @@ class AudioPauseEvent : public nsRunnable
PRBool mPause;
};
class AudioDrainDoneEvent : public nsRunnable
{
public:
AudioDrainDoneEvent(AudioParent* owner)
{
mOwner = owner;
}
NS_IMETHOD Run()
{
mOwner->SendDrainDone();
return NS_OK;
}
private:
nsRefPtr<AudioParent> mOwner;
};
class AudioDrainEvent : public nsRunnable
{
public:
AudioDrainEvent(AudioParent* parent, nsAudioStream* owner)
{
mParent = parent;
mOwner = owner;
}
NS_IMETHOD Run()
{
mOwner->Drain();
nsCOMPtr<nsIRunnable> event = new AudioDrainDoneEvent(mParent);
NS_DispatchToMainThread(event);
return NS_OK;
}
private:
nsRefPtr<nsAudioStream> mOwner;
nsRefPtr<AudioParent> mParent;
};
NS_IMPL_THREADSAFE_ISUPPORTS1(AudioParent, nsITimerCallback)
nsresult
@ -109,11 +149,11 @@ AudioParent::RecvWrite(
const PRUint32& count)
{
nsCOMPtr<nsIRunnable> event = new AudioWriteEvent(mStream, data, count);
nsCOMPtr<nsIThread> thread = nsAudioStream::GetGlobalThread();
nsCOMPtr<nsIThread> thread = mStream->GetThread();
thread->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL);
return true;
}
bool
AudioParent::RecvSetVolume(const float& aVolume)
{
@ -125,8 +165,9 @@ AudioParent::RecvSetVolume(const float& aVolume)
bool
AudioParent::RecvDrain()
{
if (mStream)
mStream->Drain();
nsCOMPtr<nsIRunnable> event = new AudioDrainEvent(this, mStream);
nsCOMPtr<nsIThread> thread = mStream->GetThread();
thread->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL);
return true;
}
@ -134,7 +175,7 @@ bool
AudioParent::RecvPause()
{
nsCOMPtr<nsIRunnable> event = new AudioPauseEvent(mStream, PR_TRUE);
nsCOMPtr<nsIThread> thread = nsAudioStream::GetGlobalThread();
nsCOMPtr<nsIThread> thread = mStream->GetThread();
thread->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL);
return true;
}
@ -143,7 +184,7 @@ bool
AudioParent::RecvResume()
{
nsCOMPtr<nsIRunnable> event = new AudioPauseEvent(mStream, PR_FALSE);
nsCOMPtr<nsIThread> thread = nsAudioStream::GetGlobalThread();
nsCOMPtr<nsIThread> thread = mStream->GetThread();
thread->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL);
return true;
}

View File

@ -42,7 +42,7 @@ include protocol PContent;
namespace mozilla {
namespace dom {
sync protocol PAudio
protocol PAudio
{
manager PContent;
@ -54,7 +54,7 @@ parent:
SetVolume(float aVolume);
sync Drain();
Drain();
Pause();
Resume();
@ -62,6 +62,7 @@ parent:
child:
SampleOffsetUpdate(PRInt64 offset, PRInt64 time);
DrainDone();
};