LCOV - code coverage report
Current view: top level - dom/media/eme - MediaKeys.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 309 0.3 %
Date: 2017-07-14 16:53:18 Functions: 2 41 4.9 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #include "mozilla/dom/MediaKeys.h"
       8             : #include "GMPCrashHelper.h"
       9             : #include "mozilla/dom/HTMLMediaElement.h"
      10             : #include "mozilla/dom/MediaKeysBinding.h"
      11             : #include "mozilla/dom/MediaKeyMessageEvent.h"
      12             : #include "mozilla/dom/MediaKeyError.h"
      13             : #include "mozilla/dom/MediaKeySession.h"
      14             : #include "mozilla/dom/DOMException.h"
      15             : #include "mozilla/dom/UnionTypes.h"
      16             : #include "mozilla/Telemetry.h"
      17             : #include "GMPCDMProxy.h"
      18             : #ifdef MOZ_WIDGET_ANDROID
      19             : #include "mozilla/MediaDrmCDMProxy.h"
      20             : #endif
      21             : #include "mozilla/EMEUtils.h"
      22             : #include "nsContentUtils.h"
      23             : #include "nsIScriptObjectPrincipal.h"
      24             : #include "nsContentTypeParser.h"
      25             : #ifdef MOZ_FMP4
      26             : #include "MP4Decoder.h"
      27             : #endif
      28             : #ifdef XP_WIN
      29             : #include "mozilla/WindowsVersion.h"
      30             : #endif
      31             : #include "nsContentCID.h"
      32             : #include "nsServiceManagerUtils.h"
      33             : #include "mozilla/dom/MediaKeySystemAccess.h"
      34             : #include "nsPrintfCString.h"
      35             : #include "ChromiumCDMProxy.h"
      36             : 
      37             : namespace mozilla {
      38             : 
      39             : namespace dom {
      40             : 
      41           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaKeys,
      42             :                                       mElement,
      43             :                                       mParent,
      44             :                                       mKeySessions,
      45             :                                       mPromises,
      46             :                                       mPendingSessions);
      47           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaKeys)
      48           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaKeys)
      49           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaKeys)
      50           0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
      51           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
      52           0 : NS_INTERFACE_MAP_END
      53             : 
      54           0 : MediaKeys::MediaKeys(nsPIDOMWindowInner* aParent,
      55             :                      const nsAString& aKeySystem,
      56           0 :                      const MediaKeySystemConfiguration& aConfig)
      57             :   : mParent(aParent)
      58             :   , mKeySystem(aKeySystem)
      59             :   , mCreatePromiseId(0)
      60           0 :   , mConfig(aConfig)
      61             : {
      62           0 :   EME_LOG("MediaKeys[%p] constructed keySystem=%s",
      63             :           this, NS_ConvertUTF16toUTF8(mKeySystem).get());
      64           0 : }
      65             : 
      66           0 : MediaKeys::~MediaKeys()
      67             : {
      68           0 :   Shutdown();
      69           0 :   EME_LOG("MediaKeys[%p] destroyed", this);
      70           0 : }
      71             : 
      72             : void
      73           0 : MediaKeys::Terminated()
      74             : {
      75           0 :   EME_LOG("MediaKeys[%p] CDM crashed unexpectedly", this);
      76             : 
      77           0 :   KeySessionHashMap keySessions;
      78             :   // Remove entries during iteration will screw it. Make a copy first.
      79           0 :   for (auto iter = mKeySessions.Iter(); !iter.Done(); iter.Next()) {
      80           0 :     RefPtr<MediaKeySession>& session = iter.Data();
      81           0 :     keySessions.Put(session->GetSessionId(), session);
      82             :   }
      83           0 :   for (auto iter = keySessions.Iter(); !iter.Done(); iter.Next()) {
      84           0 :     RefPtr<MediaKeySession>& session = iter.Data();
      85           0 :     session->OnClosed();
      86             :   }
      87           0 :   keySessions.Clear();
      88           0 :   MOZ_ASSERT(mKeySessions.Count() == 0);
      89             : 
      90             :   // Notify the element about that CDM has terminated.
      91           0 :   if (mElement) {
      92           0 :     mElement->DecodeError(NS_ERROR_DOM_MEDIA_CDM_ERR);
      93             :   }
      94             : 
      95           0 :   Shutdown();
      96           0 : }
      97             : 
      98             : void
      99           0 : MediaKeys::Shutdown()
     100             : {
     101           0 :   if (mProxy) {
     102           0 :     mProxy->Shutdown();
     103           0 :     mProxy = nullptr;
     104             :   }
     105             : 
     106           0 :   RefPtr<MediaKeys> kungFuDeathGrip = this;
     107             : 
     108           0 :   for (auto iter = mPromises.Iter(); !iter.Done(); iter.Next()) {
     109           0 :     RefPtr<dom::DetailedPromise>& promise = iter.Data();
     110           0 :     promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
     111           0 :                          NS_LITERAL_CSTRING("Promise still outstanding at MediaKeys shutdown"));
     112           0 :     Release();
     113             :   }
     114           0 :   mPromises.Clear();
     115           0 : }
     116             : 
     117             : nsPIDOMWindowInner*
     118           0 : MediaKeys::GetParentObject() const
     119             : {
     120           0 :   return mParent;
     121             : }
     122             : 
     123             : JSObject*
     124           0 : MediaKeys::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     125             : {
     126           0 :   return MediaKeysBinding::Wrap(aCx, this, aGivenProto);
     127             : }
     128             : 
     129             : void
     130           0 : MediaKeys::GetKeySystem(nsString& aOutKeySystem) const
     131             : {
     132           0 :   aOutKeySystem.Assign(mKeySystem);
     133           0 : }
     134             : 
     135             : already_AddRefed<DetailedPromise>
     136           0 : MediaKeys::SetServerCertificate(const ArrayBufferViewOrArrayBuffer& aCert, ErrorResult& aRv)
     137             : {
     138           0 :   RefPtr<DetailedPromise> promise(MakePromise(aRv,
     139           0 :     NS_LITERAL_CSTRING("MediaKeys.setServerCertificate")));
     140           0 :   if (aRv.Failed()) {
     141           0 :     return nullptr;
     142             :   }
     143             : 
     144           0 :   if (!mProxy) {
     145           0 :     NS_WARNING("Tried to use a MediaKeys without a CDM");
     146           0 :     promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
     147           0 :                          NS_LITERAL_CSTRING("Null CDM in MediaKeys.setServerCertificate()"));
     148           0 :     return promise.forget();
     149             :   }
     150             : 
     151           0 :   nsTArray<uint8_t> data;
     152           0 :   CopyArrayBufferViewOrArrayBufferData(aCert, data);
     153           0 :   if (data.IsEmpty()) {
     154           0 :     promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR,
     155           0 :       NS_LITERAL_CSTRING("Empty certificate passed to MediaKeys.setServerCertificate()"));
     156           0 :     return promise.forget();
     157             :   }
     158             : 
     159           0 :   mProxy->SetServerCertificate(StorePromise(promise), data);
     160           0 :   return promise.forget();
     161             : }
     162             : 
     163             : already_AddRefed<DetailedPromise>
     164           0 : MediaKeys::MakePromise(ErrorResult& aRv, const nsACString& aName)
     165             : {
     166           0 :   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
     167           0 :   if (!global) {
     168           0 :     NS_WARNING("Passed non-global to MediaKeys ctor!");
     169           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
     170           0 :     return nullptr;
     171             :   }
     172           0 :   return DetailedPromise::Create(global, aRv, aName);
     173             : }
     174             : 
     175             : PromiseId
     176           0 : MediaKeys::StorePromise(DetailedPromise* aPromise)
     177             : {
     178             :   static uint32_t sEMEPromiseCount = 1;
     179           0 :   MOZ_ASSERT(aPromise);
     180           0 :   uint32_t id = sEMEPromiseCount++;
     181             : 
     182           0 :   EME_LOG("MediaKeys[%p]::StorePromise() id=%d", this, id);
     183             : 
     184             :   // Keep MediaKeys alive for the lifetime of its promises. Any still-pending
     185             :   // promises are rejected in Shutdown().
     186           0 :   AddRef();
     187             : 
     188             : #ifdef DEBUG
     189             :   // We should not have already stored this promise!
     190           0 :   for (auto iter = mPromises.ConstIter(); !iter.Done(); iter.Next()) {
     191           0 :     MOZ_ASSERT(iter.Data() != aPromise);
     192             :   }
     193             : #endif
     194             : 
     195           0 :   mPromises.Put(id, aPromise);
     196           0 :   return id;
     197             : }
     198             : 
     199             : void
     200           0 : MediaKeys::ConnectPendingPromiseIdWithToken(PromiseId aId, uint32_t aToken)
     201             : {
     202             :   // Should only be called from MediaKeySession::GenerateRequest.
     203           0 :   mPromiseIdToken.Put(aId, aToken);
     204           0 :   EME_LOG("MediaKeys[%p]::ConnectPendingPromiseIdWithToken() id=%u => token(%u)",
     205             :           this, aId, aToken);
     206           0 : }
     207             : 
     208             : already_AddRefed<DetailedPromise>
     209           0 : MediaKeys::RetrievePromise(PromiseId aId)
     210             : {
     211           0 :   if (!mPromises.Contains(aId)) {
     212           0 :     NS_WARNING(nsPrintfCString("Tried to retrieve a non-existent promise id=%d", aId).get());
     213           0 :     return nullptr;
     214             :   }
     215           0 :   RefPtr<DetailedPromise> promise;
     216           0 :   mPromises.Remove(aId, getter_AddRefs(promise));
     217           0 :   Release();
     218           0 :   return promise.forget();
     219             : }
     220             : 
     221             : void
     222           0 : MediaKeys::RejectPromise(PromiseId aId, nsresult aExceptionCode,
     223             :                          const nsCString& aReason)
     224             : {
     225           0 :   EME_LOG("MediaKeys[%p]::RejectPromise(%d, 0x%" PRIx32 ")",
     226             :           this, aId, static_cast<uint32_t>(aExceptionCode));
     227             : 
     228           0 :   RefPtr<DetailedPromise> promise(RetrievePromise(aId));
     229           0 :   if (!promise) {
     230           0 :     return;
     231             :   }
     232             : 
     233             :   // This promise could be a createSession or loadSession promise,
     234             :   // so we might have a pending session waiting to be resolved into
     235             :   // the promise on success. We've been directed to reject to promise,
     236             :   // so we can throw away the corresponding session object.
     237           0 :   uint32_t token = 0;
     238           0 :   if (mPromiseIdToken.Get(aId, &token)) {
     239           0 :     MOZ_ASSERT(mPendingSessions.Contains(token));
     240           0 :     mPendingSessions.Remove(token);
     241           0 :     mPromiseIdToken.Remove(aId);
     242             :   }
     243             : 
     244           0 :   MOZ_ASSERT(NS_FAILED(aExceptionCode));
     245           0 :   promise->MaybeReject(aExceptionCode, aReason);
     246             : 
     247           0 :   if (mCreatePromiseId == aId) {
     248             :     // Note: This will probably destroy the MediaKeys object!
     249           0 :     Release();
     250             :   }
     251             : }
     252             : 
     253             : void
     254           0 : MediaKeys::OnSessionIdReady(MediaKeySession* aSession)
     255             : {
     256           0 :   if (!aSession) {
     257           0 :     NS_WARNING("Invalid MediaKeySession passed to OnSessionIdReady()");
     258           0 :     return;
     259             :   }
     260           0 :   if (mKeySessions.Contains(aSession->GetSessionId())) {
     261           0 :     NS_WARNING("MediaKeySession's made ready multiple times!");
     262           0 :     return;
     263             :   }
     264           0 :   if (mPendingSessions.Contains(aSession->Token())) {
     265           0 :     NS_WARNING("MediaKeySession made ready when it wasn't waiting to be ready!");
     266           0 :     return;
     267             :   }
     268           0 :   if (aSession->GetSessionId().IsEmpty()) {
     269           0 :     NS_WARNING("MediaKeySession with invalid sessionId passed to OnSessionIdReady()");
     270           0 :     return;
     271             :   }
     272           0 :   mKeySessions.Put(aSession->GetSessionId(), aSession);
     273             : }
     274             : 
     275             : void
     276           0 : MediaKeys::ResolvePromise(PromiseId aId)
     277             : {
     278           0 :   EME_LOG("MediaKeys[%p]::ResolvePromise(%d)", this, aId);
     279             : 
     280           0 :   RefPtr<DetailedPromise> promise(RetrievePromise(aId));
     281           0 :   MOZ_ASSERT(!mPromises.Contains(aId));
     282           0 :   if (!promise) {
     283           0 :     return;
     284             :   }
     285             : 
     286           0 :   uint32_t token = 0;
     287           0 :   if (!mPromiseIdToken.Get(aId, &token)) {
     288           0 :     promise->MaybeResolveWithUndefined();
     289           0 :     return;
     290           0 :   } else if (!mPendingSessions.Contains(token)) {
     291             :     // Pending session for CreateSession() should be removed when sessionId
     292             :     // is ready.
     293           0 :     promise->MaybeResolveWithUndefined();
     294           0 :     mPromiseIdToken.Remove(aId);
     295           0 :     return;
     296             :   }
     297           0 :   mPromiseIdToken.Remove(aId);
     298             : 
     299             :   // We should only resolve LoadSession calls via this path,
     300             :   // not CreateSession() promises.
     301           0 :   RefPtr<MediaKeySession> session;
     302           0 :   mPendingSessions.Remove(token, getter_AddRefs(session));
     303           0 :   if (!session || session->GetSessionId().IsEmpty()) {
     304           0 :     NS_WARNING("Received activation for non-existent session!");
     305           0 :     promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR,
     306           0 :                          NS_LITERAL_CSTRING("CDM LoadSession() returned a different session ID than requested"));
     307           0 :     return;
     308             :   }
     309           0 :   mKeySessions.Put(session->GetSessionId(), session);
     310           0 :   promise->MaybeResolve(session);
     311             : }
     312             : 
     313           0 : class MediaKeysGMPCrashHelper : public GMPCrashHelper
     314             : {
     315             : public:
     316           0 :   explicit MediaKeysGMPCrashHelper(MediaKeys* aMediaKeys)
     317           0 :     : mMediaKeys(aMediaKeys)
     318             :   {
     319           0 :     MOZ_ASSERT(NS_IsMainThread()); // WeakPtr isn't thread safe.
     320           0 :   }
     321             :   already_AddRefed<nsPIDOMWindowInner>
     322           0 :   GetPluginCrashedEventTarget() override
     323             :   {
     324           0 :     MOZ_ASSERT(NS_IsMainThread()); // WeakPtr isn't thread safe.
     325           0 :     EME_LOG("MediaKeysGMPCrashHelper::GetPluginCrashedEventTarget()");
     326           0 :     return (mMediaKeys && mMediaKeys->GetParentObject()) ?
     327           0 :       do_AddRef(mMediaKeys->GetParentObject()) : nullptr;
     328             :   }
     329             : private:
     330             :   WeakPtr<MediaKeys> mMediaKeys;
     331             : };
     332             : 
     333             : already_AddRefed<CDMProxy>
     334           0 : MediaKeys::CreateCDMProxy(nsIEventTarget* aMainThread)
     335             : {
     336           0 :   RefPtr<CDMProxy> proxy;
     337             : #ifdef MOZ_WIDGET_ANDROID
     338             :   if (IsWidevineKeySystem(mKeySystem)) {
     339             :     proxy = new MediaDrmCDMProxy(this,
     340             :                                  mKeySystem,
     341             :                                  mConfig.mDistinctiveIdentifier == MediaKeysRequirement::Required,
     342             :                                  mConfig.mPersistentState == MediaKeysRequirement::Required,
     343             :                                  aMainThread);
     344             :   } else
     345             : #endif
     346             :   {
     347           0 :     if (MediaPrefs::EMEChromiumAPIEnabled()) {
     348             :       proxy = new ChromiumCDMProxy(
     349             :         this,
     350             :         mKeySystem,
     351           0 :         new MediaKeysGMPCrashHelper(this),
     352           0 :         mConfig.mDistinctiveIdentifier == MediaKeysRequirement::Required,
     353           0 :         mConfig.mPersistentState == MediaKeysRequirement::Required,
     354           0 :         aMainThread);
     355             :     } else {
     356             :       proxy = new GMPCDMProxy(
     357             :         this,
     358             :         mKeySystem,
     359           0 :         new MediaKeysGMPCrashHelper(this),
     360           0 :         mConfig.mDistinctiveIdentifier == MediaKeysRequirement::Required,
     361           0 :         mConfig.mPersistentState == MediaKeysRequirement::Required,
     362           0 :         aMainThread);
     363             :     }
     364             :   }
     365           0 :   return proxy.forget();
     366             : }
     367             : 
     368             : already_AddRefed<DetailedPromise>
     369           0 : MediaKeys::Init(ErrorResult& aRv)
     370             : {
     371           0 :   RefPtr<DetailedPromise> promise(MakePromise(aRv,
     372           0 :     NS_LITERAL_CSTRING("MediaKeys::Init()")));
     373           0 :   if (aRv.Failed()) {
     374           0 :     return nullptr;
     375             :   }
     376             : 
     377             :   // Determine principal (at creation time) of the MediaKeys object.
     378           0 :   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(GetParentObject());
     379           0 :   if (!sop) {
     380           0 :     promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
     381           0 :                          NS_LITERAL_CSTRING("Couldn't get script principal in MediaKeys::Init"));
     382           0 :     return promise.forget();
     383             :   }
     384           0 :   mPrincipal = sop->GetPrincipal();
     385             : 
     386             :   // Determine principal of the "top-level" window; the principal of the
     387             :   // page that will display in the URL bar.
     388           0 :   nsCOMPtr<nsPIDOMWindowInner> window = GetParentObject();
     389           0 :   if (!window) {
     390           0 :     promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
     391           0 :                          NS_LITERAL_CSTRING("Couldn't get top-level window in MediaKeys::Init"));
     392           0 :     return promise.forget();
     393             :   }
     394           0 :   nsCOMPtr<nsPIDOMWindowOuter> top = window->GetOuterWindow()->GetTop();
     395           0 :   if (!top || !top->GetExtantDoc()) {
     396           0 :     promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
     397           0 :                          NS_LITERAL_CSTRING("Couldn't get document in MediaKeys::Init"));
     398           0 :     return promise.forget();
     399             :   }
     400             : 
     401           0 :   mTopLevelPrincipal = top->GetExtantDoc()->NodePrincipal();
     402             : 
     403           0 :   if (!mPrincipal || !mTopLevelPrincipal) {
     404           0 :     NS_WARNING("Failed to get principals when creating MediaKeys");
     405           0 :     promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
     406           0 :                          NS_LITERAL_CSTRING("Couldn't get principal(s) in MediaKeys::Init"));
     407           0 :     return promise.forget();
     408             :   }
     409             : 
     410           0 :   nsAutoCString origin;
     411           0 :   nsresult rv = mPrincipal->GetOrigin(origin);
     412           0 :   if (NS_FAILED(rv)) {
     413           0 :     promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
     414           0 :                          NS_LITERAL_CSTRING("Couldn't get principal origin string in MediaKeys::Init"));
     415           0 :     return promise.forget();
     416             :   }
     417           0 :   nsAutoCString topLevelOrigin;
     418           0 :   rv = mTopLevelPrincipal->GetOrigin(topLevelOrigin);
     419           0 :   if (NS_FAILED(rv)) {
     420           0 :     promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
     421           0 :                          NS_LITERAL_CSTRING("Couldn't get top-level principal origin string in MediaKeys::Init"));
     422           0 :     return promise.forget();
     423             :   }
     424             : 
     425           0 :   EME_LOG("MediaKeys[%p]::Create() (%s, %s)",
     426             :           this,
     427             :           origin.get(),
     428             :           topLevelOrigin.get());
     429             : 
     430           0 :   mProxy = CreateCDMProxy(top->GetExtantDoc()->EventTargetFor(TaskCategory::Other));
     431             : 
     432             :   // The CDMProxy's initialization is asynchronous. The MediaKeys is
     433             :   // refcounted, and its instance is returned to JS by promise once
     434             :   // it's been initialized. No external refs exist to the MediaKeys while
     435             :   // we're waiting for the promise to be resolved, so we must hold a
     436             :   // reference to the new MediaKeys object until it's been created,
     437             :   // or its creation has failed. Store the id of the promise returned
     438             :   // here, and hold a self-reference until that promise is resolved or
     439             :   // rejected.
     440           0 :   MOZ_ASSERT(!mCreatePromiseId, "Should only be created once!");
     441           0 :   mCreatePromiseId = StorePromise(promise);
     442           0 :   AddRef();
     443           0 :   mProxy->Init(mCreatePromiseId,
     444           0 :                NS_ConvertUTF8toUTF16(origin),
     445           0 :                NS_ConvertUTF8toUTF16(topLevelOrigin),
     446           0 :                KeySystemToGMPName(mKeySystem));
     447             : 
     448           0 :   return promise.forget();
     449             : }
     450             : 
     451             : void
     452           0 : MediaKeys::OnCDMCreated(PromiseId aId, const uint32_t aPluginId)
     453             : {
     454           0 :   RefPtr<DetailedPromise> promise(RetrievePromise(aId));
     455           0 :   if (!promise) {
     456           0 :     return;
     457             :   }
     458           0 :   RefPtr<MediaKeys> keys(this);
     459           0 :   EME_LOG("MediaKeys[%p]::OnCDMCreated() resolve promise id=%d", this, aId);
     460           0 :   promise->MaybeResolve(keys);
     461           0 :   if (mCreatePromiseId == aId) {
     462           0 :     Release();
     463             :   }
     464             : 
     465           0 :   MediaKeySystemAccess::NotifyObservers(mParent,
     466             :                                         mKeySystem,
     467           0 :                                         MediaKeySystemStatus::Cdm_created);
     468             : 
     469           0 :   Telemetry::Accumulate(Telemetry::VIDEO_CDM_CREATED, ToCDMTypeTelemetryEnum(mKeySystem));
     470             : }
     471             : 
     472             : static bool
     473           0 : IsSessionTypeSupported(const MediaKeySessionType aSessionType,
     474             :                        const MediaKeySystemConfiguration& aConfig)
     475             : {
     476           0 :   if (aSessionType == MediaKeySessionType::Temporary) {
     477             :     // Temporary is always supported.
     478           0 :     return true;
     479             :   }
     480           0 :   if (!aConfig.mSessionTypes.WasPassed()) {
     481             :     // No other session types supported.
     482           0 :     return false;
     483             :   }
     484           0 :   return aConfig.mSessionTypes.Value().Contains(ToString(aSessionType));
     485             : }
     486             : 
     487             : already_AddRefed<MediaKeySession>
     488           0 : MediaKeys::CreateSession(JSContext* aCx,
     489             :                          MediaKeySessionType aSessionType,
     490             :                          ErrorResult& aRv)
     491             : {
     492           0 :   if (!IsSessionTypeSupported(aSessionType, mConfig)) {
     493           0 :     EME_LOG("MediaKeys[%p] CreateSession() failed, unsupported session type", this);
     494           0 :     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     495           0 :     return nullptr;
     496             :   }
     497             : 
     498           0 :   if (!mProxy) {
     499           0 :     NS_WARNING("Tried to use a MediaKeys which lost its CDM");
     500           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     501           0 :     return nullptr;
     502             :   }
     503             : 
     504           0 :   EME_LOG("MediaKeys[%p] Creating session", this);
     505             : 
     506             :   RefPtr<MediaKeySession> session = new MediaKeySession(aCx,
     507           0 :                                                         GetParentObject(),
     508             :                                                         this,
     509             :                                                         mKeySystem,
     510             :                                                         aSessionType,
     511           0 :                                                         aRv);
     512             : 
     513           0 :   if (aRv.Failed()) {
     514           0 :     return nullptr;
     515             :   }
     516             : 
     517             :   // Add session to the set of sessions awaiting their sessionId being ready.
     518           0 :   mPendingSessions.Put(session->Token(), session);
     519             : 
     520           0 :   return session.forget();
     521             : }
     522             : 
     523             : void
     524           0 : MediaKeys::OnSessionLoaded(PromiseId aId, bool aSuccess)
     525             : {
     526           0 :   RefPtr<DetailedPromise> promise(RetrievePromise(aId));
     527           0 :   if (!promise) {
     528           0 :     return;
     529             :   }
     530           0 :   EME_LOG("MediaKeys[%p]::OnSessionLoaded() resolve promise id=%d", this, aId);
     531             : 
     532           0 :   promise->MaybeResolve(aSuccess);
     533             : }
     534             : 
     535             : void
     536           0 : MediaKeys::OnSessionClosed(MediaKeySession* aSession)
     537             : {
     538           0 :   nsAutoString id;
     539           0 :   aSession->GetSessionId(id);
     540           0 :   mKeySessions.Remove(id);
     541           0 : }
     542             : 
     543             : already_AddRefed<MediaKeySession>
     544           0 : MediaKeys::GetSession(const nsAString& aSessionId)
     545             : {
     546           0 :   RefPtr<MediaKeySession> session;
     547           0 :   mKeySessions.Get(aSessionId, getter_AddRefs(session));
     548           0 :   return session.forget();
     549             : }
     550             : 
     551             : already_AddRefed<MediaKeySession>
     552           0 : MediaKeys::GetPendingSession(uint32_t aToken)
     553             : {
     554           0 :   RefPtr<MediaKeySession> session;
     555           0 :   mPendingSessions.Get(aToken, getter_AddRefs(session));
     556           0 :   mPendingSessions.Remove(aToken);
     557           0 :   return session.forget();
     558             : }
     559             : 
     560             : bool
     561           0 : MediaKeys::IsBoundToMediaElement() const
     562             : {
     563           0 :   MOZ_ASSERT(NS_IsMainThread());
     564           0 :   return mElement != nullptr;
     565             : }
     566             : 
     567             : nsresult
     568           0 : MediaKeys::Bind(HTMLMediaElement* aElement)
     569             : {
     570           0 :   MOZ_ASSERT(NS_IsMainThread());
     571           0 :   if (IsBoundToMediaElement()) {
     572           0 :     return NS_ERROR_FAILURE;
     573             :   }
     574             : 
     575           0 :   mElement = aElement;
     576             : 
     577           0 :   return NS_OK;
     578             : }
     579             : 
     580             : void
     581           0 : MediaKeys::Unbind()
     582             : {
     583           0 :   MOZ_ASSERT(NS_IsMainThread());
     584           0 :   mElement = nullptr;
     585           0 : }
     586             : 
     587             : void
     588           0 : MediaKeys::GetSessionsInfo(nsString& sessionsInfo)
     589             : {
     590           0 :   for (KeySessionHashMap::Iterator it = mKeySessions.Iter();
     591           0 :        !it.Done();
     592           0 :        it.Next()) {
     593           0 :     MediaKeySession* keySession = it.Data();
     594           0 :     nsString sessionID;
     595           0 :     keySession->GetSessionId(sessionID);
     596           0 :     sessionsInfo.AppendLiteral("(sid=");
     597           0 :     sessionsInfo.Append(sessionID);
     598           0 :     MediaKeyStatusMap* keyStatusMap = keySession->KeyStatuses();
     599           0 :     for (uint32_t i = 0; i < keyStatusMap->GetIterableLength(); i++) {
     600           0 :       nsString keyID = keyStatusMap->GetKeyIDAsHexString(i);
     601           0 :       sessionsInfo.AppendLiteral("(kid=");
     602           0 :       sessionsInfo.Append(keyID);
     603             :       using IntegerType = typename std::underlying_type<MediaKeyStatus>::type;
     604           0 :       auto idx = static_cast<IntegerType>(keyStatusMap->GetValueAtIndex(i));
     605           0 :       const char* keyStatus = MediaKeyStatusValues::strings[idx].value;
     606           0 :       sessionsInfo.AppendLiteral(" status=");
     607           0 :       sessionsInfo.Append(
     608           0 :         NS_ConvertUTF8toUTF16((nsDependentCString(keyStatus))));
     609           0 :       sessionsInfo.AppendLiteral(")");
     610             :     }
     611           0 :     sessionsInfo.AppendLiteral(")");
     612             :   }
     613           0 : }
     614             : 
     615             : } // namespace dom
     616           9 : } // namespace mozilla

Generated by: LCOV version 1.13