From 2c36c43da756f466651a3a1677655494d11a6ce1 Mon Sep 17 00:00:00 2001 From: Marcin Mielczarczyk Date: Wed, 24 Sep 2025 10:01:19 +0200 Subject: [PATCH] RDKDEV-1148: Release CDM resources when not used When HTMLMediaElement has been created in WPE and HTMLMediaElement::setMediaKeys() method was called to set DRM keys, CDMThunder implementation already allocates CDM resources and they're not released until HTMLMediaElement object is destructed. HTMLMediaElement destruction is non-deterministic and it's relying on Garbage Collector. In this case very often we observe that after WPE exit (WPE process is not closed, but some #boot address is being loaded), CDM resources are not released immediately and CDM can't be used by other applications like IP Player or Netflix. Proposed solution introduces following changes: 1) CDMPrivateThunder implementation doesn't occupy CDM resources permanently, as it only needs CDM resources to check if server certificate is supported so CDM resources can be acquired before check and released afterwards 2) CDMInstanceThunder object's CDM resources are released on HTMLMediaElement::stop() to not wait for Garbage Collector --- .../WebCore/Modules/encryptedmedia/MediaKeys.cpp | 3 +++ Source/WebCore/html/HTMLMediaElement.cpp | 6 ++++++ .../WebCore/platform/encryptedmedia/CDMInstance.h | 1 + .../platform/graphics/gstreamer/eme/CDMThunder.cpp | 14 ++++++++++++-- .../platform/graphics/gstreamer/eme/CDMThunder.h | 2 +- 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Source/WebCore/Modules/encryptedmedia/MediaKeys.cpp b/Source/WebCore/Modules/encryptedmedia/MediaKeys.cpp index 9043d6c0c23f8..5dcaa2ae646e9 100644 --- a/Source/WebCore/Modules/encryptedmedia/MediaKeys.cpp +++ b/Source/WebCore/Modules/encryptedmedia/MediaKeys.cpp @@ -161,6 +161,9 @@ void MediaKeys::detachCDMClient(CDMClient& client) { ASSERT(m_cdmClients.contains(client)); m_cdmClients.remove(client); + if (m_cdmClients.computesEmpty()) { + m_instance->releaseCDM(); + } } void MediaKeys::attemptToResumePlaybackOnClients() diff --git a/Source/WebCore/html/HTMLMediaElement.cpp b/Source/WebCore/html/HTMLMediaElement.cpp index 4f9fb78960618..b3f8474c10981 100644 --- a/Source/WebCore/html/HTMLMediaElement.cpp +++ b/Source/WebCore/html/HTMLMediaElement.cpp @@ -6097,6 +6097,12 @@ void HTMLMediaElement::stop() if (m_mediaSession) m_mediaSession->stopSession(); + + if (m_mediaKeys) { + m_mediaKeys->detachCDMClient(*this); + if (m_player) + m_player->cdmInstanceDetached(m_mediaKeys->cdmInstance()); + } } void HTMLMediaElement::suspend(ReasonForSuspension reason) diff --git a/Source/WebCore/platform/encryptedmedia/CDMInstance.h b/Source/WebCore/platform/encryptedmedia/CDMInstance.h index 1374f816dcb6b..9889f9a075ca3 100644 --- a/Source/WebCore/platform/encryptedmedia/CDMInstance.h +++ b/Source/WebCore/platform/encryptedmedia/CDMInstance.h @@ -107,6 +107,7 @@ class CDMInstance : public RefCounted { virtual void setStorageDirectory(const String&) = 0; virtual const String& keySystem() const = 0; virtual RefPtr createSession() = 0; + virtual void releaseCDM() { }; enum class HDCPStatus : uint8_t { Unknown, diff --git a/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.cpp b/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.cpp index 13533c54c659c..13d2fdf0a5e28 100644 --- a/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.cpp @@ -141,7 +141,6 @@ bool CDMFactoryThunder::supportsKeySystem(const String& keySystem) CDMPrivateThunder::CDMPrivateThunder(const String& keySystem) : m_keySystem(keySystem) - , m_thunderSystem(opencdm_create_system(keySystem.utf8().data())) { }; @@ -204,7 +203,9 @@ void CDMPrivateThunder::loadAndInitialize() bool CDMPrivateThunder::supportsServerCertificates() const { - bool isSupported = opencdm_system_supports_server_certificate(m_thunderSystem.get()); + OpenCDMSystem *ocdmSystem = opencdm_create_system(m_keySystem.utf8().data()); + bool isSupported = opencdm_system_supports_server_certificate(ocdmSystem); + opencdm_destruct_system(ocdmSystem); GST_DEBUG("server certificate supported %s", boolForPrinting(isSupported)); return isSupported; } @@ -258,6 +259,9 @@ void CDMInstanceThunder::initializeWithConfiguration(const CDMKeySystemConfigura void CDMInstanceThunder::setServerCertificate(Ref&& certificate, SuccessCallback&& callback) { auto data = certificate->extractData(); + if (m_thunderSystem.get() == nullptr) { + m_thunderSystem.reset(opencdm_create_system(m_keySystem.utf8().data())); + } OpenCDMError error = opencdm_system_set_server_certificate(m_thunderSystem.get(), const_cast(data.data()), data.size()); callback(!error ? Succeeded : Failed); } @@ -267,6 +271,12 @@ void CDMInstanceThunder::setStorageDirectory(const String& storageDirectory) FileSystem::makeAllDirectories(storageDirectory); } +void CDMInstanceThunder::releaseCDM() +{ + GST_DEBUG("release CDM resources"); + m_thunderSystem.reset(); +} + CDMInstanceSessionThunder::CDMInstanceSessionThunder(CDMInstanceThunder& instance) : CDMInstanceSessionProxy(instance) { diff --git a/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.h b/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.h index a3a6eb2732c04..a0a9aaa713d08 100644 --- a/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.h +++ b/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.h @@ -99,7 +99,6 @@ class CDMPrivateThunder final : public CDMPrivate { private: String m_keySystem; - Thunder::UniqueThunderSystem m_thunderSystem; }; class CDMInstanceThunder final : public CDMInstanceProxy { @@ -114,6 +113,7 @@ class CDMInstanceThunder final : public CDMInstanceProxy { void setStorageDirectory(const String&) final; const String& keySystem() const final { return m_keySystem; } RefPtr createSession() final; + void releaseCDM() final; OpenCDMSystem& thunderSystem() const { return *m_thunderSystem.get(); };