Bug 1404230 - Part4 - Add GetStatusForPolicy method in ipdl and implement it by calling CDM.
MozReview-Commit-ID: 8L0qKgnKMES
--- a/dom/media/eme/MediaKeys.cpp
+++ b/dom/media/eme/MediaKeys.cpp
@@ -619,15 +619,29 @@ MediaKeys::GetStatusForPolicy(const Medi
if (!mProxy) {
NS_WARNING("Tried to use a MediaKeys without a CDM");
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Null CDM in MediaKeys.GetStatusForPolicy()"));
return promise.forget();
}
EME_LOG("GetStatusForPolicy minHdcpVersion = %s.", NS_ConvertUTF16toUTF8(aPolicy.mMinHdcpVersion).get());
- // TODO: Ask CDM to get the real policy.
- promise->MaybeResolve(MediaKeyStatus::Usable);
+ mProxy->GetStatusForPolicy(StorePromise(promise), aPolicy.mMinHdcpVersion);
return promise.forget();
}
+void
+MediaKeys::ResolvePromiseWithKeyStatus(PromiseId aId, MediaKeyStatus aMediaKeyStatus)
+{
+ RefPtr<DetailedPromise> promise(RetrievePromise(aId));
+ if (!promise) {
+ return;
+ }
+ RefPtr<MediaKeys> keys(this);
+ EME_LOG("MediaKeys[%p]::ResolvePromiseWithKeyStatus() resolve promise id=%d, keystatus=%" PRIu8,
+ this,
+ aId,
+ static_cast<uint8_t>(aMediaKeyStatus));
+ promise->MaybeResolve(aMediaKeyStatus);
+}
+
} // namespace dom
} // namespace mozilla
--- a/dom/media/eme/MediaKeys.h
+++ b/dom/media/eme/MediaKeys.h
@@ -11,16 +11,17 @@
#include "nsISupports.h"
#include "mozilla/Attributes.h"
#include "mozilla/RefPtr.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsRefPtrHashtable.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/MediaKeysBinding.h"
+#include "mozilla/dom/MediaKeyStatusMapBinding.h" // For MediaKeyStatus
#include "mozilla/dom/MediaKeySystemAccessBinding.h"
#include "mozIGeckoMediaPluginService.h"
#include "mozilla/DetailedPromise.h"
#include "mozilla/WeakPtr.h"
namespace mozilla {
class CDMProxy;
@@ -129,16 +130,18 @@ public:
// Returns true if this MediaKeys has been bound to a media element.
bool IsBoundToMediaElement() const;
void GetSessionsInfo(nsString& sessionsInfo);
// JavaScript: MediaKeys.GetStatusForPolicy()
already_AddRefed<Promise> GetStatusForPolicy(const MediaKeysPolicy& aPolicy,
ErrorResult& aR);
+ // Called by CDMProxy when CDM successfully GetStatusForPolicy.
+ void ResolvePromiseWithKeyStatus(PromiseId aId, dom::MediaKeyStatus aMediaKeyStatus);
private:
// Instantiate CDMProxy instance.
// It could be MediaDrmCDMProxy (Widevine on Fennec) or ChromiumCDMProxy (the rest).
already_AddRefed<CDMProxy> CreateCDMProxy(nsIEventTarget* aMainThread);
// Removes promise from mPromises, and returns it.
--- a/dom/media/gmp/ChromiumCDMCallback.h
+++ b/dom/media/gmp/ChromiumCDMCallback.h
@@ -17,16 +17,19 @@ public:
virtual ~ChromiumCDMCallback() {}
virtual void SetSessionId(uint32_t aPromiseId,
const nsCString& aSessionId) = 0;
virtual void ResolveLoadSessionPromise(uint32_t aPromiseId,
bool aSuccessful) = 0;
+ virtual void ResolvePromiseWithKeyStatus(uint32_t aPromiseId,
+ uint32_t aKeyStatus) = 0;
+
virtual void ResolvePromise(uint32_t aPromiseId) = 0;
virtual void RejectPromise(uint32_t aPromiseId,
nsresult aError,
const nsCString& aErrorMessage) = 0;
virtual void SessionMessage(const nsACString& aSessionId,
uint32_t aMessageType,
--- a/dom/media/gmp/ChromiumCDMCallbackProxy.cpp
+++ b/dom/media/gmp/ChromiumCDMCallbackProxy.cpp
@@ -112,16 +112,26 @@ ToDOMMediaKeyStatus(uint32_t aStatus)
case cdm::kReleased:
return dom::MediaKeyStatus::Released;
}
MOZ_ASSERT_UNREACHABLE("Invalid cdm::KeyStatus enum value.");
return dom::MediaKeyStatus::Internal_error;
}
void
+ChromiumCDMCallbackProxy::ResolvePromiseWithKeyStatus(uint32_t aPromiseId,
+ uint32_t aKeyStatus)
+{
+ DispatchToMainThread("ChromiumCDMProxy::OnResolvePromiseWithKeyStatus",
+ &ChromiumCDMProxy::OnResolvePromiseWithKeyStatus,
+ aPromiseId,
+ ToDOMMediaKeyStatus(aKeyStatus));
+}
+
+void
ChromiumCDMCallbackProxy::SessionKeysChange(const nsCString& aSessionId,
nsTArray<mozilla::gmp::CDMKeyInformation> && aKeysInfo)
{
bool keyStatusesChange = false;
{
CDMCaps::AutoLock caps(mProxy->Capabilites());
for (const auto& keyInfo : aKeysInfo) {
keyStatusesChange |=
--- a/dom/media/gmp/ChromiumCDMCallbackProxy.h
+++ b/dom/media/gmp/ChromiumCDMCallbackProxy.h
@@ -22,16 +22,19 @@ public:
}
void SetSessionId(uint32_t aPromiseId,
const nsCString& aSessionId) override;
void ResolveLoadSessionPromise(uint32_t aPromiseId,
bool aSuccessful) override;
+ void ResolvePromiseWithKeyStatus(uint32_t aPromiseId,
+ uint32_t aKeyStatus) override;
+
void ResolvePromise(uint32_t aPromiseId) override;
void RejectPromise(uint32_t aPromiseId,
nsresult aError,
const nsCString& aErrorMessage) override;
void SessionMessage(const nsACString& aSessionId,
uint32_t aMessageType,
--- a/dom/media/gmp/ChromiumCDMChild.cpp
+++ b/dom/media/gmp/ChromiumCDMChild.cpp
@@ -221,17 +221,23 @@ ChromiumCDMChild::CallOnMessageLoopThrea
mPlugin->GMPMessageLoop()->PostTask(t.forget());
}
}
// cdm::Host_9 interface
void
ChromiumCDMChild::OnResolveKeyStatusPromise(uint32_t aPromiseId,
cdm::KeyStatus aKeyStatus) {
- //TODO: The callback of GetStatusForPolicy, will implement it in Bug 1404230.
+ GMP_LOG("ChromiumCDMChild::OnResolveKeyStatusPromise(pid=%" PRIu32 "keystatus=%d)",
+ aPromiseId,
+ aKeyStatus);
+ CallOnMessageLoopThread("gmp::ChromiumCDMChild::OnResolveKeyStatusPromise",
+ &ChromiumCDMChild::SendOnResolvePromiseWithKeyStatus,
+ aPromiseId,
+ static_cast<uint32_t>(aKeyStatus));
}
bool
ChromiumCDMChild::OnResolveNewSessionPromiseInternal(uint32_t aPromiseId,
const nsCString& aSessionId)
{
MOZ_ASSERT(IsOnMessageLoopThread());
if (mLoadSessionPromiseIds.Contains(aPromiseId)) {
@@ -619,16 +625,74 @@ ChromiumCDMChild::RecvRemoveSession(cons
aPromiseId,
aSessionId.get());
if (mCDM) {
mCDM->RemoveSession(aPromiseId, aSessionId.get(), aSessionId.Length());
}
return IPC_OK();
}
+// See https://cs.chromium.org/chromium/src/media/blink/webcontentdecryptionmodule_impl.cc?rcl=9d4e17194fbae2839d269e0b625520eac09efa9b&l=40
+static cdm::HdcpVersion
+ToCDMHdcpVersion(const nsCString& aMinHdcpVersion)
+{
+ // String compare with ignoring case.
+ if (aMinHdcpVersion.IsEmpty()) {
+ return cdm::HdcpVersion::kHdcpVersionNone;
+ }
+ if (aMinHdcpVersion.EqualsIgnoreCase("hdcp-1.0")) {
+ return cdm::HdcpVersion::kHdcpVersion1_0;
+ }
+ if (aMinHdcpVersion.EqualsIgnoreCase("hdcp-1.1")) {
+ return cdm::HdcpVersion::kHdcpVersion1_1;
+ }
+ if (aMinHdcpVersion.EqualsIgnoreCase("hdcp-1.2")) {
+ return cdm::HdcpVersion::kHdcpVersion1_2;
+ }
+ if (aMinHdcpVersion.EqualsIgnoreCase("hdcp-1.3")) {
+ return cdm::HdcpVersion::kHdcpVersion1_3;
+ }
+ if (aMinHdcpVersion.EqualsIgnoreCase("hdcp-1.4")) {
+ return cdm::HdcpVersion::kHdcpVersion1_4;
+ }
+ if (aMinHdcpVersion.EqualsIgnoreCase("hdcp-2.0")) {
+ return cdm::HdcpVersion::kHdcpVersion2_0;
+ }
+ if (aMinHdcpVersion.EqualsIgnoreCase("hdcp-2.1")) {
+ return cdm::HdcpVersion::kHdcpVersion2_1;
+ }
+ if (aMinHdcpVersion.EqualsIgnoreCase("hdcp-2.2")) {
+ return cdm::HdcpVersion::kHdcpVersion2_2;
+ }
+
+ // Invalid hdcp version string.
+ return cdm::HdcpVersion::kHdcpVersionNone;
+}
+
+mozilla::ipc::IPCResult
+ChromiumCDMChild::RecvGetStatusForPolicy(const uint32_t& aPromiseId,
+ const nsCString& aMinHdcpVersion)
+{
+ MOZ_ASSERT(IsOnMessageLoopThread());
+ GMP_LOG("ChromiumCDMChild::RecvGetStatusForPolicy(pid=%" PRIu32 ", MinHdcpVersion=%s)",
+ aPromiseId,
+ aMinHdcpVersion.get());
+ if (mCDM) {
+ cdm::Policy policy;
+ // We didn't check the return value of ToCDMHdcpVersion.
+ // Let CDM to handle the cdm::HdcpVersion::kHdcpVersionNone case.
+ // ChromiumCDM8BackwardsCompat::GetStatusForPolicy will reject the promise
+ // since this API is only supported by CDM version 9.
+ // CDM will callback by OnResolveKeyStatusPromise when it successfully executes.
+ policy.min_hdcp_version = ToCDMHdcpVersion(aMinHdcpVersion);
+ mCDM->GetStatusForPolicy(aPromiseId, policy);
+ }
+ return IPC_OK();
+}
+
static void
InitInputBuffer(const CDMInputBuffer& aBuffer,
nsTArray<cdm::SubsampleEntry>& aSubSamples,
cdm::InputBuffer& aInputBuffer)
{
aInputBuffer.data = aBuffer.mData().get<uint8_t>();
aInputBuffer.data_size = aBuffer.mData().Size<uint8_t>();
--- a/dom/media/gmp/ChromiumCDMChild.h
+++ b/dom/media/gmp/ChromiumCDMChild.h
@@ -123,16 +123,18 @@ protected:
const nsCString& aSessionId) override;
ipc::IPCResult RecvUpdateSession(const uint32_t& aPromiseId,
const nsCString& aSessionId,
nsTArray<uint8_t>&& aResponse) override;
ipc::IPCResult RecvCloseSession(const uint32_t& aPromiseId,
const nsCString& aSessionId) override;
ipc::IPCResult RecvRemoveSession(const uint32_t& aPromiseId,
const nsCString& aSessionId) override;
+ ipc::IPCResult RecvGetStatusForPolicy(const uint32_t& aPromiseId,
+ const nsCString& aMinHdcpVersion) override;
ipc::IPCResult RecvDecrypt(const uint32_t& aId,
const CDMInputBuffer& aBuffer) override;
ipc::IPCResult RecvInitializeVideoDecoder(
const CDMVideoDecoderConfig& aConfig) override;
ipc::IPCResult RecvDeinitializeVideoDecoder() override;
ipc::IPCResult RecvResetVideoDecoder() override;
ipc::IPCResult RecvDecryptAndDecodeFrame(
const CDMInputBuffer& aBuffer) override;
--- a/dom/media/gmp/ChromiumCDMParent.cpp
+++ b/dom/media/gmp/ChromiumCDMParent.cpp
@@ -181,16 +181,35 @@ ChromiumCDMParent::RemoveSession(const n
if (!SendRemoveSession(aPromiseId, aSessionId)) {
RejectPromise(
aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Failed to send removeSession to CDM process"));
}
}
+void
+ChromiumCDMParent::GetStatusForPolicy(uint32_t aPromiseId,
+ const nsCString& aMinHdcpVersion)
+{
+ GMP_LOG("ChromiumCDMParent::GetStatusForPolicy(this=%p)", this);
+ if (mIsShutdown) {
+ RejectPromise(aPromiseId,
+ NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("CDM is shutdown."));
+ return;
+ }
+ if (!SendGetStatusForPolicy(aPromiseId, aMinHdcpVersion)) {
+ RejectPromise(
+ aPromiseId,
+ NS_ERROR_DOM_INVALID_STATE_ERR,
+ NS_LITERAL_CSTRING("Failed to send getStatusForPolicy to CDM process"));
+ }
+}
+
bool
ChromiumCDMParent::InitCDMInputBuffer(gmp::CDMInputBuffer& aBuffer,
MediaRawData* aSample)
{
const CryptoSample& crypto = aSample->mCrypto;
if (crypto.mEncryptedSizes.Length() != crypto.mPlainSizes.Length()) {
GMP_LOG("InitCDMInputBuffer clear/cipher subsamples don't match");
return false;
@@ -270,16 +289,34 @@ ChromiumCDMParent::Recv__delete__()
if (mContentParent) {
mContentParent->ChromiumCDMDestroyed(this);
mContentParent = nullptr;
}
return IPC_OK();
}
ipc::IPCResult
+ChromiumCDMParent::RecvOnResolvePromiseWithKeyStatus(const uint32_t& aPromiseId,
+ const uint32_t& aKeyStatus)
+{
+ GMP_LOG("ChromiumCDMParent::RecvOnResolvePromiseWithKeyStatus(this=%p, pid=%u, "
+ "keystatus=%u)",
+ this,
+ aPromiseId,
+ aKeyStatus);
+ if (!mCDMCallback || mIsShutdown) {
+ return IPC_OK();
+ }
+
+ mCDMCallback->ResolvePromiseWithKeyStatus(aPromiseId, aKeyStatus);
+
+ return IPC_OK();
+}
+
+ipc::IPCResult
ChromiumCDMParent::RecvOnResolveNewSessionPromise(const uint32_t& aPromiseId,
const nsCString& aSessionId)
{
GMP_LOG("ChromiumCDMParent::RecvOnResolveNewSessionPromise(this=%p, pid=%u, "
"sid=%s)",
this,
aPromiseId,
aSessionId.get());
--- a/dom/media/gmp/ChromiumCDMParent.h
+++ b/dom/media/gmp/ChromiumCDMParent.h
@@ -61,16 +61,19 @@ public:
void UpdateSession(const nsCString& aSessionId,
uint32_t aPromiseId,
const nsTArray<uint8_t>& aResponse);
void CloseSession(const nsCString& aSessionId, uint32_t aPromiseId);
void RemoveSession(const nsCString& aSessionId, uint32_t aPromiseId);
+ void GetStatusForPolicy(uint32_t aPromiseId,
+ const nsCString& aMinHdcpVersion);
+
RefPtr<DecryptPromise> Decrypt(MediaRawData* aSample);
// TODO: Add functions for clients to send data to CDM, and
// a Close() function.
RefPtr<MediaDataDecoder::InitPromise> InitializeVideoDecoder(
const gmp::CDMVideoDecoderConfig& aConfig,
const VideoInfo& aInfo,
RefPtr<layers::ImageContainer> aImageContainer);
@@ -85,16 +88,19 @@ public:
RefPtr<ShutdownPromise> ShutdownVideoDecoder();
void Shutdown();
protected:
~ChromiumCDMParent() {}
ipc::IPCResult Recv__delete__() override;
+ ipc::IPCResult RecvOnResolvePromiseWithKeyStatus(
+ const uint32_t& aPromiseId,
+ const uint32_t& aKeyStatus) override;
ipc::IPCResult RecvOnResolveNewSessionPromise(
const uint32_t& aPromiseId,
const nsCString& aSessionId) override;
ipc::IPCResult RecvResolveLoadSessionPromise(
const uint32_t& aPromiseId,
const bool& aSuccessful) override;
ipc::IPCResult RecvOnResolvePromise(const uint32_t& aPromiseId) override;
ipc::IPCResult RecvOnRejectPromise(const uint32_t& aPromiseId,
--- a/dom/media/gmp/ChromiumCDMProxy.cpp
+++ b/dom/media/gmp/ChromiumCDMProxy.cpp
@@ -461,16 +461,27 @@ ChromiumCDMProxy::OnResolveLoadSessionPr
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;
}
@@ -609,16 +620,23 @@ ChromiumCDMProxy::GetStatusForPolicy(Pro
RefPtr<gmp::ChromiumCDMParent> cdm = GetCDMParent();
if (!cdm) {
RejectPromise(aPromiseId,
NS_ERROR_DOM_INVALID_STATE_ERR,
NS_LITERAL_CSTRING("Null CDM in GetStatusForPolicy"));
return;
}
+
+ mGMPThread->Dispatch(NewRunnableMethod<uint32_t, nsCString>(
+ "gmp::ChromiumCDMParent::GetStatusForPolicy",
+ cdm,
+ &gmp::ChromiumCDMParent::GetStatusForPolicy,
+ aPromiseId,
+ NS_ConvertUTF16toUTF8(aMinHdcpVersion)));
}
void
ChromiumCDMProxy::Terminated()
{
if (!mKeys.IsNull()) {
mKeys->Terminated();
}
--- a/dom/media/gmp/ChromiumCDMProxy.h
+++ b/dom/media/gmp/ChromiumCDMProxy.h
@@ -113,16 +113,19 @@ public:
#endif
ChromiumCDMProxy* AsChromiumCDMProxy() override { return this; }
// Threadsafe. Note this may return a reference to a shutdown
// CDM, which will fail on all operations.
already_AddRefed<gmp::ChromiumCDMParent> GetCDMParent();
+ void OnResolvePromiseWithKeyStatus(uint32_t aPromiseId,
+ dom::MediaKeyStatus aKeyStatus);
+
private:
void OnCDMCreated(uint32_t aPromiseId);
~ChromiumCDMProxy();
GMPCrashHelper* mCrashHelper;
Mutex mCDMMutex;
--- a/dom/media/gmp/PChromiumCDM.ipdl
+++ b/dom/media/gmp/PChromiumCDM.ipdl
@@ -53,19 +53,26 @@ child:
async Drain();
async Destroy();
async GiveBuffer(Shmem aShmem);
async PurgeShmems();
+ // cdm::ContentDecryptionModule9
+ async GetStatusForPolicy(uint32_t aPromiseId,
+ nsCString aMinHdcpVersion);
+
parent:
async __delete__();
+ // cdm::Host9
+ async OnResolvePromiseWithKeyStatus(uint32_t aPromiseId, uint32_t aKeyStatus);
+
// cdm::Host8
async OnResolveNewSessionPromise(uint32_t aPromiseId, nsCString aSessionId);
async OnResolvePromise(uint32_t aPromiseId);
async OnRejectPromise(uint32_t aPromiseId,
uint32_t aError,
uint32_t aSystemCode,
--- a/dom/media/gtest/TestCDMStorage.cpp
+++ b/dom/media/gtest/TestCDMStorage.cpp
@@ -1067,16 +1067,19 @@ private:
}
void SetSessionId(uint32_t aPromiseId,
const nsCString& aSessionId) override { }
void ResolveLoadSessionPromise(uint32_t aPromiseId,
bool aSuccessful) override { }
+ void ResolvePromiseWithKeyStatus(uint32_t aPromiseId,
+ uint32_t aKeyStatus) override { }
+
void ResolvePromise(uint32_t aPromiseId) override { }
void RejectPromise(uint32_t aPromiseId,
nsresult aError,
const nsCString& aErrorMessage) override { }
void SessionMessage(const nsACString& aSessionId,
uint32_t aMessageType,