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