MediaKeys.h (9223B)
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 mozilla_dom_mediakeys_h__ 8 #define mozilla_dom_mediakeys_h__ 9 10 #include "DecoderDoctorLogger.h" 11 #include "mozilla/DetailedPromise.h" 12 #include "mozilla/RefPtr.h" 13 #include "mozilla/WeakPtr.h" 14 #include "mozilla/dom/MediaKeyStatusMapBinding.h" // For MediaKeyStatus 15 #include "mozilla/dom/MediaKeySystemAccessBinding.h" 16 #include "mozilla/dom/MediaKeysBinding.h" 17 #include "mozilla/dom/Promise.h" 18 #include "nsCOMPtr.h" 19 #include "nsCycleCollectionParticipant.h" 20 #include "nsIObserver.h" 21 #include "nsRefPtrHashtable.h" 22 #include "nsTHashMap.h" 23 #include "nsWrapperCache.h" 24 25 namespace mozilla { 26 27 class CDMProxy; 28 29 namespace dom { 30 class MediaKeys; 31 } // namespace dom 32 DDLoggedTypeName(dom::MediaKeys); 33 34 namespace dom { 35 36 class ArrayBufferViewOrArrayBuffer; 37 class MediaKeySession; 38 struct MediaKeysPolicy; 39 class HTMLMediaElement; 40 41 typedef nsRefPtrHashtable<nsStringHashKey, MediaKeySession> KeySessionHashMap; 42 typedef nsRefPtrHashtable<nsUint32HashKey, dom::DetailedPromise> PromiseHashMap; 43 typedef nsRefPtrHashtable<nsUint32HashKey, MediaKeySession> 44 PendingKeySessionsHashMap; 45 typedef nsTHashMap<nsUint32HashKey, uint32_t> PendingPromiseIdTokenHashMap; 46 typedef uint32_t PromiseId; 47 48 // This class is used on the main thread only. 49 // Note: its addref/release is not (and can't be) thread safe! 50 class MediaKeys final : public nsIObserver, 51 public nsWrapperCache, 52 public SupportsWeakPtr, 53 public DecoderDoctorLifeLogger<MediaKeys> { 54 ~MediaKeys(); 55 56 public: 57 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 58 NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(MediaKeys) 59 60 NS_DECL_NSIOBSERVER 61 62 MediaKeys(nsPIDOMWindowInner* aParentWindow, const nsAString& aKeySystem, 63 const MediaKeySystemConfiguration& aConfig); 64 65 already_AddRefed<DetailedPromise> Init(ErrorResult& aRv); 66 67 nsPIDOMWindowInner* GetParentObject() const; 68 69 JSObject* WrapObject(JSContext* aCx, 70 JS::Handle<JSObject*> aGivenProto) override; 71 72 nsresult Bind(HTMLMediaElement* aElement); 73 void Unbind(); 74 75 // Checks if there's any activity happening that could capture the media 76 // the keys are associated with and then expose that media outside of the 77 // origin it is in. 78 // 79 // This method does not return the results of the check, but the MediaKeys 80 // will notify mProxy of the results using `NotifyOutputProtectionStatus`. 81 void CheckIsElementCapturePossible(); 82 83 // Javascript: readonly attribute DOMString keySystem; 84 void GetKeySystem(nsString& retval) const; 85 86 // JavaScript: MediaKeys.createSession() 87 already_AddRefed<MediaKeySession> CreateSession( 88 MediaKeySessionType aSessionType, ErrorResult& aRv); 89 90 // JavaScript: MediaKeys.SetServerCertificate() 91 already_AddRefed<DetailedPromise> SetServerCertificate( 92 const ArrayBufferViewOrArrayBuffer& aServerCertificate, ErrorResult& aRv); 93 94 already_AddRefed<MediaKeySession> GetSession(const nsAString& aSessionId); 95 96 // Removes and returns MediaKeySession from the set of sessions awaiting 97 // their sessionId to be assigned. 98 already_AddRefed<MediaKeySession> GetPendingSession(uint32_t aToken); 99 100 // Called once a Init() operation succeeds. 101 void OnCDMCreated(PromiseId aId, const uint32_t aPluginId); 102 103 // Called once the CDM generates a sessionId while servicing a 104 // MediaKeySession.generateRequest() or MediaKeySession.load() call, 105 // once the sessionId of a MediaKeySession is known. 106 void OnSessionIdReady(MediaKeySession* aSession); 107 108 // Called once a LoadSession succeeds. 109 void OnSessionLoaded(PromiseId aId, bool aSuccess); 110 111 // Called once a session has closed. 112 void OnSessionClosed(MediaKeySession* aSession); 113 114 CDMProxy* GetCDMProxy() { return mProxy; } 115 116 // Makes a new promise, or nullptr on failure. 117 already_AddRefed<DetailedPromise> MakePromise(ErrorResult& aRv, 118 const nsACString& aName); 119 // Stores promise in mPromises, returning an ID that can be used to retrieve 120 // it later. The ID is passed to the CDM, so that it can signal specific 121 // promises to be resolved. 122 PromiseId StorePromise(DetailedPromise* aPromise); 123 124 // Stores a map from promise id to pending session token. Using this 125 // mapping, when a promise is rejected via its ID, we can check if the 126 // promise corresponds to a pending session and retrieve that session 127 // via the mapped-to token, and remove the pending session from the 128 // list of sessions awaiting a session id. 129 void ConnectPendingPromiseIdWithToken(PromiseId aId, uint32_t aToken); 130 131 // Reject promise with the given exception. 132 void RejectPromise(PromiseId aId, ErrorResult&& aException, 133 const nsCString& aReason); 134 // Resolves promise with "undefined". 135 void ResolvePromise(PromiseId aId); 136 137 void Shutdown(); 138 139 // Called by CDMProxy when CDM crashes or shuts down. It is different from 140 // Shutdown which is called from the script/dom side. 141 void Terminated(); 142 143 // Returns true if this MediaKeys has been bound to a media element. 144 bool IsBoundToMediaElement() const; 145 146 // Indicates to a MediaKeys instance that the inner window parent of that 147 // instance is being destroyed, this should prompt the keys to shutdown. 148 void OnInnerWindowDestroy(); 149 150 void GetSessionsInfo(nsString& sessionsInfo); 151 152 // JavaScript: MediaKeys.GetStatusForPolicy() 153 already_AddRefed<Promise> GetStatusForPolicy(const MediaKeysPolicy& aPolicy, 154 ErrorResult& aR); 155 // Called by CDMProxy when CDM successfully GetStatusForPolicy. 156 void ResolvePromiseWithKeyStatus(PromiseId aId, 157 dom::MediaKeyStatus aMediaKeyStatus); 158 159 template <typename T> 160 void ResolvePromiseWithResult(PromiseId aId, const T& aResult) { 161 RefPtr<DetailedPromise> promise(RetrievePromise(aId)); 162 if (!promise) { 163 return; 164 } 165 promise->MaybeResolve(aResult); 166 } 167 168 // The topic used for requests related to mediakeys -- observe this to be 169 // notified of such requests. 170 constexpr static const char* kMediaKeysRequestTopic = "mediakeys-request"; 171 172 nsCString GetMediaKeySystemConfigurationString() const; 173 174 private: 175 // Instantiate CDMProxy instance. 176 // It could be MediaDrmCDMProxy (Widevine on Fennec) or ChromiumCDMProxy (the 177 // rest). 178 already_AddRefed<CDMProxy> CreateCDMProxy(); 179 180 // Removes promise from mPromises, and returns it. 181 already_AddRefed<DetailedPromise> RetrievePromise(PromiseId aId); 182 183 // Helpers to connect and disconnect to the parent inner window. An inner 184 // window should track (via weak ptr) MediaKeys created within it so we can 185 // ensure MediaKeys are shutdown if that window is destroyed. 186 void ConnectInnerWindow(); 187 void DisconnectInnerWindow(); 188 189 // Owning ref to proxy. The proxy has a weak reference back to the MediaKeys, 190 // and the MediaKeys destructor clears the proxy's reference to the MediaKeys. 191 RefPtr<CDMProxy> mProxy; 192 193 // The HTMLMediaElement the MediaKeys are associated with. Note that a 194 // MediaKeys instance may not be associated with any HTMLMediaElement so 195 // this can be null (we also cannot rely on a media element to drive shutdown 196 // for this reason). 197 RefPtr<HTMLMediaElement> mElement; 198 199 // The inner window associated with an instance of MediaKeys. We will 200 // shutdown the media keys when this Window is destroyed. We do this from the 201 // window rather than a document to address the case where media keys can be 202 // created in an about:blank document that then performs an async load -- this 203 // recreates the document, but the inner window is preserved in such a case. 204 // See https://bugzilla.mozilla.org/show_bug.cgi?id=1675360 for more info. 205 nsCOMPtr<nsPIDOMWindowInner> mParent; 206 const nsString mKeySystem; 207 KeySessionHashMap mKeySessions; 208 PromiseHashMap mPromises; 209 PendingKeySessionsHashMap mPendingSessions; 210 PromiseId mCreatePromiseId; 211 212 // The principal of the relevant settings object. 213 RefPtr<nsIPrincipal> mPrincipal; 214 // The principal of the top level page. This can differ from mPrincipal if 215 // we're in an iframe. 216 RefPtr<nsIPrincipal> mTopLevelPrincipal; 217 218 const MediaKeySystemConfiguration mConfig; 219 220 PendingPromiseIdTokenHashMap mPromiseIdToken; 221 222 // The topic a MediaKeys instance will observe to receive updates from 223 // EncryptedMediaChild. 224 constexpr static const char* kMediaKeysResponseTopic = "mediakeys-response"; 225 // Tracks if we've added an observer for responses from the associated 226 // EncryptedMediaChild. When true an observer is already in place, otherwise 227 // the observer has not yet been added. 228 bool mObserverAdded = false; 229 // Stores the json request we will send to EncryptedMediaChild when querying 230 // output protection. Lazily populated upon first use. 231 nsString mCaptureCheckRequestJson; 232 }; 233 234 } // namespace dom 235 } // namespace mozilla 236 237 #endif // mozilla_dom_mediakeys_h__