Bug 1810817 - p7: implement CDMProxy for MF CDM and create/init it in MediaKeys. r=alwu

Differential Revision: https://phabricator.services.mozilla.com/D167061
This commit is contained in:
John Lin 2023-02-07 03:43:51 +00:00
Родитель dc8bf99d73
Коммит 579e5d2ac3
6 изменённых файлов: 259 добавлений и 1 удалений

Просмотреть файл

@ -108,3 +108,4 @@ speechd init
thread
thread shutdown
wifi tickler
WMFCDMThread

Просмотреть файл

@ -36,6 +36,9 @@
#ifdef XP_WIN
# include "mozilla/WindowsVersion.h"
#endif
#ifdef MOZ_MF_CDM
# include "mozilla/WMFCDMProxy.h"
#endif
namespace mozilla::dom {
@ -434,6 +437,14 @@ already_AddRefed<CDMProxy> MediaKeys::CreateCDMProxy() {
mConfig.mDistinctiveIdentifier == MediaKeysRequirement::Required,
mConfig.mPersistentState == MediaKeysRequirement::Required);
} else
#endif
#ifdef MOZ_MF_CDM
if (IsPlayReadyKeySystem(mKeySystem)) {
proxy = new WMFCDMProxy(
this, mKeySystem,
mConfig.mDistinctiveIdentifier == MediaKeysRequirement::Required,
mConfig.mPersistentState == MediaKeysRequirement::Required);
} else
#endif
{
proxy = new ChromiumCDMProxy(

Просмотреть файл

@ -17,7 +17,6 @@
#include "nsThreadUtils.h"
namespace mozilla {
class MFCDMChild;
/**
* WMFCDMImpl is a helper class for MFCDM protocol clients. It creates, manages,

Просмотреть файл

@ -0,0 +1,117 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "WMFCDMProxy.h"
#include "mozilla/dom/MediaKeySession.h"
#include "WMFCDMImpl.h"
namespace mozilla {
WMFCDMProxy::WMFCDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem,
bool aDistinctiveIdentifierRequired,
bool aPersistentStateRequired)
: CDMProxy(aKeys, aKeySystem, aDistinctiveIdentifierRequired,
aPersistentStateRequired) {
MOZ_ASSERT(NS_IsMainThread());
}
void WMFCDMProxy::Init(PromiseId aPromiseId, const nsAString& aOrigin,
const nsAString& aTopLevelOrigin,
const nsAString& aGMPName) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!aOrigin.IsEmpty());
MOZ_ASSERT(!mOwnerThread);
if (NS_FAILED(
NS_NewNamedThread("WMFCDMThread", getter_AddRefs(mOwnerThread)))) {
RejectPromiseWithStateError(
aPromiseId,
nsLiteralCString("WMFCDMProxy::Init: couldn't create CDM thread"));
return;
}
mCDM = MakeRefPtr<WMFCDMImpl>(mKeySystem);
WMFCDMImpl::InitParams params{nsString(aOrigin), mPersistentStateRequired,
mDistinctiveIdentifierRequired,
false /* HW secure? */};
mCDM->Init(params)->Then(
mMainThread, __func__,
[self = RefPtr{this}, this, aPromiseId](const bool) {
MOZ_ASSERT(mCDM->Id() > 0);
mKeys->OnCDMCreated(aPromiseId, mCDM->Id());
},
[self = RefPtr{this}, this, aPromiseId](const nsresult rv) {
RejectPromiseWithStateError(
aPromiseId,
nsLiteralCString("WMFCDMProxy::Init: WMFCDM init error"));
});
}
void WMFCDMProxy::ResolvePromise(PromiseId aId) {
auto resolve = [self = RefPtr{this}, this, aId]() {
EME_LOG("WMFCDMProxy::ResolvePromise(this=%p, pid=%" PRIu32 ")", this, aId);
if (!mKeys.IsNull()) {
mKeys->ResolvePromise(aId);
} else {
NS_WARNING("WMFCDMProxy unable to resolve promise!");
}
};
if (NS_IsMainThread()) {
resolve();
return;
}
mMainThread->Dispatch(
NS_NewRunnableFunction("WMFCDMProxy::ResolvePromise", resolve));
}
void WMFCDMProxy::RejectPromise(PromiseId aId, ErrorResult&& aException,
const nsCString& aReason) {
if (!NS_IsMainThread()) {
// Use CopyableErrorResult to store our exception in the runnable,
// because ErrorResult is not OK to move across threads.
mMainThread->Dispatch(
NewRunnableMethod<PromiseId, StoreCopyPassByRRef<CopyableErrorResult>,
nsCString>("WMFCDMProxy::RejectPromise", this,
&WMFCDMProxy::RejectPromiseOnMainThread,
aId, std::move(aException), aReason),
NS_DISPATCH_NORMAL);
return;
}
EME_LOG("WMFCDMProxy::RejectPromise(this=%p, pid=%" PRIu32
", code=0x%x, "
"reason='%s')",
this, aId, aException.ErrorCodeAsInt(), aReason.get());
if (!mKeys.IsNull()) {
mKeys->RejectPromise(aId, std::move(aException), aReason);
} else {
// We don't have a MediaKeys object to pass the exception to, so silence
// the exception to avoid it asserting due to being unused.
aException.SuppressException();
}
}
void WMFCDMProxy::RejectPromiseOnMainThread(PromiseId aId,
CopyableErrorResult&& aException,
const nsCString& aReason) {
// Moving into or out of a non-copyable ErrorResult will assert that both
// ErorResults are from our current thread. Avoid the assertion by moving
// into a current-thread CopyableErrorResult first. Note that this is safe,
// because CopyableErrorResult never holds state that can't move across
// threads.
CopyableErrorResult rv(std::move(aException));
RejectPromise(aId, std::move(rv), aReason);
}
void WMFCDMProxy::RejectPromiseWithStateError(PromiseId aId,
const nsCString& aReason) {
ErrorResult rv;
rv.ThrowInvalidStateError(aReason);
RejectPromise(aId, std::move(rv), aReason);
}
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,124 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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_EME_MEDIAFOUNDATION_WMFCDMPROXY_H_
#define DOM_MEDIA_EME_MEDIAFOUNDATION_WMFCDMPROXY_H_
#include "mozilla/CDMProxy.h"
#include "mozilla/CDMCaps.h"
#include "mozilla/dom/MediaKeys.h"
#include "mozilla/dom/MediaKeySession.h"
#include "mozilla/RefPtr.h"
#include "mozilla/WMFCDMImpl.h"
#include "nsString.h"
namespace mozilla {
class WMFCDMProxy : public CDMProxy {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WMFCDMProxy, override)
WMFCDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem,
bool aDistinctiveIdentifierRequired,
bool aPersistentStateRequired);
// CDMProxy interface
void Init(PromiseId aPromiseId, const nsAString& aOrigin,
const nsAString& aTopLevelOrigin,
const nsAString& aGMPName) override;
void CreateSession(uint32_t aCreateSessionToken,
MediaKeySessionType aSessionType, PromiseId aPromiseId,
const nsAString& aInitDataType,
nsTArray<uint8_t>& aInitData) override {}
void LoadSession(PromiseId aPromiseId, dom::MediaKeySessionType aSessionType,
const nsAString& aSessionId) override {}
void SetServerCertificate(PromiseId aPromiseId,
nsTArray<uint8_t>& aCert) override {}
void UpdateSession(const nsAString& aSessionId, PromiseId aPromiseId,
nsTArray<uint8_t>& aResponse) override {}
void CloseSession(const nsAString& aSessionId,
PromiseId aPromiseId) override {}
void RemoveSession(const nsAString& aSessionId,
PromiseId aPromiseId) override {}
void QueryOutputProtectionStatus() override {}
void NotifyOutputProtectionStatus(
OutputProtectionCheckStatus aCheckStatus,
OutputProtectionCaptureStatus aCaptureStatus) override {}
void Shutdown() override {
// TODO: reject pending promise.
}
void Terminated() override {}
void OnSetSessionId(uint32_t aCreateSessionToken,
const nsAString& aSessionId) override {}
void OnResolveLoadSessionPromise(uint32_t aPromiseId,
bool aSuccess) override {}
void OnSessionMessage(const nsAString& aSessionId,
dom::MediaKeyMessageType aMessageType,
const nsTArray<uint8_t>& aMessage) override {}
void OnExpirationChange(const nsAString& aSessionId,
UnixTime aExpiryTime) override {}
void OnSessionClosed(const nsAString& aSessionId) override {}
void OnSessionError(const nsAString& aSessionId, nsresult aException,
uint32_t aSystemCode, const nsAString& aMsg) override {}
void OnRejectPromise(uint32_t aPromiseId, ErrorResult&& aException,
const nsCString& aMsg) override {}
RefPtr<DecryptPromise> Decrypt(MediaRawData* aSample) override {
return nullptr;
}
void OnDecrypted(uint32_t aId, DecryptStatus aResult,
const nsTArray<uint8_t>& aDecryptedData) override {}
void ResolvePromise(PromiseId aId) override;
void RejectPromise(PromiseId aId, ErrorResult&& aException,
const nsCString& aReason) override;
void OnKeyStatusesChange(const nsAString& aSessionId) override {}
void GetStatusForPolicy(PromiseId aPromiseId,
const nsAString& aMinHdcpVersion) override {}
#ifdef DEBUG
bool IsOnOwnerThread() override {
return NS_GetCurrentThread() == mOwnerThread;
}
#endif
private:
virtual ~WMFCDMProxy() = default;
template <typename T>
void ResolvePromiseWithResult(PromiseId aId, const T& aResult) {}
void RejectPromiseOnMainThread(PromiseId aId,
CopyableErrorResult&& aException,
const nsCString& aReason);
// Reject promise with an InvalidStateError and the given message.
void RejectPromiseWithStateError(PromiseId aId, const nsCString& aReason);
RefPtr<WMFCDMImpl> mCDM;
};
} // namespace mozilla
#endif // DOM_MEDIA_EME_MEDIAFOUNDATION_WMFCDMPROXY_H_

Просмотреть файл

@ -4,8 +4,14 @@
# 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/.
EXPORTS.mozilla += [
"WMFCDMImpl.h",
"WMFCDMProxy.h",
]
UNIFIED_SOURCES += [
"WMFCDMImpl.cpp",
"WMFCDMProxy.cpp",
]
include("/ipc/chromium/chromium-config.mozbuild")