<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[279363] trunk/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/279363">279363</a></dd>
<dt>Author</dt> <dd>calvaris@igalia.com</dd>
<dt>Date</dt> <dd>2021-06-28 23:11:52 -0700 (Mon, 28 Jun 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>[GStreamer][EME] Fix resources release when a MediaKeySession is closed
https://bugs.webkit.org/show_bug.cgi?id=227403

Reviewed by Philippe Normand.

Thunder sessions should be a BoxPtr, already when stored at the
CDMInstanceSessionThunder, it does not make sense to store then in
a unique_ptr. This way the same session lives in the
MediaKeySession wrapper (CDMInstanceSessionThunder) and inside the
KeyStores.

Removed the CDMInstanceProxy key store. It is not needed.

When a session is closed in Thunder, there should be a cascade to
remove it from the other synced stores, that's why we introduce
the removeAllKeysFrom logic.

Regular key stores do not manage key session references
anymore. They are only needed in the CDMProxy class, which is
where the keys are shared among different sessions. We were
managing key session references in other stores and they were
messing up with the key references in the CDMProxy class. In
those cases, a key kept in a local store could have a reference
that would prevent the CDMProxy key store from removing it when
asked from it. There were also cases of removing keys from local
stores that were creating negative reference numbers, which
created the opposite effect, this is, leaving in place keys in the
CDMProxy store that should be released.

* platform/encryptedmedia/CDMProxy.cpp:
(WebCore::KeyStore::merge): Simplified to just add keys.
(WebCore::KeyStore::add): Adds references (if needed) and merges
if needed.
(WebCore::KeyStore::unrefAllKeys): Renamed. Unrefs all keys from a
store by copying itself and calling unrefAllKeysFrom that copy.
(WebCore::KeyStore::unref): Renamed. Uses proper refefencing.
(WebCore::CDMProxy::unrefAllKeysFrom): Method to unref all keys
that are contained in some other store.
(WebCore::CDMInstanceProxy::mergeKeysFrom): There is no more key
store in this class.
(WebCore::CDMInstanceProxy::unrefAllKeysFrom): Renamed. Calls the
CDMproxy to unref the keys from there.
* platform/encryptedmedia/CDMProxy.h:
(WebCore::KeyHandle::mergeKeyInto): Merges one key into self by
copying status, data and summing reference count.
(WebCore::KeyHandle::numSessionReferences const): Turn int.
(WebCore::KeyHandle::hasReferences const): Added.
(WebCore::KeyStore::addSessionReferenceTo const):
(WebCore::KeyStore::removeSessionReferenceFrom const): Helpers to
check if the store is reference counted or not. Default is do
nothing and but the ReferenceAwareKeyStore redefines them to do
reference counting.
(WebCore::KeyStore::unrefAllKeys): Deleted.
* platform/encryptedmedia/clearkey/CDMClearKey.cpp:
(WebCore::CDMInstanceSessionClearKey::updateLicense):
(WebCore::CDMInstanceSessionClearKey::removeSessionData): Use
renamed methods.
* platform/graphics/gstreamer/eme/CDMThunder.h:
* platform/graphics/gstreamer/eme/CDMThunder.cpp:
(WebCore::CDMInstanceSessionThunder::status const):
(WebCore::CDMInstanceSessionThunder::keyUpdatedCallback):
(WebCore::CDMInstanceSessionThunder::requestLicense):
(WebCore::CDMInstanceSessionThunder::updateLicense):
(WebCore::CDMInstanceSessionThunder::removeSessionData):
(WebCore::CDMInstanceSessionThunder::loadSession): Use BoxPtr in
the session.
(WebCore::CDMInstanceSessionThunder::closeSession): Close the
current session, release the BoxPtr, notify the instance and
therefore the proxy to unref all they key IDs in this session and
empty the local key store.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformencryptedmediaCDMProxycpp">trunk/Source/WebCore/platform/encryptedmedia/CDMProxy.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformencryptedmediaCDMProxyh">trunk/Source/WebCore/platform/encryptedmedia/CDMProxy.h</a></li>
<li><a href="#trunkSourceWebCoreplatformencryptedmediaclearkeyCDMClearKeycpp">trunk/Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsgstreameremeCDMThundercpp">trunk/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsgstreameremeCDMThunderh">trunk/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (279362 => 279363)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2021-06-29 04:05:14 UTC (rev 279362)
+++ trunk/Source/WebCore/ChangeLog      2021-06-29 06:11:52 UTC (rev 279363)
</span><span class="lines">@@ -1,3 +1,76 @@
</span><ins>+2021-06-28  Xabier Rodriguez Calvar  <calvaris@igalia.com>
+
+        [GStreamer][EME] Fix resources release when a MediaKeySession is closed
+        https://bugs.webkit.org/show_bug.cgi?id=227403
+
+        Reviewed by Philippe Normand.
+
+        Thunder sessions should be a BoxPtr, already when stored at the
+        CDMInstanceSessionThunder, it does not make sense to store then in
+        a unique_ptr. This way the same session lives in the
+        MediaKeySession wrapper (CDMInstanceSessionThunder) and inside the
+        KeyStores.
+
+        Removed the CDMInstanceProxy key store. It is not needed.
+
+        When a session is closed in Thunder, there should be a cascade to
+        remove it from the other synced stores, that's why we introduce
+        the removeAllKeysFrom logic.
+
+        Regular key stores do not manage key session references
+        anymore. They are only needed in the CDMProxy class, which is
+        where the keys are shared among different sessions. We were
+        managing key session references in other stores and they were
+        messing up with the key references in the CDMProxy class. In
+        those cases, a key kept in a local store could have a reference
+        that would prevent the CDMProxy key store from removing it when
+        asked from it. There were also cases of removing keys from local
+        stores that were creating negative reference numbers, which
+        created the opposite effect, this is, leaving in place keys in the
+        CDMProxy store that should be released.
+
+        * platform/encryptedmedia/CDMProxy.cpp:
+        (WebCore::KeyStore::merge): Simplified to just add keys.
+        (WebCore::KeyStore::add): Adds references (if needed) and merges
+        if needed.
+        (WebCore::KeyStore::unrefAllKeys): Renamed. Unrefs all keys from a
+        store by copying itself and calling unrefAllKeysFrom that copy.
+        (WebCore::KeyStore::unref): Renamed. Uses proper refefencing.
+        (WebCore::CDMProxy::unrefAllKeysFrom): Method to unref all keys
+        that are contained in some other store.
+        (WebCore::CDMInstanceProxy::mergeKeysFrom): There is no more key
+        store in this class.
+        (WebCore::CDMInstanceProxy::unrefAllKeysFrom): Renamed. Calls the
+        CDMproxy to unref the keys from there.
+        * platform/encryptedmedia/CDMProxy.h:
+        (WebCore::KeyHandle::mergeKeyInto): Merges one key into self by
+        copying status, data and summing reference count.
+        (WebCore::KeyHandle::numSessionReferences const): Turn int.
+        (WebCore::KeyHandle::hasReferences const): Added.
+        (WebCore::KeyStore::addSessionReferenceTo const):
+        (WebCore::KeyStore::removeSessionReferenceFrom const): Helpers to
+        check if the store is reference counted or not. Default is do
+        nothing and but the ReferenceAwareKeyStore redefines them to do
+        reference counting.
+        (WebCore::KeyStore::unrefAllKeys): Deleted.
+        * platform/encryptedmedia/clearkey/CDMClearKey.cpp:
+        (WebCore::CDMInstanceSessionClearKey::updateLicense):
+        (WebCore::CDMInstanceSessionClearKey::removeSessionData): Use
+        renamed methods.
+        * platform/graphics/gstreamer/eme/CDMThunder.h:
+        * platform/graphics/gstreamer/eme/CDMThunder.cpp:
+        (WebCore::CDMInstanceSessionThunder::status const):
+        (WebCore::CDMInstanceSessionThunder::keyUpdatedCallback):
+        (WebCore::CDMInstanceSessionThunder::requestLicense):
+        (WebCore::CDMInstanceSessionThunder::updateLicense):
+        (WebCore::CDMInstanceSessionThunder::removeSessionData):
+        (WebCore::CDMInstanceSessionThunder::loadSession): Use BoxPtr in
+        the session.
+        (WebCore::CDMInstanceSessionThunder::closeSession): Close the
+        current session, release the BoxPtr, notify the instance and
+        therefore the proxy to unref all they key IDs in this session and
+        empty the local key store.
+
</ins><span class="cx"> 2021-06-28  Darin Adler  <darin@apple.com>
</span><span class="cx"> 
</span><span class="cx">         CSS parser "consume declaration" algorithm does not handle whitespace correctly
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformencryptedmediaCDMProxycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/encryptedmedia/CDMProxy.cpp (279362 => 279363)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/encryptedmedia/CDMProxy.cpp        2021-06-29 04:05:14 UTC (rev 279362)
+++ trunk/Source/WebCore/platform/encryptedmedia/CDMProxy.cpp   2021-06-29 06:11:52 UTC (rev 279363)
</span><span class="lines">@@ -117,18 +117,8 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(isMainThread());
</span><span class="cx">     LOG(EME, "EME - CDMProxy - merging %u new keys into a key store of %u keys", other.numKeys(), numKeys());
</span><del>-    for (const auto& key : other) {
-        // NOTE: Do we care that we will not append a key if it matches a key ID
-        // in the keystore and has different data. Should we overwrite? Which is "newer"?
-        // Don't think we need this extra complexity.
-        size_t keyWithMatchingKeyIDIndex = m_keys.findMatching([&] (const RefPtr<KeyHandle>& storedKey) { return *key == *storedKey; });
-        if (keyWithMatchingKeyIDIndex == WTF::notFound)
-            m_keys.append(key);
-        else {
-            LOG(EME, "EME - CDMProxy - keys with the same ID!");
-            ASSERT(key->value() == m_keys[keyWithMatchingKeyIDIndex]->value());
-        }
-    }
</del><ins>+    for (const auto& key : other)
+        add(key.copyRef());
</ins><span class="cx"> 
</span><span class="cx"> #if !LOG_DISABLED
</span><span class="cx">     LOG(EME, "EME - CDMProxy - key store now has %u keys", numKeys());
</span><span class="lines">@@ -162,14 +152,15 @@
</span><span class="cx">         return *key == *storedKey;
</span><span class="cx">     });
</span><span class="cx"> 
</span><ins>+    addSessionReferenceTo(key);
</ins><span class="cx">     if (keyWithMatchingKeyIDIndex != WTF::notFound) {
</span><span class="cx">         auto& keyWithMatchingKeyID = m_keys[keyWithMatchingKeyIDIndex];
</span><del>-        didStoreChange = keyWithMatchingKeyID == key;
</del><ins>+        didStoreChange = keyWithMatchingKeyID != key;
</ins><span class="cx">         if (didStoreChange)
</span><del>-            keyWithMatchingKeyID = key;
</del><ins>+            keyWithMatchingKeyID->mergeKeyInto(WTFMove(key));
</ins><span class="cx">     } else {
</span><span class="cx">         LOG(EME, "EME - ClearKey - New key with ID %s getting added to key store", key->idAsString().ascii().data());      
</span><del>-        m_keys.append(key);
</del><ins>+        m_keys.append(WTFMove(key));
</ins><span class="cx">         didStoreChange = true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -183,33 +174,38 @@
</span><span class="cx">             });
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    key->addSessionReference();
</del><span class="cx">     return didStoreChange;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void KeyStore::removeAllKeysFrom(const KeyStore& other)
</del><ins>+void KeyStore::unrefAllKeysFrom(const KeyStore& other)
</ins><span class="cx"> {
</span><span class="cx">     for (const auto& key : other)
</span><del>-        remove(key);
</del><ins>+        unref(key);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool KeyStore::remove(const RefPtr<KeyHandle>& key)
</del><ins>+void KeyStore::unrefAllKeys()
</ins><span class="cx"> {
</span><ins>+    KeyStore store(*this);
+    unrefAllKeysFrom(store);
+}
+
+bool KeyStore::unref(const RefPtr<KeyHandle>& key)
+{
</ins><span class="cx">     bool storeChanged = false;
</span><span class="cx"> 
</span><span class="cx">     size_t keyWithMatchingKeyIDIndex = m_keys.find(key);
</span><del>-    LOG(EME, "EME - ClearKey - requested to remove key with ID %s and %u session references", key->idAsString().ascii().data(), key->numSessionReferences());
</del><ins>+    LOG(EME, "EME - ClearKey - requested to unref key with ID %s and %d session references", key->idAsString().ascii().data(), key->numSessionReferences());
</ins><span class="cx"> 
</span><span class="cx">     if (keyWithMatchingKeyIDIndex != WTF::notFound) {
</span><span class="cx">         auto& keyWithMatchingKeyID = m_keys[keyWithMatchingKeyIDIndex];
</span><del>-        keyWithMatchingKeyID->removeSessionReference();
-        if (!keyWithMatchingKeyID->numSessionReferences()) {
-            LOG(EME, "EME - ClearKey - remove key with ID %s", keyWithMatchingKeyID->idAsString().ascii().data());
</del><ins>+        removeSessionReferenceFrom(keyWithMatchingKeyID);
+        if (!keyWithMatchingKeyID->hasReferences()) {
+            LOG(EME, "EME - ClearKey - unref key with ID %s", keyWithMatchingKeyID->idAsString().ascii().data());
</ins><span class="cx">             m_keys.remove(keyWithMatchingKeyIDIndex);
</span><span class="cx">             storeChanged = true;
</span><span class="cx">         }
</span><span class="cx">     } else
</span><del>-        LOG(EME, "EME - ClearKey - attempt to remove key with ID %s ignored, does not exist", key->idAsString().ascii().data());
</del><ins>+        LOG(EME, "EME - ClearKey - attempt to unref key with ID %s ignored, does not exist", key->idAsString().ascii().data());
</ins><span class="cx"> 
</span><span class="cx">     return storeChanged;
</span><span class="cx"> }
</span><span class="lines">@@ -248,6 +244,14 @@
</span><span class="cx">     return m_instance;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void CDMProxy::unrefAllKeysFrom(const KeyStore& keyStore)
+{
+    Locker locker { m_keysLock };
+    m_keyStore.unrefAllKeysFrom(keyStore);
+    LOG(EME, "EME - CDMProxy - removing from key store from a session closure");
+    m_keysCondition.notifyAll();
+}
+
</ins><span class="cx"> void CDMProxy::setInstance(CDMInstanceProxy* instance)
</span><span class="cx"> {
</span><span class="cx">     Locker locker { m_instanceLock };
</span><span class="lines">@@ -377,7 +381,6 @@
</span><span class="cx"> {
</span><span class="cx">     // FIXME: Notify JS when appropriate.
</span><span class="cx">     ASSERT(isMainThread());
</span><del>-    m_keyStore.merge(keyStore);
</del><span class="cx">     if (m_cdmProxy) {
</span><span class="cx">         LOG(EME, "EME - CDMInstanceProxy - merging keys into proxy instance and notifying CDMProxy of changes");
</span><span class="cx">         m_cdmProxy->updateKeyStore(keyStore);
</span><span class="lines">@@ -384,10 +387,13 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void CDMInstanceProxy::removeAllKeysFrom(const KeyStore& keyStore)
</del><ins>+void CDMInstanceProxy::unrefAllKeysFrom(const KeyStore& keyStore)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(isMainThread());
</span><del>-    m_keyStore.removeAllKeysFrom(keyStore);
</del><ins>+    if (m_cdmProxy) {
+        LOG(EME, "EME - CDMInstanceProxy - removing keys from proxy instance and notifying CDMProxy of changes");
+        m_cdmProxy->unrefAllKeysFrom(keyStore);
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> CDMInstanceSessionProxy::CDMInstanceSessionProxy(CDMInstanceProxy& instance)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformencryptedmediaCDMProxyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/encryptedmedia/CDMProxy.h (279362 => 279363)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/encryptedmedia/CDMProxy.h  2021-06-29 04:05:14 UTC (rev 279362)
+++ trunk/Source/WebCore/platform/encryptedmedia/CDMProxy.h     2021-06-29 06:11:52 UTC (rev 279363)
</span><span class="lines">@@ -68,6 +68,12 @@
</span><span class="cx">     const KeyHandleValueVariant& value() const { return m_value; }
</span><span class="cx">     KeyHandleValueVariant& value() { return m_value; }
</span><span class="cx">     KeyStatus status() const { return m_status; }
</span><ins>+    void mergeKeyInto(RefPtr<KeyHandle>&& other)
+    {
+        m_status = other->m_status;
+        m_value = other->m_value;
+        m_numSessionReferences += other->m_numSessionReferences;
+    }
</ins><span class="cx">     bool isStatusCurrentlyValid()
</span><span class="cx">     {
</span><span class="cx">         return m_status == CDMInstanceSession::KeyStatus::Usable || m_status == CDMInstanceSession::KeyStatus::OutputRestricted
</span><span class="lines">@@ -99,8 +105,10 @@
</span><span class="cx"> private:
</span><span class="cx">     void addSessionReference() { ASSERT(isMainThread()); m_numSessionReferences++; }
</span><span class="cx">     void removeSessionReference() { ASSERT(isMainThread()); m_numSessionReferences--; }
</span><del>-    unsigned numSessionReferences() const { ASSERT(isMainThread()); return m_numSessionReferences; }
</del><ins>+    int numSessionReferences() const { ASSERT(isMainThread()); return m_numSessionReferences; }
+    bool hasReferences() const { ASSERT(isMainThread()); return m_numSessionReferences > 0; }
</ins><span class="cx">     friend class KeyStore;
</span><ins>+    friend class ReferenceAwareKeyStore;
</ins><span class="cx"> 
</span><span class="cx">     KeyHandle(KeyStatus status, KeyIDType&& keyID, KeyHandleValueVariant&& keyHandleValue)
</span><span class="cx">         : m_status(status), m_id(WTFMove(keyID)), m_value(WTFMove(keyHandleValue)) { }
</span><span class="lines">@@ -108,7 +116,7 @@
</span><span class="cx">     KeyStatus m_status;
</span><span class="cx">     KeyIDType m_id;
</span><span class="cx">     KeyHandleValueVariant m_value;
</span><del>-    unsigned m_numSessionReferences { 0 };
</del><ins>+    int m_numSessionReferences { 0 };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> class KeyStore {
</span><span class="lines">@@ -116,14 +124,15 @@
</span><span class="cx">     using KeyStatusVector = CDMInstanceSession::KeyStatusVector;
</span><span class="cx"> 
</span><span class="cx">     KeyStore() = default;
</span><ins>+    virtual ~KeyStore() = default;
</ins><span class="cx"> 
</span><span class="cx">     bool containsKeyID(const KeyIDType&) const;
</span><span class="cx">     void merge(const KeyStore&);
</span><del>-    void removeAllKeysFrom(const KeyStore&);
-    void removeAllKeys() { m_keys.clear(); }
</del><ins>+    void unrefAllKeysFrom(const KeyStore&);
+    void unrefAllKeys();
</ins><span class="cx">     bool addKeys(Vector<RefPtr<KeyHandle>>&&);
</span><span class="cx">     bool add(RefPtr<KeyHandle>&&);
</span><del>-    bool remove(const RefPtr<KeyHandle>&);
</del><ins>+    bool unref(const RefPtr<KeyHandle>&);
</ins><span class="cx">     bool hasKeys() const { return m_keys.size(); }
</span><span class="cx">     unsigned numKeys() const { return m_keys.size(); }
</span><span class="cx">     const RefPtr<KeyHandle>& keyHandle(const KeyIDType&) const;
</span><span class="lines">@@ -130,6 +139,8 @@
</span><span class="cx">     KeyStatusVector allKeysAs(CDMInstanceSession::KeyStatus) const;
</span><span class="cx">     KeyStatusVector convertToJSKeyStatusVector() const;
</span><span class="cx">     bool isEmpty() const { return m_keys.isEmpty(); }
</span><ins>+    virtual void addSessionReferenceTo(const RefPtr<KeyHandle>&) const { }
+    virtual void removeSessionReferenceFrom(const RefPtr<KeyHandle>&) const { };
</ins><span class="cx"> 
</span><span class="cx">     auto begin() { return m_keys.begin(); }
</span><span class="cx">     auto begin() const { return m_keys.begin(); }
</span><span class="lines">@@ -144,6 +155,13 @@
</span><span class="cx">     Vector<RefPtr<KeyHandle>> m_keys;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+class ReferenceAwareKeyStore : public KeyStore {
+public:
+    virtual ~ReferenceAwareKeyStore() = default;
+    void addSessionReferenceTo(const RefPtr<KeyHandle>& key) const final { key->addSessionReference(); }
+    void removeSessionReferenceFrom(const RefPtr<KeyHandle>& key) const final { key->removeSessionReference(); }
+};
+
</ins><span class="cx"> class CDMInstanceProxy;
</span><span class="cx"> class CDMProxyDecryptionClient;
</span><span class="cx"> 
</span><span class="lines">@@ -155,7 +173,8 @@
</span><span class="cx"> 
</span><span class="cx">     virtual ~CDMProxy() = default;
</span><span class="cx"> 
</span><del>-    void updateKeyStore(const KeyStore& newKeyStore);
</del><ins>+    void updateKeyStore(const KeyStore&);
+    void unrefAllKeysFrom(const KeyStore&);
</ins><span class="cx">     void setInstance(CDMInstanceProxy*);
</span><span class="cx">     void abortWaitingForKey() const;
</span><span class="cx"> 
</span><span class="lines">@@ -178,7 +197,7 @@
</span><span class="cx">     mutable Condition m_keysCondition;
</span><span class="cx">     // FIXME: Duplicated key stores in the instance and the proxy are probably not needed, but simplified
</span><span class="cx">     // the initial implementation in terms of threading invariants.
</span><del>-    KeyStore m_keyStore WTF_GUARDED_BY_LOCK(m_keysLock);
</del><ins>+    ReferenceAwareKeyStore m_keyStore WTF_GUARDED_BY_LOCK(m_keysLock);
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> class CDMProxyFactory {
</span><span class="lines">@@ -229,7 +248,7 @@
</span><span class="cx"> 
</span><span class="cx">     // Main-thread only.
</span><span class="cx">     void mergeKeysFrom(const KeyStore&);
</span><del>-    void removeAllKeysFrom(const KeyStore&);
</del><ins>+    void unrefAllKeysFrom(const KeyStore&);
</ins><span class="cx"> 
</span><span class="cx">     // Media player query methods - main thread only.
</span><span class="cx">     const RefPtr<CDMProxy>& proxy() const { ASSERT(isMainThread()); return m_cdmProxy; }
</span><span class="lines">@@ -248,8 +267,6 @@
</span><span class="cx">     MediaPlayer* m_player { nullptr }; // FIXME: MainThread<T>?
</span><span class="cx"> 
</span><span class="cx">     std::atomic<int> m_numDecryptorsWaitingForKey { 0 };
</span><del>-
-    KeyStore m_keyStore;
</del><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> class CDMProxyDecryptionClient : public CanMakeWeakPtr<CDMProxyDecryptionClient, WeakPtrFactoryInitialization::Eager> {
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformencryptedmediaclearkeyCDMClearKeycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.cpp (279362 => 279363)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.cpp    2021-06-29 04:05:14 UTC (rev 279362)
+++ trunk/Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.cpp       2021-06-29 06:11:52 UTC (rev 279363)
</span><span class="lines">@@ -520,8 +520,8 @@
</span><span class="cx"> 
</span><span class="cx">     if (parseLicenseReleaseAcknowledgementFormat(*root)) {
</span><span class="cx">         LOG(EME, "EME - ClearKey - session %s release acknowledged, clearing all known keys", sessionId.utf8().data());
</span><del>-        parentInstance().removeAllKeysFrom(m_keyStore);
-        m_keyStore.removeAllKeys();
</del><ins>+        parentInstance().unrefAllKeysFrom(m_keyStore);
+        m_keyStore.unrefAllKeys();
</ins><span class="cx">         dispatchCallback(true, std::nullopt, SuccessValue::Succeeded);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="lines">@@ -599,7 +599,7 @@
</span><span class="cx">         message = SharedBuffer::create(messageCString.data(), messageCString.length());
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    m_keyStore.removeAllKeys();
</del><ins>+    m_keyStore.unrefAllKeys();
</ins><span class="cx">     dispatchCallback(WTFMove(keyStatusVector), Ref<SharedBuffer>(*message), SuccessValue::Succeeded);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsgstreameremeCDMThundercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.cpp (279362 => 279363)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.cpp      2021-06-29 04:05:14 UTC (rev 279362)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.cpp 2021-06-29 06:11:52 UTC (rev 279363)
</span><span class="lines">@@ -432,7 +432,7 @@
</span><span class="cx"> 
</span><span class="cx"> CDMInstanceSession::KeyStatus CDMInstanceSessionThunder::status(const KeyIDType& keyID) const
</span><span class="cx"> {
</span><del>-    ThunderKeyStatus status = m_session && !m_sessionID.isEmpty() ? opencdm_session_status(m_session.get(), keyID.data(), keyID.size()) : StatusPending;
</del><ins>+    ThunderKeyStatus status = m_session && !m_sessionID.isEmpty() ? opencdm_session_status(m_session->get(), keyID.data(), keyID.size()) : StatusPending;
</ins><span class="cx"> 
</span><span class="cx">     switch (status) {
</span><span class="cx">     case Usable:
</span><span class="lines">@@ -461,7 +461,7 @@
</span><span class="cx"> 
</span><span class="cx">     auto keyStatus = status(keyID);
</span><span class="cx">     GST_DEBUG("updated with with key status %s", toString(keyStatus));
</span><del>-    m_doesKeyStoreNeedMerging |= m_keyStore.add(KeyHandle::create(keyStatus, WTFMove(keyID), BoxPtr<OpenCDMSession>()));
</del><ins>+    m_doesKeyStoreNeedMerging |= m_keyStore.add(KeyHandle::create(keyStatus, WTFMove(keyID), BoxPtr<OpenCDMSession>(m_session)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void CDMInstanceSessionThunder::keysUpdateDoneCallback()
</span><span class="lines">@@ -518,8 +518,8 @@
</span><span class="cx">         callback(initData.releaseNonNull(), { }, false, Failed);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><del>-    m_session.reset(session);
-    m_sessionID = String::fromUTF8(opencdm_session_id(m_session.get()));
</del><ins>+    m_session = adoptInBoxPtr(session);
+    m_sessionID = String::fromUTF8(opencdm_session_id(m_session->get()));
</ins><span class="cx"> 
</span><span class="cx">     auto generateChallenge = [this, callback = WTFMove(callback)]() mutable {
</span><span class="cx">         ASSERT(isMainThread());
</span><span class="lines">@@ -586,7 +586,7 @@
</span><span class="cx">             callback(false, std::nullopt, std::nullopt, std::nullopt, SuccessValue::Failed);
</span><span class="cx">         }
</span><span class="cx">     });
</span><del>-    if (!m_session || m_sessionID.isEmpty() || opencdm_session_update(m_session.get(), response->data(), response->size()))
</del><ins>+    if (!m_session || m_sessionID.isEmpty() || opencdm_session_update(m_session->get(), response->data(), response->size()))
</ins><span class="cx">         sessionFailure();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -623,7 +623,7 @@
</span><span class="cx">             callback(std::nullopt, std::nullopt, std::nullopt, SuccessValue::Failed, sessionLoadFailureFromThunder(response));
</span><span class="cx">         }
</span><span class="cx">     });
</span><del>-    if (!m_session || m_sessionID.isEmpty() || opencdm_session_load(m_session.get()))
</del><ins>+    if (!m_session || m_sessionID.isEmpty() || opencdm_session_load(m_session->get()))
</ins><span class="cx">         sessionFailure();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -631,8 +631,15 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT_UNUSED(sessionID, m_sessionID == sessionID);
</span><span class="cx"> 
</span><del>-    if (m_session && !m_sessionID.isEmpty())
-        opencdm_session_close(m_session.get());
</del><ins>+    if (m_session && !m_sessionID.isEmpty()) {
+        opencdm_session_close(m_session->get());
+        m_session = BoxPtr<OpenCDMSession>();
+        auto instance = cdmInstanceThunder();
+        if (instance) {
+            instance->unrefAllKeysFrom(m_keyStore);
+            m_keyStore.unrefAllKeys();
+        }
+    }
</ins><span class="cx"> 
</span><span class="cx">     callback();
</span><span class="cx"> }
</span><span class="lines">@@ -664,7 +671,7 @@
</span><span class="cx">             callback(m_keyStore.allKeysAs(MediaKeyStatus::InternalError), std::nullopt, SuccessValue::Failed);
</span><span class="cx">         }
</span><span class="cx">     });
</span><del>-    if (!m_session || m_sessionID.isEmpty() || opencdm_session_remove(m_session.get()))
</del><ins>+    if (!m_session || m_sessionID.isEmpty() || opencdm_session_remove(m_session->get()))
</ins><span class="cx">         sessionFailure();
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsgstreameremeCDMThunderh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.h (279362 => 279363)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.h        2021-06-29 04:05:14 UTC (rev 279362)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.h   2021-06-29 06:11:52 UTC (rev 279363)
</span><span class="lines">@@ -50,8 +50,6 @@
</span><span class="cx"> 
</span><span class="cx"> using UniqueThunderSystem = std::unique_ptr<OpenCDMSystem, ThunderSystemDeleter>;
</span><span class="cx"> 
</span><del>-using UniqueThunderSession = std::unique_ptr<OpenCDMSession, WTF::BoxPtrDeleter<OpenCDMSession>>;
-
</del><span class="cx"> } // namespace Thunder
</span><span class="cx"> 
</span><span class="cx"> class CDMFactoryThunder final : public CDMFactory, public CDMProxyFactory {
</span><span class="lines">@@ -161,7 +159,7 @@
</span><span class="cx">     bool m_doesKeyStoreNeedMerging { false };
</span><span class="cx">     InitData m_initData;
</span><span class="cx">     OpenCDMSessionCallbacks m_thunderSessionCallbacks { };
</span><del>-    Thunder::UniqueThunderSession m_session;
</del><ins>+    BoxPtr<OpenCDMSession> m_session;
</ins><span class="cx">     RefPtr<SharedBuffer> m_message;
</span><span class="cx">     bool m_needsIndividualization { false };
</span><span class="cx">     Vector<ChallengeGeneratedCallback> m_challengeCallbacks;
</span></span></pre>
</div>
</div>

</body>
</html>