Bug 614160 - Fix remote audio ownership and avoid sending IPCs when actor is being destroyed. r=dougt a=blocking-fennec

--HG--
extra : rebase_source : 0fe7883f97fb4f014b9f39ced902bc96b0eebc31
This commit is contained in:
Matthew Gregan 2010-11-26 17:13:54 +13:00
parent 35d2ba11b4
commit d96f71fdba
7 changed files with 125 additions and 45 deletions

View File

@ -138,7 +138,7 @@ class nsAudioStreamRemote : public nsAudioStream
PRInt64 GetSampleOffset();
PRBool IsPaused();
AudioChild* mAudioChild;
nsRefPtr<AudioChild> mAudioChild;
SampleFormat mFormat;
int mRate;
@ -149,12 +149,6 @@ class nsAudioStreamRemote : public nsAudioStream
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
@ -181,27 +175,27 @@ class AudioInitEvent : public nsRunnable
class AudioWriteEvent : public nsRunnable
{
public:
AudioWriteEvent(nsAudioStreamRemote* owner,
AudioWriteEvent(AudioChild* aChild,
const void* aBuf,
PRUint32 aNumberOfSamples,
PRUint32 aBytesPerSample)
{
mOwner = owner;
mAudioChild = aChild;
mBytesPerSample = aBytesPerSample;
mBuffer.Assign((const char*)aBuf, aNumberOfSamples*aBytesPerSample);
}
NS_IMETHOD Run()
{
if (!mOwner->mAudioChild)
if (!mAudioChild->IsIPCOpen())
return NS_OK;
mOwner->mAudioChild->SendWrite(mBuffer,
mBuffer.Length() / mBytesPerSample);
mAudioChild->SendWrite(mBuffer,
mBuffer.Length() / mBytesPerSample);
return NS_OK;
}
nsRefPtr<nsAudioStreamRemote> mOwner;
nsRefPtr<AudioChild> mAudioChild;
nsCString mBuffer;
PRUint32 mBytesPerSample;
};
@ -209,73 +203,90 @@ class AudioWriteEvent : public nsRunnable
class AudioSetVolumeEvent : public nsRunnable
{
public:
AudioSetVolumeEvent(nsAudioStreamRemote* owner, float volume)
AudioSetVolumeEvent(AudioChild* aChild, float volume)
{
mOwner = owner;
mAudioChild = aChild;
mVolume = volume;
}
NS_IMETHOD Run()
{
if (!mOwner->mAudioChild)
if (!mAudioChild->IsIPCOpen())
return NS_OK;
mOwner->mAudioChild->SendSetVolume(mVolume);
mAudioChild->SendSetVolume(mVolume);
return NS_OK;
}
nsRefPtr<nsAudioStreamRemote> mOwner;
nsRefPtr<AudioChild> mAudioChild;
float mVolume;
};
class AudioDrainEvent : public nsRunnable
{
public:
AudioDrainEvent(nsAudioStreamRemote* owner)
AudioDrainEvent(AudioChild* aChild)
{
mOwner = owner;
mAudioChild = aChild;
}
NS_IMETHOD Run()
{
if (!mOwner->mAudioChild)
if (!mAudioChild->IsIPCOpen())
return NS_OK;
mOwner->mAudioChild->SendDrain();
mAudioChild->SendDrain();
return NS_OK;
}
nsRefPtr<nsAudioStreamRemote> mOwner;
nsRefPtr<AudioChild> mAudioChild;
};
class AudioPauseEvent : public nsRunnable
{
public:
AudioPauseEvent(nsAudioStreamRemote* owner, PRBool pause)
AudioPauseEvent(AudioChild* aChild, PRBool pause)
{
mOwner = owner;
mAudioChild = aChild;
mPause = pause;
}
NS_IMETHOD Run()
{
if (!mOwner->mAudioChild)
if (!mAudioChild->IsIPCOpen())
return NS_OK;
if (mPause)
mOwner->mAudioChild->SendPause();
mAudioChild->SendPause();
else
mOwner->mAudioChild->SendResume();
mAudioChild->SendResume();
return NS_OK;
}
nsRefPtr<nsAudioStreamRemote> mOwner;
nsRefPtr<AudioChild> mAudioChild;
PRBool mPause;
};
class AudioShutdownEvent : public nsRunnable
{
public:
AudioShutdownEvent(AudioChild* aChild)
{
mAudioChild = aChild;
}
NS_IMETHOD Run()
{
if (mAudioChild->IsIPCOpen())
PAudioChild::Send__delete__(mAudioChild);
return NS_OK;
}
nsRefPtr<AudioChild> mAudioChild;
};
#endif // MOZ_IPC
@ -602,14 +613,17 @@ nsAudioStreamRemote::Init(PRInt32 aNumChannels,
}
nsCOMPtr<nsIRunnable> event = new AudioInitEvent(this);
NS_DispatchToMainThread(event);
NS_DispatchToMainThread(event, NS_DISPATCH_SYNC);
return NS_OK;
}
void
nsAudioStreamRemote::Shutdown()
{
PAudioChild::Send__delete__(mAudioChild);
if (!mAudioChild)
return;
nsCOMPtr<nsIRunnable> event = new AudioShutdownEvent(mAudioChild);
NS_DispatchToMainThread(event);
mAudioChild = nsnull;
}
@ -618,7 +632,9 @@ nsAudioStreamRemote::Write(const void* aBuf,
PRUint32 aCount,
PRBool aBlocking)
{
nsCOMPtr<nsIRunnable> event = new AudioWriteEvent(this,
if (!mAudioChild)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIRunnable> event = new AudioWriteEvent(mAudioChild,
aBuf,
aCount,
mBytesPerSample);
@ -635,14 +651,18 @@ nsAudioStreamRemote::Available()
void
nsAudioStreamRemote::SetVolume(float aVolume)
{
nsCOMPtr<nsIRunnable> event = new AudioSetVolumeEvent(this, aVolume);
if (!mAudioChild)
return;
nsCOMPtr<nsIRunnable> event = new AudioSetVolumeEvent(mAudioChild, aVolume);
NS_DispatchToMainThread(event);
}
void
nsAudioStreamRemote::Drain()
{
nsCOMPtr<nsIRunnable> event = new AudioDrainEvent(this);
if (!mAudioChild)
return;
nsCOMPtr<nsIRunnable> event = new AudioDrainEvent(mAudioChild);
NS_DispatchToMainThread(event, NS_DISPATCH_SYNC);
}
@ -650,7 +670,9 @@ void
nsAudioStreamRemote::Pause()
{
mPaused = PR_TRUE;
nsCOMPtr<nsIRunnable> event = new AudioPauseEvent(this, PR_TRUE);
if (!mAudioChild)
return;
nsCOMPtr<nsIRunnable> event = new AudioPauseEvent(mAudioChild, PR_TRUE);
NS_DispatchToMainThread(event);
}
@ -658,7 +680,9 @@ void
nsAudioStreamRemote::Resume()
{
mPaused = PR_FALSE;
nsCOMPtr<nsIRunnable> event = new AudioPauseEvent(this, PR_FALSE);
if (!mAudioChild)
return;
nsCOMPtr<nsIRunnable> event = new AudioPauseEvent(mAudioChild, PR_FALSE);
NS_DispatchToMainThread(event);
}

View File

@ -42,9 +42,13 @@
namespace mozilla {
namespace dom {
NS_IMPL_THREADSAFE_ADDREF(AudioChild);
NS_IMPL_THREADSAFE_RELEASE(AudioChild);
AudioChild::AudioChild()
: mLastSampleOffset(-1),
mLastSampleOffsetTime(0)
mLastSampleOffsetTime(0),
mIPCOpen(PR_TRUE)
{
MOZ_COUNT_CTOR(AudioChild);
}
@ -54,6 +58,12 @@ AudioChild::~AudioChild()
MOZ_COUNT_DTOR(AudioChild);
}
void
AudioChild::ActorDestroy(ActorDestroyReason aWhy)
{
mIPCOpen = PR_FALSE;
}
bool
AudioChild::RecvSampleOffsetUpdate(const PRInt64& offset,
const PRInt64& time)

View File

@ -48,14 +48,23 @@ namespace dom {
class AudioChild : public PAudioChild
{
public:
NS_IMETHOD_(nsrefcnt) AddRef();
NS_IMETHOD_(nsrefcnt) Release();
AudioChild();
virtual ~AudioChild();
virtual bool RecvSampleOffsetUpdate(const PRInt64&, const PRInt64&);
virtual void ActorDestroy(ActorDestroyReason);
PRInt64 GetLastKnownSampleOffset();
PRInt64 GetLastKnownSampleOffsetTime();
PRBool IsIPCOpen() { return mIPCOpen; };
private:
nsAutoRefCnt mRefCnt;
NS_DECL_OWNINGTHREAD
PRInt64 mLastSampleOffset, mLastSampleOffsetTime;
PRPackedBool mIPCOpen;
};
} // namespace dom

View File

@ -66,12 +66,35 @@ class AudioWriteEvent : public nsRunnable
PRUint32 mCount;
};
class AudioPauseEvent : public nsRunnable
{
public:
AudioPauseEvent(nsAudioStream* owner, PRBool aPause)
{
mOwner = owner;
mPause = aPause;
}
NS_IMETHOD Run()
{
if (mPause)
mOwner->Pause();
else
mOwner->Resume();
return NS_OK;
}
private:
nsRefPtr<nsAudioStream> mOwner;
PRBool mPause;
};
NS_IMPL_THREADSAFE_ISUPPORTS1(AudioParent, nsITimerCallback)
nsresult
AudioParent::Notify(nsITimer* timer)
{
if (!mStream) {
if (!mIPCOpen || !mStream) {
timer->Cancel();
return NS_ERROR_FAILURE;
}
@ -110,16 +133,18 @@ AudioParent::RecvDrain()
bool
AudioParent::RecvPause()
{
if (mStream)
mStream->Pause();
nsCOMPtr<nsIRunnable> event = new AudioPauseEvent(mStream, PR_TRUE);
nsCOMPtr<nsIThread> thread = nsAudioStream::GetGlobalThread();
thread->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL);
return true;
}
bool
AudioParent::RecvResume()
{
if (mStream)
mStream->Resume();
nsCOMPtr<nsIRunnable> event = new AudioPauseEvent(mStream, PR_FALSE);
nsCOMPtr<nsIThread> thread = nsAudioStream::GetGlobalThread();
thread->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL);
return true;
}
@ -139,6 +164,7 @@ AudioParent::Recv__delete__()
}
AudioParent::AudioParent(PRInt32 aNumChannels, PRInt32 aRate, PRInt32 aFormat)
: mIPCOpen(PR_TRUE)
{
mStream = nsAudioStream::AllocateStream();
if (mStream)
@ -156,5 +182,11 @@ AudioParent::~AudioParent()
{
}
void
AudioParent::ActorDestroy(ActorDestroyReason aWhy)
{
mIPCOpen = PR_FALSE;
}
} // namespace dom
} // namespace mozilla

View File

@ -75,10 +75,13 @@ class AudioParent : public PAudioParent, public nsITimerCallback
AudioParent(PRInt32 aNumChannels, PRInt32 aRate, PRInt32 aFormat);
virtual ~AudioParent();
virtual void ActorDestroy(ActorDestroyReason);
nsRefPtr<nsAudioStream> mStream;
nsCOMPtr<nsITimer> mTimer;
private:
PRPackedBool mIPCOpen;
};
} // namespace dom
} // namespace mozilla

View File

@ -333,14 +333,16 @@ ContentChild::AllocPAudio(const PRInt32& numChannels,
const PRInt32& rate,
const PRInt32& format)
{
PAudioChild *child = new AudioChild();
AudioChild *child = new AudioChild();
NS_ADDREF(child);
return child;
}
bool
ContentChild::DeallocPAudio(PAudioChild* doomed)
{
delete doomed;
AudioChild *child = static_cast<AudioChild*>(doomed);
NS_RELEASE(child);
return true;
}

View File

@ -427,7 +427,7 @@ ContentParent::AllocPAudio(const PRInt32& numChannels,
const PRInt32& format)
{
AudioParent *parent = new AudioParent(numChannels, rate, format);
parent->AddRef();
NS_ADDREF(parent);
return parent;
}