LCOV - code coverage report
Current view: top level - dom/media/gmp - GMPVideoDecoderParent.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 224 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 29 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "GMPVideoDecoderParent.h"
       7             : #include "mozilla/Logging.h"
       8             : #include "mozilla/SizePrintfMacros.h"
       9             : #include "mozilla/Unused.h"
      10             : #include "nsAutoRef.h"
      11             : #include "nsThreadUtils.h"
      12             : #include "GMPUtils.h"
      13             : #include "GMPVideoEncodedFrameImpl.h"
      14             : #include "GMPVideoi420FrameImpl.h"
      15             : #include "GMPContentParent.h"
      16             : #include "GMPMessageUtils.h"
      17             : #include "mozilla/gmp/GMPTypes.h"
      18             : #include "nsPrintfCString.h"
      19             : 
      20             : namespace mozilla {
      21             : 
      22             : #ifdef LOG
      23             : #undef LOG
      24             : #endif
      25             : 
      26             : extern LogModule* GetGMPLog();
      27             : 
      28             : #define LOGV(msg) MOZ_LOG(GetGMPLog(), mozilla::LogLevel::Verbose, msg)
      29             : #define LOGD(msg) MOZ_LOG(GetGMPLog(), mozilla::LogLevel::Debug, msg)
      30             : #define LOGE(msg) MOZ_LOG(GetGMPLog(), mozilla::LogLevel::Error, msg)
      31             : #define LOG(level, msg) MOZ_LOG(GetGMPLog(), (level), msg)
      32             : 
      33             : namespace gmp {
      34             : 
      35             : // States:
      36             : // Initial: mIsOpen == false
      37             : //    on InitDecode success -> Open
      38             : //    on Shutdown -> Dead
      39             : // Open: mIsOpen == true
      40             : //    on Close -> Dead
      41             : //    on ActorDestroy -> Dead
      42             : //    on Shutdown -> Dead
      43             : // Dead: mIsOpen == false
      44             : 
      45           0 : GMPVideoDecoderParent::GMPVideoDecoderParent(GMPContentParent* aPlugin)
      46             :   : GMPSharedMemManager(aPlugin)
      47             :   , mIsOpen(false)
      48             :   , mShuttingDown(false)
      49             :   , mActorDestroyed(false)
      50             :   , mIsAwaitingResetComplete(false)
      51             :   , mIsAwaitingDrainComplete(false)
      52             :   , mPlugin(aPlugin)
      53             :   , mCallback(nullptr)
      54             :   , mVideoHost(this)
      55           0 :   , mPluginId(aPlugin->GetPluginId())
      56           0 :   , mFrameCount(0)
      57             : {
      58           0 :   MOZ_ASSERT(mPlugin);
      59           0 : }
      60             : 
      61           0 : GMPVideoDecoderParent::~GMPVideoDecoderParent()
      62             : {
      63           0 : }
      64             : 
      65             : GMPVideoHostImpl&
      66           0 : GMPVideoDecoderParent::Host()
      67             : {
      68           0 :   return mVideoHost;
      69             : }
      70             : 
      71             : // Note: may be called via Terminated()
      72             : void
      73           0 : GMPVideoDecoderParent::Close()
      74             : {
      75           0 :   LOGD(("GMPVideoDecoderParent[%p]::Close()", this));
      76           0 :   MOZ_ASSERT(!mPlugin || mPlugin->GMPEventTarget()->IsOnCurrentThread());
      77             : 
      78             :   // Ensure if we've received a Close while waiting for a ResetComplete
      79             :   // or DrainComplete notification, we'll unblock the caller before processing
      80             :   // the close. This seems unlikely to happen, but better to be careful.
      81           0 :   UnblockResetAndDrain();
      82             : 
      83             :   // Consumer is done with us; we can shut down.  No more callbacks should
      84             :   // be made to mCallback.  Note: do this before Shutdown()!
      85           0 :   mCallback = nullptr;
      86             :   // Let Shutdown mark us as dead so it knows if we had been alive
      87             : 
      88             :   // In case this is the last reference
      89           0 :   RefPtr<GMPVideoDecoderParent> kungfudeathgrip(this);
      90           0 :   Release();
      91           0 :   Shutdown();
      92           0 : }
      93             : 
      94             : nsresult
      95           0 : GMPVideoDecoderParent::InitDecode(const GMPVideoCodec& aCodecSettings,
      96             :                                   const nsTArray<uint8_t>& aCodecSpecific,
      97             :                                   GMPVideoDecoderCallbackProxy* aCallback,
      98             :                                   int32_t aCoreCount)
      99             : {
     100           0 :   LOGD(("GMPVideoDecoderParent[%p]::InitDecode()", this));
     101             : 
     102           0 :   if (mActorDestroyed) {
     103           0 :     NS_WARNING("Trying to use a destroyed GMP video decoder!");
     104           0 :     return NS_ERROR_FAILURE;
     105             :   }
     106           0 :   if (mIsOpen) {
     107           0 :     NS_WARNING("Trying to re-init an in-use GMP video decoder!");
     108           0 :     return NS_ERROR_FAILURE;
     109             :   }
     110             : 
     111           0 :   MOZ_ASSERT(mPlugin->GMPEventTarget()->IsOnCurrentThread());
     112             : 
     113           0 :   if (!aCallback) {
     114           0 :     return NS_ERROR_FAILURE;
     115             :   }
     116           0 :   mCallback = aCallback;
     117             : 
     118           0 :   if (!SendInitDecode(aCodecSettings, aCodecSpecific, aCoreCount)) {
     119           0 :     return NS_ERROR_FAILURE;
     120             :   }
     121           0 :   mIsOpen = true;
     122             : 
     123             :   // Async IPC, we don't have access to a return value.
     124           0 :   return NS_OK;
     125             : }
     126             : 
     127             : static nsCString
     128           0 : CryptoInfo(const GMPUniquePtr<GMPVideoEncodedFrame>& aInputFrame)
     129             : {
     130           0 :   const GMPEncryptedBufferMetadata* crypto = aInputFrame->GetDecryptionData();
     131           0 :   if (!crypto) {
     132           0 :     return EmptyCString();
     133             :   }
     134           0 :   return nsPrintfCString(" kid=%s",
     135           0 :                          ToHexString(crypto->KeyId(), crypto->KeyIdSize()).get());
     136             : }
     137             : 
     138             : nsresult
     139           0 : GMPVideoDecoderParent::Decode(GMPUniquePtr<GMPVideoEncodedFrame> aInputFrame,
     140             :                               bool aMissingFrames,
     141             :                               const nsTArray<uint8_t>& aCodecSpecificInfo,
     142             :                               int64_t aRenderTimeMs)
     143             : {
     144           0 :   LOGV(("GMPVideoDecoderParent[%p]::Decode() timestamp=%" PRId64 " keyframe=%d%s",
     145             :         this, aInputFrame->TimeStamp(),
     146             :         aInputFrame->FrameType() == kGMPKeyFrame,
     147             :         CryptoInfo(aInputFrame).get()));
     148             : 
     149           0 :   if (!mIsOpen) {
     150           0 :     LOGE(("GMPVideoDecoderParent[%p]::Decode() ERROR; dead GMPVideoDecoder", this));
     151           0 :     NS_WARNING("Trying to use an dead GMP video decoder");
     152           0 :     return NS_ERROR_FAILURE;
     153             :   }
     154             : 
     155           0 :   MOZ_ASSERT(mPlugin->GMPEventTarget()->IsOnCurrentThread());
     156             : 
     157             :   GMPUniquePtr<GMPVideoEncodedFrameImpl> inputFrameImpl(
     158           0 :     static_cast<GMPVideoEncodedFrameImpl*>(aInputFrame.release()));
     159             : 
     160             :   // Very rough kill-switch if the plugin stops processing.  If it's merely
     161             :   // hung and continues, we'll come back to life eventually.
     162             :   // 3* is because we're using 3 buffers per frame for i420 data for now.
     163           0 :   if ((NumInUse(GMPSharedMem::kGMPFrameData) > 3*GMPSharedMem::kGMPBufLimit) ||
     164           0 :       (NumInUse(GMPSharedMem::kGMPEncodedData) > GMPSharedMem::kGMPBufLimit)) {
     165           0 :     LOGE(("GMPVideoDecoderParent[%p]::Decode() ERROR; shmem buffer limit hit frame=%d encoded=%d",
     166             :           this, NumInUse(GMPSharedMem::kGMPFrameData), NumInUse(GMPSharedMem::kGMPEncodedData)));
     167           0 :     return NS_ERROR_FAILURE;
     168             :   }
     169             : 
     170           0 :   GMPVideoEncodedFrameData frameData;
     171           0 :   inputFrameImpl->RelinquishFrameData(frameData);
     172             : 
     173           0 :   if (!SendDecode(frameData,
     174             :                   aMissingFrames,
     175             :                   aCodecSpecificInfo,
     176             :                   aRenderTimeMs)) {
     177           0 :     LOGE(("GMPVideoDecoderParent[%p]::Decode() ERROR; SendDecode() failure.", this));
     178           0 :     return NS_ERROR_FAILURE;
     179             :   }
     180           0 :   mFrameCount++;
     181             : 
     182             :   // Async IPC, we don't have access to a return value.
     183           0 :   return NS_OK;
     184             : }
     185             : 
     186             : nsresult
     187           0 : GMPVideoDecoderParent::Reset()
     188             : {
     189           0 :   LOGD(("GMPVideoDecoderParent[%p]::Reset()", this));
     190             : 
     191           0 :   if (!mIsOpen) {
     192           0 :     NS_WARNING("Trying to use an dead GMP video decoder");
     193           0 :     return NS_ERROR_FAILURE;
     194             :   }
     195             : 
     196           0 :   MOZ_ASSERT(mPlugin->GMPEventTarget()->IsOnCurrentThread());
     197             : 
     198           0 :   if (!SendReset()) {
     199           0 :     return NS_ERROR_FAILURE;
     200             :   }
     201             : 
     202           0 :   mIsAwaitingResetComplete = true;
     203             : 
     204           0 :   RefPtr<GMPVideoDecoderParent> self(this);
     205           0 :   nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction(
     206           0 :     "gmp::GMPVideoDecoderParent::Reset", [self]() -> void {
     207           0 :       LOGD(("GMPVideoDecoderParent[%p]::ResetCompleteTimeout() timed out "
     208             :             "waiting for ResetComplete",
     209             :             self.get()));
     210           0 :       self->mResetCompleteTimeout = nullptr;
     211           0 :       LogToBrowserConsole(NS_LITERAL_STRING(
     212           0 :         "GMPVideoDecoderParent timed out waiting for ResetComplete()"));
     213           0 :     });
     214           0 :   CancelResetCompleteTimeout();
     215           0 :   nsCOMPtr<nsISerialEventTarget> target = mPlugin->GMPEventTarget();
     216           0 :   mResetCompleteTimeout = SimpleTimer::Create(task, 5000, target);
     217             : 
     218             :   // Async IPC, we don't have access to a return value.
     219           0 :   return NS_OK;
     220             : }
     221             : 
     222             : void
     223           0 : GMPVideoDecoderParent::CancelResetCompleteTimeout()
     224             : {
     225           0 :   if (mResetCompleteTimeout) {
     226           0 :     mResetCompleteTimeout->Cancel();
     227           0 :     mResetCompleteTimeout = nullptr;
     228             :   }
     229           0 : }
     230             : 
     231             : nsresult
     232           0 : GMPVideoDecoderParent::Drain()
     233             : {
     234           0 :   LOGD(("GMPVideoDecoderParent[%p]::Drain() frameCount=%d", this, mFrameCount));
     235             : 
     236           0 :   if (!mIsOpen) {
     237           0 :     NS_WARNING("Trying to use an dead GMP video decoder");
     238           0 :     return NS_ERROR_FAILURE;
     239             :   }
     240             : 
     241           0 :   MOZ_ASSERT(mPlugin->GMPEventTarget()->IsOnCurrentThread());
     242             : 
     243           0 :   if (!SendDrain()) {
     244           0 :     return NS_ERROR_FAILURE;
     245             :   }
     246             : 
     247           0 :   mIsAwaitingDrainComplete = true;
     248             : 
     249             :   // Async IPC, we don't have access to a return value.
     250           0 :   return NS_OK;
     251             : }
     252             : 
     253             : const nsCString&
     254           0 : GMPVideoDecoderParent::GetDisplayName() const
     255             : {
     256           0 :   if (!mIsOpen) {
     257           0 :     NS_WARNING("Trying to use an dead GMP video decoder");
     258             :   }
     259             : 
     260           0 :   MOZ_ASSERT(mPlugin->GMPEventTarget()->IsOnCurrentThread());
     261             : 
     262           0 :   return mPlugin->GetDisplayName();
     263             : }
     264             : 
     265             : // Note: Consider keeping ActorDestroy sync'd up when making changes here.
     266             : nsresult
     267           0 : GMPVideoDecoderParent::Shutdown()
     268             : {
     269           0 :   LOGD(("GMPVideoDecoderParent[%p]::Shutdown()", this));
     270           0 :   MOZ_ASSERT(!mPlugin || mPlugin->GMPEventTarget()->IsOnCurrentThread());
     271             : 
     272           0 :   if (mShuttingDown) {
     273           0 :     return NS_OK;
     274             :   }
     275           0 :   mShuttingDown = true;
     276             : 
     277             :   // Ensure if we've received a shutdown while waiting for a ResetComplete
     278             :   // or DrainComplete notification, we'll unblock the caller before processing
     279             :   // the shutdown.
     280           0 :   UnblockResetAndDrain();
     281             : 
     282             :   // Notify client we're gone!  Won't occur after Close()
     283           0 :   if (mCallback) {
     284           0 :     mCallback->Terminated();
     285           0 :     mCallback = nullptr;
     286             :   }
     287             : 
     288           0 :   mIsOpen = false;
     289           0 :   if (!mActorDestroyed) {
     290           0 :     Unused << SendDecodingComplete();
     291             :   }
     292             : 
     293           0 :   return NS_OK;
     294             : }
     295             : 
     296             : // Note: Keep this sync'd up with Shutdown
     297             : void
     298           0 : GMPVideoDecoderParent::ActorDestroy(ActorDestroyReason aWhy)
     299             : {
     300           0 :   LOGD(("GMPVideoDecoderParent[%p]::ActorDestroy reason=%d", this, aWhy));
     301             : 
     302           0 :   mIsOpen = false;
     303           0 :   mActorDestroyed = true;
     304             : 
     305             :   // Ensure if we've received a destroy while waiting for a ResetComplete
     306             :   // or DrainComplete notification, we'll unblock the caller before processing
     307             :   // the error.
     308           0 :   UnblockResetAndDrain();
     309             : 
     310           0 :   if (mCallback) {
     311             :     // May call Close() (and Shutdown()) immediately or with a delay
     312           0 :     mCallback->Terminated();
     313           0 :     mCallback = nullptr;
     314             :   }
     315           0 :   if (mPlugin) {
     316             :     // Ignore any return code. It is OK for this to fail without killing the process.
     317           0 :     mPlugin->VideoDecoderDestroyed(this);
     318           0 :     mPlugin = nullptr;
     319             :   }
     320           0 :   mVideoHost.ActorDestroyed();
     321           0 :   MaybeDisconnect(aWhy == AbnormalShutdown);
     322           0 : }
     323             : 
     324             : mozilla::ipc::IPCResult
     325           0 : GMPVideoDecoderParent::RecvDecoded(const GMPVideoi420FrameData& aDecodedFrame)
     326             : {
     327           0 :   --mFrameCount;
     328           0 :   LOGV(("GMPVideoDecoderParent[%p]::RecvDecoded() timestamp=%" PRId64 " frameCount=%d",
     329             :     this, aDecodedFrame.mTimestamp(), mFrameCount));
     330             : 
     331           0 :   if (!mCallback) {
     332           0 :     return IPC_FAIL_NO_REASON(this);
     333             :   }
     334             : 
     335           0 :   if (!GMPVideoi420FrameImpl::CheckFrameData(aDecodedFrame)) {
     336           0 :     LOGE(("GMPVideoDecoderParent[%p]::RecvDecoded() "
     337             :           "timestamp=%" PRId64 " decoded frame corrupt, ignoring",
     338             :           this, aDecodedFrame.mTimestamp()));
     339           0 :     return IPC_FAIL_NO_REASON(this);
     340             :   }
     341           0 :   auto f = new GMPVideoi420FrameImpl(aDecodedFrame, &mVideoHost);
     342             : 
     343             :   // Ignore any return code. It is OK for this to fail without killing the process.
     344           0 :   mCallback->Decoded(f);
     345             : 
     346           0 :   return IPC_OK();
     347             : }
     348             : 
     349             : mozilla::ipc::IPCResult
     350           0 : GMPVideoDecoderParent::RecvReceivedDecodedReferenceFrame(const uint64_t& aPictureId)
     351             : {
     352           0 :   if (!mCallback) {
     353           0 :     return IPC_FAIL_NO_REASON(this);
     354             :   }
     355             : 
     356             :   // Ignore any return code. It is OK for this to fail without killing the process.
     357           0 :   mCallback->ReceivedDecodedReferenceFrame(aPictureId);
     358             : 
     359           0 :   return IPC_OK();
     360             : }
     361             : 
     362             : mozilla::ipc::IPCResult
     363           0 : GMPVideoDecoderParent::RecvReceivedDecodedFrame(const uint64_t& aPictureId)
     364             : {
     365           0 :   if (!mCallback) {
     366           0 :     return IPC_FAIL_NO_REASON(this);
     367             :   }
     368             : 
     369             :   // Ignore any return code. It is OK for this to fail without killing the process.
     370           0 :   mCallback->ReceivedDecodedFrame(aPictureId);
     371             : 
     372           0 :   return IPC_OK();
     373             : }
     374             : 
     375             : mozilla::ipc::IPCResult
     376           0 : GMPVideoDecoderParent::RecvInputDataExhausted()
     377             : {
     378           0 :   LOGV(("GMPVideoDecoderParent[%p]::RecvInputDataExhausted()", this));
     379             : 
     380           0 :   if (!mCallback) {
     381           0 :     return IPC_FAIL_NO_REASON(this);
     382             :   }
     383             : 
     384             :   // Ignore any return code. It is OK for this to fail without killing the process.
     385           0 :   mCallback->InputDataExhausted();
     386             : 
     387           0 :   return IPC_OK();
     388             : }
     389             : 
     390             : mozilla::ipc::IPCResult
     391           0 : GMPVideoDecoderParent::RecvDrainComplete()
     392             : {
     393           0 :   LOGD(("GMPVideoDecoderParent[%p]::RecvDrainComplete() frameCount=%d", this, mFrameCount));
     394           0 :   nsAutoString msg;
     395           0 :   msg.AppendLiteral("GMPVideoDecoderParent::RecvDrainComplete() outstanding frames=");
     396           0 :   msg.AppendInt(mFrameCount);
     397           0 :   LogToBrowserConsole(msg);
     398             : 
     399           0 :   if (!mCallback) {
     400             :     // We anticipate shutting down in the middle of a drain in the
     401             :     // `UnblockResetAndDrain` method, which is called when we shutdown, so
     402             :     // everything is sunny.
     403           0 :     return IPC_OK();
     404             :   }
     405             : 
     406           0 :   if (!mIsAwaitingDrainComplete) {
     407           0 :     return IPC_OK();
     408             :   }
     409           0 :   mIsAwaitingDrainComplete = false;
     410             : 
     411             :   // Ignore any return code. It is OK for this to fail without killing the process.
     412           0 :   mCallback->DrainComplete();
     413             : 
     414           0 :   return IPC_OK();
     415             : }
     416             : 
     417             : mozilla::ipc::IPCResult
     418           0 : GMPVideoDecoderParent::RecvResetComplete()
     419             : {
     420           0 :   LOGD(("GMPVideoDecoderParent[%p]::RecvResetComplete()", this));
     421             : 
     422           0 :   CancelResetCompleteTimeout();
     423             : 
     424           0 :   if (!mCallback) {
     425             :     // We anticipate shutting down in the middle of a reset in the
     426             :     // `UnblockResetAndDrain` method, which is called when we shutdown, so
     427             :     // everything is good if we reach here.
     428           0 :     return IPC_OK();
     429             :   }
     430             : 
     431           0 :   if (!mIsAwaitingResetComplete) {
     432           0 :     return IPC_OK();
     433             :   }
     434           0 :   mIsAwaitingResetComplete = false;
     435           0 :   mFrameCount = 0;
     436             : 
     437             :   // Ignore any return code. It is OK for this to fail without killing the process.
     438           0 :   mCallback->ResetComplete();
     439             : 
     440           0 :   return IPC_OK();
     441             : }
     442             : 
     443             : mozilla::ipc::IPCResult
     444           0 : GMPVideoDecoderParent::RecvError(const GMPErr& aError)
     445             : {
     446           0 :   LOGD(("GMPVideoDecoderParent[%p]::RecvError(error=%d)", this, aError));
     447             : 
     448           0 :   if (!mCallback) {
     449           0 :     return IPC_FAIL_NO_REASON(this);
     450             :   }
     451             : 
     452             :   // Ensure if we've received an error while waiting for a ResetComplete
     453             :   // or DrainComplete notification, we'll unblock the caller before processing
     454             :   // the error.
     455           0 :   UnblockResetAndDrain();
     456             : 
     457             :   // Ignore any return code. It is OK for this to fail without killing the process.
     458           0 :   mCallback->Error(aError);
     459             : 
     460           0 :   return IPC_OK();
     461             : }
     462             : 
     463             : mozilla::ipc::IPCResult
     464           0 : GMPVideoDecoderParent::RecvShutdown()
     465             : {
     466           0 :   LOGD(("GMPVideoDecoderParent[%p]::RecvShutdown()", this));
     467             : 
     468           0 :   Shutdown();
     469           0 :   return IPC_OK();
     470             : }
     471             : 
     472             : mozilla::ipc::IPCResult
     473           0 : GMPVideoDecoderParent::RecvParentShmemForPool(Shmem&& aEncodedBuffer)
     474             : {
     475           0 :   if (aEncodedBuffer.IsWritable()) {
     476           0 :     mVideoHost.SharedMemMgr()->MgrDeallocShmem(GMPSharedMem::kGMPEncodedData,
     477           0 :                                                aEncodedBuffer);
     478             :   }
     479           0 :   return IPC_OK();
     480             : }
     481             : 
     482             : mozilla::ipc::IPCResult
     483           0 : GMPVideoDecoderParent::AnswerNeedShmem(const uint32_t& aFrameBufferSize,
     484             :                                        Shmem* aMem)
     485             : {
     486           0 :   ipc::Shmem mem;
     487             : 
     488           0 :   if (!mVideoHost.SharedMemMgr()->MgrAllocShmem(GMPSharedMem::kGMPFrameData,
     489           0 :                                                 aFrameBufferSize,
     490           0 :                                                 ipc::SharedMemory::TYPE_BASIC, &mem))
     491             :   {
     492           0 :     LOGE(("%s: Failed to get a shared mem buffer for Child! size %u",
     493             :          __FUNCTION__, aFrameBufferSize));
     494           0 :     return IPC_FAIL_NO_REASON(this);
     495             :   }
     496           0 :   *aMem = mem;
     497           0 :   mem = ipc::Shmem();
     498           0 :   return IPC_OK();
     499             : }
     500             : 
     501             : mozilla::ipc::IPCResult
     502           0 : GMPVideoDecoderParent::Recv__delete__()
     503             : {
     504           0 :   LOGD(("GMPVideoDecoderParent[%p]::Recv__delete__()", this));
     505             : 
     506           0 :   if (mPlugin) {
     507             :     // Ignore any return code. It is OK for this to fail without killing the process.
     508           0 :     mPlugin->VideoDecoderDestroyed(this);
     509           0 :     mPlugin = nullptr;
     510             :   }
     511             : 
     512           0 :   return IPC_OK();
     513             : }
     514             : 
     515             : void
     516           0 : GMPVideoDecoderParent::UnblockResetAndDrain()
     517             : {
     518           0 :   LOGD(("GMPVideoDecoderParent[%p]::UnblockResetAndDrain() "
     519             :         "awaitingResetComplete=%d awaitingDrainComplete=%d",
     520             :        this, mIsAwaitingResetComplete, mIsAwaitingDrainComplete));
     521             : 
     522           0 :   if (!mCallback) {
     523           0 :     MOZ_ASSERT(!mIsAwaitingResetComplete);
     524           0 :     MOZ_ASSERT(!mIsAwaitingDrainComplete);
     525           0 :     return;
     526             :   }
     527           0 :   if (mIsAwaitingResetComplete) {
     528           0 :     mIsAwaitingResetComplete = false;
     529           0 :     mCallback->ResetComplete();
     530             :   }
     531           0 :   if (mIsAwaitingDrainComplete) {
     532           0 :     mIsAwaitingDrainComplete = false;
     533           0 :     mCallback->DrainComplete();
     534             :   }
     535           0 :   CancelResetCompleteTimeout();
     536             : }
     537             : 
     538             : } // namespace gmp
     539             : } // namespace mozilla

Generated by: LCOV version 1.13