WMFClearKeyCDM.h (9443B)
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 #ifndef DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYCDM_H 6 #define DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYCDM_H 7 8 #include <mfidl.h> 9 #include <unordered_map> 10 #include <variant> 11 #include <windows.h> 12 #include <windows.media.protection.h> 13 #include <wrl.h> 14 #include <wrl/client.h> 15 16 #include "ClearKeySessionManager.h" 17 #include "MFCDMExtra.h" 18 #include "WMFClearKeyUtils.h" 19 #include "content_decryption_module.h" 20 21 namespace mozilla { 22 23 class SessionManagerWrapper; 24 class WMFClearKeySession; 25 26 // This our customized MFCDM for supporting clearkey in our testing. It would 27 // use ClearKeySessionManager via SessionManagerWrapper to perform decryption. 28 class WMFClearKeyCDM final 29 : public Microsoft::WRL::RuntimeClass< 30 Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, 31 IMFContentDecryptionModule, IMFGetService, IMFShutdown, 32 Microsoft::WRL::FtmBase> { 33 public: 34 WMFClearKeyCDM() = default; 35 ~WMFClearKeyCDM(); 36 WMFClearKeyCDM(const WMFClearKeyCDM&) = delete; 37 WMFClearKeyCDM& operator=(const WMFClearKeyCDM&) = delete; 38 39 HRESULT RuntimeClassInitialize(IPropertyStore* aProperties); 40 41 // IMFContentDecryptionModule 42 STDMETHODIMP SetContentEnabler(IMFContentEnabler* aContentEnabler, 43 IMFAsyncResult* aResult) override; 44 STDMETHODIMP GetSuspendNotify(IMFCdmSuspendNotify** aNotify) override; 45 STDMETHODIMP SetPMPHostApp(IMFPMPHostApp* aPmpHostApp) override; 46 STDMETHODIMP CreateSession( 47 MF_MEDIAKEYSESSION_TYPE aSessionType, 48 IMFContentDecryptionModuleSessionCallbacks* aCallbacks, 49 IMFContentDecryptionModuleSession** aSession) override; 50 STDMETHODIMP SetServerCertificate(const BYTE* aCertificate, 51 DWORD aCertificateSize) override; 52 STDMETHODIMP CreateTrustedInput(const BYTE* aContentInitData, 53 DWORD aContentInitDataSize, 54 IMFTrustedInput** aTrustedInput) override; 55 STDMETHODIMP GetProtectionSystemIds(GUID** aSystemIds, 56 DWORD* aCount) override; 57 // IMFGetService 58 STDMETHODIMP GetService(REFGUID aGuidService, REFIID aRiid, 59 LPVOID* aPpvObject) override; 60 61 // IMFShutdown 62 STDMETHODIMP Shutdown() override; 63 STDMETHODIMP GetShutdownStatus(MFSHUTDOWN_STATUS* aStatus) override; 64 65 private: 66 RefPtr<SessionManagerWrapper> mSessionManager; 67 Microsoft::WRL::ComPtr< 68 ABI::Windows::Media::Protection::IMediaProtectionPMPServer> 69 mPMPServer; 70 }; 71 72 // In order to reuse existing Gecko clearkey implementation, we need to 73 // inherit the class `cdm::Host_11`. 74 // TODO : add a way to assert thread usage. It would be used on MF thread pool 75 // and the media supervisor thread pool. 76 class SessionManagerWrapper final : public RefCounted, private cdm::Host_11 { 77 public: 78 explicit SessionManagerWrapper(WMFClearKeyCDM* aCDM); 79 80 HRESULT GenerateRequest(cdm::InitDataType aInitDataType, 81 const BYTE* aInitData, DWORD aInitDataSize, 82 cdm::SessionType aSessionType, 83 WMFClearKeySession* aSession, 84 std::string& aSessionIdOut); 85 HRESULT UpdateSession(const std::string& aSessionId, const BYTE* aResponse, 86 DWORD aResponseSize); 87 HRESULT CloseSession(const std::string& aSessionId); 88 HRESULT RemoveSession(const std::string& aSessionId); 89 HRESULT Decrypt(const cdm::InputBuffer_2& aBuffer, 90 cdm::DecryptedBlock* aDecryptedBlock); 91 92 void Shutdown(); 93 bool IsShutdown(); 94 95 private: 96 ~SessionManagerWrapper(); 97 // cdm::Host_11 98 void OnInitialized(bool aSuccess) override {} 99 void OnResolveKeyStatusPromise(uint32_t aPromiseId, 100 cdm::KeyStatus aKeyStatus) override {} 101 void OnResolveNewSessionPromise(uint32_t aPromiseId, const char* aSessionId, 102 uint32_t aSessionIdSize) override; 103 void OnResolvePromise(uint32_t aPromiseId) override; 104 void OnRejectPromise(uint32_t aPromiseId, cdm::Exception aException, 105 uint32_t aSystemCode, const char* aErrorMessage, 106 uint32_t aErrorMessageSize) override; 107 void OnSessionMessage(const char* aSessionId, uint32_t aSessionIdSize, 108 cdm::MessageType aMessageType, const char* aMessage, 109 uint32_t aMessageSize) override; 110 void OnSessionKeysChange(const char* aSessionId, uint32_t aSessionIdSize, 111 bool aHasAdditionalUsableKey, 112 const cdm::KeyInformation* aKeysInfo, 113 uint32_t aKeysInfoCount) override; 114 void OnExpirationChange(const char* aSessionId, uint32_t aSessionIdSize, 115 cdm::Time aNewExpiryTime) override { 116 // No need to implement this because the session would never expire in 117 // testing. 118 }; 119 void OnSessionClosed(const char* aSessionId, 120 uint32_t aSessionIdSize) override { 121 // No need to implement this because session doesn't have close callback 122 // or events. 123 }; 124 cdm::FileIO* CreateFileIO(cdm::FileIOClient* aClient) override { 125 // We don't support this because we only support temporary session. 126 return nullptr; 127 } 128 void SendPlatformChallenge(const char* aServiceId, uint32_t aServiceIdSize, 129 const char* aChallenge, 130 uint32_t aChallengeSize) override {} 131 void EnableOutputProtection(uint32_t aDesiredProtectionMask) override {} 132 void QueryOutputProtectionStatus() override {}; 133 void OnDeferredInitializationDone(cdm::StreamType aStreamType, 134 cdm::Status aDecoderStatus) override {} 135 void RequestStorageId(uint32_t aVersion) override {} 136 void ReportMetrics(cdm::MetricName aMetricName, uint64_t aValue) override {} 137 cdm::Buffer* Allocate(uint32_t aCapacity) override; 138 void SetTimer(int64_t aDelayMs, void* aContext) override {} 139 cdm::Time GetCurrentWallTime() override { return 0.0; } 140 friend class SessionManager; 141 142 Microsoft::WRL::ComPtr<WMFClearKeyCDM> mOwnerCDM; 143 RefPtr<ClearKeySessionManager> mSessionManager; 144 std::unordered_map<std::string, Microsoft::WRL::ComPtr<WMFClearKeySession>> 145 mSessions; 146 147 // This is a RAII helper class to use ClearKeySessionManager::XXXSession 148 // methods in a sync style, which is what MFCDM is required. 149 // ClearKeySessionManager uses cdm::Host_11's OnResolve/RejectXXX as callback 150 // to report whether those function calls relatd with specific promise id 151 // succeed or not. As we only do temporary session for ClearKey testing, we 152 // don't need to wait to setup the storage so calling those XXXsession 153 // functions are actully a sync process. We guarantee that 154 // ClearKeySessionManager will use OnResolve/Reject methods to notify us 155 // result, right after we calling the session related method. 156 // [How to to use this class, not thread-safe] 157 // 1. create it on the stack 158 // 2. use GetPromiseId() to generate a fake promise id for tracking 159 // 3. in cdm::Host_11's callback function, check promise id to know what 160 // result needs to be set 161 // 4. check result to see if the session method succeed or not 162 class SyncResultChecker final { 163 public: 164 using ResultType = std::variant<const char*, bool>; 165 explicit SyncResultChecker(SessionManagerWrapper& aOwner) 166 : mOwner(aOwner), mIdx(sIdx++), mKeySession(nullptr) { 167 mOwner.mActiveSyncResultChecker.insert({mIdx, this}); 168 } 169 SyncResultChecker(SessionManagerWrapper& aOwner, 170 WMFClearKeySession* aKeySession) 171 : mOwner(aOwner), mIdx(sIdx++), mKeySession(aKeySession) { 172 mOwner.mActiveSyncResultChecker.insert({mIdx, this}); 173 } 174 ~SyncResultChecker() { mOwner.mActiveSyncResultChecker.erase(mIdx); } 175 uint32_t GetPromiseId() const { return mIdx; } 176 const ResultType& GetResult() const { return mResult; } 177 WMFClearKeySession* GetKeySession() const { return mKeySession; } 178 179 private: 180 // Only allow setting result from these callbacks. 181 friend void SessionManagerWrapper::OnResolveNewSessionPromise(uint32_t, 182 const char*, 183 uint32_t); 184 friend void SessionManagerWrapper::OnResolvePromise(uint32_t); 185 friend void SessionManagerWrapper::OnRejectPromise(uint32_t, cdm::Exception, 186 uint32_t, const char*, 187 uint32_t); 188 void SetResultConstChar(const char* aResult) { 189 mResult.emplace<const char*>(aResult); 190 } 191 void SetResultBool(bool aResult) { mResult.emplace<bool>(aResult); } 192 193 static inline uint32_t sIdx = 0; 194 SessionManagerWrapper& mOwner; 195 const uint32_t mIdx; 196 ResultType mResult; 197 WMFClearKeySession* const mKeySession; 198 }; 199 std::unordered_map<uint32_t, SyncResultChecker*> mActiveSyncResultChecker; 200 201 // Protect following members. 202 std::mutex mMutex; 203 bool mIsShutdown = false; 204 }; 205 206 } // namespace mozilla 207 208 #endif // DOM_MEDIA_PLATFORM_WMF_CLEARKEY_WMFCLEARKEYCDM_H