Bug 1187163 - Ensure we send Reset/Drain complete notifications no matter what happens in GMP{Audio,Video}Decoder. r=gerald

This commit is contained in:
Chris Pearce 2015-07-27 11:52:16 +12:00
parent 9aaf830c11
commit 1755d289d6
4 changed files with 118 additions and 0 deletions

View File

@ -28,6 +28,8 @@ GMPAudioDecoderParent::GMPAudioDecoderParent(GMPContentParent* aPlugin)
: mIsOpen(false)
, mShuttingDown(false)
, mActorDestroyed(false)
, mIsAwaitingResetComplete(false)
, mIsAwaitingDrainComplete(false)
, mPlugin(aPlugin)
, mCallback(nullptr)
{
@ -109,6 +111,8 @@ GMPAudioDecoderParent::Reset()
return NS_ERROR_FAILURE;
}
mIsAwaitingResetComplete = true;
// Async IPC, we don't have access to a return value.
return NS_OK;
}
@ -127,6 +131,8 @@ GMPAudioDecoderParent::Drain()
return NS_ERROR_FAILURE;
}
mIsAwaitingDrainComplete = true;
// Async IPC, we don't have access to a return value.
return NS_OK;
}
@ -138,6 +144,11 @@ GMPAudioDecoderParent::Close()
LOGD(("%s: %p", __FUNCTION__, this));
MOZ_ASSERT(!mPlugin || mPlugin->GMPThread() == NS_GetCurrentThread());
// Ensure if we've received a Close while waiting for a ResetComplete
// or DrainComplete notification, we'll unblock the caller before processing
// the close. This seems unlikely to happen, but better to be careful.
UnblockResetAndDrain();
// Consumer is done with us; we can shut down. No more callbacks should
// be made to mCallback. Note: do this before Shutdown()!
mCallback = nullptr;
@ -163,6 +174,11 @@ GMPAudioDecoderParent::Shutdown()
}
mShuttingDown = true;
// Ensure if we've received a shutdown while waiting for a ResetComplete
// or DrainComplete notification, we'll unblock the caller before processing
// the shutdown.
UnblockResetAndDrain();
// Notify client we're gone! Won't occur after Close()
if (mCallback) {
mCallback->Terminated();
@ -183,6 +199,12 @@ GMPAudioDecoderParent::ActorDestroy(ActorDestroyReason aWhy)
{
mIsOpen = false;
mActorDestroyed = true;
// Ensure if we've received a destroy while waiting for a ResetComplete
// or DrainComplete notification, we'll unblock the caller before processing
// the error.
UnblockResetAndDrain();
if (mCallback) {
// May call Close() (and Shutdown()) immediately or with a delay
mCallback->Terminated();
@ -230,6 +252,11 @@ GMPAudioDecoderParent::RecvDrainComplete()
return false;
}
if (!mIsAwaitingDrainComplete) {
return true;
}
mIsAwaitingDrainComplete = false;
// Ignore any return code. It is OK for this to fail without killing the process.
mCallback->DrainComplete();
@ -243,6 +270,11 @@ GMPAudioDecoderParent::RecvResetComplete()
return false;
}
if (!mIsAwaitingResetComplete) {
return true;
}
mIsAwaitingResetComplete = false;
// Ignore any return code. It is OK for this to fail without killing the process.
mCallback->ResetComplete();
@ -256,6 +288,11 @@ GMPAudioDecoderParent::RecvError(const GMPErr& aError)
return false;
}
// Ensure if we've received an error while waiting for a ResetComplete
// or DrainComplete notification, we'll unblock the caller before processing
// the error.
UnblockResetAndDrain();
// Ignore any return code. It is OK for this to fail without killing the process.
mCallback->Error(aError);
@ -281,5 +318,23 @@ GMPAudioDecoderParent::Recv__delete__()
return true;
}
void
GMPAudioDecoderParent::UnblockResetAndDrain()
{
if (!mCallback) {
MOZ_ASSERT(!mIsAwaitingResetComplete);
MOZ_ASSERT(!mIsAwaitingDrainComplete);
return;
}
if (mIsAwaitingResetComplete) {
mIsAwaitingResetComplete = false;
mCallback->ResetComplete();
}
if (mIsAwaitingDrainComplete) {
mIsAwaitingDrainComplete = false;
mCallback->DrainComplete();
}
}
} // namespace gmp
} // namespace mozilla

View File

@ -53,9 +53,13 @@ private:
virtual bool RecvShutdown() override;
virtual bool Recv__delete__() override;
void UnblockResetAndDrain();
bool mIsOpen;
bool mShuttingDown;
bool mActorDestroyed;
bool mIsAwaitingResetComplete;
bool mIsAwaitingDrainComplete;
nsRefPtr<GMPContentParent> mPlugin;
GMPAudioDecoderCallbackProxy* mCallback;
};

View File

@ -43,6 +43,8 @@ GMPVideoDecoderParent::GMPVideoDecoderParent(GMPContentParent* aPlugin)
, mIsOpen(false)
, mShuttingDown(false)
, mActorDestroyed(false)
, mIsAwaitingResetComplete(false)
, mIsAwaitingDrainComplete(false)
, mPlugin(aPlugin)
, mCallback(nullptr)
, mVideoHost(this)
@ -67,6 +69,12 @@ GMPVideoDecoderParent::Close()
{
LOGD(("%s: %p", __FUNCTION__, this));
MOZ_ASSERT(!mPlugin || mPlugin->GMPThread() == NS_GetCurrentThread());
// Ensure if we've received a Close while waiting for a ResetComplete
// or DrainComplete notification, we'll unblock the caller before processing
// the close. This seems unlikely to happen, but better to be careful.
UnblockResetAndDrain();
// Consumer is done with us; we can shut down. No more callbacks should
// be made to mCallback. Note: do this before Shutdown()!
mCallback = nullptr;
@ -161,6 +169,8 @@ GMPVideoDecoderParent::Reset()
return NS_ERROR_FAILURE;
}
mIsAwaitingResetComplete = true;
// Async IPC, we don't have access to a return value.
return NS_OK;
}
@ -179,6 +189,8 @@ GMPVideoDecoderParent::Drain()
return NS_ERROR_FAILURE;
}
mIsAwaitingDrainComplete = true;
// Async IPC, we don't have access to a return value.
return NS_OK;
}
@ -207,6 +219,11 @@ GMPVideoDecoderParent::Shutdown()
}
mShuttingDown = true;
// Ensure if we've received a shutdown while waiting for a ResetComplete
// or DrainComplete notification, we'll unblock the caller before processing
// the shutdown.
UnblockResetAndDrain();
// Notify client we're gone! Won't occur after Close()
if (mCallback) {
mCallback->Terminated();
@ -229,6 +246,11 @@ GMPVideoDecoderParent::ActorDestroy(ActorDestroyReason aWhy)
mActorDestroyed = true;
mVideoHost.DoneWithAPI();
// Ensure if we've received a destroy while waiting for a ResetComplete
// or DrainComplete notification, we'll unblock the caller before processing
// the error.
UnblockResetAndDrain();
if (mCallback) {
// May call Close() (and Shutdown()) immediately or with a delay
mCallback->Terminated();
@ -307,6 +329,11 @@ GMPVideoDecoderParent::RecvDrainComplete()
return false;
}
if (!mIsAwaitingDrainComplete) {
return true;
}
mIsAwaitingDrainComplete = false;
// Ignore any return code. It is OK for this to fail without killing the process.
mCallback->DrainComplete();
@ -320,6 +347,11 @@ GMPVideoDecoderParent::RecvResetComplete()
return false;
}
if (!mIsAwaitingResetComplete) {
return true;
}
mIsAwaitingResetComplete = false;
// Ignore any return code. It is OK for this to fail without killing the process.
mCallback->ResetComplete();
@ -333,6 +365,11 @@ GMPVideoDecoderParent::RecvError(const GMPErr& aError)
return false;
}
// Ensure if we've received an error while waiting for a ResetComplete
// or DrainComplete notification, we'll unblock the caller before processing
// the error.
UnblockResetAndDrain();
// Ignore any return code. It is OK for this to fail without killing the process.
mCallback->Error(aError);
@ -387,5 +424,23 @@ GMPVideoDecoderParent::Recv__delete__()
return true;
}
void
GMPVideoDecoderParent::UnblockResetAndDrain()
{
if (!mCallback) {
MOZ_ASSERT(!mIsAwaitingResetComplete);
MOZ_ASSERT(!mIsAwaitingDrainComplete);
return;
}
if (mIsAwaitingResetComplete) {
mIsAwaitingResetComplete = false;
mCallback->ResetComplete();
}
if (mIsAwaitingDrainComplete) {
mIsAwaitingDrainComplete = false;
mCallback->DrainComplete();
}
}
} // namespace gmp
} // namespace mozilla

View File

@ -79,9 +79,13 @@ private:
Shmem* aMem) override;
virtual bool Recv__delete__() override;
void UnblockResetAndDrain();
bool mIsOpen;
bool mShuttingDown;
bool mActorDestroyed;
bool mIsAwaitingResetComplete;
bool mIsAwaitingDrainComplete;
nsRefPtr<GMPContentParent> mPlugin;
GMPVideoDecoderCallbackProxy* mCallback;
GMPVideoHostImpl mVideoHost;