diff --git a/dom/media/gmp/GMPAudioDecoderParent.cpp b/dom/media/gmp/GMPAudioDecoderParent.cpp index 2b801b45433..72facefc3fb 100644 --- a/dom/media/gmp/GMPAudioDecoderParent.cpp +++ b/dom/media/gmp/GMPAudioDecoderParent.cpp @@ -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 diff --git a/dom/media/gmp/GMPAudioDecoderParent.h b/dom/media/gmp/GMPAudioDecoderParent.h index 8379f6f89fe..cb19021f5d7 100644 --- a/dom/media/gmp/GMPAudioDecoderParent.h +++ b/dom/media/gmp/GMPAudioDecoderParent.h @@ -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 mPlugin; GMPAudioDecoderCallbackProxy* mCallback; }; diff --git a/dom/media/gmp/GMPVideoDecoderParent.cpp b/dom/media/gmp/GMPVideoDecoderParent.cpp index 8491a67d15d..68e633f8701 100644 --- a/dom/media/gmp/GMPVideoDecoderParent.cpp +++ b/dom/media/gmp/GMPVideoDecoderParent.cpp @@ -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 diff --git a/dom/media/gmp/GMPVideoDecoderParent.h b/dom/media/gmp/GMPVideoDecoderParent.h index 9b54403146f..1f477ed4176 100644 --- a/dom/media/gmp/GMPVideoDecoderParent.h +++ b/dom/media/gmp/GMPVideoDecoderParent.h @@ -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 mPlugin; GMPVideoDecoderCallbackProxy* mCallback; GMPVideoHostImpl mVideoHost;