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 102 // Main thread only. 103 // Uses the CDM to create a key session. 104 // Calls MediaKeys::OnSessionActivated() when session is created. 105 // Assumes ownership of (std::move()s) aInitData's contents. 106 virtual void CreateSession(uint32_t aCreateSessionToken, 107 MediaKeySessionType aSessionType, 108 PromiseId aPromiseId, 109 const nsAString& aInitDataType, 110 nsTArray<uint8_t>& aInitData) = 0; 111 112 // Main thread only. 113 // Uses the CDM to load a presistent session stored on disk. 114 // Calls MediaKeys::OnSessionActivated() when session is loaded. 115 virtual void LoadSession(PromiseId aPromiseId, 116 dom::MediaKeySessionType aSessionType, 117 const nsAString& aSessionId) = 0; 118 119 // Main thread only. 120 // Sends a new certificate to the CDM. 121 // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has 122 // processed the request. 123 // Assumes ownership of (std::move()s) aCert's contents. 124 virtual void SetServerCertificate(PromiseId aPromiseId, 125 nsTArray<uint8_t>& aCert) = 0; 126 127 // Main thread only. 128 // Sends an update to the CDM. 129 // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has 130 // processed the request. 131 // Assumes ownership of (std::move()s) aResponse's contents. 132 virtual void UpdateSession(const nsAString& aSessionId, PromiseId aPromiseId, 133 nsTArray<uint8_t>& aResponse) = 0; 134 135 // Main thread only. 136 // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has 137 // processed the request. 138 // If processing this operation results in the session actually closing, 139 // we also call MediaKeySession::OnClosed(), which in turn calls 140 // MediaKeys::OnSessionClosed(). 141 virtual void CloseSession(const nsAString& aSessionId, 142 PromiseId aPromiseId) = 0; 143 144 // Main thread only. 145 // Removes all data for a persisent session. 146 // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has 147 // processed the request. 148 virtual void RemoveSession(const nsAString& aSessionId, 149 PromiseId aPromiseId) = 0; 150 151 // Main thread only. 152 // Called to signal a request for output protection information from the CDM. 153 // This should forward the call up the stack where the query should be 154 // performed and then responded to via `NotifyOutputProtectionStatus`. 155 virtual void QueryOutputProtectionStatus() = 0; 156 157 // NotifyOutputProtectionStatus enums. Explicit values are specified to make 158 // it easy to match values in logs. 159 enum class OutputProtectionCheckStatus : uint8_t { 160 CheckFailed = 0, 161 CheckSuccessful = 1, 162 }; 163 164 enum class OutputProtectionCaptureStatus : uint8_t { 165 CapturePossilbe = 0, 166 CaptureNotPossible = 1, 167 Unused = 2, 168 }; 169 // End NotifyOutputProtectionStatus enums 170 171 // Main thread only. 172 // Notifies this proxy of the protection status for the media the CDM is 173 // associated with. This can be called in response to 174 // `QueryOutputProtectionStatus`, but can also be called without an 175 // associated query. In both cases the information will be forwarded to 176 // the CDM host machinery and used to handle requests from the CDM. 177 // @param aCheckStatus did the check succeed or not. 178 // @param aCaptureStatus if the check succeeded, this reflects if capture 179 // of media could take place. This doesn't mean capture is taking place. 180 // Callers should be conservative with this value such that it's okay to pass 181 // CapturePossilbe even if capture is not happening, but should never pass 182 // CaptureNotPossible if it could happen. If the check failed, this value is 183 // not used, and callers should pass Unused to indicate this. 184 virtual void NotifyOutputProtectionStatus( 185 OutputProtectionCheckStatus aCheckStatus, 186 OutputProtectionCaptureStatus aCaptureStatus) = 0; 187 188 // Main thread only. 189 virtual void Shutdown() = 0; 190 191 // Main thread only. 192 virtual void Terminated() = 0; 193 194 // Threadsafe. 195 virtual const nsCString& GetNodeId() const = 0; 196 197 // Main thread only. 198 virtual void OnSetSessionId(uint32_t aCreateSessionToken, 199 const nsAString& aSessionId) = 0; 200 201 // Main thread only. 202 virtual void OnResolveLoadSessionPromise(uint32_t aPromiseId, 203 bool aSuccess) = 0; 204 205 // Main thread only. 206 virtual void OnSessionMessage(const nsAString& aSessionId, 207 dom::MediaKeyMessageType aMessageType, 208 const nsTArray<uint8_t>& aMessage) = 0; 209 210 // Main thread only. 211 virtual void OnExpirationChange(const nsAString& aSessionId, 212 UnixTime aExpiryTime) = 0; 213 214 // Main thread only. 215 virtual void OnSessionClosed(const nsAString& aSessionId) = 0; 216 217 // Main thread only. 218 virtual void OnSessionError(const nsAString& aSessionId, nsresult aException, 219 uint32_t aSystemCode, const nsAString& aMsg) = 0; 220 221 // Main thread only. 222 virtual void OnRejectPromise(uint32_t aPromiseId, ErrorResult&& aException, 223 const nsCString& aMsg) = 0; 224 225 virtual RefPtr<DecryptPromise> Decrypt(MediaRawData* aSample) = 0; 226 227 // Owner thread only. 228 virtual void OnDecrypted(uint32_t aId, DecryptStatus aResult, 229 const nsTArray<uint8_t>& aDecryptedData) = 0; 230 231 // Reject promise with the given ErrorResult. 232 // 233 // Can be called from any thread. 234 virtual void RejectPromise(PromiseId aId, ErrorResult&& aException, 235 const nsCString& aReason) = 0; 236 237 // Resolves promise with "undefined". 238 // Can be called from any thread. 239 virtual void ResolvePromise(PromiseId aId) = 0; 240 241 // Threadsafe. 242 virtual const nsString& KeySystem() const = 0; 243 244 virtual DataMutex<CDMCaps>& Capabilites() = 0; 245 246 // Main thread only. 247 virtual void OnKeyStatusesChange(const nsAString& aSessionId) = 0; 248 249 // Main thread only. 250 // Calls MediaKeys->ResolvePromiseWithKeyStatus(aPromiseId, aKeyStatus) after 251 // the CDM has processed the request. 252 virtual void GetStatusForPolicy(PromiseId aPromiseId, 253 const nsAString& aMinHdcpVersion) = 0; 254 255 #ifdef DEBUG 256 virtual bool IsOnOwnerThread() = 0; 257 #endif 258 AsChromiumCDMProxy()259 virtual ChromiumCDMProxy* AsChromiumCDMProxy() { return nullptr; } 260 261 protected: ~CDMProxy()262 virtual ~CDMProxy() {} 263 264 // Helper to enforce that a raw pointer is only accessed on the main thread. 265 template <class Type> 266 class MainThreadOnlyRawPtr { 267 public: MainThreadOnlyRawPtr(Type * aPtr)268 explicit MainThreadOnlyRawPtr(Type* aPtr) : mPtr(aPtr) { 269 MOZ_ASSERT(NS_IsMainThread()); 270 } 271 IsNull()272 bool IsNull() const { 273 MOZ_ASSERT(NS_IsMainThread()); 274 return !mPtr; 275 } 276 Clear()277 void Clear() { 278 MOZ_ASSERT(NS_IsMainThread()); 279 mPtr = nullptr; 280 } 281 282 Type* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { 283 MOZ_ASSERT(NS_IsMainThread()); 284 return mPtr; 285 } 286 287 private: 288 Type* mPtr; 289 }; 290 291 // Our reference back to the MediaKeys object. 292 // WARNING: This is a non-owning reference that is cleared by MediaKeys 293 // destructor. only use on main thread, and always nullcheck before using! 294 MainThreadOnlyRawPtr<dom::MediaKeys> mKeys; 295 296 const nsString mKeySystem; 297 298 // Onwer specified thread. e.g. Gecko Media Plugin thread. 299 // All interactions with the out-of-process EME plugin must come from this 300 // thread. 301 RefPtr<nsIThread> mOwnerThread; 302 303 nsCString mNodeId; 304 305 DataMutex<CDMCaps> mCapabilites; 306 307 const bool mDistinctiveIdentifierRequired; 308 const bool mPersistentStateRequired; 309 310 // The main thread associated with the root document. 311 const nsCOMPtr<nsISerialEventTarget> mMainThread; 312 }; 313 314 } // namespace mozilla 315 316 #endif // CDMProxy_h_ 317