diff options
Diffstat (limited to 'media/wmf-clearkey/WMFClearKeySession.cpp')
-rw-r--r-- | media/wmf-clearkey/WMFClearKeySession.cpp | 233 |
1 files changed, 233 insertions, 0 deletions
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 |