summaryrefslogtreecommitdiffstats
path: root/media/wmf-clearkey
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /media/wmf-clearkey
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'media/wmf-clearkey')
-rw-r--r--media/wmf-clearkey/WMFClearKey.def5
-rw-r--r--media/wmf-clearkey/WMFClearKeyActivate.cpp213
-rw-r--r--media/wmf-clearkey/WMFClearKeyActivate.h77
-rw-r--r--media/wmf-clearkey/WMFClearKeyCDM.cpp371
-rw-r--r--media/wmf-clearkey/WMFClearKeyCDM.h207
-rw-r--r--media/wmf-clearkey/WMFClearKeyCDMAccess.cpp53
-rw-r--r--media/wmf-clearkey/WMFClearKeyCDMAccess.h38
-rw-r--r--media/wmf-clearkey/WMFClearKeyCDMFactory.cpp82
-rw-r--r--media/wmf-clearkey/WMFClearKeyCDMFactory.h45
-rw-r--r--media/wmf-clearkey/WMFClearKeyContentEnabler.cpp65
-rw-r--r--media/wmf-clearkey/WMFClearKeyContentEnabler.h42
-rw-r--r--media/wmf-clearkey/WMFClearKeyInputTrustAuthority.cpp115
-rw-r--r--media/wmf-clearkey/WMFClearKeyInputTrustAuthority.h56
-rw-r--r--media/wmf-clearkey/WMFClearKeyOutputPolicy.cpp203
-rw-r--r--media/wmf-clearkey/WMFClearKeyOutputPolicy.h81
-rw-r--r--media/wmf-clearkey/WMFClearKeySession.cpp233
-rw-r--r--media/wmf-clearkey/WMFClearKeySession.h78
-rw-r--r--media/wmf-clearkey/WMFClearKeyTrustedInput.cpp35
-rw-r--r--media/wmf-clearkey/WMFClearKeyTrustedInput.h41
-rw-r--r--media/wmf-clearkey/WMFClearKeyUtils.h229
-rw-r--r--media/wmf-clearkey/WMFDecryptedBlock.h67
-rw-r--r--media/wmf-clearkey/WMFPMPServer.cpp68
-rw-r--r--media/wmf-clearkey/WMFPMPServer.h57
-rw-r--r--media/wmf-clearkey/dllmain.cpp37
-rw-r--r--media/wmf-clearkey/moz.build43
25 files changed, 2541 insertions, 0 deletions
diff --git a/media/wmf-clearkey/WMFClearKey.def b/media/wmf-clearkey/WMFClearKey.def
new file mode 100644
index 0000000000..c473b44d79
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKey.def
@@ -0,0 +1,5 @@
+LIBRARY WMFClearKey.dll
+EXPORTS
+ DllCanUnloadNow PRIVATE
+ DllGetActivationFactory PRIVATE
+ DllGetClassObject PRIVATE
diff --git a/media/wmf-clearkey/WMFClearKeyActivate.cpp b/media/wmf-clearkey/WMFClearKeyActivate.cpp
new file mode 100644
index 0000000000..494e58d922
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKeyActivate.cpp
@@ -0,0 +1,213 @@
+/* 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 "WMFClearKeyActivate.h"
+
+#include <mfapi.h>
+#include <mferror.h>
+
+#include "WMFClearKeyContentEnabler.h"
+#include "WMFClearKeyUtils.h"
+
+namespace mozilla {
+
+using Microsoft::WRL::ComPtr;
+using Microsoft::WRL::MakeAndInitialize;
+
+HRESULT WMFClearKeyActivate::RuntimeClassInitialize() { return S_OK; }
+
+STDMETHODIMP WMFClearKeyActivate::ActivateObject(REFIID aRiid, void** aPpv) {
+ ENTRY_LOG();
+ ComPtr<IMFContentEnabler> contentEnabler;
+ RETURN_IF_FAILED(
+ MakeAndInitialize<WMFClearKeyContentEnabler>(&contentEnabler));
+ RETURN_IF_FAILED(contentEnabler.CopyTo(aRiid, aPpv));
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeyActivate::ShutdownObject() {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::DetachObject() {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+// IMFAttributes inherited by IMFActivate
+STDMETHODIMP WMFClearKeyActivate::GetItem(REFGUID aGuidKey,
+ PROPVARIANT* aValue) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::GetItemType(REFGUID aGuidKey,
+ MF_ATTRIBUTE_TYPE* aType) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::CompareItem(REFGUID aGuidKey,
+ REFPROPVARIANT aValue,
+ BOOL* aResult) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::Compare(IMFAttributes* aAttributes,
+ MF_ATTRIBUTES_MATCH_TYPE aType,
+ BOOL* aResult) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::GetUINT32(REFGUID aGuidKey, UINT32* aValue) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::GetUINT64(REFGUID aGuidKey, UINT64* aValue) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::GetDouble(REFGUID aGuidKey, double* aValue) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::GetGUID(REFGUID aGuidKey, GUID* aGuidValue) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::GetStringLength(REFGUID aGuidKey,
+ UINT32* aPcchLength) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::GetString(REFGUID aGuidKey, LPWSTR aPwszValue,
+ UINT32 aCchBufSize,
+ UINT32* aPcchLength) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::GetAllocatedString(REFGUID aGuidKey,
+ LPWSTR* aPpwszValue,
+ UINT32* aPcchLength) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::GetBlobSize(REFGUID aGuidKey,
+ UINT32* aPcbBlobSize) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::GetBlob(REFGUID aGuidKey, UINT8* pBuf,
+ UINT32 aCbBufSize,
+ UINT32* aPcbBlobSize) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::GetAllocatedBlob(REFGUID aGuidKey,
+ UINT8** aBuf,
+ UINT32* aPcbSize) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::GetUnknown(REFGUID aGuidKey, REFIID aRiid,
+ LPVOID* aPpv) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::SetItem(REFGUID aGuidKey,
+ REFPROPVARIANT aValue) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::DeleteItem(REFGUID aGuidKey) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::DeleteAllItems() {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::SetUINT32(REFGUID aGuidKey, UINT32 aValue) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::SetUINT64(REFGUID aGuidKey, UINT64 aValue) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::SetDouble(REFGUID aGuidKey, double aValue) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::SetGUID(REFGUID aGuidKey,
+ REFGUID aGuidValue) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::SetString(REFGUID aGuidKey,
+ LPCWSTR aWszValue) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::SetBlob(REFGUID aGuidKey, const UINT8* aBuf,
+ UINT32 aCbBufSize) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::SetUnknown(REFGUID aGuidKey,
+ IUnknown* aUnknown) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::LockStore() {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::UnlockStore() {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::GetCount(UINT32* aPcItems) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::GetItemByIndex(UINT32 aIndex, GUID* aGuidKey,
+ PROPVARIANT* aValue) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyActivate::CopyAllItems(IMFAttributes* aDest) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+} // namespace mozilla
diff --git a/media/wmf-clearkey/WMFClearKeyActivate.h b/media/wmf-clearkey/WMFClearKeyActivate.h
new file mode 100644
index 0000000000..cd992221e7
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKeyActivate.h
@@ -0,0 +1,77 @@
+/* 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/. */
+
+#ifndef DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYACTIVATE_H
+#define DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYACTIVATE_H
+
+#include <wrl.h>
+#include <wrl/client.h>
+
+#include "MFCDMExtra.h"
+
+namespace mozilla {
+
+// This class is used to provide WMFClearKeyContentEnabler.
+class WMFClearKeyActivate
+ : public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
+ IMFActivate, Microsoft::WRL::FtmBase> {
+ public:
+ WMFClearKeyActivate() = default;
+ ~WMFClearKeyActivate() = default;
+ WMFClearKeyActivate(const WMFClearKeyActivate&) = delete;
+ WMFClearKeyActivate& operator=(const WMFClearKeyActivate&) = delete;
+
+ HRESULT RuntimeClassInitialize();
+
+ // IMFActivate
+ STDMETHODIMP ActivateObject(REFIID aRiid, void** aPpv) override;
+ STDMETHODIMP ShutdownObject() override;
+ STDMETHODIMP DetachObject() override;
+
+ // IMFAttributes inherited by IMFActivate
+ STDMETHODIMP GetItem(REFGUID aGuidKey, PROPVARIANT* aValue) override;
+ STDMETHODIMP GetItemType(REFGUID aGuidKey, MF_ATTRIBUTE_TYPE* aType) override;
+ STDMETHODIMP CompareItem(REFGUID aGuidKey, REFPROPVARIANT aValue,
+ BOOL* aResult) override;
+ STDMETHODIMP Compare(IMFAttributes* aAttributes,
+ MF_ATTRIBUTES_MATCH_TYPE aType, BOOL* aResult) override;
+ STDMETHODIMP GetUINT32(REFGUID aGuidKey, UINT32* aValue) override;
+ STDMETHODIMP GetUINT64(REFGUID aGuidKey, UINT64* aValue) override;
+ STDMETHODIMP GetDouble(REFGUID aGuidKey, double* aValue) override;
+ STDMETHODIMP GetGUID(REFGUID aGuidKey, GUID* aGuidValue) override;
+ STDMETHODIMP GetStringLength(REFGUID aGuidKey, UINT32* aPcchLength) override;
+ STDMETHODIMP GetString(REFGUID aGuidKey, LPWSTR aPwszValue,
+ UINT32 aCchBufSize, UINT32* aPcchLength) override;
+ STDMETHODIMP GetAllocatedString(REFGUID aGuidKey, LPWSTR* aPpwszValue,
+ UINT32* aPcchLength) override;
+ STDMETHODIMP GetBlobSize(REFGUID aGuidKey, UINT32* aPcbBlobSize) override;
+ STDMETHODIMP GetBlob(REFGUID aGuidKey, UINT8* aBuf, UINT32 aCbBufSize,
+ UINT32* aPcbBlobSize) override;
+ STDMETHODIMP GetAllocatedBlob(REFGUID aGuidKey, UINT8** aBuf,
+ UINT32* aPcbSize) override;
+ STDMETHODIMP GetUnknown(REFGUID aGuidKey, REFIID aRiid,
+ LPVOID* aPpv) override;
+ STDMETHODIMP SetItem(REFGUID aGuidKey, REFPROPVARIANT aValue) override;
+ STDMETHODIMP DeleteItem(REFGUID aGuidKey) override;
+ STDMETHODIMP DeleteAllItems() override;
+ STDMETHODIMP SetUINT32(REFGUID aGuidKey, UINT32 aValue) override;
+ STDMETHODIMP SetUINT64(REFGUID aGuidKey, UINT64 aValue) override;
+ STDMETHODIMP SetDouble(REFGUID aGuidKey, double aValue) override;
+ STDMETHODIMP SetGUID(REFGUID aGuidKey, REFGUID aGuidValue) override;
+ STDMETHODIMP SetString(REFGUID aGuidKey, LPCWSTR aWszValue) override;
+ STDMETHODIMP SetBlob(REFGUID aGuidKey, const UINT8* aBuf,
+ UINT32 aCbBufSize) override;
+ STDMETHODIMP SetUnknown(REFGUID aGuidKey, IUnknown* aUnknown) override;
+ STDMETHODIMP LockStore() override;
+ STDMETHODIMP UnlockStore() override;
+ STDMETHODIMP GetCount(UINT32* aPcItems) override;
+ STDMETHODIMP GetItemByIndex(UINT32 aIndex, GUID* aGuidKey,
+ PROPVARIANT* aValue) override;
+ STDMETHODIMP CopyAllItems(IMFAttributes* aDest) override;
+};
+
+} // namespace mozilla
+
+#endif // DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYACTIVATE_H
diff --git a/media/wmf-clearkey/WMFClearKeyCDM.cpp b/media/wmf-clearkey/WMFClearKeyCDM.cpp
new file mode 100644
index 0000000000..b782aec5da
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKeyCDM.cpp
@@ -0,0 +1,371 @@
+/* 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 "WMFClearKeyCDM.h"
+
+#include <Mferror.h>
+#include <mfapi.h>
+#include <oleauto.h>
+#include <optional>
+#include <windows.h>
+#include <windows.media.h>
+
+#include "WMFClearKeyTrustedInput.h"
+#include "WMFClearKeySession.h"
+#include "WMFDecryptedBlock.h"
+#include "WMFPMPServer.h"
+
+using Microsoft::WRL::ComPtr;
+using Microsoft::WRL::MakeAndInitialize;
+
+static HRESULT AddPropertyToSet(
+ ABI::Windows::Foundation::Collections::IPropertySet* aPropertySet,
+ LPCWSTR aName, IInspectable* aInspectable) {
+ boolean replaced = false;
+ ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable*>>
+ map;
+ RETURN_IF_FAILED(aPropertySet->QueryInterface(IID_PPV_ARGS(&map)));
+ RETURN_IF_FAILED(
+ map->Insert(Microsoft::WRL::Wrappers::HStringReference(aName).Get(),
+ aInspectable, &replaced));
+ return S_OK;
+}
+
+static HRESULT AddStringToPropertySet(
+ ABI::Windows::Foundation::Collections::IPropertySet* aPropertySet,
+ LPCWSTR aName, LPCWSTR aString) {
+ ComPtr<ABI::Windows::Foundation::IPropertyValue> propertyValue;
+ ComPtr<ABI::Windows::Foundation::IPropertyValueStatics> propertyValueStatics;
+ RETURN_IF_FAILED(ABI::Windows::Foundation::GetActivationFactory(
+ Microsoft::WRL::Wrappers::HStringReference(
+ RuntimeClass_Windows_Foundation_PropertyValue)
+ .Get(),
+ &propertyValueStatics));
+ RETURN_IF_FAILED(propertyValueStatics->CreateString(
+ Microsoft::WRL::Wrappers::HStringReference(aString).Get(),
+ &propertyValue));
+ RETURN_IF_FAILED(AddPropertyToSet(aPropertySet, aName, propertyValue.Get()));
+ return S_OK;
+}
+
+static HRESULT AddBoolToPropertySet(
+ ABI::Windows::Foundation::Collections::IPropertySet* aPropertySet,
+ LPCWSTR aName, BOOL aValue) {
+ ComPtr<ABI::Windows::Foundation::IPropertyValue> propertyValue;
+ ComPtr<ABI::Windows::Foundation::IPropertyValueStatics> propertyValueStatics;
+ RETURN_IF_FAILED(ABI::Windows::Foundation::GetActivationFactory(
+ Microsoft::WRL::Wrappers::HStringReference(
+ RuntimeClass_Windows_Foundation_PropertyValue)
+ .Get(),
+ &propertyValueStatics));
+ RETURN_IF_FAILED(
+ propertyValueStatics->CreateBoolean(!!aValue, &propertyValue));
+ RETURN_IF_FAILED(AddPropertyToSet(aPropertySet, aName, propertyValue.Get()));
+ return S_OK;
+}
+
+MF_MEDIAKEYSESSION_MESSAGETYPE ToMFMessageType(cdm::MessageType aMessageType) {
+ switch (aMessageType) {
+ case cdm::MessageType::kLicenseRequest:
+ return MF_MEDIAKEYSESSION_MESSAGETYPE_LICENSE_REQUEST;
+ case cdm::MessageType::kLicenseRenewal:
+ return MF_MEDIAKEYSESSION_MESSAGETYPE_LICENSE_RENEWAL;
+ case cdm::MessageType::kLicenseRelease:
+ return MF_MEDIAKEYSESSION_MESSAGETYPE_LICENSE_RELEASE;
+ case cdm::MessageType::kIndividualizationRequest:
+ return MF_MEDIAKEYSESSION_MESSAGETYPE_INDIVIDUALIZATION_REQUEST;
+ }
+}
+
+namespace mozilla {
+
+HRESULT WMFClearKeyCDM::RuntimeClassInitialize(IPropertyStore* aProperties) {
+ ENTRY_LOG();
+ // A workaround in order to create an in-process PMP server regardless of the
+ // system's HWDRM capability. As accoriding to Microsoft, only PlayReady is
+ // supported for the in-process PMP so we pretend ourselves as a PlayReady
+ // CDM for the PMP server.
+ ComPtr<ABI::Windows::Foundation::Collections::IPropertySet> propertyPmp;
+ RETURN_IF_FAILED(Windows::Foundation::ActivateInstance(
+ Microsoft::WRL::Wrappers::HStringReference(
+ RuntimeClass_Windows_Foundation_Collections_PropertySet)
+ .Get(),
+ &propertyPmp));
+ RETURN_IF_FAILED(AddStringToPropertySet(
+ propertyPmp.Get(), L"Windows.Media.Protection.MediaProtectionSystemId",
+ PLAYREADY_GUID_MEDIA_PROTECTION_SYSTEM_ID_STRING));
+ RETURN_IF_FAILED(AddBoolToPropertySet(
+ propertyPmp.Get(), L"Windows.Media.Protection.UseHardwareProtectionLayer",
+ TRUE));
+ RETURN_IF_FAILED((MakeAndInitialize<
+ WMFPMPServer,
+ ABI::Windows::Media::Protection::IMediaProtectionPMPServer>(
+ &mPMPServer, propertyPmp.Get())));
+
+ mSessionManager = new SessionManagerWrapper(this);
+ return S_OK;
+}
+
+WMFClearKeyCDM::~WMFClearKeyCDM() { ENTRY_LOG(); }
+
+STDMETHODIMP WMFClearKeyCDM::SetContentEnabler(
+ IMFContentEnabler* aContentEnabler, IMFAsyncResult* aResult) {
+ ENTRY_LOG();
+ if (!aContentEnabler || !aResult) {
+ return E_INVALIDARG;
+ }
+ // Invoke the callback immediately but will determine whether the keyid exists
+ // or not in the decryptor's ProcessOutput().
+ RETURN_IF_FAILED(MFInvokeCallback(aResult));
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeyCDM::SetPMPHostApp(IMFPMPHostApp* aPmpHostApp) {
+ ENTRY_LOG();
+ // Simply return S_OK and ignore IMFPMPHostApp, which is only used for the
+ // out-of-process PMP.
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeyCDM::CreateSession(
+ MF_MEDIAKEYSESSION_TYPE aSessionType,
+ IMFContentDecryptionModuleSessionCallbacks* aCallbacks,
+ IMFContentDecryptionModuleSession** aSession) {
+ ENTRY_LOG();
+ RETURN_IF_FAILED(
+ (MakeAndInitialize<WMFClearKeySession, IMFContentDecryptionModuleSession>(
+ aSession, aSessionType, aCallbacks, mSessionManager)));
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeyCDM::CreateTrustedInput(
+ const BYTE* aContentInitData, DWORD aContentInitDataSize,
+ IMFTrustedInput** aTrustedInput) {
+ ENTRY_LOG();
+ ComPtr<IMFTrustedInput> trustedInput;
+ RETURN_IF_FAILED((MakeAndInitialize<WMFClearKeyTrustedInput, IMFTrustedInput>(
+ &trustedInput, mSessionManager)));
+ *aTrustedInput = trustedInput.Detach();
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeyCDM::GetProtectionSystemIds(GUID** aSystemIds,
+ DWORD* aCount) {
+ ENTRY_LOG();
+ GUID* systemId = static_cast<GUID*>(CoTaskMemAlloc(sizeof(GUID)));
+ if (!systemId) {
+ return E_OUTOFMEMORY;
+ }
+ *systemId = CLEARKEY_GUID_CLEARKEY_PROTECTION_SYSTEM_ID;
+ *aSystemIds = systemId;
+ *aCount = 1;
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeyCDM::GetService(REFGUID aGuidService, REFIID aRiid,
+ LPVOID* aPpvObject) {
+ ENTRY_LOG();
+ if (MF_CONTENTDECRYPTIONMODULE_SERVICE != aGuidService) {
+ ENTRY_LOG_ARGS("unsupported guid!");
+ return MF_E_UNSUPPORTED_SERVICE;
+ }
+ if (!mPMPServer) {
+ ENTRY_LOG_ARGS("no PMP server!");
+ return MF_INVALID_STATE_ERR;
+ }
+ if (aRiid == ABI::Windows::Media::Protection::IID_IMediaProtectionPMPServer) {
+ RETURN_IF_FAILED(mPMPServer.CopyTo(aRiid, aPpvObject));
+ } else {
+ ComPtr<IMFGetService> getService;
+ RETURN_IF_FAILED(mPMPServer.As(&getService));
+ RETURN_IF_FAILED(getService->GetService(MF_PMP_SERVICE, aRiid, aPpvObject));
+ }
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeyCDM::GetSuspendNotify(IMFCdmSuspendNotify** aNotify) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyCDM::SetServerCertificate(const BYTE* aCertificate,
+ DWORD aCertificateSize) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyCDM::Shutdown() {
+ ENTRY_LOG();
+ mSessionManager->Shutdown();
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeyCDM::GetShutdownStatus(MFSHUTDOWN_STATUS* aStatus) {
+ ENTRY_LOG();
+ // https://learn.microsoft.com/en-us/windows/win32/api/mfidl/nf-mfidl-imfshutdown-getshutdownstatus#return-value
+ if (mSessionManager->IsShutdown()) {
+ return MF_E_INVALIDREQUEST;
+ }
+ return S_OK;
+}
+
+// SessionManagerWrapper
+
+SessionManagerWrapper::SessionManagerWrapper(WMFClearKeyCDM* aCDM)
+ : mOwnerCDM(aCDM), mSessionManager(new ClearKeySessionManager(this)) {
+ // For testing, we don't care about these.
+ mSessionManager->Init(false /* aDistinctiveIdentifierAllowed */,
+ false /* aPersistentStateAllowed*/);
+}
+
+SessionManagerWrapper::~SessionManagerWrapper() { ENTRY_LOG(); }
+
+// Callback methods
+void SessionManagerWrapper::OnResolveNewSessionPromise(
+ uint32_t aPromiseId, const char* aSessionId, uint32_t aSessionIdSize) {
+ if (auto rv = mActiveSyncResultChecker.find(aPromiseId);
+ rv != mActiveSyncResultChecker.end()) {
+ LOG("Generated request (promise-id=%u, sessionId=%s)", aPromiseId,
+ aSessionId);
+ rv->second->SetResultConstChar(aSessionId);
+ std::string sessionId{aSessionId};
+ MOZ_ASSERT(mSessions.find(sessionId) == mSessions.end());
+ mSessions[sessionId] = rv->second->GetKeySession();
+ }
+}
+
+void SessionManagerWrapper::OnResolvePromise(uint32_t aPromiseId) {
+ if (auto rv = mActiveSyncResultChecker.find(aPromiseId);
+ rv != mActiveSyncResultChecker.end()) {
+ LOG("Resolved promise (promise-id=%u)", aPromiseId);
+ rv->second->SetResultBool(true);
+ }
+}
+
+void SessionManagerWrapper::OnRejectPromise(uint32_t aPromiseId,
+ cdm::Exception aException,
+ uint32_t aSystemCode,
+ const char* aErrorMessage,
+ uint32_t aErrorMessageSize) {
+ if (auto rv = mActiveSyncResultChecker.find(aPromiseId);
+ rv != mActiveSyncResultChecker.end()) {
+ LOG("Rejected promise (promise-id=%u)", aPromiseId);
+ rv->second->SetResultBool(false);
+ }
+}
+
+HRESULT SessionManagerWrapper::GenerateRequest(cdm::InitDataType aInitDataType,
+ const BYTE* aInitData,
+ DWORD aInitDataSize,
+ cdm::SessionType aSessionType,
+ WMFClearKeySession* aSession,
+ std::string& aSessionIdOut) {
+ ENTRY_LOG();
+ MOZ_DIAGNOSTIC_ASSERT(aSessionType == cdm::SessionType::kTemporary);
+ SyncResultChecker checker(*this, aSession);
+ mSessionManager->CreateSession(checker.GetPromiseId(), aInitDataType,
+ aInitData, aInitDataSize, aSessionType);
+ auto* rv = std::get_if<const char*>(&checker.GetResult());
+ if (!rv) {
+ LOG("Failed to generate request, no session Id!");
+ return E_FAIL;
+ }
+ aSessionIdOut = std::string(*rv);
+ return S_OK;
+}
+
+HRESULT SessionManagerWrapper::UpdateSession(const std::string& aSessionId,
+ const BYTE* aResponse,
+ DWORD aResponseSize) {
+ ENTRY_LOG();
+ SyncResultChecker checker(*this);
+ mSessionManager->UpdateSession(checker.GetPromiseId(), aSessionId.c_str(),
+ aSessionId.size(), aResponse, aResponseSize);
+ auto* rv = std::get_if<bool>(&checker.GetResult());
+ return rv && *rv ? S_OK : E_FAIL;
+}
+
+HRESULT SessionManagerWrapper::CloseSession(const std::string& aSessionId) {
+ ENTRY_LOG();
+ SyncResultChecker checker(*this);
+ mSessionManager->CloseSession(checker.GetPromiseId(), aSessionId.c_str(),
+ aSessionId.size());
+ auto* rv = std::get_if<bool>(&checker.GetResult());
+ return rv && *rv ? S_OK : E_FAIL;
+}
+
+HRESULT SessionManagerWrapper::RemoveSession(const std::string& aSessionId) {
+ ENTRY_LOG();
+ SyncResultChecker checker(*this);
+ MOZ_ASSERT(mSessions.find(aSessionId) != mSessions.end());
+ mSessions.erase(aSessionId);
+ mSessionManager->RemoveSession(checker.GetPromiseId(), aSessionId.c_str(),
+ aSessionId.size());
+ auto* rv = std::get_if<bool>(&checker.GetResult());
+ return rv && *rv ? S_OK : E_FAIL;
+}
+
+HRESULT SessionManagerWrapper::Decrypt(const cdm::InputBuffer_2& aBuffer,
+ cdm::DecryptedBlock* aDecryptedBlock) {
+ ENTRY_LOG();
+ // From MF thread pool.
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mIsShutdown) {
+ return MF_E_SHUTDOWN;
+ }
+ auto rv = mSessionManager->Decrypt(aBuffer, aDecryptedBlock);
+ return rv == cdm::kSuccess ? S_OK : E_FAIL;
+}
+
+void SessionManagerWrapper::OnSessionMessage(const char* aSessionId,
+ uint32_t aSessionIdSize,
+ cdm::MessageType aMessageType,
+ const char* aMessage,
+ uint32_t aMessageSize) {
+ ENTRY_LOG_ARGS("sessionId=%s, sz=%u", aSessionId, aSessionIdSize);
+ std::string sessionId(aSessionId);
+ MOZ_ASSERT(mSessions.find(sessionId) != mSessions.end());
+ mSessions[sessionId]->OnKeyMessage(ToMFMessageType(aMessageType),
+ reinterpret_cast<const BYTE*>(aMessage),
+ aMessageSize);
+}
+
+void SessionManagerWrapper::OnSessionKeysChange(
+ const char* aSessionId, uint32_t aSessionIdSize,
+ bool aHasAdditionalUsableKey, const cdm::KeyInformation* aKeysInfo,
+ uint32_t aKeysInfoCount) {
+ ENTRY_LOG_ARGS("sessionId=%s, sz=%u", aSessionId, aSessionIdSize);
+ std::string sessionId(aSessionId);
+ MOZ_ASSERT(mSessions.find(sessionId) != mSessions.end());
+ mSessions[sessionId]->OnKeyStatusChanged(aKeysInfo, aKeysInfoCount);
+}
+
+// `ClearKeySessionManager::Decrypt` will call this method to allocate buffer
+// for decryted data.
+cdm::Buffer* SessionManagerWrapper::Allocate(uint32_t aCapacity) {
+ ENTRY_LOG_ARGS("capacity=%u", aCapacity);
+ return new WMFDecryptedBuffer(aCapacity);
+}
+
+void SessionManagerWrapper::Shutdown() {
+ ENTRY_LOG();
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mIsShutdown) {
+ return;
+ }
+ mOwnerCDM = nullptr;
+ for (const auto& session : mSessions) {
+ session.second->Shutdown();
+ }
+ mSessions.clear();
+ mSessionManager = nullptr;
+ mIsShutdown = true;
+}
+
+bool SessionManagerWrapper::IsShutdown() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mIsShutdown;
+}
+
+} // namespace mozilla
diff --git a/media/wmf-clearkey/WMFClearKeyCDM.h b/media/wmf-clearkey/WMFClearKeyCDM.h
new file mode 100644
index 0000000000..765cac36f0
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKeyCDM.h
@@ -0,0 +1,207 @@
+/* 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/. */
+
+#ifndef DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYCDM_H
+#define DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYCDM_H
+
+#include <mfidl.h>
+#include <unordered_map>
+#include <variant>
+#include <windows.h>
+#include <windows.media.protection.h>
+#include <wrl.h>
+#include <wrl/client.h>
+
+#include "ClearKeySessionManager.h"
+#include "MFCDMExtra.h"
+#include "WMFClearKeyUtils.h"
+#include "content_decryption_module.h"
+
+namespace mozilla {
+
+class SessionManagerWrapper;
+class WMFClearKeySession;
+
+// This our customized MFCDM for supporting clearkey in our testing. It would
+// use ClearKeySessionManager via SessionManagerWrapper to perform decryption.
+class WMFClearKeyCDM final
+ : public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
+ IMFContentDecryptionModule, IMFGetService, IMFShutdown,
+ Microsoft::WRL::FtmBase> {
+ public:
+ WMFClearKeyCDM() = default;
+ ~WMFClearKeyCDM();
+ WMFClearKeyCDM(const WMFClearKeyCDM&) = delete;
+ WMFClearKeyCDM& operator=(const WMFClearKeyCDM&) = delete;
+
+ HRESULT RuntimeClassInitialize(IPropertyStore* aProperties);
+
+ // IMFContentDecryptionModule
+ STDMETHODIMP SetContentEnabler(IMFContentEnabler* aContentEnabler,
+ IMFAsyncResult* aResult) override;
+ STDMETHODIMP GetSuspendNotify(IMFCdmSuspendNotify** aNotify) override;
+ STDMETHODIMP SetPMPHostApp(IMFPMPHostApp* aPmpHostApp) override;
+ STDMETHODIMP CreateSession(
+ MF_MEDIAKEYSESSION_TYPE aSessionType,
+ IMFContentDecryptionModuleSessionCallbacks* aCallbacks,
+ IMFContentDecryptionModuleSession** aSession) override;
+ STDMETHODIMP SetServerCertificate(const BYTE* aCertificate,
+ DWORD aCertificateSize) override;
+ STDMETHODIMP CreateTrustedInput(const BYTE* aContentInitData,
+ DWORD aContentInitDataSize,
+ IMFTrustedInput** aTrustedInput) override;
+ STDMETHODIMP GetProtectionSystemIds(GUID** aSystemIds,
+ DWORD* aCount) override;
+ // IMFGetService
+ STDMETHODIMP GetService(REFGUID aGuidService, REFIID aRiid,
+ LPVOID* aPpvObject) override;
+
+ // IMFShutdown
+ STDMETHODIMP Shutdown() override;
+ STDMETHODIMP GetShutdownStatus(MFSHUTDOWN_STATUS* aStatus) override;
+
+ private:
+ RefPtr<SessionManagerWrapper> mSessionManager;
+ Microsoft::WRL::ComPtr<
+ ABI::Windows::Media::Protection::IMediaProtectionPMPServer>
+ mPMPServer;
+};
+
+// In order to reuse existing Gecko clearkey implementation, we need to
+// inherit the class `cdm::Host_10`.
+// TODO : add a way to assert thread usage. It would be used on MF thread pool
+// and the media supervisor thread pool.
+class SessionManagerWrapper final : public RefCounted, private cdm::Host_10 {
+ public:
+ explicit SessionManagerWrapper(WMFClearKeyCDM* aCDM);
+
+ HRESULT GenerateRequest(cdm::InitDataType aInitDataType,
+ const BYTE* aInitData, DWORD aInitDataSize,
+ cdm::SessionType aSessionType,
+ WMFClearKeySession* aSession,
+ std::string& aSessionIdOut);
+ HRESULT UpdateSession(const std::string& aSessionId, const BYTE* aResponse,
+ DWORD aResponseSize);
+ HRESULT CloseSession(const std::string& aSessionId);
+ HRESULT RemoveSession(const std::string& aSessionId);
+ HRESULT Decrypt(const cdm::InputBuffer_2& aBuffer,
+ cdm::DecryptedBlock* aDecryptedBlock);
+
+ void Shutdown();
+ bool IsShutdown();
+
+ private:
+ ~SessionManagerWrapper();
+ // cdm::Host_10
+ void OnInitialized(bool aSuccess) override {}
+ void OnResolveKeyStatusPromise(uint32_t aPromiseId,
+ cdm::KeyStatus aKeyStatus) override {}
+ void OnResolveNewSessionPromise(uint32_t aPromiseId, const char* aSessionId,
+ uint32_t aSessionIdSize) override;
+ void OnResolvePromise(uint32_t aPromiseId) override;
+ void OnRejectPromise(uint32_t aPromiseId, cdm::Exception aException,
+ uint32_t aSystemCode, const char* aErrorMessage,
+ uint32_t aErrorMessageSize) override;
+ void OnSessionMessage(const char* aSessionId, uint32_t aSessionIdSize,
+ cdm::MessageType aMessageType, const char* aMessage,
+ uint32_t aMessageSize) override;
+ void OnSessionKeysChange(const char* aSessionId, uint32_t aSessionIdSize,
+ bool aHasAdditionalUsableKey,
+ const cdm::KeyInformation* aKeysInfo,
+ uint32_t aKeysInfoCount) override;
+ void OnExpirationChange(const char* aSessionId, uint32_t aSessionIdSize,
+ cdm::Time aNewExpiryTime) override{
+ // No need to implement this because the session would never expire in
+ // testing.
+ };
+ void OnSessionClosed(const char* aSessionId,
+ uint32_t aSessionIdSize) override{
+ // No need to implement this because session doesn't have close callback
+ // or events.
+ };
+ cdm::FileIO* CreateFileIO(cdm::FileIOClient* aClient) override {
+ // We don't support this because we only support temporary session.
+ return nullptr;
+ }
+ void SendPlatformChallenge(const char* aServiceId, uint32_t aServiceIdSize,
+ const char* aChallenge,
+ uint32_t aChallengeSize) override {}
+ void EnableOutputProtection(uint32_t aDesiredProtectionMask) override {}
+ void QueryOutputProtectionStatus() override{};
+ void OnDeferredInitializationDone(cdm::StreamType aStreamType,
+ cdm::Status aDecoderStatus) override {}
+ void RequestStorageId(uint32_t aVersion) override {}
+ cdm::Buffer* Allocate(uint32_t aCapacity) override;
+ void SetTimer(int64_t aDelayMs, void* aContext) override {}
+ cdm::Time GetCurrentWallTime() override { return 0.0; }
+ friend class SessionManager;
+
+ Microsoft::WRL::ComPtr<WMFClearKeyCDM> mOwnerCDM;
+ RefPtr<ClearKeySessionManager> mSessionManager;
+ std::unordered_map<std::string, Microsoft::WRL::ComPtr<WMFClearKeySession>>
+ mSessions;
+
+ // This is a RAII helper class to use ClearKeySessionManager::XXXSession
+ // methods in a sync style, which is what MFCDM is required.
+ // ClearKeySessionManager uses cdm::Host_10's OnResolve/RejectXXX as callback
+ // to report whether those function calls relatd with specific promise id
+ // succeed or not. As we only do temporary session for ClearKey testing, we
+ // don't need to wait to setup the storage so calling those XXXsession
+ // functions are actully a sync process. We guarantee that
+ // ClearKeySessionManager will use OnResolve/Reject methods to notify us
+ // result, right after we calling the session related method.
+ // [How to to use this class, not thread-safe]
+ // 1. create it on the stack
+ // 2. use GetPromiseId() to generate a fake promise id for tracking
+ // 3. in cdm::Host_10's callback function, check promise id to know what
+ // result needs to be set
+ // 4. check result to see if the session method succeed or not
+ class SyncResultChecker final {
+ public:
+ using ResultType = std::variant<const char*, bool>;
+ explicit SyncResultChecker(SessionManagerWrapper& aOwner)
+ : mOwner(aOwner), mIdx(sIdx++), mKeySession(nullptr) {
+ mOwner.mActiveSyncResultChecker.insert({mIdx, this});
+ }
+ SyncResultChecker(SessionManagerWrapper& aOwner,
+ WMFClearKeySession* aKeySession)
+ : mOwner(aOwner), mIdx(sIdx++), mKeySession(aKeySession) {
+ mOwner.mActiveSyncResultChecker.insert({mIdx, this});
+ }
+ ~SyncResultChecker() { mOwner.mActiveSyncResultChecker.erase(mIdx); }
+ uint32_t GetPromiseId() const { return mIdx; }
+ const ResultType& GetResult() const { return mResult; }
+ WMFClearKeySession* GetKeySession() const { return mKeySession; }
+
+ private:
+ // Only allow setting result from these callbacks.
+ friend void SessionManagerWrapper::OnResolveNewSessionPromise(uint32_t,
+ const char*,
+ uint32_t);
+ friend void SessionManagerWrapper::OnResolvePromise(uint32_t);
+ friend void SessionManagerWrapper::OnRejectPromise(uint32_t, cdm::Exception,
+ uint32_t, const char*,
+ uint32_t);
+ void SetResultConstChar(const char* aResult) {
+ mResult.emplace<const char*>(aResult);
+ }
+ void SetResultBool(bool aResult) { mResult.emplace<bool>(aResult); }
+
+ static inline uint32_t sIdx = 0;
+ SessionManagerWrapper& mOwner;
+ const uint32_t mIdx;
+ ResultType mResult;
+ WMFClearKeySession* const mKeySession;
+ };
+ std::unordered_map<uint32_t, SyncResultChecker*> mActiveSyncResultChecker;
+
+ // Protect following members.
+ std::mutex mMutex;
+ bool mIsShutdown = false;
+};
+
+} // namespace mozilla
+
+#endif // DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYCDM_H
diff --git a/media/wmf-clearkey/WMFClearKeyCDMAccess.cpp b/media/wmf-clearkey/WMFClearKeyCDMAccess.cpp
new file mode 100644
index 0000000000..709690e48f
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKeyCDMAccess.cpp
@@ -0,0 +1,53 @@
+/* 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 "WMFClearKeyCDMAccess.h"
+
+#include <Mferror.h>
+#include <oleauto.h>
+
+#include "WMFClearKeyCDM.h"
+#include "WMFClearKeyUtils.h"
+
+namespace mozilla {
+
+using Microsoft::WRL::ComPtr;
+using Microsoft::WRL::MakeAndInitialize;
+
+STDMETHODIMP WMFClearKeyCDMAccess::CreateContentDecryptionModule(
+ IPropertyStore* aProperties, IMFContentDecryptionModule** aCdm) {
+ ENTRY_LOG();
+ if (!aProperties) {
+ ENTRY_LOG_ARGS("Null properties!");
+ return MF_E_UNEXPECTED;
+ }
+
+ *aCdm = nullptr;
+ ComPtr<IMFContentDecryptionModule> cdm;
+ RETURN_IF_FAILED(
+ (MakeAndInitialize<WMFClearKeyCDM, IMFContentDecryptionModule>(
+ &cdm, aProperties)));
+ *aCdm = cdm.Detach();
+ ENTRY_LOG_ARGS("Created clearkey CDM!");
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeyCDMAccess::GetConfiguration(IPropertyStore** aConfig) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyCDMAccess::GetKeySystem(LPWSTR* aKeySystem) {
+ ENTRY_LOG();
+ *aKeySystem = (LPWSTR)CoTaskMemAlloc((wcslen(kCLEARKEY_SYSTEM_NAME) + 1) *
+ sizeof(wchar_t));
+ if (*aKeySystem == NULL) {
+ return E_OUTOFMEMORY;
+ }
+ wcscpy_s(*aKeySystem, wcslen(kCLEARKEY_SYSTEM_NAME) + 1,
+ kCLEARKEY_SYSTEM_NAME);
+ return S_OK;
+}
+
+} // namespace mozilla
diff --git a/media/wmf-clearkey/WMFClearKeyCDMAccess.h b/media/wmf-clearkey/WMFClearKeyCDMAccess.h
new file mode 100644
index 0000000000..49bd80b660
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKeyCDMAccess.h
@@ -0,0 +1,38 @@
+/* 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/. */
+
+#ifndef DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYCDMACCESS_H
+#define DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYCDMACCESS_H
+
+#include <mfidl.h>
+#include <windows.h>
+#include <wrl.h>
+
+#include "MFCDMExtra.h"
+
+namespace mozilla {
+
+// This class is used to create WMFClearKeyCDM.
+class WMFClearKeyCDMAccess final
+ : public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
+ IMFContentDecryptionModuleAccess, Microsoft::WRL::FtmBase> {
+ public:
+ WMFClearKeyCDMAccess() = default;
+ ~WMFClearKeyCDMAccess() = default;
+ WMFClearKeyCDMAccess(const WMFClearKeyCDMAccess&) = delete;
+ WMFClearKeyCDMAccess& operator=(const WMFClearKeyCDMAccess&) = delete;
+
+ HRESULT RuntimeClassInitialize() { return S_OK; };
+
+ // IMFContentDecryptionModuleAccess
+ STDMETHODIMP CreateContentDecryptionModule(
+ IPropertyStore* aProperties, IMFContentDecryptionModule** aCdm) override;
+ STDMETHODIMP GetConfiguration(IPropertyStore** aConfig) override;
+ STDMETHODIMP GetKeySystem(LPWSTR* aKeySystem) override;
+};
+
+} // namespace mozilla
+
+#endif // DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYCDMACCESS_H
diff --git a/media/wmf-clearkey/WMFClearKeyCDMFactory.cpp b/media/wmf-clearkey/WMFClearKeyCDMFactory.cpp
new file mode 100644
index 0000000000..6ec253850d
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKeyCDMFactory.cpp
@@ -0,0 +1,82 @@
+/* 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 "WMFClearKeyCDMFactory.h"
+
+#include <string>
+
+#include <Mferror.h>
+
+#include "WMFClearKeyCDMAccess.h"
+#include "WMFClearKeyUtils.h"
+
+namespace mozilla {
+
+using Microsoft::WRL::MakeAndInitialize;
+
+ActivatableClass(WMFClearKeyCDMFactory);
+
+bool isRequiringHDCP22OrAbove(LPCWSTR aType) {
+ if (aType == nullptr || *aType == L'\0') {
+ return false;
+ }
+
+ // The HDCP value follows the feature value in
+ // https://docs.microsoft.com/en-us/uwp/api/windows.media.protection.protectioncapabilities.istypesupported?view=winrt-19041
+ // - 1 (on without HDCP 2.2 Type 1 restriction)
+ // - 2 (on with HDCP 2.2 Type 1 restriction)
+ std::wstring wstr(aType);
+ std::string hdcpStr(wstr.begin(), wstr.end());
+ return wstr.find(L"hdcp=2") != std::string::npos;
+}
+
+STDMETHODIMP_(BOOL)
+WMFClearKeyCDMFactory::IsTypeSupported(_In_ LPCWSTR aKeySystem,
+ _In_opt_ LPCWSTR aContentType) {
+ // For testing, return support for most of cases. Only returns false for some
+ // special cases.
+
+ bool needHDCP22OrAbove = isRequiringHDCP22OrAbove(aContentType);
+ ENTRY_LOG_ARGS("Need-HDCP2.2+=%d", needHDCP22OrAbove);
+
+ // As the API design of the Media Foundation, we can only know whether the
+ // requester is asking for HDCP 2.2+ or not, we can't know the exact HDCP
+ // version which is used in getStatusPolicy web api. Therefore, we pretend
+ // ourselves only having HDCP 2.1 compliant.
+ if (needHDCP22OrAbove) {
+ return false;
+ }
+ return true;
+}
+
+STDMETHODIMP
+WMFClearKeyCDMFactory::CreateContentDecryptionModuleAccess(
+ LPCWSTR aKeySystem, IPropertyStore** aConfigurations,
+ DWORD aNumConfigurations, IMFContentDecryptionModuleAccess** aCdmAccess) {
+ ENTRY_LOG();
+ if (aKeySystem == nullptr || aKeySystem[0] == L'\0') {
+ ENTRY_LOG_ARGS("Key system is null or empty");
+ return MF_TYPE_ERR;
+ }
+
+ if (aNumConfigurations == 0) {
+ ENTRY_LOG_ARGS("No available configration");
+ return MF_TYPE_ERR;
+ }
+
+ if (!IsTypeSupported(aKeySystem, nullptr)) {
+ ENTRY_LOG_ARGS("Not supported type");
+ return MF_NOT_SUPPORTED_ERR;
+ }
+
+ RETURN_IF_FAILED((
+ MakeAndInitialize<WMFClearKeyCDMAccess, IMFContentDecryptionModuleAccess>(
+ aCdmAccess)));
+ ENTRY_LOG_ARGS("Created CDM access!");
+ return S_OK;
+}
+
+#undef LOG
+
+} // namespace mozilla
diff --git a/media/wmf-clearkey/WMFClearKeyCDMFactory.h b/media/wmf-clearkey/WMFClearKeyCDMFactory.h
new file mode 100644
index 0000000000..af1fbd5db7
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKeyCDMFactory.h
@@ -0,0 +1,45 @@
+/* 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/. */
+
+#ifndef DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYCDMFACTORY_H
+#define DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYCDMFACTORY_H
+
+#include <mfidl.h>
+#include <windows.h>
+#include <wrl.h>
+
+#include "MFCDMExtra.h"
+
+namespace mozilla {
+
+// This class is used to return WMFClearKeyCDMAccess and answer what kind of key
+// system is supported.
+class WMFClearKeyCDMFactory final
+ : public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::WinRtClassicComMix>,
+ Microsoft::WRL::CloakedIid<IMFContentDecryptionModuleFactory>,
+ Microsoft::WRL::FtmBase> {
+ InspectableClass(L"org.w3.clearkey", BaseTrust);
+
+ public:
+ WMFClearKeyCDMFactory() = default;
+ ~WMFClearKeyCDMFactory() = default;
+ WMFClearKeyCDMFactory(const WMFClearKeyCDMFactory&) = delete;
+ WMFClearKeyCDMFactory& operator=(const WMFClearKeyCDMFactory&) = delete;
+
+ HRESULT RuntimeClassInitialize() { return S_OK; }
+
+ // IMFContentDecryptionModuleFactory
+ STDMETHODIMP_(BOOL)
+ IsTypeSupported(LPCWSTR aKeySystem, LPCWSTR aContentType) override;
+
+ STDMETHODIMP CreateContentDecryptionModuleAccess(
+ LPCWSTR aKeySystem, IPropertyStore** aConfigurations,
+ DWORD aNumConfigurations,
+ IMFContentDecryptionModuleAccess** aCdmAccess) override;
+};
+
+} // namespace mozilla
+
+#endif // DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYCDMFACTORY_H
diff --git a/media/wmf-clearkey/WMFClearKeyContentEnabler.cpp b/media/wmf-clearkey/WMFClearKeyContentEnabler.cpp
new file mode 100644
index 0000000000..a9aa230e11
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKeyContentEnabler.cpp
@@ -0,0 +1,65 @@
+/* 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 "WMFClearKeyContentEnabler.h"
+
+#include <mfapi.h>
+#include <mferror.h>
+
+#include "WMFClearKeyUtils.h"
+
+namespace mozilla {
+
+using Microsoft::WRL::ComPtr;
+
+HRESULT WMFClearKeyContentEnabler::RuntimeClassInitialize() { return S_OK; }
+
+STDMETHODIMP WMFClearKeyContentEnabler::AutomaticEnable() {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyContentEnabler::Cancel() {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyContentEnabler::GetEnableData(BYTE** aData,
+ DWORD* aDataSize) {
+ ENTRY_LOG();
+ // Does not support this method of content enabling with EME.
+ return MF_E_NOT_AVAILABLE;
+}
+
+STDMETHODIMP WMFClearKeyContentEnabler::GetEnableURL(
+ LPWSTR* aUrl, DWORD* aUrlSize, MF_URL_TRUST_STATUS* aTrustStatus) {
+ ENTRY_LOG();
+ // Does not support this method of content enabling with EME.
+ return MF_E_NOT_AVAILABLE;
+}
+
+STDMETHODIMP WMFClearKeyContentEnabler::IsAutomaticSupported(BOOL* aAutomatic) {
+ ENTRY_LOG();
+ if (!aAutomatic) {
+ return E_INVALIDARG;
+ }
+ *aAutomatic = FALSE;
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeyContentEnabler::MonitorEnable() {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyContentEnabler::GetEnableType(GUID* aType) {
+ LOG("WMFClearKeyContentEnabler::GetEnableType");
+ if (!aType) {
+ return E_INVALIDARG;
+ }
+ *aType = MEDIA_FOUNDATION_CLEARKEY_GUID_CONTENT_ENABLER_TYPE;
+ return S_OK;
+}
+
+} // namespace mozilla
diff --git a/media/wmf-clearkey/WMFClearKeyContentEnabler.h b/media/wmf-clearkey/WMFClearKeyContentEnabler.h
new file mode 100644
index 0000000000..ebaf5be7ad
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKeyContentEnabler.h
@@ -0,0 +1,42 @@
+/* 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/. */
+
+#ifndef DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYCONTENTENABLER_H
+#define DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYCONTENTENABLER_H
+
+#include <wrl.h>
+#include <wrl/client.h>
+
+#include "MFCDMExtra.h"
+
+namespace mozilla {
+
+// This class is used to return correct enable type.
+class WMFClearKeyContentEnabler
+ : public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
+ IMFContentEnabler, Microsoft::WRL::FtmBase> {
+ public:
+ WMFClearKeyContentEnabler() = default;
+ ~WMFClearKeyContentEnabler() = default;
+ WMFClearKeyContentEnabler(const WMFClearKeyContentEnabler&) = delete;
+ WMFClearKeyContentEnabler& operator=(const WMFClearKeyContentEnabler&) =
+ delete;
+
+ HRESULT RuntimeClassInitialize();
+
+ // IMFContentEnabler
+ STDMETHODIMP AutomaticEnable() override;
+ STDMETHODIMP Cancel() override;
+ STDMETHODIMP GetEnableData(BYTE** aData, DWORD* aDataSize) override;
+ STDMETHODIMP GetEnableType(GUID* aType) override;
+ STDMETHODIMP GetEnableURL(LPWSTR* aUrl, DWORD* aUrlSize,
+ MF_URL_TRUST_STATUS* aTrustStatus) override;
+ STDMETHODIMP IsAutomaticSupported(BOOL* automatic) override;
+ STDMETHODIMP MonitorEnable() override;
+};
+
+} // namespace mozilla
+
+#endif // DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYCONTENTENABLER_H
diff --git a/media/wmf-clearkey/WMFClearKeyInputTrustAuthority.cpp b/media/wmf-clearkey/WMFClearKeyInputTrustAuthority.cpp
new file mode 100644
index 0000000000..3943c03e4d
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKeyInputTrustAuthority.cpp
@@ -0,0 +1,115 @@
+/* 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 "WMFClearKeyInputTrustAuthority.h"
+
+#include <mfapi.h>
+#include <mferror.h>
+
+#include "WMFClearKeyActivate.h"
+#include "WMFClearKeyCDM.h"
+// #include "WMFClearKeyDecryptor.h"
+#include "WMFClearKeyUtils.h"
+#include "WMFClearKeyOutputPolicy.h"
+
+namespace mozilla {
+
+using Microsoft::WRL::ComPtr;
+using Microsoft::WRL::MakeAndInitialize;
+
+HRESULT WMFClearKeyInputTrustAuthority::RuntimeClassInitialize(
+ UINT32 aStreamId, SessionManagerWrapper* aSessionManager) {
+ ENTRY_LOG();
+ mSessionManager = aSessionManager;
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeyInputTrustAuthority::GetDecrypter(REFIID aRiid,
+ void** aPpv) {
+ ENTRY_LOG();
+ ComPtr<IMFTransform> decryptor;
+ // TODO : As currently we are still not able to make decryption working in the
+ // media foundation pipeline, we will finish the implementation for
+ // WMFClearKeyDecryptor later.
+ // RETURN_IF_FAILED((MakeAndInitialize<WMFClearKeyDecryptor, IMFTransform>(
+ // &decryptor, mSessionManager)));
+ RETURN_IF_FAILED(decryptor.CopyTo(aRiid, aPpv));
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeyInputTrustAuthority::RequestAccess(
+ MFPOLICYMANAGER_ACTION aAction, IMFActivate** aContentEnablerActivate) {
+ ENTRY_LOG_ARGS("aAction=%d", aAction);
+ // The ITA only allows the PLAY, EXTRACT and NO actions
+ // NOTE: Topology created only on the basis of EXTRACT or NO action will NOT
+ // decrypt content.
+ if (PEACTION_EXTRACT == aAction || PEACTION_NO == aAction) {
+ return S_OK;
+ }
+ if (PEACTION_PLAY != aAction) {
+ ENTRY_LOG_ARGS("Unsupported action");
+ return MF_E_ITA_UNSUPPORTED_ACTION;
+ }
+ ComPtr<IMFActivate> activate;
+ RETURN_IF_FAILED(MakeAndInitialize<WMFClearKeyActivate>(&activate));
+ *aContentEnablerActivate = activate.Detach();
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeyInputTrustAuthority::GetPolicy(
+ MFPOLICYMANAGER_ACTION aAction, IMFOutputPolicy** aPolicy) {
+ ENTRY_LOG();
+ // For testing purpose, we don't need to set the output policy/
+ *aPolicy = nullptr;
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeyInputTrustAuthority::BindAccess(
+ MFINPUTTRUSTAUTHORITY_ACCESS_PARAMS* aParams) {
+ ENTRY_LOG();
+ if (aParams == nullptr || aParams->dwVer != 0) {
+ return E_INVALIDARG;
+ }
+ for (DWORD i = 0; i < aParams->cActions; ++i) {
+ MFPOLICYMANAGER_ACTION action = aParams->rgOutputActions[i].Action;
+ if (action != PEACTION_PLAY && action != PEACTION_EXTRACT &&
+ action != PEACTION_NO) {
+ ENTRY_LOG_ARGS("Unexpected action!");
+ return MF_E_UNEXPECTED;
+ }
+ }
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeyInputTrustAuthority::UpdateAccess(
+ MFINPUTTRUSTAUTHORITY_ACCESS_PARAMS* aParams) {
+ ENTRY_LOG();
+ return BindAccess(aParams);
+}
+
+STDMETHODIMP WMFClearKeyInputTrustAuthority::Reset() {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyInputTrustAuthority::GetShutdownStatus(
+ MFSHUTDOWN_STATUS* aStatus) {
+ ENTRY_LOG();
+ // https://learn.microsoft.com/en-us/windows/win32/api/mfidl/nf-mfidl-imfshutdown-getshutdownstatus#return-value
+ if (mSessionManager->IsShutdown()) {
+ return MF_E_INVALIDREQUEST;
+ }
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeyInputTrustAuthority::Shutdown() {
+ ENTRY_LOG();
+ if (mSessionManager->IsShutdown()) {
+ return MF_E_SHUTDOWN;
+ }
+ mSessionManager->Shutdown();
+ return S_OK;
+}
+
+} // namespace mozilla
diff --git a/media/wmf-clearkey/WMFClearKeyInputTrustAuthority.h b/media/wmf-clearkey/WMFClearKeyInputTrustAuthority.h
new file mode 100644
index 0000000000..9eb2beea87
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKeyInputTrustAuthority.h
@@ -0,0 +1,56 @@
+/* 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/. */
+
+#ifndef DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYINPUTTRUSTAUTHORITY_H
+#define DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYINPUTTRUSTAUTHORITY_H
+
+#include <wrl.h>
+#include <wrl/client.h>
+
+#include "MFCDMExtra.h"
+#include "RefCounted.h"
+
+namespace mozilla {
+
+class SessionManagerWrapper;
+
+// This class is used to provide WMFClearKeyActivate and WMFClearKeyDecryptor.
+class WMFClearKeyInputTrustAuthority final
+ : public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
+ IMFInputTrustAuthority, IMFShutdown, Microsoft::WRL::FtmBase> {
+ public:
+ WMFClearKeyInputTrustAuthority() = default;
+ ~WMFClearKeyInputTrustAuthority() = default;
+ WMFClearKeyInputTrustAuthority(const WMFClearKeyInputTrustAuthority&) =
+ delete;
+ WMFClearKeyInputTrustAuthority& operator=(
+ const WMFClearKeyInputTrustAuthority&) = delete;
+
+ HRESULT RuntimeClassInitialize(UINT32 aStreamId,
+ SessionManagerWrapper* aSessionManager);
+
+ // IMFInputTrustAuthority
+ STDMETHODIMP GetDecrypter(REFIID aRiid, void** aPpv) override;
+ STDMETHODIMP RequestAccess(MFPOLICYMANAGER_ACTION aAction,
+ IMFActivate** aContentEnablerActivate) override;
+ STDMETHODIMP GetPolicy(MFPOLICYMANAGER_ACTION aAction,
+ IMFOutputPolicy** aPolicy) override;
+ STDMETHODIMP BindAccess(
+ MFINPUTTRUSTAUTHORITY_ACCESS_PARAMS* aParams) override;
+ STDMETHODIMP UpdateAccess(
+ MFINPUTTRUSTAUTHORITY_ACCESS_PARAMS* aParams) override;
+ STDMETHODIMP Reset() override;
+
+ // IMFShutdown
+ STDMETHODIMP GetShutdownStatus(MFSHUTDOWN_STATUS* aStatus) override;
+ STDMETHODIMP Shutdown() override;
+
+ private:
+ RefPtr<SessionManagerWrapper> mSessionManager;
+};
+
+} // namespace mozilla
+
+#endif // DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYINPUTTRUSTAUTHORITY_H
diff --git a/media/wmf-clearkey/WMFClearKeyOutputPolicy.cpp b/media/wmf-clearkey/WMFClearKeyOutputPolicy.cpp
new file mode 100644
index 0000000000..b992d931dd
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKeyOutputPolicy.cpp
@@ -0,0 +1,203 @@
+/* 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 "WMFClearKeyOutputPolicy.h"
+
+#include <mfapi.h>
+#include <mferror.h>
+
+#include "WMFClearKeyUtils.h"
+
+namespace mozilla {
+
+using Microsoft::WRL::ComPtr;
+using Microsoft::WRL::MakeAndInitialize;
+
+HRESULT WMFClearKeyOutputPolicy::RuntimeClassInitialize(
+ MFPOLICYMANAGER_ACTION aAction) {
+ ENTRY_LOG_ARGS("aAction=%d", aAction);
+ if (aAction != PEACTION_PLAY && aAction != PEACTION_EXTRACT &&
+ aAction != PEACTION_NO) {
+ return MF_E_UNEXPECTED;
+ }
+ return S_OK;
+}
+
+// IMFOutputPolicy
+STDMETHODIMP WMFClearKeyOutputPolicy::GenerateRequiredSchemas(
+ DWORD aAttributes, GUID aGuidOutputSubtype,
+ GUID* aGuidProtectionSchemasSupported,
+ DWORD aProtectionSchemasSupportedCount,
+ IMFCollection** aRequiredProtectionSchemas) {
+ ENTRY_LOG();
+ // We don't require an OTA (output trust authority) to enforce for testing.
+ // However, we still need to return an empty collection on success.
+ ComPtr<IMFCollection> collection;
+ RETURN_IF_FAILED(MFCreateCollection(&collection));
+ *aRequiredProtectionSchemas = collection.Detach();
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::GetOriginatorID(GUID* aGuidOriginatorId) {
+ ENTRY_LOG();
+ *aGuidOriginatorId = GUID_NULL;
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::GetMinimumGRLVersion(
+ DWORD* aMinimumGrlVersion) {
+ ENTRY_LOG();
+ *aMinimumGrlVersion = 0;
+ return S_OK;
+}
+
+// IMFAttributes inherited by IMFOutputPolicy
+STDMETHODIMP WMFClearKeyOutputPolicy::GetItem(REFGUID aGuidKey,
+ PROPVARIANT* aValue) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::GetItemType(REFGUID aGuidKey,
+ MF_ATTRIBUTE_TYPE* aType) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::CompareItem(REFGUID aGuidKey,
+ REFPROPVARIANT aValue,
+ BOOL* aResult) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::Compare(IMFAttributes* aAttributes,
+ MF_ATTRIBUTES_MATCH_TYPE aType,
+ BOOL* aResult) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::GetUINT32(REFGUID aGuidKey,
+ UINT32* aValue) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::GetUINT64(REFGUID aGuidKey,
+ UINT64* aValue) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::GetDouble(REFGUID aGuidKey,
+ double* aValue) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::GetGUID(REFGUID aGuidKey,
+ GUID* aGuidValue) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::GetStringLength(REFGUID aGuidKey,
+ UINT32* aPcchLength) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::GetString(REFGUID aGuidKey,
+ LPWSTR aPwszValue,
+ UINT32 aCchBufSize,
+ UINT32* aPcchLength) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::GetAllocatedString(REFGUID aGuidKey,
+ LPWSTR* aPpwszValue,
+ UINT32* aPcchLength) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::GetBlobSize(REFGUID aGuidKey,
+ UINT32* aPcbBlobSize) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::GetBlob(REFGUID aGuidKey, UINT8* pBuf,
+ UINT32 aCbBufSize,
+ UINT32* aPcbBlobSize) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::GetAllocatedBlob(REFGUID aGuidKey,
+ UINT8** aBuf,
+ UINT32* aPcbSize) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::GetUnknown(REFGUID aGuidKey, REFIID aRiid,
+ LPVOID* aPpv) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::SetItem(REFGUID aGuidKey,
+ REFPROPVARIANT aValue) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::DeleteItem(REFGUID aGuidKey) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::DeleteAllItems() { return E_NOTIMPL; }
+
+STDMETHODIMP WMFClearKeyOutputPolicy::SetUINT32(REFGUID aGuidKey,
+ UINT32 aValue) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::SetUINT64(REFGUID aGuidKey,
+ UINT64 aValue) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::SetDouble(REFGUID aGuidKey,
+ double aValue) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::SetGUID(REFGUID aGuidKey,
+ REFGUID aGuidValue) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::SetString(REFGUID aGuidKey,
+ LPCWSTR aWszValue) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::SetBlob(REFGUID aGuidKey,
+ const UINT8* aBuf,
+ UINT32 aCbBufSize) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::SetUnknown(REFGUID aGuidKey,
+ IUnknown* aUnknown) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::LockStore() { return E_NOTIMPL; }
+
+STDMETHODIMP WMFClearKeyOutputPolicy::UnlockStore() { return E_NOTIMPL; }
+
+STDMETHODIMP WMFClearKeyOutputPolicy::GetCount(UINT32* aPcItems) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::GetItemByIndex(UINT32 aIndex,
+ GUID* aGuidKey,
+ PROPVARIANT* aValue) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFClearKeyOutputPolicy::CopyAllItems(IMFAttributes* aDest) {
+ return E_NOTIMPL;
+}
+
+} // namespace mozilla
diff --git a/media/wmf-clearkey/WMFClearKeyOutputPolicy.h b/media/wmf-clearkey/WMFClearKeyOutputPolicy.h
new file mode 100644
index 0000000000..b53f77a88d
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKeyOutputPolicy.h
@@ -0,0 +1,81 @@
+/* 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/. */
+
+#ifndef DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYOUTPUTPOLICY_H
+#define DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYOUTPUTPOLICY_H
+
+#include <wrl.h>
+#include <wrl/client.h>
+
+#include "MFCDMExtra.h"
+
+namespace mozilla {
+
+// This class is used to return output protection scheme.
+class WMFClearKeyOutputPolicy final
+ : public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
+ IMFOutputPolicy, Microsoft::WRL::FtmBase> {
+ public:
+ WMFClearKeyOutputPolicy() = default;
+ ~WMFClearKeyOutputPolicy() = default;
+ WMFClearKeyOutputPolicy(const WMFClearKeyOutputPolicy&) = delete;
+ WMFClearKeyOutputPolicy& operator=(const WMFClearKeyOutputPolicy&) = delete;
+
+ HRESULT RuntimeClassInitialize(MFPOLICYMANAGER_ACTION aAction);
+
+ // IMFOutputPolicy
+ STDMETHODIMP GenerateRequiredSchemas(
+ DWORD aAttributes, GUID aGuidOutputSubtype,
+ GUID* aGuidProtectionSchemasSupported,
+ DWORD aProtectionSchemasSupportedCount,
+ IMFCollection** aRequiredProtectionSchemas) override;
+ STDMETHODIMP GetOriginatorID(_Out_ GUID* aGuidOriginatorId) override;
+ STDMETHODIMP GetMinimumGRLVersion(_Out_ DWORD* aMinimumGrlVersion) override;
+
+ // IMFAttributes inherited by IMFOutputPolicy
+ STDMETHODIMP GetItem(REFGUID aGuidKey, PROPVARIANT* aValue) override;
+ STDMETHODIMP GetItemType(REFGUID aGuidKey, MF_ATTRIBUTE_TYPE* aType) override;
+ STDMETHODIMP CompareItem(REFGUID aGuidKey, REFPROPVARIANT aValue,
+ BOOL* aResult) override;
+ STDMETHODIMP Compare(IMFAttributes* aAttributes,
+ MF_ATTRIBUTES_MATCH_TYPE aType, BOOL* aResult) override;
+ STDMETHODIMP GetUINT32(REFGUID aGuidKey, UINT32* aValue) override;
+ STDMETHODIMP GetUINT64(REFGUID aGuidKey, UINT64* aValue) override;
+ STDMETHODIMP GetDouble(REFGUID aGuidKey, double* aValue) override;
+ STDMETHODIMP GetGUID(REFGUID aGuidKey, GUID* aGuidValue) override;
+ STDMETHODIMP GetStringLength(REFGUID aGuidKey, UINT32* aPcchLength) override;
+ STDMETHODIMP GetString(REFGUID aGuidKey, LPWSTR aPwszValue,
+ UINT32 aCchBufSize, UINT32* aPcchLength) override;
+ STDMETHODIMP GetAllocatedString(REFGUID aGuidKey, LPWSTR* aPpwszValue,
+ UINT32* aPcchLength) override;
+ STDMETHODIMP GetBlobSize(REFGUID aGuidKey, UINT32* aPcbBlobSize) override;
+ STDMETHODIMP GetBlob(REFGUID aGuidKey, UINT8* aBuf, UINT32 aCbBufSize,
+ UINT32* aPcbBlobSize) override;
+ STDMETHODIMP GetAllocatedBlob(REFGUID aGuidKey, UINT8** aBuf,
+ UINT32* aPcbSize) override;
+ STDMETHODIMP GetUnknown(REFGUID aGuidKey, REFIID aRiid,
+ LPVOID* aPpv) override;
+ STDMETHODIMP SetItem(REFGUID aGuidKey, REFPROPVARIANT aValue) override;
+ STDMETHODIMP DeleteItem(REFGUID aGuidKey) override;
+ STDMETHODIMP DeleteAllItems() override;
+ STDMETHODIMP SetUINT32(REFGUID aGuidKey, UINT32 aValue) override;
+ STDMETHODIMP SetUINT64(REFGUID aGuidKey, UINT64 aValue) override;
+ STDMETHODIMP SetDouble(REFGUID aGuidKey, double aValue) override;
+ STDMETHODIMP SetGUID(REFGUID aGuidKey, REFGUID aGuidValue) override;
+ STDMETHODIMP SetString(REFGUID aGuidKey, LPCWSTR aWszValue) override;
+ STDMETHODIMP SetBlob(REFGUID aGuidKey, const UINT8* aBuf,
+ UINT32 aCbBufSize) override;
+ STDMETHODIMP SetUnknown(REFGUID aGuidKey, IUnknown* aUnknown) override;
+ STDMETHODIMP LockStore() override;
+ STDMETHODIMP UnlockStore() override;
+ STDMETHODIMP GetCount(UINT32* aPcItems) override;
+ STDMETHODIMP GetItemByIndex(UINT32 aIndex, GUID* aGuidKey,
+ PROPVARIANT* aValue) override;
+ STDMETHODIMP CopyAllItems(IMFAttributes* aDest) override;
+};
+
+} // namespace mozilla
+
+#endif // DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYOUTPUTPOLICY_H
diff --git a/media/wmf-clearkey/WMFClearKeySession.cpp b/media/wmf-clearkey/WMFClearKeySession.cpp
new file mode 100644
index 0000000000..077665a8ae
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKeySession.cpp
@@ -0,0 +1,233 @@
+/* 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 "WMFClearKeySession.h"
+
+#include <codecvt>
+#include <cmath>
+#include <Mferror.h>
+#include <winerror.h>
+
+#include "WMFClearKeyCDM.h"
+#include "WMFClearKeyUtils.h"
+
+namespace mozilla {
+
+using Microsoft::WRL::ComPtr;
+
+static cdm::SessionType ToCdmSessionType(MF_MEDIAKEYSESSION_TYPE aSessionType) {
+ switch (aSessionType) {
+ case MF_MEDIAKEYSESSION_TYPE_TEMPORARY:
+ return cdm::SessionType::kTemporary;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Only support temporary type for testing");
+ return cdm::SessionType::kTemporary;
+ }
+}
+
+static MF_MEDIAKEY_STATUS ToMFKeyStatus(cdm::KeyStatus aStatus) {
+ switch (aStatus) {
+ case cdm::KeyStatus::kUsable:
+ return MF_MEDIAKEY_STATUS_USABLE;
+ case cdm::KeyStatus::kExpired:
+ return MF_MEDIAKEY_STATUS_EXPIRED;
+ case cdm::KeyStatus::kOutputDownscaled:
+ return MF_MEDIAKEY_STATUS_OUTPUT_DOWNSCALED;
+ case cdm::KeyStatus::kStatusPending:
+ return MF_MEDIAKEY_STATUS_STATUS_PENDING;
+ case cdm::KeyStatus::kInternalError:
+ return MF_MEDIAKEY_STATUS_INTERNAL_ERROR;
+ case cdm::KeyStatus::kReleased:
+ return MF_MEDIAKEY_STATUS_RELEASED;
+ case cdm::KeyStatus::kOutputRestricted:
+ return MF_MEDIAKEY_STATUS_OUTPUT_RESTRICTED;
+ }
+}
+
+HRESULT WMFClearKeySession::RuntimeClassInitialize(
+ MF_MEDIAKEYSESSION_TYPE aSessionType,
+ IMFContentDecryptionModuleSessionCallbacks* aCallbacks,
+ SessionManagerWrapper* aManager) {
+ ENTRY_LOG();
+ MOZ_ASSERT(aCallbacks);
+ MOZ_ASSERT(aManager);
+ mSessionType = ToCdmSessionType(aSessionType);
+ mCallbacks = aCallbacks;
+ mSessionManager = aManager;
+ return S_OK;
+}
+
+WMFClearKeySession::~WMFClearKeySession() { ENTRY_LOG(); }
+
+STDMETHODIMP WMFClearKeySession::GenerateRequest(LPCWSTR aInitDataType,
+ const BYTE* aInitData,
+ DWORD aInitDataSize) {
+ if (!mSessionManager) {
+ return MF_E_SHUTDOWN;
+ }
+ ENTRY_LOG_ARGS("init-type=%ls", aInitDataType);
+ cdm::InitDataType initType;
+ if (wcscmp(aInitDataType, L"cenc") == 0) {
+ initType = cdm::InitDataType::kCenc;
+ } else if (wcscmp(aInitDataType, L"keyids") == 0) {
+ initType = cdm::InitDataType::kKeyIds;
+ } else if (wcscmp(aInitDataType, L"webm") == 0) {
+ initType = cdm::InitDataType::kWebM;
+ } else {
+ return MF_NOT_SUPPORTED_ERR;
+ }
+ RETURN_IF_FAILED(mSessionManager->GenerateRequest(
+ initType, aInitData, aInitDataSize, mSessionType, this, mSessionId));
+ MOZ_ASSERT(!mSessionId.empty());
+ ENTRY_LOG_ARGS("created session, sid=%s", mSessionId.c_str());
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeySession::Load(LPCWSTR session_id, BOOL* loaded) {
+ ENTRY_LOG();
+ // Per step 5, Load can only be called on persistent session, but we only
+ // support temporary session for MF clearkey due to testing reason.
+ // https://rawgit.com/w3c/encrypted-media/V1/index.html#dom-mediakeysession-load
+ return MF_E_NOT_AVAILABLE;
+}
+
+STDMETHODIMP WMFClearKeySession::Update(const BYTE* aResponse,
+ DWORD aResponseSize) {
+ ENTRY_LOG();
+ if (!mSessionManager) {
+ return MF_E_SHUTDOWN;
+ }
+ RETURN_IF_FAILED(
+ mSessionManager->UpdateSession(mSessionId, aResponse, aResponseSize));
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeySession::Close() {
+ ENTRY_LOG();
+ // It has been shutdowned and sesssion has been closed.
+ if (!mSessionManager) {
+ return S_OK;
+ }
+ RETURN_IF_FAILED(mSessionManager->CloseSession(mSessionId));
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeySession::Remove() {
+ ENTRY_LOG();
+ // It has been shutdowned and sesssion has been removed.
+ if (!mSessionManager) {
+ return S_OK;
+ }
+ RETURN_IF_FAILED(mSessionManager->RemoveSession(mSessionId));
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeySession::GetSessionId(LPWSTR* aSessionId) {
+ ENTRY_LOG();
+ if (!mSessionManager) {
+ return S_OK;
+ }
+ if (mSessionId.empty()) {
+ *aSessionId = (LPWSTR)CoTaskMemAlloc(sizeof(wchar_t));
+ if (*aSessionId != NULL) {
+ **aSessionId = L'\0';
+ return S_OK;
+ } else {
+ return E_OUTOFMEMORY;
+ }
+ }
+
+ std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
+ std::wstring wideStr = converter.from_bytes(mSessionId);
+ *aSessionId =
+ (LPWSTR)CoTaskMemAlloc((wideStr.length() + 1) * sizeof(wchar_t));
+ if (*aSessionId != NULL) {
+ wcscpy_s(*aSessionId, wideStr.length() + 1, wideStr.c_str());
+ return S_OK;
+ } else {
+ return E_OUTOFMEMORY;
+ }
+}
+
+STDMETHODIMP WMFClearKeySession::GetExpiration(double* expiration) {
+ ENTRY_LOG();
+ // This is used for testing, never expires.
+ *expiration = std::nan("1");
+ return S_OK;
+}
+
+STDMETHODIMP WMFClearKeySession::GetKeyStatuses(MFMediaKeyStatus** aKeyStatuses,
+ UINT* aKeyStatusesCount) {
+ ENTRY_LOG();
+ *aKeyStatuses = nullptr;
+ *aKeyStatusesCount = 0;
+
+ const auto keyStatusCount = mKeyInfo.size();
+ if (mSessionId.empty() || keyStatusCount == 0) {
+ ENTRY_LOG_ARGS("No session ID or no key info!");
+ return S_OK;
+ }
+
+ MFMediaKeyStatus* keyStatusArray = nullptr;
+ keyStatusArray = static_cast<MFMediaKeyStatus*>(
+ CoTaskMemAlloc(keyStatusCount * sizeof(MFMediaKeyStatus)));
+ if (!keyStatusArray) {
+ ENTRY_LOG_ARGS("OOM when alloacting keyStatusArray!");
+ return E_OUTOFMEMORY;
+ }
+ ZeroMemory(keyStatusArray, keyStatusCount * sizeof(MFMediaKeyStatus));
+ for (UINT idx = 0; idx < keyStatusCount; idx++) {
+ keyStatusArray[idx].cbKeyId = mKeyInfo[idx].mKeyId.size();
+ keyStatusArray[idx].pbKeyId =
+ static_cast<BYTE*>(CoTaskMemAlloc(sizeof(mKeyInfo[idx].mKeyId.size())));
+ if (keyStatusArray[idx].pbKeyId == nullptr) {
+ ENTRY_LOG_ARGS("OOM when alloacting keyStatusArray's pbKeyId!");
+ return E_OUTOFMEMORY;
+ }
+
+ keyStatusArray[idx].eMediaKeyStatus =
+ ToMFKeyStatus(mKeyInfo[idx].mKeyStatus);
+ memcpy(keyStatusArray[idx].pbKeyId, mKeyInfo[idx].mKeyId.data(),
+ mKeyInfo[idx].mKeyId.size());
+ }
+
+ *aKeyStatuses = keyStatusArray;
+ *aKeyStatusesCount = keyStatusCount;
+ ENTRY_LOG_ARGS("return key status!");
+ return S_OK;
+}
+
+void WMFClearKeySession::OnKeyMessage(
+ MF_MEDIAKEYSESSION_MESSAGETYPE aMessageType, const BYTE* aMessage,
+ DWORD aMessageSize) {
+ ENTRY_LOG_ARGS("aMessageSize=%lu", aMessageSize);
+ if (!mSessionManager) {
+ return;
+ }
+ mCallbacks->KeyMessage(aMessageType, aMessage, aMessageSize, nullptr);
+}
+
+void WMFClearKeySession::OnKeyStatusChanged(
+ const cdm::KeyInformation* aKeysInfo, uint32_t aKeysInfoCount) {
+ ENTRY_LOG_ARGS("aKeysInfoCount=%u", aKeysInfoCount);
+ if (!mSessionManager) {
+ return;
+ }
+ mKeyInfo.clear();
+ for (uint32_t idx = 0; idx < aKeysInfoCount; idx++) {
+ const cdm::KeyInformation& key = aKeysInfo[idx];
+ mKeyInfo.push_back(KeyInformation{key.key_id, key.key_id_size, key.status});
+ ENTRY_LOG_ARGS("idx=%u, keySize=%u, status=%u", idx, key.key_id_size,
+ key.status);
+ }
+ mCallbacks->KeyStatusChanged();
+}
+
+void WMFClearKeySession::Shutdown() {
+ ENTRY_LOG();
+ mCallbacks = nullptr;
+ mSessionManager = nullptr;
+}
+
+} // namespace mozilla
diff --git a/media/wmf-clearkey/WMFClearKeySession.h b/media/wmf-clearkey/WMFClearKeySession.h
new file mode 100644
index 0000000000..d2032cccef
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKeySession.h
@@ -0,0 +1,78 @@
+/* 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/. */
+
+#ifndef DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYSESSION_H
+#define DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYSESSION_H
+
+#include <mfidl.h>
+#include <windows.h>
+#include <wrl.h>
+
+#include "content_decryption_module.h"
+#include "MFCDMExtra.h"
+#include "RefCounted.h"
+#include "WMFClearKeyUtils.h"
+
+namespace mozilla {
+
+class SessionManagerWrapper;
+
+// This is the implementation for EME API's MediaKeySession.
+// TODO : add a way to assert thread usage. It would only be used on the media
+// supervisor thread pool.
+class WMFClearKeySession final
+ : public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
+ IMFContentDecryptionModuleSession, Microsoft::WRL::FtmBase> {
+ public:
+ WMFClearKeySession() = default;
+ ~WMFClearKeySession();
+ WMFClearKeySession(const WMFClearKeySession&) = delete;
+ WMFClearKeySession& operator=(const WMFClearKeySession&) = delete;
+
+ HRESULT RuntimeClassInitialize(
+ MF_MEDIAKEYSESSION_TYPE aSessionType,
+ IMFContentDecryptionModuleSessionCallbacks* aCallbacks,
+ SessionManagerWrapper* aManager);
+
+ void Shutdown();
+
+ // IMFContentDecryptionModuleSession
+ STDMETHODIMP GenerateRequest(LPCWSTR init_data_type,
+
+ const BYTE* init_data,
+ DWORD init_data_size) override;
+ STDMETHODIMP Load(LPCWSTR session_id, BOOL* loaded) override;
+ STDMETHODIMP Update(const BYTE* aResponse, DWORD aResponseSize) override;
+ STDMETHODIMP Close() override;
+ STDMETHODIMP Remove() override;
+ STDMETHODIMP GetSessionId(LPWSTR* aSessionId) override;
+ STDMETHODIMP GetExpiration(double* aExpiration) override;
+ STDMETHODIMP GetKeyStatuses(MFMediaKeyStatus** aKeyStatuses,
+ UINT* aKeyStatusesCount) override;
+
+ void OnKeyMessage(MF_MEDIAKEYSESSION_MESSAGETYPE aMessageType,
+ const BYTE* aMessage, DWORD aMessageSize);
+ void OnKeyStatusChanged(const cdm::KeyInformation* aKeysInfo,
+ uint32_t aKeysInfoCount);
+
+ private:
+ cdm::SessionType mSessionType;
+ std::string mSessionId;
+ Microsoft::WRL::ComPtr<IMFContentDecryptionModuleSessionCallbacks> mCallbacks;
+ RefPtr<SessionManagerWrapper> mSessionManager;
+
+ struct KeyInformation {
+ KeyInformation(const uint8_t* aKeyId, uint32_t aKeyIdSize,
+ cdm::KeyStatus aKeyStatus)
+ : mKeyId(aKeyId, aKeyId + aKeyIdSize), mKeyStatus(aKeyStatus) {}
+ std::vector<uint8_t> mKeyId;
+ cdm::KeyStatus mKeyStatus;
+ };
+ std::vector<KeyInformation> mKeyInfo;
+};
+
+} // namespace mozilla
+
+#endif // DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYSESSION_H
diff --git a/media/wmf-clearkey/WMFClearKeyTrustedInput.cpp b/media/wmf-clearkey/WMFClearKeyTrustedInput.cpp
new file mode 100644
index 0000000000..37ce108886
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKeyTrustedInput.cpp
@@ -0,0 +1,35 @@
+/* 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 "WMFClearKeyTrustedInput.h"
+
+#include "WMFClearKeyCDM.h"
+#include "WMFClearKeyInputTrustAuthority.h"
+#include "WMFClearKeyUtils.h"
+
+namespace mozilla {
+
+using Microsoft::WRL::ComPtr;
+using Microsoft::WRL::MakeAndInitialize;
+
+HRESULT WMFClearKeyTrustedInput::RuntimeClassInitialize(
+ SessionManagerWrapper* aSessionManager) {
+ ENTRY_LOG();
+ mSessionManager = aSessionManager;
+ return S_OK;
+}
+
+// IMFTrustedInput
+STDMETHODIMP WMFClearKeyTrustedInput::GetInputTrustAuthority(
+ DWORD aStreamId, REFIID aRiid, IUnknown** aAuthority) {
+ ENTRY_LOG();
+ ComPtr<IMFInputTrustAuthority> ita;
+ RETURN_IF_FAILED((
+ MakeAndInitialize<WMFClearKeyInputTrustAuthority, IMFInputTrustAuthority>(
+ &ita, aStreamId, mSessionManager)));
+ *aAuthority = ita.Detach();
+ return S_OK;
+}
+
+} // namespace mozilla
diff --git a/media/wmf-clearkey/WMFClearKeyTrustedInput.h b/media/wmf-clearkey/WMFClearKeyTrustedInput.h
new file mode 100644
index 0000000000..b89c64f5c9
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKeyTrustedInput.h
@@ -0,0 +1,41 @@
+/* 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/. */
+
+#ifndef DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYTRUSTEDINPUT_H
+#define DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYTRUSTEDINPUT_H
+
+#include <wrl.h>
+#include <wrl/client.h>
+
+#include "MFCDMExtra.h"
+#include "RefCounted.h"
+
+namespace mozilla {
+
+class SessionManagerWrapper;
+
+// This class is used to provide WMFClearKeyInputTrustAuthority.
+class WMFClearKeyTrustedInput final
+ : public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::WinRtClassicComMix>,
+ IMFTrustedInput, Microsoft::WRL::FtmBase> {
+ public:
+ WMFClearKeyTrustedInput() = default;
+ ~WMFClearKeyTrustedInput() = default;
+ WMFClearKeyTrustedInput(const WMFClearKeyTrustedInput&) = delete;
+ WMFClearKeyTrustedInput& operator=(const WMFClearKeyTrustedInput&) = delete;
+
+ HRESULT RuntimeClassInitialize(SessionManagerWrapper* aSessionManager);
+
+ // IMFTrustedInput
+ STDMETHODIMP GetInputTrustAuthority(DWORD aStreamId, REFIID aRiid,
+ IUnknown** aAuthority) override;
+
+ private:
+ RefPtr<SessionManagerWrapper> mSessionManager;
+};
+
+} // namespace mozilla
+
+#endif // DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYTRUSTEDINPUT_H
diff --git a/media/wmf-clearkey/WMFClearKeyUtils.h b/media/wmf-clearkey/WMFClearKeyUtils.h
new file mode 100644
index 0000000000..e834e6cb9a
--- /dev/null
+++ b/media/wmf-clearkey/WMFClearKeyUtils.h
@@ -0,0 +1,229 @@
+/* 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/. */
+
+#ifndef DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYCDMUTILS_H
+#define DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYCDMUTILS_H
+
+#include <initguid.h>
+#include <memory>
+#include <mfidl.h>
+#include <mutex>
+#include <thread>
+#include <windows.h>
+#include <wrl.h>
+#include <sstream>
+#include <stdio.h>
+
+#include "MFCDMExtra.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Unused.h"
+
+namespace mozilla {
+
+inline constexpr WCHAR kCLEARKEY_SYSTEM_NAME[] = L"org.w3.clearkey";
+
+#define WMF_CLEARKEY_DEBUG 0
+
+#ifdef WMF_CLEARKEY_DEBUG
+# define LOG(msg, ...) \
+ printf(("[Thread %lu]: D/WMFClearKey " msg "\n"), \
+ static_cast<unsigned long>( \
+ std::hash<std::thread::id>{}(std::this_thread::get_id())), \
+ ##__VA_ARGS__)
+#else
+# define LOG(msg, ...)
+#endif
+
+#define PRETTY_FUNC \
+ ([&]() -> std::string { \
+ std::string prettyFunction(__PRETTY_FUNCTION__); \
+ std::size_t pos1 = prettyFunction.find("::"); \
+ std::size_t pos2 = prettyFunction.find("(", pos1); \
+ return prettyFunction.substr(0, pos2); \
+ })() \
+ .c_str()
+
+// We can't reuse the definition in the `MediaEngineUtils.h` due to the
+// restriction of not being able to use XPCOM string in the external library.
+#ifndef RETURN_IF_FAILED
+# define RETURN_IF_FAILED(x) \
+ do { \
+ HRESULT rv = x; \
+ if (FAILED(rv)) { \
+ LOG("(" #x ") failed, rv=%lx", rv); \
+ return rv; \
+ } \
+ } while (false)
+#endif
+
+#ifndef NOT_IMPLEMENTED
+# define NOT_IMPLEMENTED() \
+ do { \
+ LOG("WARNING : '%s' NOT IMPLEMENTED!", PRETTY_FUNC); \
+ } while (0)
+#endif
+
+#ifndef ENTRY_LOG
+# define ENTRY_LOG(...) \
+ do { \
+ LOG("%s [%p]", PRETTY_FUNC, this); \
+ } while (0)
+# define ENTRY_LOG_ARGS(fmt, ...) \
+ do { \
+ LOG("%s [%p]: " fmt, PRETTY_FUNC, this, ##__VA_ARGS__); \
+ (void)(0, ##__VA_ARGS__); \
+ } while (0)
+#endif
+
+// TODO : should we use Microsoft's definition or Chromium's defintion?
+
+// This is defined in Microsoft's sample code
+// https://github.com/microsoft/media-foundation/blob/dc81175a3e893c7c58fcbf1a943ac342e39f172c/samples/storecdm/clearkeyStoreCDM/clearkeydll/guids.h#L17-L18C14
+// DEFINE_GUID(CLEARKEY_GUID_CLEARKEY_PROTECTION_SYSTEM_ID, 0x9b0ff3ca, 0x1378,
+// 0x4f28, 0x96, 0x65, 0x18, 0x9e, 0x15, 0x30, 0x2a, 0x71);
+
+// Media Foundation Clear Key protection system ID from Chromium
+// {E4E94971-696A-447E-96E4-93FDF3A57A7A}
+// https://source.chromium.org/chromium/chromium/src/+/main:media/cdm/win/test/media_foundation_clear_key_guids.h;l=16-29?q=CLEARKEY_GUID_CLEARKEY_PROTECTION_SYSTEM_ID&ss=chromium%2Fchromium%2Fsrc
+DEFINE_GUID(CLEARKEY_GUID_CLEARKEY_PROTECTION_SYSTEM_ID, 0xe4e94971, 0x696a,
+ 0x447e, 0x96, 0xe4, 0x93, 0xfd, 0xf3, 0xa5, 0x7a, 0x7a);
+
+// Media Foundation Clear Key content enabler type
+// {C262FD73-2F13-41C2-94E7-4CAF087AE1D1}
+DEFINE_GUID(MEDIA_FOUNDATION_CLEARKEY_GUID_CONTENT_ENABLER_TYPE, 0xc262fd73,
+ 0x2f13, 0x41c2, 0x94, 0xe7, 0x4c, 0xaf, 0x8, 0x7a, 0xe1, 0xd1);
+
+// https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:media/cdm/win/test/media_foundation_clear_key_guids.h;l=46;drc=fcefb4563e8ea5b2036ecde882f4f228dd1e4338
+#define PLAYREADY_GUID_MEDIA_PROTECTION_SYSTEM_ID_STRING \
+ L"{F4637010-03C3-42CD-B932-B48ADF3A6A54}"
+
+// A PROPVARIANT that is automatically initialized and cleared upon respective
+// construction and destruction of this class.
+class AutoPropVar final {
+ public:
+ AutoPropVar() { PropVariantInit(&mVar); }
+
+ ~AutoPropVar() { Reset(); }
+
+ AutoPropVar(const AutoPropVar&) = delete;
+ AutoPropVar& operator=(const AutoPropVar&) = delete;
+ bool operator==(const AutoPropVar&) const = delete;
+ bool operator!=(const AutoPropVar&) const = delete;
+
+ // Returns a pointer to the underlying PROPVARIANT for use as an out param
+ // in a function call.
+ PROPVARIANT* Receive() {
+ MOZ_ASSERT(mVar.vt == VT_EMPTY);
+ return &mVar;
+ }
+
+ // Clears the instance to prepare it for re-use (e.g., via Receive).
+ void Reset() {
+ if (mVar.vt != VT_EMPTY) {
+ HRESULT hr = PropVariantClear(&mVar);
+ MOZ_ASSERT(SUCCEEDED(hr));
+ Unused << hr;
+ }
+ }
+
+ const PROPVARIANT& get() const { return mVar; }
+ const PROPVARIANT* ptr() const { return &mVar; }
+
+ private:
+ PROPVARIANT mVar;
+};
+
+template <typename T>
+class ScopedCoMem final {
+ public:
+ ScopedCoMem() : mPtr(nullptr) {}
+
+ ~ScopedCoMem() { Reset(nullptr); }
+
+ ScopedCoMem(const ScopedCoMem&) = delete;
+ ScopedCoMem& operator=(const ScopedCoMem&) = delete;
+
+ T** operator&() { // NOLINT
+ MOZ_ASSERT(mPtr == nullptr); // To catch memory leaks.
+ return &mPtr;
+ }
+
+ operator T*() { return mPtr; }
+
+ T* operator->() {
+ MOZ_ASSERT(mPtr != nullptr);
+ return mPtr;
+ }
+
+ const T* operator->() const {
+ MOZ_ASSERT(mPtr != nullptr);
+ return mPtr;
+ }
+
+ explicit operator bool() const { return mPtr; }
+
+ friend bool operator==(const ScopedCoMem& lhs, std::nullptr_t) {
+ return lhs.Get() == nullptr;
+ }
+
+ friend bool operator==(std::nullptr_t, const ScopedCoMem& rhs) {
+ return rhs.Get() == nullptr;
+ }
+
+ friend bool operator!=(const ScopedCoMem& lhs, std::nullptr_t) {
+ return lhs.Get() != nullptr;
+ }
+
+ friend bool operator!=(std::nullptr_t, const ScopedCoMem& rhs) {
+ return rhs.Get() != nullptr;
+ }
+
+ void Reset(T* ptr) {
+ if (mPtr) {
+ CoTaskMemFree(mPtr);
+ }
+ mPtr = ptr;
+ }
+
+ T* Get() const { return mPtr; }
+
+ private:
+ T* mPtr;
+};
+
+template <typename T>
+class DataMutex final {
+ public:
+ DataMutex() = default;
+
+ template <typename... Args>
+ explicit DataMutex(Args&&... args) : mData(std::forward<Args>(args)...) {}
+
+ class AutoLock {
+ public:
+ AutoLock(std::unique_lock<std::mutex>&& lock, DataMutex<T>* mutex)
+ : mLock(std::move(lock)), mMutex(mutex) {}
+ T& operator*() { return ref(); }
+ T* operator->() { return &ref(); }
+ T& ref() const& { return mMutex->mData; }
+ operator T*() const& { return &ref(); }
+ ~AutoLock() { mMutex = nullptr; }
+
+ private:
+ std::unique_lock<std::mutex> mLock;
+ DataMutex<T>* mMutex;
+ };
+
+ AutoLock Lock() {
+ return AutoLock(std::unique_lock<std::mutex>(mMutex), this);
+ }
+
+ private:
+ std::mutex mMutex;
+ T mData;
+};
+
+} // namespace mozilla
+
+#endif // DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYCDMUTILS_H
diff --git a/media/wmf-clearkey/WMFDecryptedBlock.h b/media/wmf-clearkey/WMFDecryptedBlock.h
new file mode 100644
index 0000000000..1ffa41e7c9
--- /dev/null
+++ b/media/wmf-clearkey/WMFDecryptedBlock.h
@@ -0,0 +1,67 @@
+/* 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/. */
+
+#ifndef DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFDECRYPTEDBLOCK_H
+#define DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFDECRYPTEDBLOCK_H
+
+#include <vector>
+
+#include "WMFClearKeyUtils.h"
+#include "content_decryption_module.h"
+
+namespace mozilla {
+
+// This class is used to store the decrypted data. It will be allocated by
+// `SessionManagerWrapper::Allocate`.
+class WMFDecryptedBuffer : public cdm::Buffer {
+ public:
+ explicit WMFDecryptedBuffer(size_t aSize) {
+ SetSize(aSize);
+ LOG("WMFDecryptedBuffer ctor %p, sz=%u", this, Size());
+ }
+ ~WMFDecryptedBuffer() override {
+ LOG("WMFDecryptedBuffer dtor %p, sz=%u", this, Size());
+ }
+ WMFDecryptedBuffer(const WMFDecryptedBuffer&) = delete;
+ WMFDecryptedBuffer& operator=(const WMFDecryptedBuffer&) = delete;
+
+ // This is not good, but that is how cdm::buffer works.
+ void Destroy() override { delete this; }
+ uint32_t Capacity() const override { return mBuffer.size(); }
+ uint8_t* Data() override { return mBuffer.data(); }
+ void SetSize(uint32_t aSize) override { return mBuffer.resize(aSize); }
+ uint32_t Size() const override { return mBuffer.size(); }
+
+ private:
+ std::vector<uint8_t> mBuffer;
+};
+
+class WMFDecryptedBlock : public cdm::DecryptedBlock {
+ public:
+ WMFDecryptedBlock() : mBuffer(nullptr), mTimestamp(0) {
+ LOG("WMFDecryptedBlock ctor %p", this);
+ }
+ ~WMFDecryptedBlock() override {
+ LOG("WMFDecryptedBlock dtor %p", this);
+ if (mBuffer) {
+ mBuffer->Destroy();
+ mBuffer = nullptr;
+ }
+ }
+ void SetDecryptedBuffer(cdm::Buffer* aBuffer) override {
+ LOG("WMFDecryptedBlock(%p)::SetDecryptedBuffer, buffer=%p", this, aBuffer);
+ mBuffer = aBuffer;
+ }
+ cdm::Buffer* DecryptedBuffer() override { return mBuffer; }
+ void SetTimestamp(int64_t aTimestamp) override { mTimestamp = aTimestamp; }
+ int64_t Timestamp() const override { return mTimestamp; }
+
+ private:
+ cdm::Buffer* mBuffer;
+ int64_t mTimestamp;
+};
+
+} // namespace mozilla
+
+#endif // DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFDECRYPTEDBLOCK_H
diff --git a/media/wmf-clearkey/WMFPMPServer.cpp b/media/wmf-clearkey/WMFPMPServer.cpp
new file mode 100644
index 0000000000..86036cc0c0
--- /dev/null
+++ b/media/wmf-clearkey/WMFPMPServer.cpp
@@ -0,0 +1,68 @@
+/* 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 "WMFPMPServer.h"
+
+#include <mfapi.h>
+#include <mferror.h>
+
+#include "WMFClearKeyUtils.h"
+
+namespace mozilla {
+
+using Microsoft::WRL::ComPtr;
+using Microsoft::WRL::MakeAndInitialize;
+
+HRESULT WMFPMPServer::RuntimeClassInitialize(
+ ABI::Windows::Foundation::Collections::IPropertySet* aPropertyPmp) {
+ ENTRY_LOG();
+ mPropertyPmp = aPropertyPmp;
+ RETURN_IF_FAILED(MFCreatePMPMediaSession(MFPMPSESSION_IN_PROCESS, nullptr,
+ &mMediaSession, nullptr));
+ RETURN_IF_FAILED(MFGetService(mMediaSession.Get(), MF_PMP_SERVER_CONTEXT,
+ IID_PPV_ARGS(&mPmpServer)));
+ RETURN_IF_FAILED(MFGetService(mMediaSession.Get(), MF_PMP_SERVICE,
+ IID_PPV_ARGS(&mPmpHost)));
+ return S_OK;
+}
+
+STDMETHODIMP WMFPMPServer::GetIids(ULONG* aIidCount, IID** aIids) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFPMPServer::GetRuntimeClassName(
+ _COM_Outptr_ HSTRING* aClassName) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WMFPMPServer::GetTrustLevel(TrustLevel* aTrustLevel) {
+ NOT_IMPLEMENTED();
+ return E_NOTIMPL;
+}
+STDMETHODIMP WMFPMPServer::get_Properties(
+ ABI::Windows::Foundation::Collections::IPropertySet** aPpProperties) {
+ ENTRY_LOG();
+ RETURN_IF_FAILED(mPropertyPmp.CopyTo(aPpProperties));
+ return S_OK;
+}
+
+STDMETHODIMP WMFPMPServer::GetService(REFGUID aGuidService, REFIID aRiid,
+ LPVOID* aObject) {
+ ENTRY_LOG();
+ if (!aObject) {
+ return E_POINTER;
+ }
+ if (aGuidService == MF_PMP_SERVER_CONTEXT) {
+ RETURN_IF_FAILED(mPmpServer.CopyTo(aRiid, aObject));
+ } else if (aGuidService == MF_PMP_SERVICE && aRiid == IID_IMFPMPHost) {
+ RETURN_IF_FAILED(mPmpHost.CopyTo(aRiid, aObject));
+ } else {
+ RETURN_IF_FAILED(MF_E_UNSUPPORTED_SERVICE);
+ }
+ return S_OK;
+}
+
+} // namespace mozilla
diff --git a/media/wmf-clearkey/WMFPMPServer.h b/media/wmf-clearkey/WMFPMPServer.h
new file mode 100644
index 0000000000..15d9116bac
--- /dev/null
+++ b/media/wmf-clearkey/WMFPMPServer.h
@@ -0,0 +1,57 @@
+/* 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/. */
+
+#ifndef DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFPMPSERVER_H
+#define DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFPMPSERVER_H
+
+#include <mfidl.h>
+#include <windows.h>
+#include <windows.media.protection.h>
+#include <wrl.h>
+
+#include "MFCDMExtra.h"
+
+namespace mozilla {
+
+// A mock PMP server in order to allow media engine to create in-process PMP
+// server.
+class WMFPMPServer final
+ : public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
+ ABI::Windows::Media::Protection::IMediaProtectionPMPServer,
+ IMFGetService, Microsoft::WRL::FtmBase> {
+ public:
+ WMFPMPServer() = default;
+ ~WMFPMPServer() = default;
+ WMFPMPServer(const WMFPMPServer&) = delete;
+ WMFPMPServer& operator=(const WMFPMPServer&) = delete;
+
+ HRESULT RuntimeClassInitialize(
+ ABI::Windows::Foundation::Collections::IPropertySet* aPropertyPmp);
+
+ // IInspectable
+ STDMETHODIMP GetIids(ULONG* aIidCount, IID** aIids) override;
+ STDMETHODIMP GetRuntimeClassName(HSTRING* aClassName) override;
+ STDMETHODIMP GetTrustLevel(TrustLevel* aTrustLevel) override;
+
+ // IMediaProtectionPMPServer
+ STDMETHODIMP get_Properties(
+ ABI::Windows::Foundation::Collections::IPropertySet** aPpProperties)
+ override;
+
+ // IMFGetService
+ STDMETHODIMP GetService(REFGUID aGuidService, REFIID aRiid,
+ LPVOID* aObject) override;
+
+ private:
+ Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IPropertySet>
+ mPropertyPmp;
+ Microsoft::WRL::ComPtr<IMFPMPServer> mPmpServer;
+ Microsoft::WRL::ComPtr<IMFPMPHost> mPmpHost;
+ Microsoft::WRL::ComPtr<IMFMediaSession> mMediaSession;
+};
+
+} // namespace mozilla
+
+#endif // DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFPMPSERVER_H
diff --git a/media/wmf-clearkey/dllmain.cpp b/media/wmf-clearkey/dllmain.cpp
new file mode 100644
index 0000000000..6b5da38ae5
--- /dev/null
+++ b/media/wmf-clearkey/dllmain.cpp
@@ -0,0 +1,37 @@
+/* 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 <windows.h>
+#include <wrl.h>
+
+using namespace Microsoft::WRL;
+
+BOOL WINAPI DllMain(_In_opt_ HINSTANCE aInstance, _In_ DWORD aReason,
+ _In_opt_ LPVOID aReserved) {
+ if (DLL_PROCESS_ATTACH == aReason) {
+ DisableThreadLibraryCalls(aInstance);
+ Module<InProc>::GetModule().Create();
+ } else if (DLL_PROCESS_DETACH == aReason) {
+ Module<InProc>::GetModule().Terminate();
+ }
+ return TRUE;
+}
+
+HRESULT WINAPI
+DllGetActivationFactory(_In_ HSTRING aActivatibleClassId,
+ _COM_Outptr_ IActivationFactory** aFactory) {
+ auto& module = Module<InProc>::GetModule();
+ return module.GetActivationFactory(aActivatibleClassId, aFactory);
+}
+
+HRESULT WINAPI DllCanUnloadNow() {
+ auto& module = Module<InProc>::GetModule();
+ return (module.Terminate()) ? S_OK : S_FALSE;
+}
+
+STDAPI DllGetClassObject(_In_ REFCLSID aRclsid, _In_ REFIID aRiid,
+ _COM_Outptr_ LPVOID FAR* aPpv) {
+ auto& module = Module<InProc>::GetModule();
+ return module.GetClassObject(aRclsid, aRiid, aPpv);
+}
diff --git a/media/wmf-clearkey/moz.build b/media/wmf-clearkey/moz.build
new file mode 100644
index 0000000000..74680a50e0
--- /dev/null
+++ b/media/wmf-clearkey/moz.build
@@ -0,0 +1,43 @@
+# 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/.
+
+DEFINES["CDM_IMPLEMENTATION"] = True
+
+SOURCES += [
+ "dllmain.cpp",
+ "WMFClearKeyActivate.cpp",
+ "WMFClearKeyCDM.cpp",
+ "WMFClearKeyCDMAccess.cpp",
+ "WMFClearKeyCDMFactory.cpp",
+ "WMFClearKeyContentEnabler.cpp",
+ # TODO : enable decryptor in bug 1870722.
+ # "WMFClearKeyDecryptor.cpp",
+ "WMFClearKeyInputTrustAuthority.cpp",
+ "WMFClearKeyOutputPolicy.cpp",
+ "WMFClearKeySession.cpp",
+ "WMFClearKeyTrustedInput.cpp",
+ "WMFPMPServer.cpp",
+]
+
+OS_LIBS += [
+ "mf",
+ "mfplat",
+ "mfuuid",
+ "oleaut32",
+ "propsys",
+ "runtimeobject",
+]
+
+USE_LIBS += ["gecko-clearkey"]
+
+DEFFILE = "WMFClearKey.def"
+
+# Suppress warnings in platform headers, eg. wrl/module.h
+if CONFIG["CC_TYPE"] == "clang-cl":
+ CXXFLAGS += [
+ "-Wno-missing-braces",
+ "-Wunused-result",
+ ]
+
+GeckoSharedLibrary("wmfclearkey", linkage=None)