Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/dom/media/gmp/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 23 kB image not shown  

Quelle  ChromiumCDMProxy.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "ChromiumCDMProxy.h"
#include "ChromiumCDMCallbackProxy.h"
#include "MediaResult.h"
#include "mozilla/StaticPrefs_media.h"
#include "mozilla/dom/MediaKeySession.h"
#include "mozilla/dom/MediaKeysBinding.h"
#include "GMPUtils.h"
#include "nsPrintfCString.h"
#include "GMPService.h"
#include "content_decryption_module.h"

#define NS_DispatchToMainThread(...) CompileError_UseAbstractMainThreadInstead

namespace mozilla {

ChromiumCDMProxy::ChromiumCDMProxy(dom::MediaKeys* aKeys,
                                   const nsAString& aKeySystem,
                                   GMPCrashHelper* aCrashHelper,
                                   bool aDistinctiveIdentifierRequired,
                                   bool aPersistentStateRequired)
    : CDMProxy(aKeys, aKeySystem, aDistinctiveIdentifierRequired,
               aPersistentStateRequired),
      mCrashHelper(aCrashHelper),
      mCDMMutex("ChromiumCDMProxy"),
      mGMPThread(GetGMPThread()) {
  MOZ_ASSERT(NS_IsMainThread());
}

ChromiumCDMProxy::~ChromiumCDMProxy() {
  EME_LOG("ChromiumCDMProxy::~ChromiumCDMProxy(this=%p)"this);
}

void ChromiumCDMProxy::Init(PromiseId aPromiseId, const nsAString& aOrigin,
                            const nsAString& aTopLevelOrigin,
                            const nsAString& aGMPName) {
  MOZ_ASSERT(NS_IsMainThread());

  RefPtr<GMPCrashHelper> helper(std::move(mCrashHelper));

  NS_ENSURE_TRUE_VOID(!mKeys.IsNull());

  EME_LOG("ChromiumCDMProxy::Init(this=%p, pid=%" PRIu32
          ", origin=%s, topLevelOrigin=%s, "
          "gmp=%s)",
          this, aPromiseId, NS_ConvertUTF16toUTF8(aOrigin).get(),
          NS_ConvertUTF16toUTF8(aTopLevelOrigin).get(),
          NS_ConvertUTF16toUTF8(aGMPName).get());

  if (!mGMPThread) {
    RejectPromiseWithStateError(
        aPromiseId, "Couldn't get GMP thread ChromiumCDMProxy::Init"_ns);
    return;
  }

  if (aGMPName.IsEmpty()) {
    RejectPromiseWithStateError(
        aPromiseId, nsPrintfCString("Unknown GMP for keysystem '%s'",
                                    NS_ConvertUTF16toUTF8(mKeySystem).get()));
    return;
  }

  gmp::NodeIdParts nodeIdParts{nsString(aOrigin), nsString(aTopLevelOrigin),
                               nsString(aGMPName)};
  nsCOMPtr<nsISerialEventTarget> thread = mGMPThread;
  RefPtr<ChromiumCDMProxy> self(this);
  nsCString keySystem = NS_ConvertUTF16toUTF8(mKeySystem);
  RefPtr<Runnable> task(NS_NewRunnableFunction(
      "ChromiumCDMProxy::Init",
      [self, nodeIdParts, helper, aPromiseId, thread, keySystem]() -> void {
        MOZ_ASSERT(self->IsOnOwnerThread());

        RefPtr<gmp::GeckoMediaPluginService> service =
            gmp::GeckoMediaPluginService::GetGeckoMediaPluginService();
        if (!service) {
          self->RejectPromiseWithStateError(
              aPromiseId,
              nsLiteralCString("Couldn't get GeckoMediaPluginService in "
                               "ChromiumCDMProxy::Init"));
          return;
        }
        RefPtr<gmp::GetCDMParentPromise> promise =
            service->GetCDM(nodeIdParts, keySystem, helper);
        promise->Then(
            thread, __func__,
            [self, aPromiseId, thread](RefPtr<gmp::ChromiumCDMParent> cdm) {
              // service->GetCDM succeeded
              self->mCallback =
                  MakeUnique<ChromiumCDMCallbackProxy>(self, self->mMainThread);
              cdm->Init(self->mCallback.get(),
                        self->mDistinctiveIdentifierRequired,
                        self->mPersistentStateRequired, self->mMainThread)
                  ->Then(
                      self->mMainThread, __func__,
                      [self, aPromiseId, cdm](bool /* unused */) {
                        // CDM init succeeded
                        {
                          MutexAutoLock lock(self->mCDMMutex);
                          self->mCDM = cdm;
                        }
                        if (self->mIsShutdown) {
                          self->RejectPromiseWithStateError(
                              aPromiseId, nsLiteralCString(
                                              "ChromiumCDMProxy shutdown "
                                              "during ChromiumCDMProxy::Init"));
                          // If shutdown happened while waiting to init, we
                          // need to explicitly shutdown the CDM to avoid it
                          // referencing this proxy which is on its way out.
                          self->ShutdownCDMIfExists();
                          return;
                        }
                        self->OnCDMCreated(aPromiseId);
                      },
                      [self, aPromiseId](MediaResult aResult) {
                        // CDM init failed.
                        ErrorResult rv;
                        // XXXbz MediaResult should really store a
                        // CopyableErrorResult or something.  See
                        // <https://bugzilla.mozilla.org/show_bug.cgi?id=1612216>.
                        rv.Throw(aResult.Code());
                        self->RejectPromise(aPromiseId, std::move(rv),
                                            aResult.Message());
                      });
            },
            [self, aPromiseId](MediaResult rv) {
              // service->GetCDM failed
              ErrorResult result;
              // XXXbz MediaResult should really store a CopyableErrorResult or
              // something.  See
              // <https://bugzilla.mozilla.org/show_bug.cgi?id=1612216>.
              result.Throw(rv.Code());
              self->RejectPromise(aPromiseId, std::move(result),
                                  rv.Description());
            });
      }));

  mGMPThread->Dispatch(task.forget());
}

void ChromiumCDMProxy::OnCDMCreated(uint32_t aPromiseId) {
  EME_LOG("ChromiumCDMProxy::OnCDMCreated(this=%p, pid=%" PRIu32
          ") isMainThread=%d",
          this, aPromiseId, NS_IsMainThread());
  MOZ_ASSERT(NS_IsMainThread());
  if (mKeys.IsNull()) {
    return;
  }
  RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
  // This should only be called once the CDM has been created.
  MOZ_ASSERT(cdm);
  if (cdm) {
    mKeys->OnCDMCreated(aPromiseId, cdm->PluginId());
  } else {
    // No CDM? Shouldn't be possible, but reject the promise anyway...
    constexpr auto err = "Null CDM in OnCDMCreated()"_ns;
    ErrorResult rv;
    rv.ThrowInvalidStateError(err);
    mKeys->RejectPromise(aPromiseId, std::move(rv), err);
  }
}

void ChromiumCDMProxy::ShutdownCDMIfExists() {
  EME_LOG(
      "ChromiumCDMProxy::ShutdownCDMIfExists(this=%p) mCDM=%p, mIsShutdown=%s",
      this, mCDM.get(), mIsShutdown ? "true" : "false");
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(mGMPThread);
  MOZ_ASSERT(mIsShutdown,
             "Should only shutdown the CDM if the proxy is shutting down");
  RefPtr<gmp::ChromiumCDMParent> cdm;
  {
    MutexAutoLock lock(mCDMMutex);
    cdm.swap(mCDM);
  }
  if (cdm) {
    // We need to keep this proxy alive until the parent has finished its
    // Shutdown (as it may still try to use the proxy until then).
    RefPtr<ChromiumCDMProxy> self(this);
    nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction(
        "ChromiumCDMProxy::Shutdown", [self, cdm]() { cdm->Shutdown(); });
    mGMPThread->Dispatch(task.forget());
  }
}

#ifdef DEBUG
bool ChromiumCDMProxy::IsOnOwnerThread() {
  return mGMPThread && mGMPThread->IsOnCurrentThread();
}
#endif

static uint32_t ToCDMSessionType(dom::MediaKeySessionType aSessionType) {
  switch (aSessionType) {
    case dom::MediaKeySessionType::Temporary:
      return static_cast<uint32_t>(cdm::kTemporary);
    case dom::MediaKeySessionType::Persistent_license:
      return static_cast<uint32_t>(cdm::kPersistentLicense);
    default:
      return static_cast<uint32_t>(cdm::kTemporary);
  };
};

static uint32_t ToCDMInitDataType(const nsAString& aInitDataType) {
  if (aInitDataType.EqualsLiteral("cenc")) {
    return static_cast<uint32_t>(cdm::kCenc);
  }
  if (aInitDataType.EqualsLiteral("webm")) {
    return static_cast<uint32_t>(cdm::kWebM);
  }
  if (aInitDataType.EqualsLiteral("keyids")) {
    return static_cast<uint32_t>(cdm::kKeyIds);
  }
  return static_cast<uint32_t>(cdm::kCenc);
}

void ChromiumCDMProxy::CreateSession(uint32_t aCreateSessionToken,
                                     dom::MediaKeySessionType aSessionType,
                                     PromiseId aPromiseId,
                                     const nsAString& aInitDataType,
                                     nsTArray<uint8_t>& aInitData) {
  MOZ_ASSERT(NS_IsMainThread());
  EME_LOG("ChromiumCDMProxy::CreateSession(this=%p, token=%" PRIu32
          ", type=%d, pid=%" PRIu32
          ") "
          "initDataLen=%zu",
          this, aCreateSessionToken, (int)aSessionType, aPromiseId,
          aInitData.Length());

  uint32_t sessionType = ToCDMSessionType(aSessionType);
  uint32_t initDataType = ToCDMInitDataType(aInitDataType);

  RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
  if (!cdm) {
    RejectPromiseWithStateError(aPromiseId, "Null CDM in CreateSession"_ns);
    return;
  }

  mGMPThread->Dispatch(NewRunnableMethod<uint32_t, uint32_t, uint32_t, uint32_t,
                                         nsTArray<uint8_t>>(
      "gmp::ChromiumCDMParent::CreateSession", cdm,
      &gmp::ChromiumCDMParent::CreateSession, aCreateSessionToken, sessionType,
      initDataType, aPromiseId, std::move(aInitData)));
}

void ChromiumCDMProxy::LoadSession(PromiseId aPromiseId,
                                   dom::MediaKeySessionType aSessionType,
                                   const nsAString& aSessionId) {
  MOZ_ASSERT(NS_IsMainThread());

  RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
  if (!cdm) {
    RejectPromiseWithStateError(aPromiseId, "Null CDM in LoadSession"_ns);
    return;
  }

  mGMPThread->Dispatch(NewRunnableMethod<uint32_t, uint32_t, nsString>(
      "gmp::ChromiumCDMParent::LoadSession", cdm,
      &gmp::ChromiumCDMParent::LoadSession, aPromiseId,
      ToCDMSessionType(aSessionType), aSessionId));
}

void ChromiumCDMProxy::SetServerCertificate(PromiseId aPromiseId,
                                            nsTArray<uint8_t>& aCert) {
  MOZ_ASSERT(NS_IsMainThread());
  EME_LOG("ChromiumCDMProxy::SetServerCertificate(this=%p, pid=%" PRIu32
          ") certLen=%zu",
          this, aPromiseId, aCert.Length());

  RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
  if (!cdm) {
    RejectPromiseWithStateError(aPromiseId,
                                "Null CDM in SetServerCertificate"_ns);
    return;
  }

  mGMPThread->Dispatch(NewRunnableMethod<uint32_t, nsTArray<uint8_t>>(
      "gmp::ChromiumCDMParent::SetServerCertificate", cdm,
      &gmp::ChromiumCDMParent::SetServerCertificate, aPromiseId,
      std::move(aCert)));
}

void ChromiumCDMProxy::UpdateSession(const nsAString& aSessionId,
                                     PromiseId aPromiseId,
                                     nsTArray<uint8_t>& aResponse) {
  MOZ_ASSERT(NS_IsMainThread());
  EME_LOG("ChromiumCDMProxy::UpdateSession(this=%p, sid='%s', pid=%" PRIu32
          ") "
          "responseLen=%zu",
          this, NS_ConvertUTF16toUTF8(aSessionId).get(), aPromiseId,
          aResponse.Length());

  RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
  if (!cdm) {
    RejectPromiseWithStateError(aPromiseId, "Null CDM in UpdateSession"_ns);
    return;
  }
  mGMPThread->Dispatch(
      NewRunnableMethod<nsCString, uint32_t, nsTArray<uint8_t>>(
          "gmp::ChromiumCDMParent::UpdateSession", cdm,
          &gmp::ChromiumCDMParent::UpdateSession,
          NS_ConvertUTF16toUTF8(aSessionId), aPromiseId, std::move(aResponse)));
}

void ChromiumCDMProxy::CloseSession(const nsAString& aSessionId,
                                    PromiseId aPromiseId) {
  MOZ_ASSERT(NS_IsMainThread());
  EME_LOG("ChromiumCDMProxy::CloseSession(this=%p, sid='%s', pid=%" PRIu32 ")",
          this, NS_ConvertUTF16toUTF8(aSessionId).get(), aPromiseId);

  RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
  if (!cdm) {
    RejectPromiseWithStateError(aPromiseId, "Null CDM in CloseSession"_ns);
    return;
  }
  mGMPThread->Dispatch(NewRunnableMethod<nsCString, uint32_t>(
      "gmp::ChromiumCDMParent::CloseSession", cdm,
      &gmp::ChromiumCDMParent::CloseSession, NS_ConvertUTF16toUTF8(aSessionId),
      aPromiseId));
}

void ChromiumCDMProxy::RemoveSession(const nsAString& aSessionId,
                                     PromiseId aPromiseId) {
  MOZ_ASSERT(NS_IsMainThread());
  EME_LOG("ChromiumCDMProxy::RemoveSession(this=%p, sid='%s', pid=%" PRIu32 ")",
          this, NS_ConvertUTF16toUTF8(aSessionId).get(), aPromiseId);

  RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
  if (!cdm) {
    RejectPromiseWithStateError(aPromiseId, "Null CDM in RemoveSession"_ns);
    return;
  }
  mGMPThread->Dispatch(NewRunnableMethod<nsCString, uint32_t>(
      "gmp::ChromiumCDMParent::RemoveSession", cdm,
      &gmp::ChromiumCDMParent::RemoveSession, NS_ConvertUTF16toUTF8(aSessionId),
      aPromiseId));
}

void ChromiumCDMProxy::QueryOutputProtectionStatus() {
  MOZ_ASSERT(NS_IsMainThread());
  EME_LOG("ChromiumCDMProxy::QueryOutputProtectionStatus(this=%p)"this);

  if (mKeys.IsNull()) {
    EME_LOG(
        "ChromiumCDMProxy::QueryOutputProtectionStatus(this=%p), mKeys "
        "missing!",
        this);
    // If we can't get mKeys, we're probably in shutdown. But do our best to
    // respond to the request and indicate the check failed.
    NotifyOutputProtectionStatus(OutputProtectionCheckStatus::CheckFailed,
                                 OutputProtectionCaptureStatus::Unused);
    return;
  }
  // The keys will call back via `NotifyOutputProtectionStatus` to notify the
  // result of the check.
  mKeys->CheckIsElementCapturePossible();
}

void ChromiumCDMProxy::NotifyOutputProtectionStatus(
    OutputProtectionCheckStatus aCheckStatus,
    OutputProtectionCaptureStatus aCaptureStatus) {
  MOZ_ASSERT(NS_IsMainThread());
  // If the check failed aCaptureStatus should be unused, otherwise not.
  MOZ_ASSERT_IF(aCheckStatus == OutputProtectionCheckStatus::CheckFailed,
                aCaptureStatus == OutputProtectionCaptureStatus::Unused);
  MOZ_ASSERT_IF(aCheckStatus == OutputProtectionCheckStatus::CheckSuccessful,
                aCaptureStatus != OutputProtectionCaptureStatus::Unused);
  EME_LOG(
      "ChromiumCDMProxy::NotifyOutputProtectionStatus(this=%p) "
      "aCheckStatus=%" PRIu8 " aCaptureStatus=%" PRIu8,
      thisstatic_cast<uint8_t>(aCheckStatus),
      static_cast<uint8_t>(aCaptureStatus));

  RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
  if (!cdm) {
    // If we're in shutdown the CDM may have been cleared while a notification
    // is in flight. If this happens outside of shutdown we have a bug.
    MOZ_ASSERT(mIsShutdown);
    return;
  }

  uint32_t linkMask{};
  uint32_t protectionMask{};
  if (aCheckStatus == OutputProtectionCheckStatus::CheckSuccessful &&
      aCaptureStatus == OutputProtectionCaptureStatus::CapturePossilbe) {
    // The result indicates the capture is possible, so set the mask
    // to indicate this.
    linkMask |= cdm::OutputLinkTypes::kLinkTypeNetwork;
  }
  // `kProtectionNone` can cause playback to stop if HDCP_V1 is required. Report
  // HDCP protection if there's no potential capturing.
  if (linkMask == cdm::OutputLinkTypes::kLinkTypeNone &&
      StaticPrefs::media_widevine_hdcp_protection_mask()) {
    protectionMask = cdm::OutputProtectionMethods::kProtectionHDCP;
  }
  mGMPThread->Dispatch(NewRunnableMethod<bool, uint32_t, uint32_t>(
      "gmp::ChromiumCDMParent::NotifyOutputProtectionStatus", cdm,
      &gmp::ChromiumCDMParent::NotifyOutputProtectionStatus,
      aCheckStatus == OutputProtectionCheckStatus::CheckSuccessful, linkMask,
      protectionMask));
}

void ChromiumCDMProxy::Shutdown() {
  MOZ_ASSERT(NS_IsMainThread());
  EME_LOG("ChromiumCDMProxy::Shutdown(this=%p) mCDM=%p, mIsShutdown=%s"this,
          mCDM.get(), mIsShutdown ? "true" : "false");
  if (mIsShutdown) {
    return;
  }
  mIsShutdown = true;
  mKeys.Clear();
  ShutdownCDMIfExists();
}

void ChromiumCDMProxy::RejectPromise(PromiseId aId, ErrorResult&& aException,
                                     const nsCString& aReason) {
  if (!NS_IsMainThread()) {
    // Use CopyableErrorResult to store our exception in the runnable,
    // because ErrorResult is not OK to move across threads.
    mMainThread->Dispatch(
        NewRunnableMethod<PromiseId, StoreCopyPassByRRef<CopyableErrorResult>,
                          nsCString>(
            "ChromiumCDMProxy::RejectPromise"this,
            &ChromiumCDMProxy::RejectPromiseOnMainThread, aId,
            std::move(aException), aReason),
        NS_DISPATCH_NORMAL);
    return;
  }
  EME_LOG("ChromiumCDMProxy::RejectPromise(this=%p, pid=%" PRIu32
          ", code=0x%x, "
          "reason='%s')",
          this, aId, aException.ErrorCodeAsInt(), aReason.get());
  if (!mKeys.IsNull()) {
    mKeys->RejectPromise(aId, std::move(aException), aReason);
  } else {
    // We don't have a MediaKeys object to pass the exception to, so silence
    // the exception to avoid it asserting due to being unused.
    aException.SuppressException();
  }
}

void ChromiumCDMProxy::RejectPromiseWithStateError(PromiseId aId,
                                                   const nsCString& aReason) {
  ErrorResult rv;
  rv.ThrowInvalidStateError(aReason);
  RejectPromise(aId, std::move(rv), aReason);
}

void ChromiumCDMProxy::RejectPromiseOnMainThread(
    PromiseId aId, CopyableErrorResult&& aException, const nsCString& aReason) {
  // Moving into or out of a non-copyable ErrorResult will assert that both
  // ErorResults are from our current thread.  Avoid the assertion by moving
  // into a current-thread CopyableErrorResult first.  Note that this is safe,
  // because CopyableErrorResult never holds state that can't move across
  // threads.
  CopyableErrorResult rv(std::move(aException));
  RejectPromise(aId, std::move(rv), aReason);
}

void ChromiumCDMProxy::ResolvePromise(PromiseId aId) {
  if (!NS_IsMainThread()) {
    mMainThread->Dispatch(
        NewRunnableMethod<PromiseId>("ChromiumCDMProxy::ResolvePromise"this,
                                     &ChromiumCDMProxy::ResolvePromise, aId),
        NS_DISPATCH_NORMAL);
    return;
  }

  EME_LOG("ChromiumCDMProxy::ResolvePromise(this=%p, pid=%" PRIu32 ")"this,
          aId);
  if (!mKeys.IsNull()) {
    mKeys->ResolvePromise(aId);
  } else {
    NS_WARNING("ChromiumCDMProxy unable to resolve promise!");
  }
}

void ChromiumCDMProxy::OnSetSessionId(uint32_t aCreateSessionToken,
                                      const nsAString& aSessionId) {
  MOZ_ASSERT(NS_IsMainThread());
  EME_LOG("ChromiumCDMProxy::OnSetSessionId(this=%p, token=%" PRIu32
          ", sid='%s')",
          this, aCreateSessionToken, NS_ConvertUTF16toUTF8(aSessionId).get());

  if (mKeys.IsNull()) {
    return;
  }
  RefPtr<dom::MediaKeySession> session(
      mKeys->GetPendingSession(aCreateSessionToken));
  if (session) {
    session->SetSessionId(aSessionId);
  }
}

void ChromiumCDMProxy::OnResolveLoadSessionPromise(uint32_t aPromiseId,
                                                   bool aSuccess) {
  MOZ_ASSERT(NS_IsMainThread());
  if (mKeys.IsNull()) {
    return;
  }
  mKeys->OnSessionLoaded(aPromiseId, aSuccess);
}

void ChromiumCDMProxy::OnResolvePromiseWithKeyStatus(
    uint32_t aPromiseId, dom::MediaKeyStatus aKeyStatus) {
  MOZ_ASSERT(NS_IsMainThread());
  if (mKeys.IsNull()) {
    return;
  }
  mKeys->ResolvePromiseWithKeyStatus(aPromiseId, aKeyStatus);
}

void ChromiumCDMProxy::OnSessionMessage(const nsAString& aSessionId,
                                        dom::MediaKeyMessageType aMessageType,
                                        const nsTArray<uint8_t>& aMessage) {
  MOZ_ASSERT(NS_IsMainThread());
  if (mKeys.IsNull()) {
    return;
  }
  RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
  if (session) {
    session->DispatchKeyMessage(aMessageType, aMessage);
  }
}

void ChromiumCDMProxy::OnKeyStatusesChange(const nsAString& aSessionId) {
  MOZ_ASSERT(NS_IsMainThread());
  if (mKeys.IsNull()) {
    return;
  }
  RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
  if (session) {
    session->DispatchKeyStatusesChange();
  }
}

void ChromiumCDMProxy::OnExpirationChange(const nsAString& aSessionId,
                                          UnixTime aExpiryTime) {
  MOZ_ASSERT(NS_IsMainThread());
  if (mKeys.IsNull()) {
    return;
  }
  RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
  if (session) {
    // Expiry of 0 is interpreted as "never expire". See bug 1345341.
    double t = (aExpiryTime == 0) ? std::numeric_limits<double>::quiet_NaN()
                                  : static_cast<double>(aExpiryTime);
    session->SetExpiration(t);
  }
}

void ChromiumCDMProxy::OnSessionClosed(const nsAString& aSessionId) {
  MOZ_ASSERT(NS_IsMainThread());

  bool keyStatusesChange = false;
  {
    auto caps = Capabilites().Lock();
    keyStatusesChange = caps->RemoveKeysForSession(nsString(aSessionId));
  }
  if (keyStatusesChange) {
    OnKeyStatusesChange(aSessionId);
  }
  if (mKeys.IsNull()) {
    return;
  }
  RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
  if (session) {
    session->OnClosed();
  }
}

void ChromiumCDMProxy::OnDecrypted(uint32_t aId, DecryptStatus aResult,
                                   const nsTArray<uint8_t>& aDecryptedData) {}

void ChromiumCDMProxy::OnSessionError(const nsAString& aSessionId,
                                      nsresult aException, uint32_t aSystemCode,
                                      const nsAString& aMsg) {
  MOZ_ASSERT(NS_IsMainThread());
  if (mKeys.IsNull()) {
    return;
  }
  RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
  if (session) {
    session->DispatchKeyError(aSystemCode);
  }
  LogToConsole(aMsg);
}

void ChromiumCDMProxy::OnRejectPromise(uint32_t aPromiseId,
                                       ErrorResult&& aException,
                                       const nsCString& aMsg) {
  MOZ_ASSERT(NS_IsMainThread());
  RejectPromise(aPromiseId, std::move(aException), aMsg);
}

RefPtr<DecryptPromise> ChromiumCDMProxy::Decrypt(MediaRawData* aSample) {
  RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
  if (!cdm) {
    return DecryptPromise::CreateAndReject(
        DecryptResult(eme::AbortedErr, aSample), __func__);
  }
  RefPtr<MediaRawData> sample = aSample;
  return InvokeAsync(mGMPThread, __func__,
                     [cdm, sample]() { return cdm->Decrypt(sample); });
}

void ChromiumCDMProxy::GetStatusForPolicy(
    PromiseId aPromiseId, const dom::HDCPVersion& aMinHdcpVersion) {
  MOZ_ASSERT(NS_IsMainThread());
  EME_LOG("ChromiumCDMProxy::GetStatusForPolicy(this=%p, pid=%" PRIu32
          ") minHdcpVersion=%s",
          this, aPromiseId, dom::GetEnumString(aMinHdcpVersion).get());

  RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
  if (!cdm) {
    RejectPromiseWithStateError(aPromiseId,
                                "Null CDM in GetStatusForPolicy"_ns);
    return;
  }

  mGMPThread->Dispatch(NewRunnableMethod<uint32_t, dom::HDCPVersion>(
      "gmp::ChromiumCDMParent::GetStatusForPolicy", cdm,
      &gmp::ChromiumCDMParent::GetStatusForPolicy, aPromiseId,
      aMinHdcpVersion));
}

void ChromiumCDMProxy::Terminated() {
  if (!mKeys.IsNull()) {
    mKeys->Terminated();
  }
}

already_AddRefed<gmp::ChromiumCDMParent> ChromiumCDMProxy::GetCDMParent() {
  MutexAutoLock lock(mCDMMutex);
  RefPtr<gmp::ChromiumCDMParent> cdm = mCDM;
  return cdm.forget();
}

}  // namespace mozilla

#undef NS_DispatchToMainThread

Messung V0.5
C=93 H=98 G=95

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.