[EME] Bug 25536 - Make persisted session removal more explicit
authorDavid Dorwin <ddorwin@google.com>
Wed, 07 May 2014 15:48:37 -0700
changeset 306 5a3cac55ca65
parent 305 bf4b3f85e6ba
child 307 d426f69d04bc
[EME] Bug 25536 - Make persisted session removal more explicit
encrypted-media/encrypted-media.html
encrypted-media/encrypted-media.xml
--- a/encrypted-media/encrypted-media.html	Tue May 06 14:25:56 2014 -0700
+++ b/encrypted-media/encrypted-media.html	Wed May 07 15:48:37 2014 -0700
@@ -98,7 +98,7 @@
     <div class="head">
       <p><a href="http://www.w3.org/"><img src="https://www.w3.org/Icons/w3c_home" alt="W3C" width="72" height="48"></a></p>
       <h1>Encrypted Media Extensions</h1>
-      <h2 id="draft-date">W3C Editor's Draft 5 May 2014</h2>
+      <h2 id="draft-date">W3C Editor's Draft 7 May 2014</h2>
       <dl>
         <dt>This Version:</dt>
         <dd><a href="http://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html">http://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html</a></dd>
@@ -356,11 +356,12 @@
   readonly attribute DOMString <a href="#dom-sessionkeysystem">keySystem</a>;
   readonly attribute DOMString <a href="#dom-sessionid">sessionId</a>;
   readonly attribute Array&lt;Uint8Array&gt; <a href="#dom-usablekeyids">usableKeyIds</a>;
-  readonly attribute Promise&lt;any&gt; <a href="#dom-close">close</a>;
+  readonly attribute Promise&lt;any&gt; <a href="#dom-closed">closed</a>;
 
   // session operations
   Promise&lt;any&gt; <a href="#dom-update">update</a>(Uint8Array response);
-  Promise&lt;any&gt; <a href="#dom-release">release</a>();
+  Promise&lt;any&gt; <a href="#dom-close">close</a>();
+  Promise&lt;any&gt; <a href="#dom-remove">remove</a>();
 };
 
 <div class="issue">
@@ -504,7 +505,7 @@
               <li><p>Set the <code><a href="#dom-sessionkeysystem">keySystem</a></code> attribute to the value of the <code><a href="#dom-mediakeys">MediaKeys</a></code> object's <code><a href="#dom-keysystem">keySystem</a></code> attribute.</p></li>
               <li><p>Set the <code><a href="#dom-sessionid">sessionId</a></code> attribute to <var title="true">session ID</var>.</p></li>
               <li><p>Set the <code><a href="#dom-usablekeyids">usableKeyIds</a></code> attribute to an empty Array.</p></li>
-              <li><p>Let <code><a href="#dom-close">close</a></code> be a new promise.</p></li>
+              <li><p>Let <code><a href="#dom-closed">closed</a></code> be a new promise.</p></li>
               <li><p>Let the session type be <var title="true">sessionType</var>.</p></li>
               <li><p>Let the session initData be the <var title="true">initDataType</var>-<var>init data</var> pair.</p></li>
             </ol>
@@ -556,7 +557,7 @@
 <p>Set the <code><a href="#dom-usablekeyids">usableKeyIds</a></code> attribute to an Array containing the set of key IDs for which the session contains a currently usable key.</p>
                 <p>The <a href="#algorithms-update-usable-key-ids">Update Usable Key IDs</a> algorithm may also be run later should additional processing be necessary.</p>
               </li>
-              <li><p>Let <code><a href="#dom-close">close</a></code> be a new promise.</p></li>
+              <li><p>Let <code><a href="#dom-closed">closed</a></code> be a new promise.</p></li>
               <li><p>Let the session type be "<code><a href="#dom-sessiontypepersistent">persistent</a></code>".</p></li>
             </ol>
           </li>
@@ -703,7 +704,7 @@
       Each element must be unique.
     </p>
 
-    <p>The <dfn id="dom-close"><code>close</code></dfn> attribute signals when object becomes closed as a result of the <a href="#algorithms-session-close">Session Close</a> algorithm being run.
+    <p>The <dfn id="dom-closed"><code>closed</code></dfn> attribute signals when object becomes closed as a result of the <a href="#algorithms-session-close">Session Close</a> algorithm being run.
     This promise can only be fulfilled and is never rejected.</p>
 
     <p>The <dfn id="dom-update"><code>update(response)</code></dfn> method provides messages, including licenses, to the CDM. It must run the following steps:</p>
@@ -766,7 +767,9 @@
       <li><p>Return <var>promise</var>.</p></li>
     </ol>
 
-    <p>The <dfn id="dom-release"><code>release()</code></dfn> method allows an application to indicate to the system that it may release any resources associated with this object. It must run the following steps:</p>
+    <p>The <dfn id="dom-close"><code>close()</code></dfn> method allows an application to indicate that it no longer needs the session and the CDM should release any resources associated with this object and close it.
+    <span class="non-normative">The returned promise is resolved when the request has been processed, and the <dfn id="dom-closed"><code>closed</code></dfn> attribute promise is resolved when the session is closed.</span>
+    It must run the following steps:</p>
 
     <ol>
       <li><p>If the <a href="#algorithms-session-close">Session Close</a> algorithm has been run on this object, return a promise fulfilled with <code>undefined</code>.</p></li>
@@ -779,9 +782,8 @@
 <p>Use the <var title="true">cdm</var> to execute the following steps:</p>
             <ol>
               <li>
-                <p>Process the release request.</p>
-                <p class="non-normative">Note: the release() method is intended to act as a hint to the user agent that the application believes the session is no longer needed.
-                However, the CDM determines whether resources can now be released.</p>
+                <p>Process the close request.</p>
+                <p>Do not remove stored session data.</p>
               </li>
               <li><p>If the previous step caused the session to be closed, run the <a href="#algorithms-session-close">Session Close</a> algorithm on this object.</p></li>
             </ol>
@@ -792,6 +794,42 @@
       <li><p>Return <var>promise</var>.</p></li>
     </ol>
 
+    <p>The <dfn id="dom-remove"><code>remove()</code></dfn> method allows an application to remove stored session data associated with this object.
+    It must run the following steps:</p>
+
+    <ol>
+      <li><p>If the session type is not "<code><a href="#dom-sessiontypepersistent">persistent</a></code>", return a promise rejected with a new <code><a href="http://www.w3.org/TR/dom/#exception-domexception">DOMException</a></code> whose name is <code><a href="#dfn-InvalidAccessError">"InvalidAccessError"</a></code> and that has the message "The operation is not supported on <var title="true">session type</var> sessions."</p></li>
+      <li><p>If the <a href="#algorithms-session-close">Session Close</a> algorithm has been run on this object, return a promise rejected with a new <code><a href="http://www.w3.org/TR/dom/#exception-domexception">DOMException</a></code> whose name is <code><a href="#dfn-InvalidStateError">"InvalidStateError"</a></code> and that has the message "The session is closed."</p></li>
+      <li><p>Let <var>promise</var> be a new promise.</p></li>
+      <li>
+<p>Run the following steps asynchronously:</p>
+        <ol>
+          <li><p>Let <var title="true">cdm</var> be the <var title="true">cdm</var> loaded in <code><a href="#dom-create">create()</a></code>.</p></li>
+          <li>
+<p>Use the <var title="true">cdm</var> to execute the following steps:</p>
+            <ol>
+              <li>
+                <p>Process the remove request.</p>
+                <p>This may involve exchanging message(s) with the application.</p>
+                <p>Unless this step fails, the CDM must have cleared all stored session data associated with this object, including the <code><a href="#dom-sessionid">sessionId</a></code>, before proceeding to the next step.
+                  <span class="non-normative">(A subsequent call to <code><a href="#dom-loadsession">loadSession()</a></code> with <code><a href="#dom-sessionid">sessionId</a></code> would fail because there is no data stored for the <var title="true">sessionId</var>.)</span>
+                </p>
+              </li>
+            </ol>
+          </li>
+          <li>
+<p>Run the following steps asynchronously once the above step has completed:</p>
+            <ol>
+              <li><p>If any of the preceding steps failed, reject <var>promise</var> with a new <code><a href="http://www.w3.org/TR/dom/#exception-domexception">DOMException</a></code> whose name is the appropriate <a href="#mediakeyerror-names">error name</a> and that has an appropriate message.</p></li>
+              <li><p>Run the <a href="#algorithms-session-close">Session Close</a> algorithm on this object.</p></li>
+              <li><p>Resolve <var>promise</var> with <code>undefined</code>.</p></li>
+            </ol>
+          </li>
+        </ol>
+      </li>
+      <li><p>Return <var>promise</var>.</p></li>
+    </ol>
+
 
     <p>The <dfn id="dom-sourcekeysystem"><code>keySystem</code></dfn> attribute of <code><a href="#dom-htmlsourceelement">HTMLSourceElement</a></code> specifies the <a href="#key-system">Key System</a> to be used with the <code><a href="http://www.w3.org/TR/html5/embedded-content-0.html#media-resource">media resource</a></code>. The <code><a href="#dom-sourcekeysystem">keySystem</a></code> attribute must be supported by all HTMLSourceElement as both an IDL attribute and also a content attribute named <dfn id="dom-sourcecontentkeysystem"><code>keysystem</code></dfn>.
     The <a href="http://www.w3.org/TR/html5/embedded-content-0.html#concept-media-load-algorithm">resource selection algorithm</a> is modified to check the <code><a href="#dom-sourcekeysystem">keySystem</a></code> attribute after the existing <em>step 5</em> of the <em>Otherwise</em> branch of <em>step 6</em>:
@@ -820,7 +858,8 @@
             The key system <em>name</em> is not supported.<br>
             The initialization data type <em>type</em> is not supported by the key system.<br>
             <em>type</em> sessions are not supported by the key system.<br>
-            The operation is not supported by the key system.
+            The operation is not supported by the key system.<br>
+            The session is closed.
           </td>
         </tr>
         <tr>
@@ -829,7 +868,10 @@
         </tr>
         <tr>
           <td><dfn id="dfn-InvalidAccessError"><code>InvalidAccessError</code></dfn></td>
-          <td>The <em>name</em> parameter is empty.</td>
+          <td>
+            The <em>name</em> parameter is empty.<br>
+            The operation is not supported on <em>session type</em> sessions.
+          </td>
         </tr>
         <tr>
           <td><dfn id="dfn-QuotaExceededError"><code>QuotaExceededError</code></dfn></td>
@@ -1214,16 +1256,15 @@
 
     <h3 id="algorithms-session-close">4.6. Session Close</h3>
     <p>The Session Close algorithm is run when the CDM closes the session associated with a <code><a href="#dom-mediakeysession">MediaKeySession</a></code> object.</p>
-    <p class="non-normative">The CDM may close a session at any point, such as in response to a <code><a href="#dom-release">release()</a></code> call, when the session is no longer needed, or when resources are lost.
+    <p class="non-normative">The CDM may close a session at any point, such as in response to a <code><a href="#dom-close">close()</a></code> call, when the session is no longer needed, or when system resources are lost.
     Keys in other sessions should be unaffected, even if they have overlapping key IDs.
     </p>
-    <p>If <var title="true">sessionType</var> is "<code><a href="#dom-sessiontypepersistent">persistent</a></code>", the CDM must have cleared all stored session data associated with the <code><a href="#dom-mediakeysession">MediaKeySession</a></code> object.</p>
     <p>The following steps are run:</p>
     <ol>
       <li><p>Let the <var title="true">session</var> be the associated <code><a href="#dom-mediakeysession">MediaKeySession</a></code> object.</p></li>
       <li><p>If the session initData of the <var title="true">session</var> is not empty, remove its entry from the <var title="true">list of active session Initialization Data</var> for the MediaKeys object that created the <var title="true">session</var>.</p></li>
       <li><p>Set the <var title="true">session</var>'s <code><a href="#dom-usablekeyids">usableKeyIds</a></code> attribute to an empty Array.</p></li>
-      <li><p>Let <var>promise</var> be the <code><a href="#dom-close">close</a></code> attribute of the <var title="true">session</var>.</p></li>
+      <li><p>Let <var>promise</var> be the <code><a href="#dom-closed">closed</a></code> attribute of the <var title="true">session</var>.</p></li>
       <li><p>Resolve <var>promise</var> with <code>undefined</code>.</p></li>
     </ol>
 
@@ -1606,7 +1647,7 @@
         keySession.addEventListener("<a href="#dom-eventmessage">message</a>", handleMessage, false);
         keySession.addEventListener("<a href="#dom-eventkeyschange">keyschange</a>", handleKeysChange, false);
         keySession.addEventListener("<a href="#dom-eventerror">error</a>", handleError, false);
-        keySession.close.then(
+        keySession.<a href="#dom-closed">closed</a>.then(
           console.log.bind(console, "Session closed")
         );
       }
@@ -1669,8 +1710,6 @@
     <h3 id="example-stored-license" class="exampleheader">8.5. Stored License</h3>
     <p class="exampledescription">This example requests a persistent license for future use and stores it. It also provides functions for later retrieving the license and for destroying it.</p>
 
-    <div class="issue">
-<div class="issue-title"><span>Issue 7</span></div>There could be a race condition between a CDM-triggered close and setting <var>releaseRequested</var>. This needs to be fixed in the spec. See <a href="https://www.w3.org/Bugs/Public/show_bug.cgi?id=25536">Bug 25536</a>.</div>
     <div class="example">
       <pre class="code">
 &lt;script&gt;
@@ -1693,14 +1732,10 @@
           return; // A session already exists for the initData.
         keySession.addEventListener("<a href="#dom-eventmessage">message</a>", handleMessage, false);
         keySession.addEventListener("<a href="#dom-eventerror">error</a>", handleError, false);
-        keySession.close.then(
+        keySession.<a href="#dom-closed">closed</a>.then(
           function() {
             console.log("Session " + this.sessionId + " closed");
-            if (this.releaseRequested) {
-              console.log("Session " + this.sessionId + " destroyed");
-              // The application should remove its record of this.sessionId.
-            }
-          }.bind(keySession),        
+          }.bind(keySession)        
         );
         // Store keySession.<a href="#dom-sessionid">sessionId</a> in the application.
       }
@@ -1720,7 +1755,7 @@
         }
         keySession.addEventListener("<a href="#dom-eventmessage">message</a>", handleMessage, false);
         keySession.addEventListener("<a href="#dom-eventerror">error</a>", handleError, false);
-        keySession.close.then(
+        keySession.<a href="#dom-closed">closed</a>.then(
           console.log.bind(console, "Session closed")
         );
       }
@@ -1729,16 +1764,22 @@
     );
   }
 
-  // Called when the application wants to remove the license for the media resource.
-  // Calling release() may initiate a series of messages to/from the server.
-  // The license has not been removed until the close promise is fulfilled and
-  // releaseRequested == true.
+  // Called when the application wants to stop using the session without removing the stored license.
+  closeSession(keySession) {
+    keySession.<a href="#dom-close">close</a>();
+  }
+
+  // Called when the application wants to remove the stored license.
+  // Calling remove() may initiate a series of messages to/from the server.
+  // The stored session data has not been completely removed until the returned promise is fulfilled.
   removeStoredSession(keySession) {
-    keySession.<a href="#dom-release">release</a>().then(
+    keySession.<a href="#dom-remove">remove</a>().then(
       function() {
-        this.releaseRequested = true;
-      }.bind(keySession),
-      console.error.bind(console, "Unable to release the session")
+        console.log("Session " + this.sessionId + " removed");
+        // The application should remove its record of this.sessionId.
+      }.bind(keySession)
+    ).catch(
+      console.error.bind(console, "Failed to remove the session")
     );
   }
 
--- a/encrypted-media/encrypted-media.xml	Tue May 06 14:25:56 2014 -0700
+++ b/encrypted-media/encrypted-media.xml	Wed May 07 15:48:37 2014 -0700
@@ -97,7 +97,7 @@
     <div class="head">
       <p><a href="http://www.w3.org/"><img src="https://www.w3.org/Icons/w3c_home" alt="W3C" width="72" height="48" /></a></p>
       <h1>Encrypted Media Extensions</h1>
-      <h2 id="draft-date">W3C Editor's Draft 5 May 2014</h2>
+      <h2 id="draft-date">W3C Editor's Draft 7 May 2014</h2>
       <dl>
         <dt>This Version:</dt>
         <dd><a href="http://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html">http://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html</a></dd>
@@ -353,11 +353,12 @@
   readonly attribute DOMString <precoderef prefix="session">keySystem</precoderef>;
   readonly attribute DOMString <precoderef>sessionId</precoderef>;
   readonly attribute Array&lt;Uint8Array&gt; <precoderef>usableKeyIds</precoderef>;
-  readonly attribute Promise&lt;any&gt; <precoderef>close</precoderef>;
+  readonly attribute Promise&lt;any&gt; <precoderef>closed</precoderef>;
 
   // session operations
   Promise&lt;any&gt; <premethodref>update</premethodref>(Uint8Array response);
-  Promise&lt;any&gt; <premethodref>release</premethodref>();
+  Promise&lt;any&gt; <premethodref>close</premethodref>();
+  Promise&lt;any&gt; <premethodref>remove</premethodref>();
 };
 
 <div class="issue"><div class="issue-title"><span>Issue 1</span></div><p class="">Extensions to <precoderef>HTMLSourceElement</precoderef> may be at risk as discussed in <a href="https://www.w3.org/Bugs/Public/show_bug.cgi?id=23827">Bug 23827</a>.</p></div>
@@ -486,7 +487,7 @@
               <li><p>Set the <coderef prefix="session">keySystem</coderef> attribute to the value of the <coderef>MediaKeys</coderef> object's <coderef>keySystem</coderef> attribute.</p></li>
               <li><p>Set the <coderef>sessionId</coderef> attribute to <var title="true">session ID</var>.</p></li>
               <li><p>Set the <coderef>usableKeyIds</coderef> attribute to an empty Array.</p></li>
-              <li><p>Let <coderef>close</coderef> be a new promise.</p></li>
+              <li><p>Let <coderef>closed</coderef> be a new promise.</p></li>
               <li><p>Let the session type be <var title="true">sessionType</var>.</p></li>
               <li><p>Let the session initData be the <var title="true">initDataType</var>-<var>init data</var> pair.</p></li>
             </ol>
@@ -533,7 +534,7 @@
               <li><p>Set the <coderef>usableKeyIds</coderef> attribute to an Array containing the set of key IDs for which the session contains a currently usable key.</p>
                 <p>The <a href="#algorithms-update-usable-key-ids">Update Usable Key IDs</a> algorithm may also be run later should additional processing be necessary.</p>
               </li>
-              <li><p>Let <coderef>close</coderef> be a new promise.</p></li>
+              <li><p>Let <coderef>closed</coderef> be a new promise.</p></li>
               <li><p>Let the session type be "<coderef prefix="sessiontype">persistent</coderef>".</p></li>
             </ol>
           </li>
@@ -665,7 +666,7 @@
       Each element must be unique.
     </p>
 
-    <p>The <codedfn>close</codedfn> attribute signals when object becomes closed as a result of the <a href="#algorithms-session-close">Session Close</a> algorithm being run.
+    <p>The <codedfn>closed</codedfn> attribute signals when object becomes closed as a result of the <a href="#algorithms-session-close">Session Close</a> algorithm being run.
     This promise can only be fulfilled and is never rejected.</p>
 
     <p>The <methoddfn name="update">update(<var title="true">response</var>)</methoddfn> method provides messages, including licenses, to the CDM. It must run the following steps:</p>
@@ -723,7 +724,9 @@
       <li><p>Return <var>promise</var>.</p></li>
     </ol>
 
-    <p>The <methoddfn name="release">release()</methoddfn> method allows an application to indicate to the system that it may release any resources associated with this object. It must run the following steps:</p>
+    <p>The <methoddfn name="close">close()</methoddfn> method allows an application to indicate that it no longer needs the session and the CDM should release any resources associated with this object and close it.
+    <span class="non-normative">The returned promise is resolved when the request has been processed, and the <codedfn>closed</codedfn> attribute promise is resolved when the session is closed.</span>
+    It must run the following steps:</p>
 
     <ol>
       <li><p>If the <a href="#algorithms-session-close">Session Close</a> algorithm has been run on this object, return a promise fulfilled with <code>undefined</code>.</p></li>
@@ -734,9 +737,8 @@
           <li><p>Use the <var title="true">cdm</var> to execute the following steps:</p>
             <ol>
               <li>
-                <p>Process the release request.</p>
-                <p class="non-normative">Note: the release() method is intended to act as a hint to the user agent that the application believes the session is no longer needed.
-                However, the CDM determines whether resources can now be released.</p>
+                <p>Process the close request.</p>
+                <p>Do not remove stored session data.</p>
               </li>
               <li><p>If the previous step caused the session to be closed, run the <a href="#algorithms-session-close">Session Close</a> algorithm on this object.</p></li>
             </ol>
@@ -747,6 +749,39 @@
       <li><p>Return <var>promise</var>.</p></li>
     </ol>
 
+    <p>The <methoddfn name="remove">remove()</methoddfn> method allows an application to remove stored session data associated with this object.
+    It must run the following steps:</p>
+
+    <ol>
+      <li><p>If the session type is not "<coderef prefix="sessiontype">persistent</coderef>", return a promise rejected with a new <code><dom4ref name="exception-domexception">DOMException</dom4ref></code> whose name is <code><a href="#dfn-InvalidAccessError">"InvalidAccessError"</a></code> and that has the message "The operation is not supported on <var title="true">session type</var> sessions."</p></li>
+      <li><p>If the <a href="#algorithms-session-close">Session Close</a> algorithm has been run on this object, return a promise rejected with a new <code><dom4ref name="exception-domexception">DOMException</dom4ref></code> whose name is <code><a href="#dfn-InvalidStateError">"InvalidStateError"</a></code> and that has the message "The session is closed."</p></li>
+      <li><p>Let <var>promise</var> be a new promise.</p></li>
+      <li><p>Run the following steps asynchronously:</p>
+        <ol>
+          <li><p>Let <var title="true">cdm</var> be the <var title="true">cdm</var> loaded in <methodref>create</methodref>.</p></li>
+          <li><p>Use the <var title="true">cdm</var> to execute the following steps:</p>
+            <ol>
+              <li>
+                <p>Process the remove request.</p>
+                <p>This may involve exchanging message(s) with the application.</p>
+                <p>Unless this step fails, the CDM must have cleared all stored session data associated with this object, including the <coderef>sessionId</coderef>, before proceeding to the next step.
+                  <span class="non-normative">(A subsequent call to <methodref>loadSession</methodref> with <coderef>sessionId</coderef> would fail because there is no data stored for the <var title="true">sessionId</var>.)</span>
+                </p>
+              </li>
+            </ol>
+          </li>
+          <li><p>Run the following steps asynchronously once the above step has completed:</p>
+            <ol>
+              <li><p>If any of the preceding steps failed, reject <var>promise</var> with a new <code><dom4ref name="exception-domexception">DOMException</dom4ref></code> whose name is the appropriate <a href="#mediakeyerror-names">error name</a> and that has an appropriate message.</p></li>
+              <li><p>Run the <a href="#algorithms-session-close">Session Close</a> algorithm on this object.</p></li>
+              <li><p>Resolve <var>promise</var> with <code>undefined</code>.</p></li>
+            </ol>
+          </li>
+        </ol>
+      </li>
+      <li><p>Return <var>promise</var>.</p></li>
+    </ol>
+
 <!-- Begin HTMLSourceElement -->
     <p>The <codedfn prefix="source">keySystem</codedfn> attribute of <coderef>HTMLSourceElement</coderef> specifies the <a href="#key-system">Key System</a> to be used with the <videoref name="media-resource">media resource</videoref>. The <coderef prefix="source">keySystem</coderef> attribute must be supported by all HTMLSourceElement as both an IDL attribute and also a content attribute named <codedfn prefix="sourcecontent">keysystem</codedfn>.
     The <resource-selection-algorithm/> is modified to check the <coderef prefix="source">keySystem</coderef> attribute after the existing <em>step 5</em> of the <em>Otherwise</em> branch of <em>step 6</em>:
@@ -775,7 +810,8 @@
             The key system <em>name</em> is not supported.<br/>
             The initialization data type <em>type</em> is not supported by the key system.<br/>
             <em>type</em> sessions are not supported by the key system.<br/>
-            The operation is not supported by the key system.
+            The operation is not supported by the key system.<br/>
+            The session is closed.
           </td>
         </tr>
         <tr>
@@ -784,7 +820,10 @@
         </tr>
         <tr>
           <td><dfn id="dfn-InvalidAccessError"><code>InvalidAccessError</code></dfn></td>
-          <td>The <em>name</em> parameter is empty.</td>
+          <td>
+            The <em>name</em> parameter is empty.<br/>
+            The operation is not supported on <em>session type</em> sessions.
+          </td>
         </tr>
         <tr>
           <td><dfn id="dfn-QuotaExceededError"><code>QuotaExceededError</code></dfn></td>
@@ -1145,16 +1184,15 @@
 
     <h3 id="algorithms-session-close">4.6. Session Close</h3>
     <p>The Session Close algorithm is run when the CDM closes the session associated with a <coderef>MediaKeySession</coderef> object.</p>
-    <p class="non-normative">The CDM may close a session at any point, such as in response to a <methodref>release</methodref> call, when the session is no longer needed, or when resources are lost.
+    <p class="non-normative">The CDM may close a session at any point, such as in response to a <methodref>close</methodref> call, when the session is no longer needed, or when system resources are lost.
     Keys in other sessions should be unaffected, even if they have overlapping key IDs.
     </p>
-    <p>If <var title="true">sessionType</var> is "<coderef prefix="sessiontype">persistent</coderef>", the CDM must have cleared all stored session data associated with the <coderef>MediaKeySession</coderef> object.</p>
     <p>The following steps are run:</p>
     <ol>
       <li><p>Let the <var title="true">session</var> be the associated <coderef>MediaKeySession</coderef> object.</p></li>
       <li><p>If the session initData of the <var title="true">session</var> is not empty, remove its entry from the <var title="true">list of active session Initialization Data</var> for the MediaKeys object that created the <var title="true">session</var>.</p></li><!-- Check for empty because loadSession() does not set session initData. -->
       <li><p>Set the <var title="true">session</var>'s <coderef>usableKeyIds</coderef> attribute to an empty Array.</p></li>
-      <li><p>Let <var>promise</var> be the <coderef>close</coderef> attribute of the <var title="true">session</var>.</p></li>
+      <li><p>Let <var>promise</var> be the <coderef>closed</coderef> attribute of the <var title="true">session</var>.</p></li>
       <li><p>Resolve <var>promise</var> with <code>undefined</code>.</p></li>
     </ol>
 
@@ -1535,7 +1573,7 @@
         keySession.addEventListener("<precoderef prefix="event">message</precoderef>", handleMessage, false);
         keySession.addEventListener("<precoderef prefix="event">keyschange</precoderef>", handleKeysChange, false);
         keySession.addEventListener("<precoderef prefix="event">error</precoderef>", handleError, false);
-        keySession.close.then(
+        keySession.<precoderef>closed</precoderef>.then(
           console.log.bind(console, "Session closed")
         );
       }
@@ -1598,7 +1636,6 @@
     <h3 id="example-stored-license" class="exampleheader">8.5. Stored License</h3>
     <p class="exampledescription">This example requests a persistent license for future use and stores it. It also provides functions for later retrieving the license and for destroying it.</p>
 
-    <div class="issue"><div class="issue-title"><span>Issue 7</span></div>There could be a race condition between a CDM-triggered close and setting <var>releaseRequested</var>. This needs to be fixed in the spec. See <a href="https://www.w3.org/Bugs/Public/show_bug.cgi?id=25536">Bug 25536</a>.</div>
     <div class="example">
       <pre class="code">
 &lt;script&gt;
@@ -1621,14 +1658,10 @@
           return; // A session already exists for the initData.
         keySession.addEventListener("<precoderef prefix="event">message</precoderef>", handleMessage, false);
         keySession.addEventListener("<precoderef prefix="event">error</precoderef>", handleError, false);
-        keySession.close.then(
+        keySession.<precoderef>closed</precoderef>.then(
           function() {
             console.log("Session " + this.sessionId + " closed");
-            if (this.releaseRequested) {
-              console.log("Session " + this.sessionId + " destroyed");
-              // The application should remove its record of this.sessionId.
-            }
-          }.bind(keySession),        
+          }.bind(keySession)        
         );
         // Store keySession.<precoderef>sessionId</precoderef> in the application.
       }
@@ -1648,7 +1681,7 @@
         }
         keySession.addEventListener("<precoderef prefix="event">message</precoderef>", handleMessage, false);
         keySession.addEventListener("<precoderef prefix="event">error</precoderef>", handleError, false);
-        keySession.close.then(
+        keySession.<precoderef>closed</precoderef>.then(
           console.log.bind(console, "Session closed")
         );
       }
@@ -1657,16 +1690,22 @@
     );
   }
 
-  // Called when the application wants to remove the license for the media resource.
-  // Calling release() may initiate a series of messages to/from the server.
-  // The license has not been removed until the close promise is fulfilled and
-  // releaseRequested == true.
+  // Called when the application wants to stop using the session without removing the stored license.
+  closeSession(keySession) {
+    keySession.<premethodref>close</premethodref>();
+  }
+
+  // Called when the application wants to remove the stored license.
+  // Calling remove() may initiate a series of messages to/from the server.
+  // The stored session data has not been completely removed until the returned promise is fulfilled.
   removeStoredSession(keySession) {
-    keySession.<premethodref>release</premethodref>().then(
+    keySession.<premethodref>remove</premethodref>().then(
       function() {
-        this.releaseRequested = true;
-      }.bind(keySession),
-      console.error.bind(console, "Unable to release the session")
+        console.log("Session " + this.sessionId + " removed");
+        // The application should remove its record of this.sessionId.
+      }.bind(keySession)
+    ).catch(
+      console.error.bind(console, "Failed to remove the session")
     );
   }