summaryrefslogtreecommitdiffstats
path: root/media/wmf-clearkey/WMFClearKeySession.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/wmf-clearkey/WMFClearKeySession.cpp')
-rw-r--r--media/wmf-clearkey/WMFClearKeySession.cpp233
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