CDMProxy.h (11344B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef CDMProxy_h_ 8 #define CDMProxy_h_ 9 10 #include "mozilla/CDMCaps.h" 11 #include "mozilla/DataMutex.h" 12 #include "mozilla/MozPromise.h" 13 #include "mozilla/dom/MediaKeyMessageEvent.h" 14 #include "mozilla/dom/MediaKeySessionBinding.h" 15 #include "mozilla/dom/MediaKeys.h" 16 #include "nsIThread.h" 17 18 namespace mozilla { 19 class ErrorResult; 20 class MediaRawData; 21 class ChromiumCDMProxy; 22 class RemoteCDMChild; 23 #ifdef MOZ_WMF_CDM 24 class WMFCDMProxy; 25 #endif 26 27 namespace eme { 28 enum DecryptStatus { 29 Ok = 0, 30 GenericErr = 1, 31 NoKeyErr = 2, 32 AbortedErr = 3, 33 }; 34 } 35 36 using eme::DecryptStatus; 37 38 struct DecryptResult { 39 DecryptResult(DecryptStatus aStatus, MediaRawData* aSample) 40 : mStatus(aStatus), mSample(aSample) {} 41 DecryptStatus mStatus; 42 RefPtr<MediaRawData> mSample; 43 }; 44 45 typedef MozPromise<DecryptResult, DecryptResult, /* IsExclusive = */ true> 46 DecryptPromise; 47 48 class CDMKeyInfo { 49 public: 50 explicit CDMKeyInfo(const nsTArray<uint8_t>& aKeyId) 51 : mKeyId(aKeyId.Clone()), mStatus() {} 52 53 CDMKeyInfo(const nsTArray<uint8_t>& aKeyId, 54 const dom::Optional<dom::MediaKeyStatus>& aStatus) 55 : mKeyId(aKeyId.Clone()), mStatus(aStatus.Value()) {} 56 57 // The copy-ctor and copy-assignment operator for Optional<T> are declared as 58 // delete, so override CDMKeyInfo copy-ctor for nsTArray operations. 59 CDMKeyInfo(const CDMKeyInfo& aKeyInfo) { 60 mKeyId = aKeyInfo.mKeyId.Clone(); 61 if (aKeyInfo.mStatus.WasPassed()) { 62 mStatus.Construct(aKeyInfo.mStatus.Value()); 63 } 64 } 65 66 CDMKeyInfo() = default; 67 68 nsTArray<uint8_t> mKeyId; 69 dom::Optional<dom::MediaKeyStatus> mStatus; 70 }; 71 72 // Time is defined as the number of milliseconds since the 73 // Epoch (00:00:00 UTC, January 1, 1970). 74 typedef int64_t UnixTime; 75 76 // Proxies calls CDM, and proxies calls back. 77 // Note: Promises are passed in via a PromiseId, so that the ID can be 78 // passed via IPC to the CDM, which can then signal when to reject or 79 // resolve the promise using its PromiseId. 80 class CDMProxy { 81 protected: 82 typedef dom::PromiseId PromiseId; 83 84 public: 85 NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING 86 87 // Main thread only. 88 // Loads the CDM corresponding to mKeySystem. 89 // Calls MediaKeys::OnCDMCreated() when the CDM is created. 90 virtual void Init(PromiseId aPromiseId, const nsAString& aOrigin, 91 const nsAString& aTopLevelOrigin, 92 const nsAString& aName) = 0; 93 94 // Main thread only. 95 // Uses the CDM to create a key session. 96 // Calls MediaKeys::OnSessionActivated() when session is created. 97 // Assumes ownership of (std::move()s) aInitData's contents. 98 virtual void CreateSession(uint32_t aCreateSessionToken, 99 dom::MediaKeySessionType aSessionType, 100 PromiseId aPromiseId, 101 const nsAString& aInitDataType, 102 nsTArray<uint8_t>& aInitData) = 0; 103 104 // Main thread only. 105 // Uses the CDM to load a presistent session stored on disk. 106 // Calls MediaKeys::OnSessionActivated() when session is loaded. 107 virtual void LoadSession(PromiseId aPromiseId, 108 dom::MediaKeySessionType aSessionType, 109 const nsAString& aSessionId) = 0; 110 111 // Main thread only. 112 // Sends a new certificate to the CDM. 113 // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has 114 // processed the request. 115 // Assumes ownership of (std::move()s) aCert's contents. 116 virtual void SetServerCertificate(PromiseId aPromiseId, 117 nsTArray<uint8_t>& aCert) = 0; 118 119 // Main thread only. 120 // Sends an update to the CDM. 121 // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has 122 // processed the request. 123 // Assumes ownership of (std::move()s) aResponse's contents. 124 virtual void UpdateSession(const nsAString& aSessionId, PromiseId aPromiseId, 125 nsTArray<uint8_t>& aResponse) = 0; 126 127 // Main thread only. 128 // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has 129 // processed the request. 130 // If processing this operation results in the session actually closing, 131 // we also call MediaKeySession::OnClosed(), which in turn calls 132 // MediaKeys::OnSessionClosed(). 133 virtual void CloseSession(const nsAString& aSessionId, 134 PromiseId aPromiseId) = 0; 135 136 // Main thread only. 137 // Removes all data for a persisent session. 138 // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has 139 // processed the request. 140 virtual void RemoveSession(const nsAString& aSessionId, 141 PromiseId aPromiseId) = 0; 142 143 // Main thread only. 144 // Called to signal a request for output protection information from the CDM. 145 // This should forward the call up the stack where the query should be 146 // performed and then responded to via `NotifyOutputProtectionStatus`. 147 virtual void QueryOutputProtectionStatus() = 0; 148 149 // NotifyOutputProtectionStatus enums. Explicit values are specified to make 150 // it easy to match values in logs. 151 enum class OutputProtectionCheckStatus : uint8_t { 152 CheckFailed = 0, 153 CheckSuccessful = 1, 154 }; 155 156 enum class OutputProtectionCaptureStatus : uint8_t { 157 CapturePossilbe = 0, 158 CaptureNotPossible = 1, 159 Unused = 2, 160 }; 161 // End NotifyOutputProtectionStatus enums 162 163 // Main thread only. 164 // Notifies this proxy of the protection status for the media the CDM is 165 // associated with. This can be called in response to 166 // `QueryOutputProtectionStatus`, but can also be called without an 167 // associated query. In both cases the information will be forwarded to 168 // the CDM host machinery and used to handle requests from the CDM. 169 // @param aCheckStatus did the check succeed or not. 170 // @param aCaptureStatus if the check succeeded, this reflects if capture 171 // of media could take place. This doesn't mean capture is taking place. 172 // Callers should be conservative with this value such that it's okay to pass 173 // CapturePossilbe even if capture is not happening, but should never pass 174 // CaptureNotPossible if it could happen. If the check failed, this value is 175 // not used, and callers should pass Unused to indicate this. 176 virtual void NotifyOutputProtectionStatus( 177 OutputProtectionCheckStatus aCheckStatus, 178 OutputProtectionCaptureStatus aCaptureStatus) = 0; 179 180 // Main thread only. 181 virtual void Shutdown() = 0; 182 183 // Main thread only. 184 virtual void Terminated() = 0; 185 186 // Threadsafe. 187 const nsCString& GetNodeId() const { return mNodeId; }; 188 189 // Main thread only. 190 virtual void OnSetSessionId(uint32_t aCreateSessionToken, 191 const nsAString& aSessionId) = 0; 192 193 // Main thread only. 194 virtual void OnResolveLoadSessionPromise(uint32_t aPromiseId, 195 bool aSuccess) = 0; 196 197 // Main thread only. 198 virtual void OnSessionMessage(const nsAString& aSessionId, 199 dom::MediaKeyMessageType aMessageType, 200 const nsTArray<uint8_t>& aMessage) = 0; 201 202 // Main thread only. 203 virtual void OnExpirationChange(const nsAString& aSessionId, 204 UnixTime aExpiryTime) = 0; 205 206 // Main thread only. 207 virtual void OnSessionClosed(const nsAString& aSessionId, 208 dom::MediaKeySessionClosedReason aReason) = 0; 209 210 // Main thread only. 211 virtual void OnSessionError(const nsAString& aSessionId, nsresult aException, 212 uint32_t aSystemCode, const nsAString& aMsg) = 0; 213 214 // Main thread only. 215 virtual void OnRejectPromise(uint32_t aPromiseId, ErrorResult&& aException, 216 const nsCString& aMsg) = 0; 217 218 virtual RefPtr<DecryptPromise> Decrypt(MediaRawData* aSample) = 0; 219 220 // Owner thread only. 221 virtual void OnDecrypted(uint32_t aId, DecryptStatus aResult, 222 const nsTArray<uint8_t>& aDecryptedData) = 0; 223 224 // Reject promise with the given ErrorResult. 225 // 226 // Can be called from any thread. 227 virtual void RejectPromise(PromiseId aId, ErrorResult&& aException, 228 const nsCString& aReason) = 0; 229 230 // Resolves promise with "undefined". 231 // Can be called from any thread. 232 virtual void ResolvePromise(PromiseId aId) = 0; 233 234 // Threadsafe. 235 const nsString& KeySystem() const { return mKeySystem; }; 236 237 DataMutex<CDMCaps>& Capabilites() { return mCapabilites; }; 238 239 // Main thread only. 240 virtual void OnKeyStatusesChange(const nsAString& aSessionId) = 0; 241 242 // Main thread only. 243 // Calls MediaKeys->ResolvePromiseWithKeyStatus(aPromiseId, aKeyStatus) after 244 // the CDM has processed the request. 245 virtual void GetStatusForPolicy(PromiseId aPromiseId, 246 const dom::HDCPVersion& aMinHdcpVersion) = 0; 247 248 #ifdef DEBUG 249 virtual bool IsOnOwnerThread() = 0; 250 #endif 251 252 virtual ChromiumCDMProxy* AsChromiumCDMProxy() { return nullptr; } 253 254 #ifdef MOZ_WMF_CDM 255 virtual WMFCDMProxy* AsWMFCDMProxy() { return nullptr; } 256 #endif 257 258 virtual RemoteCDMChild* AsRemoteCDMChild() { return nullptr; } 259 260 virtual bool IsHardwareDecryptionSupported() const { return false; } 261 262 protected: 263 // Main thread only. 264 CDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem, 265 bool aDistinctiveIdentifierRequired, bool aPersistentStateRequired) 266 : mKeys(aKeys), 267 mKeySystem(aKeySystem), 268 mCapabilites("CDMProxy::mCDMCaps"), 269 mDistinctiveIdentifierRequired(aDistinctiveIdentifierRequired), 270 mPersistentStateRequired(aPersistentStateRequired), 271 mMainThread(GetMainThreadSerialEventTarget()) { 272 MOZ_ASSERT(NS_IsMainThread()); 273 } 274 275 virtual ~CDMProxy() {} 276 277 // Helper to enforce that a raw pointer is only accessed on the main thread. 278 template <class Type> 279 class MainThreadOnlyRawPtr { 280 public: 281 explicit MainThreadOnlyRawPtr(Type* aPtr) : mPtr(aPtr) { 282 MOZ_ASSERT(NS_IsMainThread()); 283 } 284 285 bool IsNull() const { 286 MOZ_ASSERT(NS_IsMainThread()); 287 return !mPtr; 288 } 289 290 void Clear() { 291 MOZ_ASSERT(NS_IsMainThread()); 292 mPtr = nullptr; 293 } 294 295 Type* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { 296 MOZ_ASSERT(NS_IsMainThread()); 297 return mPtr; 298 } 299 300 private: 301 Type* mPtr; 302 }; 303 304 // Our reference back to the MediaKeys object. 305 // WARNING: This is a non-owning reference that is cleared by MediaKeys 306 // destructor. only use on main thread, and always nullcheck before using! 307 MainThreadOnlyRawPtr<dom::MediaKeys> mKeys; 308 309 const nsString mKeySystem; 310 311 // Onwer specified thread. e.g. Gecko Media Plugin thread. 312 // All interactions with the out-of-process EME plugin must come from this 313 // thread. 314 RefPtr<nsIThread> mOwnerThread; 315 316 nsCString mNodeId; 317 318 DataMutex<CDMCaps> mCapabilites; 319 320 const bool mDistinctiveIdentifierRequired; 321 const bool mPersistentStateRequired; 322 323 // The main thread associated with the root document. 324 const nsCOMPtr<nsISerialEventTarget> mMainThread; 325 }; 326 327 } // namespace mozilla 328 329 #endif // CDMProxy_h_