Skip to content
Permalink
Browse files
[EME] Keep MediaKeySystemAccess alive in createMediaKeys() async task
https://bugs.webkit.org/show_bug.cgi?id=247490

Reviewed by Philippe Normand.

Put MediaKeySystemAccess under ActiveDOMObject interface
and make sure that GC won't destroy an object before
it executes its async task and createMediaKeys() func is completed.

Sometimes it happens that GC destroys MediaKeySystemAccess object
in the middle of createMediaKeys() func, before promise is completed
and JS MediaKeys are never created.

This fixes YT Cert Test: EME, WidevineH264MultiMediaKeySessions

Patch based on one by Andrzej Surdej <Andrzej_Surdej@comcast.com> coming from
WebPlatformForEmbedded/WPEWebKit#922 .

* Source/WebCore/Modules/encryptedmedia/MediaKeySystemAccess.cpp:
(WebCore::MediaKeySystemAccess::create):
(WebCore::MediaKeySystemAccess::MediaKeySystemAccess):
(WebCore::MediaKeySystemAccess::createMediaKeys):
* Source/WebCore/Modules/encryptedmedia/MediaKeySystemAccess.h:
* Source/WebCore/Modules/encryptedmedia/MediaKeySystemAccess.idl:
* Source/WebCore/Modules/encryptedmedia/NavigatorEME.cpp:
(WebCore::NavigatorEME::requestMediaKeySystemAccess):
(WebCore::tryNextSupportedConfiguration):

Canonical link: https://commits.webkit.org/256442@main
  • Loading branch information
calvaris committed Nov 8, 2022
1 parent 48b51f0 commit ce9671b4d61efff2bce123ee2ec64018d9dc86fb
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 14 deletions.
@@ -42,13 +42,16 @@

namespace WebCore {

Ref<MediaKeySystemAccess> MediaKeySystemAccess::create(const String& keySystem, MediaKeySystemConfiguration&& configuration, Ref<CDM>&& implementation)
Ref<MediaKeySystemAccess> MediaKeySystemAccess::create(Document& document, const String& keySystem, MediaKeySystemConfiguration&& configuration, Ref<CDM>&& implementation)
{
return adoptRef(*new MediaKeySystemAccess(keySystem, WTFMove(configuration), WTFMove(implementation)));
auto access = adoptRef(*new MediaKeySystemAccess(document, keySystem, WTFMove(configuration), WTFMove(implementation)));
access->suspendIfNeeded();
return access;
}

MediaKeySystemAccess::MediaKeySystemAccess(const String& keySystem, MediaKeySystemConfiguration&& configuration, Ref<CDM>&& implementation)
: m_keySystem(keySystem)
MediaKeySystemAccess::MediaKeySystemAccess(Document& document, const String& keySystem, MediaKeySystemConfiguration&& configuration, Ref<CDM>&& implementation)
: ActiveDOMObject(document)
, m_keySystem(keySystem)
, m_configuration(new MediaKeySystemConfiguration(WTFMove(configuration)))
, m_implementation(WTFMove(implementation))
{
@@ -64,7 +67,7 @@ void MediaKeySystemAccess::createMediaKeys(Document& document, Ref<DeferredPromi
// When this method is invoked, the user agent must run the following steps:
// 1. Let promise be a new promise.
// 2. Run the following steps in parallel:
document.eventLoop().queueTask(TaskSource::MediaElement, [this, weakThis = WeakPtr { *this }, weakDocument = WeakPtr<Document, WeakPtrImplWithEventTargetData> { document }, promise = WTFMove(promise)] () mutable {
queueTaskKeepingObjectAlive(*this, TaskSource::MediaElement, [this, weakThis = WeakPtr { *this }, weakDocument = WeakPtr<Document, WeakPtrImplWithEventTargetData> { document }, promise = WTFMove(promise)]() mutable {
RefPtr protectedThis = weakThis.get();
if (!protectedThis)
return;
@@ -30,6 +30,7 @@

#if ENABLE(ENCRYPTED_MEDIA)

#include "ActiveDOMObject.h"
#include "MediaKeySystemConfiguration.h"
#include <wtf/RefCounted.h>
#include <wtf/WeakPtr.h>
@@ -42,17 +43,20 @@ class DeferredPromise;
class Document;
class MediaKeys;

class MediaKeySystemAccess : public RefCounted<MediaKeySystemAccess>, public CanMakeWeakPtr<MediaKeySystemAccess> {
class MediaKeySystemAccess : public RefCounted<MediaKeySystemAccess>, public CanMakeWeakPtr<MediaKeySystemAccess>, public ActiveDOMObject {
public:
static Ref<MediaKeySystemAccess> create(const String& keySystem, MediaKeySystemConfiguration&&, Ref<CDM>&&);
static Ref<MediaKeySystemAccess> create(Document&, const String& keySystem, MediaKeySystemConfiguration&&, Ref<CDM>&&);
~MediaKeySystemAccess();

const String& keySystem() const { return m_keySystem; }
const MediaKeySystemConfiguration& getConfiguration() const { return *m_configuration; }
void createMediaKeys(Document&, Ref<DeferredPromise>&&);

private:
MediaKeySystemAccess(const String& keySystem, MediaKeySystemConfiguration&&, Ref<CDM>&&);
MediaKeySystemAccess(Document&, const String& keySystem, MediaKeySystemConfiguration&&, Ref<CDM>&&);

// ActiveDOMObject
const char *activeDOMObjectName() const final { return "MediaKeySystemAccess"; }

String m_keySystem;
std::unique_ptr<MediaKeySystemConfiguration> m_configuration;
@@ -27,6 +27,7 @@
*/

[
ActiveDOMObject,
Conditional=ENCRYPTED_MEDIA,
EnabledBySetting=EncryptedMediaAPIEnabled,
DisabledByQuirk=hasBrokenEncryptedMediaAPISupport,
@@ -80,7 +80,7 @@ inline void infoLog(Logger& logger, const Arguments&... arguments)
#endif
}

static void tryNextSupportedConfiguration(RefPtr<CDM>&& implementation, Vector<MediaKeySystemConfiguration>&& supportedConfigurations, RefPtr<DeferredPromise>&&, Ref<Logger>&&, Logger::LogSiteIdentifier&&);
static void tryNextSupportedConfiguration(Document&, RefPtr<CDM>&&, Vector<MediaKeySystemConfiguration>&&, RefPtr<DeferredPromise>&&, Ref<Logger>&&, Logger::LogSiteIdentifier&&);

void NavigatorEME::requestMediaKeySystemAccess(Navigator& navigator, Document& document, const String& keySystem, Vector<MediaKeySystemConfiguration>&& supportedConfigurations, Ref<DeferredPromise>&& promise)
{
@@ -117,13 +117,13 @@ void NavigatorEME::requestMediaKeySystemAccess(Navigator& navigator, Document& d

// 6.2. Let implementation be the implementation of keySystem.
auto implementation = CDM::create(document, keySystem);
tryNextSupportedConfiguration(WTFMove(implementation), WTFMove(supportedConfigurations), WTFMove(promise), WTFMove(logger), WTFMove(identifier));
tryNextSupportedConfiguration(document, WTFMove(implementation), WTFMove(supportedConfigurations), WTFMove(promise), WTFMove(logger), WTFMove(identifier));
});
});
request->start();
}

static void tryNextSupportedConfiguration(RefPtr<CDM>&& implementation, Vector<MediaKeySystemConfiguration>&& supportedConfigurations, RefPtr<DeferredPromise>&& promise, Ref<Logger>&& logger, Logger::LogSiteIdentifier&& identifier)
static void tryNextSupportedConfiguration(Document& document, RefPtr<CDM>&& implementation, Vector<MediaKeySystemConfiguration>&& supportedConfigurations, RefPtr<DeferredPromise>&& promise, Ref<Logger>&& logger, Logger::LogSiteIdentifier&& identifier)
{
// 6.3. For each value in supportedConfigurations:
if (!supportedConfigurations.isEmpty()) {
@@ -133,7 +133,7 @@ static void tryNextSupportedConfiguration(RefPtr<CDM>&& implementation, Vector<M
MediaKeySystemConfiguration candidateConfiguration = WTFMove(supportedConfigurations.first());
supportedConfigurations.remove(0);

CDM::SupportedConfigurationCallback callback = [implementation = implementation, supportedConfigurations = WTFMove(supportedConfigurations), promise, logger = WTFMove(logger), identifier = WTFMove(identifier)] (std::optional<MediaKeySystemConfiguration> supportedConfiguration) mutable {
CDM::SupportedConfigurationCallback callback = [&document, implementation = implementation, supportedConfigurations = WTFMove(supportedConfigurations), promise, logger = WTFMove(logger), identifier = WTFMove(identifier)] (std::optional<MediaKeySystemConfiguration> supportedConfiguration) mutable {
// 6.3.3. If supported configuration is not NotSupported, run the following steps:
if (supportedConfiguration) {
// 6.3.3.1. Let access be a new MediaKeySystemAccess object, and initialize it as follows:
@@ -143,15 +143,15 @@ static void tryNextSupportedConfiguration(RefPtr<CDM>&& implementation, Vector<M

// Obtain reference to the key system string before the `implementation` RefPtr<> is cleared out.
const String& keySystem = implementation->keySystem();
auto access = MediaKeySystemAccess::create(keySystem, WTFMove(supportedConfiguration.value()), implementation.releaseNonNull());
auto access = MediaKeySystemAccess::create(document, keySystem, WTFMove(supportedConfiguration.value()), implementation.releaseNonNull());

// 6.3.3.2. Resolve promise with access and abort the parallel steps of this algorithm.
infoLog(logger, identifier, "Resolved: keySystem(", keySystem, "), supportedConfiguration(", supportedConfiguration, ")");
promise->resolveWithNewlyCreated<IDLInterface<MediaKeySystemAccess>>(WTFMove(access));
return;
}

tryNextSupportedConfiguration(WTFMove(implementation), WTFMove(supportedConfigurations), WTFMove(promise), WTFMove(logger), WTFMove(identifier));
tryNextSupportedConfiguration(document, WTFMove(implementation), WTFMove(supportedConfigurations), WTFMove(promise), WTFMove(logger), WTFMove(identifier));
};
implementation->getSupportedConfiguration(WTFMove(candidateConfiguration), WTFMove(callback));
return;

0 comments on commit ce9671b

Please sign in to comment.