[EME] Bug 20622 - SessionID may be assigned asynchronously in MediaKeys.createSession
authorDavid Dorwin <ddorwin@google.com>
Mon, 28 Oct 2013 12:58:16 -0700
changeset 176 cc4f10560960
parent 175 5369218d899b
child 177 9060ac54fe3d
[EME] Bug 20622 - SessionID may be assigned asynchronously in MediaKeys.createSession

Includes the following changes to the createSession() algorithm:
* Use "message exchange" and "request" instead of "key request".
* Explicitly determine whether a message exchange is required and allow errors
to occur in the not required case.
* sessionId is set asynchronously and possibly as part of or after determining
whether a request is necessary and generating it. It must be set before firing
keymessage or keyready.

Also updated the Session ID definition and added a definition for Key Session.
encrypted-media/encrypted-media.html
encrypted-media/encrypted-media.xml
--- a/encrypted-media/encrypted-media.html	Mon Oct 28 12:54:32 2013 -0700
+++ b/encrypted-media/encrypted-media.html	Mon Oct 28 12:58:16 2013 -0700
@@ -204,23 +204,26 @@
     Key System providers should keep in mind that these will be used for comparison and discovery, so they should be easy to compare and the structure should remain reasonably simple.
     </p>
 
-
-    <h4 id="session-id">1.1.3. Session ID</h4>
-    <p>A Session ID is a string ID that can be used to associate calls related to a key/license lifetime, starting with the request.
-    <span class="non-normative">It is a local binding between a request and key/license.
-    It does not associate keys or licenses for different streams (i.e. audio and video).</span>
-    It is generated by the user agent/CDM and provided to the application in the <code><a href="#dom-keymessage">keymessage</a></code> event.
-    <span class="non-normative">(Session IDs need not necessarily be supported by the underlying content protection client or server.)</span>
+    <h4 id="key-session">1.1.3. Key Session</h4>
+    <p>A Key Session, or simply Session, represents the lifetime of the key(s) it contains and associates all messages related to them.
+    Sessions are embodied as <code><a href="#dom-mediakeysession">MediaKeySession</a></code> objects.
+    Each Key session is associated with a single instance of <a href="#initialization-data">Initialization Data</a> provided in the <code><a href="#dom-createsession">createSession()</a></code> call.
     </p>
 
-    <p>A new Session ID will be generated each time <code><a href="#dom-createsession">createSession()</a></code> successfully creates a <code><a href="#dom-mediakeysession">MediaKeySession</a></code> object.
-    The user agent/CDM manage the lifetime of Session IDs.
-    All Session IDs are cleared from the <a href="#media-element">media element</a> when a load occurs, although the CDM may retain them for longer periods.
+    <h4 id="session-id">1.1.4. Session ID</h4>
+    <p>A Session ID is a unique string identifier generated by the user agent or CDM that can be used by the application to identify <code><a href="#dom-mediakeysession">MediaKeySession</a></code> objects.
+    <span class="non-normative">(The underlying content protection client or server do not necessarily need to support Session IDs.)</span>
     </p>
-    <p>Each SessionID shall be unique within the browsing context in which it was created. If secure proof of key release is supported each Session ID shall
-    be unique within the origin. Note that this last requirement implies that Session IDs shall be unique over time including across browsing sessions.</p>
 
-    <h4 id="initialization-data">1.1.4. Initialization Data</h4>
+    <p>A new Session ID is generated each time the user agent successfully initializes a <code><a href="#dom-mediakeysession">MediaKeySession</a></code> object.
+    It must be valid before the <code><a href="#dom-mediakeysession">MediaKeySession</a></code> enters the <code><a href="#dom-pending">PENDING</a></code> or <code><a href="#dom-ready">READY</a></code> states and the user agent fires the associated events.
+    </p>
+
+    <p>Each Session ID shall be unique within the browsing context in which it was created.
+    <span class="non-normative">(Note: Some use cases may require that Session IDs be unique within the origin over time, including across browsing sessions.)</span>
+    </p>
+
+    <h4 id="initialization-data">1.1.5. Initialization Data</h4>
     <p><i>This section is non-normative.</i></p>
     <p>Initialization Data is a generic term for container-specific data that is used by <a href="#cdm">Content Decryption Modules</a> to generate a key request.
     It should always allow unique identification of the key or keys needed to decrypt the content, possibly after being parsed by a CDM or server.
@@ -236,7 +239,7 @@
     This data has a container-specific format and is assumed to contain one or more generic or Key System-specific sets of initialization information.
     </p>
 
-    <h4 id="cross-origin-support">1.1.5. Cross Origin Support</h4>
+    <h4 id="cross-origin-support">1.1.6. Cross Origin Support</h4>
     <p>During playback, embedded media data is exposed to script in the embedding origin. In order for the API to fire <code><a href="#dom-needkey">needkey</a></code>
     and <code><a href="#dom-keymessage">keymessage</a></code> events, <a href="http://www.w3.org/TR/html5/embedded-content-0.html#media-data">media data</a> must be <a href="http://www.w3.org/TR/html5/infrastructure.html#cors-same-origin">CORS-same-origin</a> with the embedding page.
     If <a href="http://www.w3.org/TR/html5/embedded-content-0.html#media-data">media data</a> is cross-origin with the embedding document, authors should use the <a href="http://www.w3.org/TR/html5/embedded-content-0.html#attr-media-crossorigin">crossorigin</a> attribute
@@ -353,7 +356,6 @@
       <li>Create a new <code><a href="#dom-mediakeysession">MediaKeySession</a></code> object.
         <ol>
           <li><p>Let the <code><a href="#dom-keysystem">keySystem</a></code> attribute be <var title="true">keySystem</var>.</p></li>
-          <li><p>Let the <code><a href="#dom-sessionid">sessionId</a></code> attribute be a unique <a href="#session-id">Session ID</a> string. <span class="non-normative">It may be generated by <var title="true">cdm</var>.</span></p></li>
           <li><p>Let the state of the session be <code><a href="#dom-created">CREATED</a></code>.</p></li>
         </ol>
       </li>
@@ -366,44 +368,57 @@
       </p></li>
 
       <li>
-<p>Schedule a task to generate a key request, providing <var title="true">type</var>, <var title="true">initData</var>, and the new object.</p>
+<p>Schedule a task to initialize the session, providing <var title="true">type</var>, <var title="true">initData</var>, and the new object.</p>
         <p>The user agent will asynchronously execute the following steps in the task:</p>
         <ol>
           <li><p>Let <var title="true">defaultURL</var> be null.</p></li>
+          <li><p>Let <var title="true">request</var> be null.</p></li>
           <li>
-<p>Use <var title="true">cdm</var> to generate a key request and follow the steps for the first matching condition from the following list:</p>
-            <dl class="switch">
-              <dt>If a request is successfully generated</dt>
-              <dd>
-              <ol>
-                <li>
-<p>Let <var title="true">key request</var> be a key request generated by the <a href="#cdm">CDM</a> using <var title="true">initData</var>, if provided. The <var title="true">key request</var> may be empty if the <a href="#cdm">CDM</a> does not need a message exchange.</p>
-                  <p>Note: <var title="true">cdm</var> must not use any stream-specific data, including <a href="http://www.w3.org/TR/html5/embedded-content-0.html#media-data">media data</a>, not provided via <var title="true">initData</var>.</p>
-                  <p class="non-normative"><var title="true">type</var> may be used to determine how to interpret <var title="true">initData</var>.</p>
-                </li>
-                <li><p>If <var title="true">initData</var> contains a default URL for <var title="true">keySystem</var>, let <var title="true">defaultURL</var> be that URL.</p></li> 
-              </ol>
-              </dd>
-              <dt>Otherwise</dt>
-              <dd><ol>
-                <li>
+<p>Use <var title="true">cdm</var> to process <var title="true">type</var> and <var title="true">initData</var>.</p>
+            <ol>
+              <li><p>Determine whether a message exchange <span class="non-normative">(e.g. a license request)</span> is required.</p></li>
+              <li>
+<p>Follow the steps for the first matching condition from the following list:</p>
+                <dl class="switch">
+                  <dt>If a message exchange is required</dt>
+                  <dd>
+                    <ol>
+                      <li>
+<p>Let <var title="true">request</var> be a request generated by the <a href="#cdm">CDM</a> using <var title="true">initData</var>.</p>
+                        <p>Note: <var title="true">cdm</var> must not use any stream-specific data, including <a href="http://www.w3.org/TR/html5/embedded-content-0.html#media-data">media data</a>, not provided via <var title="true">initData</var>.</p>
+                        <p class="non-normative"><var title="true">type</var> may be used to determine how to interpret <var title="true">initData</var>.</p>
+                        <p class="non-normative"><var title="true">request</var> may be a request for multiple keys, depending on the <var title="true"><a href="#key-system">keySystem</a></var> and/or <var title="true">initData</var>. This is transparent to the application.</p>                
+                      </li>
+                      <li><p>If <var title="true">initData</var> contains a default URL for <var title="true">keySystem</var>, let <var title="true">defaultURL</var> be that URL.</p></li> 
+                    </ol>
+                    </dd>
+                  <dt>Otherwise</dt>
+                  <dd>Continue.</dd>
+                </dl>
+              </li>
+              <li>
+<p><i>Error</i>: If any of the preceding processing steps failed</p>
+                  <ol>
+                    <li>
 <p>Create a new <code><a href="#dom-mediakeyerror">MediaKeyError</a></code> object with the following attributes:</p>
-                  <ul style="list-style-type:none"><li>
-                    <code><a href="#dom-code">code</a></code> = the appropriate <code><a href="#dom-mediakeyerror">MediaKeyError</a></code> code<br>
-                    <code><a href="#dom-systemcode">systemCode</a></code> = a Key System-specific value, if provided, and 0 otherwise
-                  </li></ul>
-                </li>
-                <li><p>Set the <code><a href="#dom-mediakeysession">MediaKeySession</a></code> object's <code><a href="#dom-error">error</a></code> attribute to the error object created in the previous step.</p></li>
-                <li><p>Let the state of the session be <code><a href="#dom-stateerror">ERROR</a></code>.</p></li>
-                <li><p><a href="http://www.w3.org/TR/html5/webappapis.html#queue-a-task">queue a task</a> to <a href="http://www.w3.org/TR/html5/webappapis.html#fire-a-simple-event">fire a simple event</a> named <code><a href="#dom-keyerror">keyerror</a></code> at the <code><a href="#dom-mediakeysession">MediaKeySession</a></code> object.</p></li>
-                <li><p>Abort the task.</p></li>
-              </ol></dd>
-            </dl>
+                      <ul style="list-style-type:none"><li>
+                        <code><a href="#dom-code">code</a></code> = the appropriate <code><a href="#dom-mediakeyerror">MediaKeyError</a></code> code<br>
+                        <code><a href="#dom-systemcode">systemCode</a></code> = a Key System-specific value, if provided, and 0 otherwise
+                      </li></ul>
+                    </li>
+                    <li><p>Set the <code><a href="#dom-mediakeysession">MediaKeySession</a></code> object's <code><a href="#dom-error">error</a></code> attribute to the error object created in the previous step.</p></li>
+                    <li><p>Let the state of the session be <code><a href="#dom-stateerror">ERROR</a></code>.</p></li>
+                    <li><p><a href="http://www.w3.org/TR/html5/webappapis.html#queue-a-task">queue a task</a> to <a href="http://www.w3.org/TR/html5/webappapis.html#fire-a-simple-event">fire a simple event</a> named <code><a href="#dom-keyerror">keyerror</a></code> at the <code><a href="#dom-mediakeysession">MediaKeySession</a></code> object.</p></li>
+                    <li><p>Abort the task.</p></li>
+                  </ol>
+              </li>
+            </ol>
           </li>
+          <li><p>Let the <code><a href="#dom-sessionid">sessionId</a></code> attribute be a unique <a href="#session-id">Session ID</a> string. <span class="non-normative">It may be obtained from <var title="true">cdm</var>.</span></p></li>
           <li>
 <p>Follow the steps for the first matching condition from the following list:</p>
             <dl class="switch">
-              <dt>If the <var title="true">key request</var> is not empty</dt>
+              <dt>If <var title="true">request</var> is not null</dt>
               <dd>
                 <ol>
                   <li><p>Let the state of the session be <code><a href="#dom-pending">PENDING</a></code>.</p></li>
@@ -411,14 +426,13 @@
                     <p><a href="http://www.w3.org/TR/html5/webappapis.html#queue-a-task">queue a task</a> to <a href="http://www.w3.org/TR/html5/webappapis.html#fire-a-simple-event">fire a simple event</a> named <code><a href="#dom-keymessage">keymessage</a></code> at the new object.</p>
                     <p>The event is of type <code><a href="#dom-mediakeymessageevent">MediaKeyMessageEvent</a></code> and has:</p>
                     <ul style="list-style-type:none"><li>
-                      <code><a href="#dom-message">message</a></code> = <var title="true">key request</var><br>
+                      <code><a href="#dom-message">message</a></code> = <var title="true">request</var><br>
                       <code><a href="#dom-destinationurl">destinationURL</a></code> = <var title="true">defaultURL</var>
                     </li></ul>
-                    <p class="non-normative">Note: <code><a href="#dom-message">message</a></code> may be a request for multiple keys, depending on the <var title="true"><a href="#key-system">keySystem</a></var> and/or <var title="true">initData</var>. This is transparent to the application.</p>                
                   </li>
                 </ol>
               </dd>
-              <dt>If the <var title="true">key request</var> is empty</dt>
+              <dt>Otherwise</dt>
               <dd>
                 <ol>
                   <li><p>Let the state of the session be <code><a href="#dom-ready">READY</a></code>.</p></li>
--- a/encrypted-media/encrypted-media.xml	Mon Oct 28 12:54:32 2013 -0700
+++ b/encrypted-media/encrypted-media.xml	Mon Oct 28 12:58:16 2013 -0700
@@ -201,23 +201,26 @@
     Key System providers should keep in mind that these will be used for comparison and discovery, so they should be easy to compare and the structure should remain reasonably simple.
     </p>
 
-
-    <h4 id="session-id">1.1.3. Session ID</h4>
-    <p>A Session ID is a string ID that can be used to associate calls related to a key/license lifetime, starting with the request.
-    <span class="non-normative">It is a local binding between a request and key/license.
-    It does not associate keys or licenses for different streams (i.e. audio and video).</span>
-    It is generated by the user agent/CDM and provided to the application in the <coderef>keymessage</coderef> event.
-    <span class="non-normative">(Session IDs need not necessarily be supported by the underlying content protection client or server.)</span>
+    <h4 id="key-session">1.1.3. Key Session</h4>
+    <p>A Key Session, or simply Session, represents the lifetime of the key(s) it contains and associates all messages related to them.
+    Sessions are embodied as <coderef>MediaKeySession</coderef> objects.
+    Each Key session is associated with a single instance of <a href="#initialization-data">Initialization Data</a> provided in the <methodref>createSession</methodref> call.
     </p>
 
-    <p>A new Session ID will be generated each time <methodref>createSession</methodref> successfully creates a <coderef>MediaKeySession</coderef> object.
-    The user agent/CDM manage the lifetime of Session IDs.
-    All Session IDs are cleared from the <a href="#media-element">media element</a> when a load occurs, although the CDM may retain them for longer periods.
+    <h4 id="session-id">1.1.4. Session ID</h4>
+    <p>A Session ID is a unique string identifier generated by the user agent or CDM that can be used by the application to identify <coderef>MediaKeySession</coderef> objects.
+    <span class="non-normative">(The underlying content protection client or server do not necessarily need to support Session IDs.)</span>
     </p>
-    <p>Each SessionID shall be unique within the browsing context in which it was created. If secure proof of key release is supported each Session ID shall
-    be unique within the origin. Note that this last requirement implies that Session IDs shall be unique over time including across browsing sessions.</p>
 
-    <h4 id="initialization-data">1.1.4. Initialization Data</h4>
+    <p>A new Session ID is generated each time the user agent successfully initializes a <coderef>MediaKeySession</coderef> object.
+    It must be valid before the <coderef>MediaKeySession</coderef> enters the <coderef>PENDING</coderef> or <coderef>READY</coderef> states and the user agent fires the associated events.
+    </p>
+
+    <p>Each Session ID shall be unique within the browsing context in which it was created.
+    <span class="non-normative">(Note: Some use cases may require that Session IDs be unique within the origin over time, including across browsing sessions.)</span>
+    </p>
+
+    <h4 id="initialization-data">1.1.5. Initialization Data</h4>
     <non-normative-section/>
     <p>Initialization Data is a generic term for container-specific data that is used by <a href="#cdm">Content Decryption Modules</a> to generate a key request.
     It should always allow unique identification of the key or keys needed to decrypt the content, possibly after being parsed by a CDM or server.
@@ -233,7 +236,7 @@
     This data has a container-specific format and is assumed to contain one or more generic or Key System-specific sets of initialization information.
     </p>
 
-    <h4 id="cross-origin-support">1.1.5. Cross Origin Support</h4>
+    <h4 id="cross-origin-support">1.1.6. Cross Origin Support</h4>
     <p>During playback, embedded media data is exposed to script in the embedding origin. In order for the API to fire <coderef>needkey</coderef>
     and <coderef>keymessage</coderef> events, <videoanchor name="media-data">media data</videoanchor> must be <cors-same-origin/> with the embedding page.
     If <videoanchor name="media-data">media data</videoanchor> is cross-origin with the embedding document, authors should use the <videoanchor name="attr-media-crossorigin">crossorigin</videoanchor> attribute
@@ -348,7 +351,6 @@
       <li>Create a new <coderef>MediaKeySession</coderef> object.
         <ol>
           <li><p>Let the <coderef>keySystem</coderef> attribute be <var title="true">keySystem</var>.</p></li>
-          <li><p>Let the <coderef>sessionId</coderef> attribute be a unique <a href="#session-id">Session ID</a> string. <span class="non-normative">It may be generated by <var title="true">cdm</var>.</span></p></li>
           <li><p>Let the state of the session be <coderef>CREATED</coderef>.</p></li>
         </ol>
       </li>
@@ -360,40 +362,51 @@
         then <queue-a-task/> to <fire-a-simple-event/> named <coderef>keyerror</coderef> at the <coderef>MediaKeySession</coderef> object and abort these steps.
       </p></li>
 
-      <li><p>Schedule a task to generate a key request, providing <var title="true">type</var>, <var title="true">initData</var>, and the new object.</p>
+      <li><p>Schedule a task to initialize the session, providing <var title="true">type</var>, <var title="true">initData</var>, and the new object.</p>
         <p>The user agent will asynchronously execute the following steps in the task:</p>
         <ol>
           <li><p>Let <var title="true">defaultURL</var> be null.</p></li>
-          <li><p>Use <var title="true">cdm</var> to generate a key request and follow the steps for the first matching condition from the following list:</p>
-            <dl class="switch">
-              <dt>If a request is successfully generated</dt>
-              <dd>
-              <ol>
-                <li><p>Let <var title="true">key request</var> be a key request generated by the <a href="#cdm">CDM</a> using <var title="true">initData</var>, if provided. The <var title="true">key request</var> may be empty if the <a href="#cdm">CDM</a> does not need a message exchange.</p>
-                  <p>Note: <var title="true">cdm</var> must not use any stream-specific data, including <videoanchor name="media-data">media data</videoanchor>, not provided via <var title="true">initData</var>.</p>
-                  <p class="non-normative"><var title="true">type</var> may be used to determine how to interpret <var title="true">initData</var>.</p>
-                </li>
-                <li><p>If <var title="true">initData</var> contains a default URL for <var title="true">keySystem</var>, let <var title="true">defaultURL</var> be that URL.</p></li> 
-              </ol>
-              </dd>
-              <dt>Otherwise</dt>
-              <dd><ol>
-                <li><p>Create a new <coderef>MediaKeyError</coderef> object with the following attributes:</p>
-                  <ul style="list-style-type:none"><li>
-                    <coderef>code</coderef> = the appropriate <coderef>MediaKeyError</coderef> code<br></br>
-                    <coderef>systemCode</coderef> = a Key System-specific value, if provided, and 0 otherwise
-                  </li></ul>
-                </li>
-                <li><p>Set the <coderef>MediaKeySession</coderef> object's <coderef>error</coderef> attribute to the error object created in the previous step.</p></li>
-                <li><p>Let the state of the session be <coderef prefix="state">ERROR</coderef>.</p></li>
-                <li><p><queue-a-task/> to <fire-a-simple-event/> named <coderef>keyerror</coderef> at the <coderef>MediaKeySession</coderef> object.</p></li>
-                <li><p>Abort the task.</p></li>
-              </ol></dd>
-            </dl>
+          <li><p>Let <var title="true">request</var> be null.</p></li>
+          <li><p>Use <var title="true">cdm</var> to process <var title="true">type</var> and <var title="true">initData</var>.</p>
+            <ol>
+              <li><p>Determine whether a message exchange <span class="non-normative">(e.g. a license request)</span> is required.</p></li>
+              <li><p>Follow the steps for the first matching condition from the following list:</p>
+                <dl class="switch">
+                  <dt>If a message exchange is required</dt>
+                  <dd>
+                    <ol>
+                      <li><p>Let <var title="true">request</var> be a request generated by the <a href="#cdm">CDM</a> using <var title="true">initData</var>.</p>
+                        <p>Note: <var title="true">cdm</var> must not use any stream-specific data, including <videoanchor name="media-data">media data</videoanchor>, not provided via <var title="true">initData</var>.</p>
+                        <p class="non-normative"><var title="true">type</var> may be used to determine how to interpret <var title="true">initData</var>.</p>
+                        <p class="non-normative"><var title="true">request</var> may be a request for multiple keys, depending on the <var title="true"><a href="#key-system">keySystem</a></var> and/or <var title="true">initData</var>. This is transparent to the application.</p>                
+                      </li>
+                      <li><p>If <var title="true">initData</var> contains a default URL for <var title="true">keySystem</var>, let <var title="true">defaultURL</var> be that URL.</p></li> 
+                    </ol>
+                    </dd>
+                  <dt>Otherwise</dt>
+                  <dd>Continue.</dd>
+                </dl>
+              </li>
+              <li><p><i>Error</i>: If any of the preceding processing steps failed</p>
+                  <ol>
+                    <li><p>Create a new <coderef>MediaKeyError</coderef> object with the following attributes:</p>
+                      <ul style="list-style-type:none"><li>
+                        <coderef>code</coderef> = the appropriate <coderef>MediaKeyError</coderef> code<br></br>
+                        <coderef>systemCode</coderef> = a Key System-specific value, if provided, and 0 otherwise
+                      </li></ul>
+                    </li>
+                    <li><p>Set the <coderef>MediaKeySession</coderef> object's <coderef>error</coderef> attribute to the error object created in the previous step.</p></li>
+                    <li><p>Let the state of the session be <coderef prefix="state">ERROR</coderef>.</p></li>
+                    <li><p><queue-a-task/> to <fire-a-simple-event/> named <coderef>keyerror</coderef> at the <coderef>MediaKeySession</coderef> object.</p></li>
+                    <li><p>Abort the task.</p></li>
+                  </ol>
+              </li>
+            </ol>
           </li>
+          <li><p>Let the <coderef>sessionId</coderef> attribute be a unique <a href="#session-id">Session ID</a> string. <span class="non-normative">It may be obtained from <var title="true">cdm</var>.</span></p></li>
           <li><p>Follow the steps for the first matching condition from the following list:</p>
             <dl class="switch">
-              <dt>If the <var title="true">key request</var> is not empty</dt>
+              <dt>If <var title="true">request</var> is not null</dt>
               <dd>
                 <ol>
                   <li><p>Let the state of the session be <coderef>PENDING</coderef>.</p></li>
@@ -401,14 +414,13 @@
                     <p><queue-a-task/> to <fire-a-simple-event/> named <coderef>keymessage</coderef> at the new object.</p>
                     <p>The event is of type <coderef>MediaKeyMessageEvent</coderef> and has:</p>
                     <ul style="list-style-type:none"><li>
-                      <coderef>message</coderef> = <var title="true">key request</var><br></br>
+                      <coderef>message</coderef> = <var title="true">request</var><br></br>
                       <coderef>destinationURL</coderef> = <var title="true">defaultURL</var>
                     </li></ul>
-                    <p class="non-normative">Note: <coderef>message</coderef> may be a request for multiple keys, depending on the <var title="true"><a href="#key-system">keySystem</a></var> and/or <var title="true">initData</var>. This is transparent to the application.</p>                
                   </li>
                 </ol>
               </dd>
-              <dt>If the <var title="true">key request</var> is empty</dt>
+              <dt>Otherwise</dt>
               <dd>
                 <ol>
                   <li><p>Let the state of the session be <coderef>READY</coderef>.</p></li>