mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-24 03:19:06 +00:00
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:
parent
d96f71fdba
commit
461a2eb686
@ -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
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user