nsresult
GMPVideoDecoderParent::Reset()
{
  LOGD(("GMPVideoDecoderParent[%p]::Reset()", this));

  if (!mIsOpen) {
    NS_WARNING("Trying to use an dead GMP video decoder");
    return NS_ERROR_FAILURE;
  }

  MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());

  if (!SendReset()) {
    return NS_ERROR_FAILURE;
  }

  mIsAwaitingResetComplete = true;

  RefPtr<GMPVideoDecoderParent> self(this);
  nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction([self]() -> void
  {
    LOGD(("GMPVideoDecoderParent[%p]::ResetCompleteTimeout() timed out waiting for ResetComplete", self.get()));
    self->mResetCompleteTimeout = nullptr;
    LogToBrowserConsole(NS_LITERAL_STRING("GMPVideoDecoderParent timed out waiting for ResetComplete()"));
  });
  CancelResetCompleteTimeout();
  mResetCompleteTimeout = SimpleTimer::Create(task, 5000, mPlugin->GMPThread());

  // Async IPC, we don't have access to a return value.
  return NS_OK;
}
mozilla::ipc::IPCResult
GMPVideoDecoderParent::RecvResetComplete()
{
  LOGD(("GMPVideoDecoderParent[%p]::RecvResetComplete()", this));

  CancelResetCompleteTimeout();

  if (!mCallback) {
    // We anticipate shutting down in the middle of a reset in the
    // `UnblockResetAndDrain` method, which is called when we shutdown, so
    // everything is good if we reach here.
    return IPC_OK();
  }

  if (!mIsAwaitingResetComplete) {
    return IPC_OK();
  }
  mIsAwaitingResetComplete = false;
  mFrameCount = 0;

  // Ignore any return code. It is OK for this to fail without killing the process.
  mCallback->ResetComplete();

  return IPC_OK();
}
void
GMPVideoDecoderParent::UnblockResetAndDrain()
{
  LOGD(("GMPVideoDecoderParent[%p]::UnblockResetAndDrain() "
        "awaitingResetComplete=%d awaitingDrainComplete=%d",
       this, mIsAwaitingResetComplete, mIsAwaitingDrainComplete));

  if (!mCallback) {
    MOZ_ASSERT(!mIsAwaitingResetComplete);
    MOZ_ASSERT(!mIsAwaitingDrainComplete);
    return;
  }
  if (mIsAwaitingResetComplete) {
    mIsAwaitingResetComplete = false;
    mCallback->ResetComplete();
  }
  if (mIsAwaitingDrainComplete) {
    mIsAwaitingDrainComplete = false;
    mCallback->DrainComplete();
  }
  CancelResetCompleteTimeout();
}
bool
GMPVideoDecoderParent::RecvResetComplete()
{
  LOGD(("GMPVideoDecoderParent[%p]::RecvResetComplete()", this));

  CancelResetCompleteTimeout();

  if (!mCallback) {
    return false;
  }

  if (!mIsAwaitingResetComplete) {
    return true;
  }
  mIsAwaitingResetComplete = false;
  mFrameCount = 0;

  // Ignore any return code. It is OK for this to fail without killing the process.
  mCallback->ResetComplete();

  return true;
}