WMFClearKeySession.cpp (7337B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "WMFClearKeySession.h" 6 7 #include <codecvt> 8 #include <cmath> 9 #include <Mferror.h> 10 #include <winerror.h> 11 12 #include "WMFClearKeyCDM.h" 13 #include "WMFClearKeyUtils.h" 14 15 namespace mozilla { 16 17 using Microsoft::WRL::ComPtr; 18 19 static cdm::SessionType ToCdmSessionType(MF_MEDIAKEYSESSION_TYPE aSessionType) { 20 switch (aSessionType) { 21 case MF_MEDIAKEYSESSION_TYPE_TEMPORARY: 22 return cdm::SessionType::kTemporary; 23 default: 24 MOZ_ASSERT_UNREACHABLE("Only support temporary type for testing"); 25 return cdm::SessionType::kTemporary; 26 } 27 } 28 29 static MF_MEDIAKEY_STATUS ToMFKeyStatus(cdm::KeyStatus aStatus) { 30 switch (aStatus) { 31 case cdm::KeyStatus::kUsable: 32 return MF_MEDIAKEY_STATUS_USABLE; 33 case cdm::KeyStatus::kExpired: 34 return MF_MEDIAKEY_STATUS_EXPIRED; 35 case cdm::KeyStatus::kOutputDownscaled: 36 return MF_MEDIAKEY_STATUS_OUTPUT_DOWNSCALED; 37 case cdm::KeyStatus::kStatusPending: 38 return MF_MEDIAKEY_STATUS_STATUS_PENDING; 39 case cdm::KeyStatus::kInternalError: 40 return MF_MEDIAKEY_STATUS_INTERNAL_ERROR; 41 case cdm::KeyStatus::kReleased: 42 return MF_MEDIAKEY_STATUS_RELEASED; 43 case cdm::KeyStatus::kOutputRestricted: 44 return MF_MEDIAKEY_STATUS_OUTPUT_RESTRICTED; 45 } 46 } 47 48 HRESULT WMFClearKeySession::RuntimeClassInitialize( 49 MF_MEDIAKEYSESSION_TYPE aSessionType, 50 IMFContentDecryptionModuleSessionCallbacks* aCallbacks, 51 SessionManagerWrapper* aManager) { 52 ENTRY_LOG(); 53 MOZ_ASSERT(aCallbacks); 54 MOZ_ASSERT(aManager); 55 mSessionType = ToCdmSessionType(aSessionType); 56 mCallbacks = aCallbacks; 57 mSessionManager = aManager; 58 return S_OK; 59 } 60 61 WMFClearKeySession::~WMFClearKeySession() { ENTRY_LOG(); } 62 63 STDMETHODIMP WMFClearKeySession::GenerateRequest(LPCWSTR aInitDataType, 64 const BYTE* aInitData, 65 DWORD aInitDataSize) { 66 if (!mSessionManager) { 67 return MF_E_SHUTDOWN; 68 } 69 ENTRY_LOG_ARGS("init-type=%ls", aInitDataType); 70 cdm::InitDataType initType; 71 if (wcscmp(aInitDataType, L"cenc") == 0) { 72 initType = cdm::InitDataType::kCenc; 73 } else if (wcscmp(aInitDataType, L"keyids") == 0) { 74 initType = cdm::InitDataType::kKeyIds; 75 } else if (wcscmp(aInitDataType, L"webm") == 0) { 76 initType = cdm::InitDataType::kWebM; 77 } else { 78 return MF_NOT_SUPPORTED_ERR; 79 } 80 RETURN_IF_FAILED(mSessionManager->GenerateRequest( 81 initType, aInitData, aInitDataSize, mSessionType, this, mSessionId)); 82 MOZ_ASSERT(!mSessionId.empty()); 83 ENTRY_LOG_ARGS("created session, sid=%s", mSessionId.c_str()); 84 return S_OK; 85 } 86 87 STDMETHODIMP WMFClearKeySession::Load(LPCWSTR session_id, BOOL* loaded) { 88 ENTRY_LOG(); 89 // Per step 5, Load can only be called on persistent session, but we only 90 // support temporary session for MF clearkey due to testing reason. 91 // https://rawgit.com/w3c/encrypted-media/V1/index.html#dom-mediakeysession-load 92 return MF_E_NOT_AVAILABLE; 93 } 94 95 STDMETHODIMP WMFClearKeySession::Update(const BYTE* aResponse, 96 DWORD aResponseSize) { 97 ENTRY_LOG(); 98 if (!mSessionManager) { 99 return MF_E_SHUTDOWN; 100 } 101 RETURN_IF_FAILED( 102 mSessionManager->UpdateSession(mSessionId, aResponse, aResponseSize)); 103 return S_OK; 104 } 105 106 STDMETHODIMP WMFClearKeySession::Close() { 107 ENTRY_LOG(); 108 // It has been shutdowned and sesssion has been closed. 109 if (!mSessionManager) { 110 return S_OK; 111 } 112 RETURN_IF_FAILED(mSessionManager->CloseSession(mSessionId)); 113 return S_OK; 114 } 115 116 STDMETHODIMP WMFClearKeySession::Remove() { 117 ENTRY_LOG(); 118 // It has been shutdowned and sesssion has been removed. 119 if (!mSessionManager) { 120 return S_OK; 121 } 122 RETURN_IF_FAILED(mSessionManager->RemoveSession(mSessionId)); 123 return S_OK; 124 } 125 126 STDMETHODIMP WMFClearKeySession::GetSessionId(LPWSTR* aSessionId) { 127 ENTRY_LOG(); 128 if (!mSessionManager) { 129 return S_OK; 130 } 131 if (mSessionId.empty()) { 132 *aSessionId = (LPWSTR)CoTaskMemAlloc(sizeof(wchar_t)); 133 if (*aSessionId != NULL) { 134 **aSessionId = L'\0'; 135 return S_OK; 136 } else { 137 return E_OUTOFMEMORY; 138 } 139 } 140 141 std::wstring_convert<std::codecvt_utf8<wchar_t>> converter; 142 std::wstring wideStr = converter.from_bytes(mSessionId); 143 *aSessionId = 144 (LPWSTR)CoTaskMemAlloc((wideStr.length() + 1) * sizeof(wchar_t)); 145 if (*aSessionId != NULL) { 146 wcscpy_s(*aSessionId, wideStr.length() + 1, wideStr.c_str()); 147 return S_OK; 148 } else { 149 return E_OUTOFMEMORY; 150 } 151 } 152 153 STDMETHODIMP WMFClearKeySession::GetExpiration(double* expiration) { 154 ENTRY_LOG(); 155 // This is used for testing, never expires. 156 *expiration = std::nan("1"); 157 return S_OK; 158 } 159 160 STDMETHODIMP WMFClearKeySession::GetKeyStatuses(MFMediaKeyStatus** aKeyStatuses, 161 UINT* aKeyStatusesCount) { 162 ENTRY_LOG(); 163 *aKeyStatuses = nullptr; 164 *aKeyStatusesCount = 0; 165 166 const auto keyStatusCount = mKeyInfo.size(); 167 if (mSessionId.empty() || keyStatusCount == 0) { 168 ENTRY_LOG_ARGS("No session ID or no key info!"); 169 return S_OK; 170 } 171 172 MFMediaKeyStatus* keyStatusArray = nullptr; 173 keyStatusArray = static_cast<MFMediaKeyStatus*>( 174 CoTaskMemAlloc(keyStatusCount * sizeof(MFMediaKeyStatus))); 175 if (!keyStatusArray) { 176 ENTRY_LOG_ARGS("OOM when alloacting keyStatusArray!"); 177 return E_OUTOFMEMORY; 178 } 179 ZeroMemory(keyStatusArray, keyStatusCount * sizeof(MFMediaKeyStatus)); 180 for (UINT idx = 0; idx < keyStatusCount; idx++) { 181 keyStatusArray[idx].cbKeyId = mKeyInfo[idx].mKeyId.size(); 182 keyStatusArray[idx].pbKeyId = 183 static_cast<BYTE*>(CoTaskMemAlloc(sizeof(mKeyInfo[idx].mKeyId.size()))); 184 if (keyStatusArray[idx].pbKeyId == nullptr) { 185 ENTRY_LOG_ARGS("OOM when alloacting keyStatusArray's pbKeyId!"); 186 return E_OUTOFMEMORY; 187 } 188 189 keyStatusArray[idx].eMediaKeyStatus = 190 ToMFKeyStatus(mKeyInfo[idx].mKeyStatus); 191 memcpy(keyStatusArray[idx].pbKeyId, mKeyInfo[idx].mKeyId.data(), 192 mKeyInfo[idx].mKeyId.size()); 193 } 194 195 *aKeyStatuses = keyStatusArray; 196 *aKeyStatusesCount = keyStatusCount; 197 ENTRY_LOG_ARGS("return key status!"); 198 return S_OK; 199 } 200 201 void WMFClearKeySession::OnKeyMessage( 202 MF_MEDIAKEYSESSION_MESSAGETYPE aMessageType, const BYTE* aMessage, 203 DWORD aMessageSize) { 204 ENTRY_LOG_ARGS("aMessageSize=%lu", aMessageSize); 205 if (!mSessionManager) { 206 return; 207 } 208 mCallbacks->KeyMessage(aMessageType, aMessage, aMessageSize, nullptr); 209 } 210 211 void WMFClearKeySession::OnKeyStatusChanged( 212 const cdm::KeyInformation* aKeysInfo, uint32_t aKeysInfoCount) { 213 ENTRY_LOG_ARGS("aKeysInfoCount=%u", aKeysInfoCount); 214 if (!mSessionManager) { 215 return; 216 } 217 mKeyInfo.clear(); 218 for (uint32_t idx = 0; idx < aKeysInfoCount; idx++) { 219 const cdm::KeyInformation& key = aKeysInfo[idx]; 220 mKeyInfo.push_back(KeyInformation{key.key_id, key.key_id_size, key.status}); 221 ENTRY_LOG_ARGS("idx=%u, keySize=%u, status=%u", idx, key.key_id_size, 222 key.status); 223 } 224 mCallbacks->KeyStatusChanged(); 225 } 226 227 void WMFClearKeySession::Shutdown() { 228 ENTRY_LOG(); 229 mCallbacks = nullptr; 230 mSessionManager = nullptr; 231 } 232 233 } // namespace mozilla