HTML Standard Tracker

Diff (omit for latest revision)
Filter

Short URL: http://html5.org/r/5945

File a bug

SVNBugCommentTime (UTC)
5945[Gecko] [Internet Explorer] [Opera] [Webkit] Completely revamp how peer-to-peer networking works (and some minor typo fixes in other parts of the spec). This is only a second draft, and therefore this feature will likely evolve a lot over the coming months. Detailed responses to feedback on the topic will be sent out soon.2011-03-14 10:19
Index: source
===================================================================
--- source	(revision 5944)
+++ source	(revision 5945)
@@ -74,7 +74,7 @@
   of HTML5) currently consist of:</p>
 
   <ul class="brief">
-   <li>The <code>device</code> element.</li> <!--DEVICE-->
+   <li>The <code>PeerConnection</code> API and related video-conferencing features.</li> <!--DEVICE-->
    <li>The <code title="attr-hyperlink-ping">ping</code> attribute and related <span>hyperlink auditing</span> features.</li> <!--PING-->
    <li>The <span>WebVTT</span> format and some <span>text track</span> API features.</li> <!--TT--> <!--TTVTT-->
    <li>Rules for <a href="#atom">converting HTML to Atom</a>.</li> <!--MD-->
@@ -26631,7 +26631,7 @@
  zero or more <code>track</code> elements, then
 <!--KEEP-START w3c-html--><!--TT-->
  <span>transparent</span>, but with no <span>media element</span> descendants.</dd>
-   <dd>If the element does not have a <code title="attr-media-src">src</code> attribute: one or more <code>source</code> elements, then
+   <dd>If the element does not have a <code title="attr-media-src">src</code> attribute: zero or more <code>source</code> elements, then
 <!--KEEP-END w3c-html--><!--TT-->
  zero or more <code>track</code> elements, then
 <!--KEEP-START w3c-html--><!--TT-->
@@ -29593,8 +29593,8 @@
     <span>queue a task</span> to <span>fire a simple event</span>
     named <code title="event-media-playing">playing</code>.</p>
 
-    <p class="note">User agents are not required to autoplay, and it
-    is suggested that user agents honor user preferences on the
+    <p class="note">User agents do not need to support autoplay,
+    and it is suggested that user agents honor user preferences on the
     matter. Authors are urged to use the <code
     title="attr-media-autoplay">autoplay</code> attribute rather than
     using script to force the video to play, so as to allow the user
@@ -57097,256 +57097,8 @@
   </div>
 
 
-<!--END w3c-html--><!--DEVICE-->
-<div data-component="other Hixie drafts (editor: Ian Hickson)">
-<!--START html-device-->
 
-  <h4 id="devices">The <dfn><code>device</code></dfn> element</h4>
 
-  <dl class="element">
-   <dt>Categories</dt>
-   <dd><span>Flow content</span>.</dd>
-   <dd><span>Phrasing content</span>.</dd>
-   <dd><span>Interactive content</span>.</dd>
-   <dt>Contexts in which this element can be used:</dt>
-   <dd>Where <span>phrasing content</span> is expected.</dd>
-   <dt>Content model:</dt>
-   <dd>Empty.</dd>
-   <dt>Content attributes:</dt>
-   <dd><span>Global attributes</span></dd>
-   <dd><code title="attr-device-type">type</code></dd>
-   <dt>DOM interface:</dt>
-   <dd>
-<pre class="idl">interface <dfn>HTMLDeviceElement</dfn> : <span>HTMLElement</span> {
-           attribute DOMString <span title="dom-device-type">type</span>;
-  readonly attribute any <span title="dom-device-data">data</span>;
-};</pre>
-  </dl>
-
-  <p>The <code>device</code> element represents a device selector, to
-  allow the user to give the page access to a device, for example a
-  video camera.</p>
-
-  <p>The <dfn title="attr-device-type"><code>type</code></dfn>
-  attribute allows the author to specify which kind of device the page
-  would like access to. The attribute is an <span>enumerated
-  attribute</span> with the keywords given in the first column of the
-  following table, and their corresponding states given in the cell in
-  second column of the same row.</p>
-
-  <p class="XXX">RS232 and USB are only included below to give an idea
-  of where we could go with this. <strong>Should we instead just make
-  this only useful for audiovisual streams?</strong> Unless there are
-  compelling reasons, we probably should not be this generic. So far,
-  the reasons for RS232 aren't that compelling. For USB, slightly more
-  so.</p>
-
-  <table>
-   <thead>
-    <tr>
-     <th>Keyword
-     <th>State
-     <th>Device description
-     <th>Examples
-   <tbody>
-    <tr>
-     <td><dfn title="attr-device-type-keyword-media"><code>media</code></dfn>
-     <td><span title="attr-device-type-media">Media</span>
-     <td>Stream of audio and/or video data.
-     <td>A webcam.
-    <tr>
-     <td><dfn title="attr-device-type-keyword-fs"><code>fs</code></dfn>
-     <td><span title="attr-device-type-fs">File system</span>
-     <td>File system.
-     <td>A USB-connected media player.
-    <tr>
-     <td><dfn title="attr-device-type-keyword-rs232"><code>rs232</code></dfn>
-     <td><span title="attr-device-type-rs232">RS232</span>
-     <td>RS232 device.
-     <td>A serial port.
-    <tr>
-     <td><dfn title="attr-device-type-keyword-usb"><code>usb</code></dfn>
-     <td><span title="attr-device-type-usb">USB</span>
-     <td>USB device.
-     <td>A scanner, a music player, a disk jockey, a fish tank.
-  </table>
-
-  <p class="XXX">processing model: 'change' event fires once user
-  selects a new device; .data is set to new Stream, LocalFS, USB, or
-  RS232 object as appropriate.</p>
-
-  <div class="example">
-
-   <pre>&lt;p>To start chatting, select a video camera: &lt;device type=media onchange="update(this.data)">&lt;/p>
-&lt;video autoplay>&lt;/video>
-&lt;script>
- function update(stream) {
-   document.getElementsByTagName('video')[0].src = stream.url;
- }
-&lt;/script></pre>
-
-  </div>
-
-  <p class="XXX">The <code>device</code> element is intended to be a
-  void element, but the parser spec hasn't yet been updated. This
-  section of the spec is very much awaiting implementation
-  experience.</p>
-
-
-  <h5>Stream API</h5>
-
-  <p>The <code>Stream</code> interface is used to represent
-  streams.</p>
-
-  <pre class="idl">interface <dfn>Stream</dfn> {
-  readonly attribute DOMString <span title="dom-stream-url">url</span>;
-  <span>StreamRecorder</span> <span title="dom-stream-record">record</span>();
-};</pre>
-
-  <p>The <dfn title="dom-stream-url"><code>url</code></dfn> attribute
-  must return a <span title="fileURN">File URN</span> representing the
-  stream. <a href="#refsFILEAPI">[FILEAPI]</a></p>
-
-  <p>For audio and video streams, the stream must be in a format
-  supported by the user agent for use in <code>audio</code> and
-  <code>video</code> elements.</p>
-
-  <p class="XXX">This will be pinned down to a specific codec.</p>
-
-  <p>When the <dfn
-  title="dom-stream-record"><code>record()</code></dfn> method is
-  invoked, the user agent must return a new
-  <code>StreamRecorder</code> object associated with the stream.</p>
-
-  <pre class="idl">interface <dfn>StreamRecorder</dfn> {
-  <span>File</span> <span title="dom-StreamRecorder-stop">stop</span>();
-};</pre>
-
-  <p>The <dfn
-  title="dom-StreamRecorder-stop"><code>stop()</code></dfn> method
-  must return a new <code>File</code> object representing the data
-  that was streamed between the creation of the
-  <code>StreamRecorder</code> object and the invocation of the <code
-  title="dom-StreamRecorder-stop">stop()</code> method. <a
-  href="#refsFILEAPI">[FILEAPI]</a></p>
-
-  <p>For audio and video streams, the file must be in a format
-  supported by the user agent for use in <code>audio</code> and
-  <code>video</code> elements.</p>
-
-  <p class="XXX">This again will be pinned down to a specific codec.</p>
-
-
-  <h5>Peer-to-peer connections</h5>
-
-  <p class="XXX">This section will be moved to a more appropriate
-  location in due course; it is here currently to keep it near the
-  <code>device</code> element to allow reviewers to look at it.</p>
-
-  <pre class="idl">[Constructor(in DOMString serverConfiguration)]
-interface <dfn>ConnectionPeer</dfn> {
-  void sendText(in DOMString text, in optional boolean unimportant); // if second arg is true, then use unreliable low-latency transport (UDP-like), otherwise guarantee delivery (TCP-like)
-           attribute <span>Function</span> ontext; // receiving
-
-  void sendBitmap(in HTMLImageElement image);
-           attribute <span>Function</span> onbitmap; // receiving
-
-  void sendFile(in File file);
-           attribute <span>Function</span> onfile; // receiving
-
-  void addStream(in Stream stream);
-  void removeStream(in Stream stream);
-  readonly attribute Stream[] localStreams;
-  readonly attribute Stream[] remoteStreams;
-           attribute <span>Function</span> onstream; // receiving
-
-  void <span title="dom-ConnectionPeer-getLocalConfiguration">getLocalConfiguration</span>(in <span>ConnectionPeerConfigurationCallback</span> callback); // maybe this should be in the constructor, or be an event
-  void <span title="dom-ConnectionPeer-addRemoteConfiguration">addRemoteConfiguration</span>(in DOMString configuration, in optional DOMString remoteOrigin); // remote origin is assumed to be same-origin if not specified. If specified, has to match remote origin (checked in handshake). Should support leading "*." to mean "any subdomain of".
-  void close(); // disconnects and stops listening
-
-           attribute <span>Function</span> onconnect;
-           attribute <span>Function</span> onerror;
-           attribute <span>Function</span> ondisconnect;
-};
-<span>ConnectionPeer</span> implements <span>EventTarget</span>;
-
-[Callback=FunctionOnly, NoInterfaceObject]
-interface <dfn>ConnectionPeerConfigurationCallback</dfn> {
-  void <span title="dom-ConnectionPeerConfigurationCallback-handleEvent">handleEvent</span>(in <span>ConnectionPeer</span> server, in DOMString configuration);
-};</pre>
-
-  <p class="XXX">...</p>
-
-  <div class="XXX">
-
-   <p>This relies on some currently hypothetical other standard to
-   define:</p>
-
-   <ul>
-    <li>The format of server configuration strings.
-    <li>The format of client configuration strings.
-    <li>The protocols that clients use to talk to third-party servers mentioned in the server configuration strings.
-    <li>The protocols that clients use to talk to each other.
-   </ul>
-
-  </div>
-
-  <div class="example">
-
-   <p>When two peers decide they are going to set up a connection to
-   each other, they both go through these steps. The serverConfig
-   comes from a third-party server they can use to get things like
-   their public IP address or to set up NAT traversal. They also have
-   to send their respective configuration to each other using the same
-   out-of-band mechanism they used to establish that they were going
-   to communicate in the first place.</p>
-
-   <pre>var serverConfig = ...; // configuration string obtained from server
-// contains details such as the IP address of a server that can speak some
-// protocol to help the client determine its public IP address, route packets
-// if necessary, etc.
-
-var local = new ConnectionPeer(serverConfig);
-local.getLocalConfiguration(function (configuration) {
-  if (configuration != '') {
-    ...; // send configuration to other peer using out-of-band mechanism
-  } else {
-    // we've exhausted our options; wait for connection
-  }
-});
-
-function ... (configuration) {
-  // called whenever we get configuration information out-of-band
-  local.addRemoteConfiguration(configuration);
-}
-
-local.onconnect = function (event) {
-  // we are connected!
-  local.sendText('Hello');
-  local.addStream(...); // send video
-  local.onstream = function (event) {
-    // receive video
-    // (videoElement is some &lt;video> element)
-    if (local.remoteStreams.length > 0)
-      videoElement.src = local.remoteStreams[0].url;
-  };
-};</pre>
-
-  </div>
-
-  <p class="warning">To prevent network sniffing from allowing a
-  fourth party to establish a connection to a peer using the
-  information sent out-of-band to the other peer and thus spoofing the
-  client, the configuration information should always be transmitted
-  using an encrypted connection.</p>
-
-<!--END html-device-->
-</div>
-<!--START w3c-html--><!--DEVICE-->
-
-
-
-
   <h3 id="links">Links</h3>
 
   <h4>Introduction</h4>
@@ -75962,7 +75714,6 @@
 
 
 
-
   <h2 id="editing"><dfn>User interaction</dfn></h2>
 
 
@@ -81193,9 +80944,1711 @@
  "justifycenter", "justifyright", "justifyfull", "indent", "outdent"
 -->
 
+<!--END w3c-html-->
+<div data-component="other Hixie drafts (editor: Ian Hickson)">
 
-<!--END html--><!--END dev-html--><!--END w3c-html-->
+  <h2>Video conferencing and peer-to-peer communication</h2>
 
+  <h3>Introduction</h3>
+
+  <!--END dev-html--><p><i>This section is non-normative.</i></p><!--START dev-html-->
+
+  <p>There are a number of facets to video-conferencing in HTML:</p>
+
+  <ul>
+
+   <li>Getting a multimedia stream (video, audio, or both) from local
+   devices (video cameras, microphones, Web cams) or from prerecorded
+   files provided by the user.</li>
+
+   <li>Recording such streams locally.</li>
+
+   <li>Connecting to remote peers using NAT-traversal technologies
+   such as ICE, STUN, and TURN.</li>
+
+   <li>Sending the locally-produced streams to remote peers and
+   receiving streams from remote peers.</li>
+
+   <li>Displaying such streams (both the locally-produced ones and the
+   remotely-obtained ones) locally using the <code>video</code> or
+   <code>audio</code> elements.</li>
+
+   <li>Sending arbitrary data to remote peers.</li>
+
+  </ul>
+
+  <p>This section defines the APIs used for these features.</p>
+
+
+  <h4>Obtaining local multimedia content</h4>
+
+  <pre class="idl">[Supplemental, NoInterfaceObject]
+interface <dfn>NavigatorUserMedia</dfn> {
+  void <span title="dom-navigator-getUserMedia">getUserMedia</span>(in DOMString options, in <span>NavigatorUserMediaSuccessCallback</span> successCallback, in optional <span>NavigatorUserMediaErrorCallback</span> errorCallback);
+};
+<span>Navigator</span> implements <span>NavigatorUserMedia</span>;
+
+[Callback=FunctionOnly, NoInterfaceObject]
+interface <dfn>NavigatorUserMediaSuccessCallback</dfn> {
+  void <span title="dom-NavigatorUserMediaSuccessCallback-handleEvent">handleEvent</span>(in <span>GeneratedStream</span> stream);
+};
+
+[NoInterfaceObject]<!-- this is based on PositionError in geolocation -->
+interface <dfn>NavigatorUserMediaError</dfn> {
+  const unsigned short <span title="dom-NavigatorUserMediaError-PERMISSION_DENIED">PERMISSION_DENIED</span> = 1;<!--
+  const unsigned short <span title="dom-NavigatorUserMediaError-UNAVAILABLE">UNAVAILABLE</span> = 2;
+  const unsigned short <span title="dom-NavigatorUserMediaError-TIMEOUT">TIMEOUT</span> = 3;-->
+  readonly attribute unsigned short <span title="dom-NavigatorUserMediaError-code">code</span>;<!--
+  readonly attribute DOMString <span title="dom-NavigatorUserMediaError-message">message</span>;-->
+};
+
+[Callback=FunctionOnly, NoInterfaceObject]
+interface <dfn>NavigatorUserMediaErrorCallback</dfn> {
+  void <span title="dom-NavigatorUserMediaSuccessCallback-handleEvent">handleEvent</span>(in <span>NavigatorUserMediaError</span> error);
+};</pre>
+
+  <dl class="domintro">
+
+   <dt><var title="">window</var> . <code title="dom-navigator">navigator</code> . <code title="dom-navigator-getUserMedia">getUserMedia</code>(<var title="">options</var>, <var title="">successCallback</var> [, <var title="">errorCallback</var> ] )</dt>
+
+   <dd>
+
+    <p>Prompts the user for permission to use their Web cam or other
+    video or audio input.</p>
+
+    <p>The <var title="">options</var> argument is a string of
+    comma-separated values from the following list:</p>
+
+    <dl>
+
+
+     <dt>"<code title="">audio</code>"</dt>
+
+     <dd>The provided media needs to include audio data.</dd>
+
+
+     <dt>"<code title="">video</code>"</dt>
+
+     <dd>The provided media needs to include video data.</dd>
+
+
+    </dl>
+
+    <p>If the user accepts, the <var title="">successCallback</var> is
+    invoked, with a suitable <code>GeneratedStream</code> object as
+    its argument.</p>
+
+    <p>If the user declines, the <var title="">errorCallback</var> (if
+    any) is invoked.</p>
+
+   </dd>
+
+
+   <dt><var title="">error</var> . <code title="dom-NavigatorUserMediaError-code">code</code></dt>
+
+   <dd>
+
+    <p>Returns the current error's error code. At this time, this will
+    always be 1, for which the constant <code
+    title="dom-NavigatorUserMediaError-PERMISSION_DENIED">PERMISSION_DENIED</code>
+    is defined.</p>
+
+   </dd>
+
+  </dl>
+
+  <div class="impl">
+
+  <p>When the <dfn
+  title="dom-navigator-getUserMedia"><code>getUserMedia()</code></dfn>
+  method is called, the user agent must run the following steps:</p>
+
+  <ol>
+
+   <li><p>Let <var title="">options</var> be the method's first
+   argument.</p></li>
+
+   <li><p>Let <var title="">successCallback</var> be the callback
+   indicated by the method's second argument.</p></li>
+
+   <li><p>Let <var title="">errorCallback</var> be the callback
+   indicated by the method's third argument, if any, or null
+   otherwise.</p></li>
+
+   <li><p>If <var title="">successCallback</var> is null, abort these
+   steps.</p></li> <!-- we could throw an exception instead (that's
+   why the method doesn't return until later: so that we can add an
+   exception here, or for /options/ below, without changing the
+   algorithm) -->
+
+   <li><p><span title="split a string on spaces">Split <var
+   title="">options</var> on spaces</span> to obtain <var
+   title="">list of options</var>.</p></li>
+
+   <li><p>If one of the tokens in <var title="">list of options</var>
+   is a <span>case-sensitive</span> match for the string "<code
+   title="">audio</code>", let <var title="">audio</var> be true.
+   Otherwise, let it be false.</p></li>
+
+   <li><p>If one of the tokens in <var title="">list of options</var>
+   is a <span>case-sensitive</span> match for the string "<code
+   title="">video</code>", let <var title="">video</var> be true.
+   Otherwise, let it be false.</p></li>
+
+   <!-- any error handling for /options/ should be done here (that's
+   why the method doesn't return until the next step: so we can add
+   exception throwing here) -->
+
+   <li><p>Return, and run the remaining steps asynchronously.</p></li>
+
+   <li><p>Optionally, e.g. based on a previously-established user
+   preference, for security reasons, or due to platform limitations,
+   jump to the step labeled <i>failure</i> below.</p></li>
+
+   <li>
+
+    <p>Prompt the user in a user-agent-specific manner for permission
+    to provide the <span>entry script</span>'s <span>origin</span>
+    with a <code>GeneratedStream</code> object representing a media
+    stream.</p>
+
+    <p>If <var title="">audio</var> is true, then the provided media
+    should include an audio component. If <var title="">audio</var>
+    is false, then the provided media must not include an audio
+    component.</p>
+
+    <p>If <var title="">video</var> is true, then the provided media
+    should include a video component. If <var title="">video</var> is
+    false, then the provided media must not include a video
+    component.</p>
+
+    <p>User agents are encouraged to default to using the user's
+    primary or system default camera and/or microphone (as
+    appropriate) to generate the media stream. User agents may allow
+    users to use any media source, including pre-recorded media
+    files.</p>
+
+    <p>If the user grants permission to use local recording devices,
+    user agents are encouraged to include a prominent indicator that
+    the devices are "hot" (i.e. an "on-air" or "recording"
+    indicator).</p>
+
+    <p>If the user denies permission, jump to the step labeled
+    <i>failure</i> below. If the user never responds, this algorithm
+    stalls on this step.</p>
+
+   </li>
+
+   <li><p>Let <var title="">stream</var> be the
+   <code>GeneratedStream</code> object for which the user granted
+   permission.</p></li>
+
+   <li><p><span>Queue a task</span> to invoke <var
+   title="">successCallback</var> with <var title="">stream</var> as
+   its argument.</p></li>
+
+   <li><p>Abort these steps.</p></li>
+
+   <li><p><i>Failure</i>: If <var title="">errorCallback</var> is
+   null, abort these steps.</p></li>
+
+   <li><p>Let <var title="">error</var> be a new
+   <code>NavigatorUserMediaError</code> object whose <code
+   title="dom-NavigatorUserMediaError-code">code</code> attribute has
+   the numeric value 1 (<code
+   title="dom-NavigatorUserMediaError-PERMISSION_DENIED">PERMISSION_DENIED</code>).</p></li>
+
+   <li><p><span>Queue a task</span> to invoke <var
+   title="">errorCallback</var> with <var title="">error</var> as its
+   argument.</p></li>
+
+  </ol>
+
+  <p>The <span>task source</span> for these <span
+  title="concept-task">tasks</span> is the <span>user interaction task
+  source</span>.</p>
+
+  <hr>
+
+  <p>The <dfn title="dom-NavigatorUserMediaError-code"><code>code</code></dfn>
+  attribute of a <code>NavigatorUserMediaError</code> object must return the code
+  for the error, which must be <!--one of--> the following:</p>
+
+  <dl>
+
+   <dt><dfn title="dom-NavigatorUserMediaError-PERMISSION_DENIED"><code>PERMISSION_DENIED</code></dfn> (numeric value 1)</dt>
+
+   <dd>The user denied the page permission to use the user's media devices.</dd>
+
+  </dl>
+
+  </div>
+
+  <div class="example">
+
+   <p>A voice chat feature in a game could attempt to get access to
+   the user's microphone by calling the API as follows:</p>
+
+   <pre>&lt;script>
+ navigator.getUserMedia('audio', gotAudio);
+ function gotAudio(stream) {
+   // ... use 'stream' ...
+ }
+&lt;/script></pre>
+
+  </div>
+
+  <div class="example">
+
+   <p>A video-conferencing system would ask for both audio and video:</p>
+
+   <pre>&lt;script>
+ function beginCall() {
+   navigator.getUserMedia('audio,video', gotStream);
+ }
+ function gotStream(stream) {
+   // ... use 'stream' ...
+ }
+&lt;/script></pre>
+
+  </div>
+
+
+
+  <h4>Stream API</h4>
+
+  <p>The <code>Stream</code> interface is used to represent streams,
+  typically (but not necessarily) of audio and/or video content, e.g.
+  from a local camera or a remote site.</p>
+
+  <p>The <code>GeneratedStream</code> interface is used when the user
+  agent is generating the stream's data (e.g. from a camera or
+  streaming it from a local video file). It allows authors to pause
+  the generation of the content, e.g. to allow the user to temporarily
+  disable a local camera during a video-conference chat.</p>
+
+  <p>When a <code>GeneratedStream</code> object is being generated
+  from a local file (as opposed to a live audio/video source), the
+  user agent should stream the data from the file in real time, not
+  all at once. This reduces the ease with which pages can distinguish
+  live video from pre-recorded video, which can help protect the
+  user's privacy.</p>
+
+  <!-- v2: support reading the bits from the stream directly, for use
+  with streaming over WebSocket? Or do we rely on FileReader for that? -->
+
+  <pre class="idl">interface <dfn>Stream</dfn> {
+  readonly attribute DOMString <span title="dom-stream-label">label</span>;
+  <span>StreamRecorder</span> <span title="dom-stream-record">record</span>();
+<!--
+  const unsigned short <span title="dom-stream-LOADING">LOADING</span> = 0; -->
+  const unsigned short <span title="dom-stream-LIVE">LIVE</span> = 1;
+  const unsigned short <span title="dom-stream-ENDED">ENDED</span> = 2;
+  readonly attribute unsigned short <span title="dom-stream-readyState">readyState</span>;
+           attribute <span>Function</span> <span title="handler-stream-onreadystatechange">onreadystatechange</span>;
+           attribute <span>Function</span> <span title="handler-stream-onended">onended</span>;
+};
+<span>Stream</span> implements <span>EventTarget</span>;
+
+interface <dfn>GeneratedStream</dfn> {
+  void <span title="dom-stream-stop">stop</span>();
+
+  // temporarily pausing the stream
+  const unsigned short <span title="dom-stream-PAUSED">PAUSED</span> = 3;
+  void <span title="dom-stream-pause">pause</span>();
+  void <span title="dom-stream-resume">resume</span>();
+           attribute <span>Function</span> <span title="handler-stream-onpause">onpause</span>;
+           attribute <span>Function</span> <span title="handler-stream-onplay">onplay</span>;
+};</pre>
+
+  <dl class="domintro">
+
+   <dt><var title="">stream</var> . <code title="dom-stream-label">label</code></dt>
+
+   <dd>
+
+    <p>Returns a label that is unique to this stream, so that streams
+    can be recognised after they are sent through the
+    <code>PeerConnection</code> API.</p>
+
+   </dd>
+
+
+   <dt><var title="">recorder</var> = <var title="">stream</var> . <code title="dom-stream-record">record</code>()</dt>
+
+   <dd>
+
+    <p>Begins recording the stream. The returned
+    <code>StreamRecorder</code> object provides access to the recorded
+    data.</p>
+
+   </dd>
+
+
+   <dt><var title="">stream</var> . <code title="dom-stream-stop">stop</code>()</dt>
+
+   <dd>
+
+    <p>Permanently stops the generation of media data for the stream.</p>
+
+   </dd>
+
+
+   <dt><var title="">stream</var> . <code title="dom-stream-paused">paused</code></dt>
+
+   <dd>
+
+    <p>Returns false if the stream is generating data; true if it is pause.</p>
+
+   </dd>
+
+
+   <dt><var title="">stream</var> . <code title="dom-stream-pause">pause</code>()</dt>
+
+   <dd>
+
+    <p>Temporarily stops the generation of media data for the stream.</p>
+
+   </dd>
+
+
+   <dt><var title="">stream</var> . <code title="dom-stream-resume">resume</code>()</dt>
+
+   <dd>
+
+    <p>Resumes the generation of media data for the stream if it was temporarily stopped.</p>
+
+   </dd>
+
+  </dl>
+
+  <div class="impl">
+
+  <p>The <dfn
+  title="dom-stream-readyState"><code>readyState</code></dfn>
+  attribute represents the state of the stream. It must return the
+  value to which the user agent last set it (as defined below). It can
+  have the following values:</p>
+
+  <dl>
+
+   <dt><dfn title="dom-stream-LIVE"><code>LIVE</code></dfn> (numeric value 1)</dt>
+
+   <dd>The stream is active (the user agent is making a best-effort
+   attempt to receive or generate data in real time).</dd>
+
+   <dt><dfn title="dom-stream-ENDED"><code>ENDED</code></dfn> (numeric value 2)</dt>
+
+   <dd>The stream has finished (the user agent is no longer receiving
+   or generating data, and will never receive or generate more data
+   for this stream).</dd>
+
+   <dt><dfn title="dom-stream-PAUSED"><code>PAUSED</code></dfn> (numeric value 3)</dt>
+
+   <dd>The stream is not generating data at this time, but could still
+   be resumed. Only <code>GeneratedStream</code> objects can be in
+   this state.</dd>
+
+  </dl>
+
+  <p>When a <code>Stream</code> object is created, its <code
+  title="dom-stream-readyState">readyState</code> attribute must be
+  set to <code title="dom-stream-LIVE">LIVE</code> (1).</p>
+
+  <p>When a <code>Stream</code> object ends for any reason other than
+  the <code title="dom-stream-stop">stop()</code> method being invoke
+  (e.g. because the user rescinds the permission for the page to use
+  the local camera, or because the data comes from a finite file and
+  the file's end has been reached and the user has not requested that
+  it be looped, or because the stream comes from a remote peer and the
+  remote peer has permanently stopped sending data), the user agent
+  must <span>queue a task</span> that runs the following steps:</p>
+
+  <ol>
+
+   <li><p>If the object's <code
+   title="dom-stream-readyState">readyState</code> attribute has the
+   value <code title="dom-stream-ENDED">ENDED</code> (2) already, then
+   abort these steps. (The <code title="dom-stream-stop">stop()</code>
+   method was probably called just before the stream stopped for other
+   reasons, e.g. the user clicked an in-page stop button and then the
+   user-agent-provided stop button.)</p></li>
+
+   <li><p>Set the object's <code
+   title="dom-stream-readyState">readyState</code> attribute to <code
+   title="dom-stream-ENDED">ENDED</code> (2).</p></li>
+
+   <li><p><span>Fire a simple event</span> named <code
+   title="event-readystatechange">readystatechange</code> at the
+   object.</p></li>
+
+   <li><p><span>Fire a simple event</span> named <code
+   title="event-stream-ended">ended</code> at the object.</p></li>
+
+  </ol>
+
+  <p>If the end of the stream was reached due to a user request, the
+  <span>task source</span> for this <span
+  title="concept-task">task</span> is the <span>user interaction task
+  source</span>. Otherwise the <span>task source</span> for this <span
+  title="concept-task">task</span> is the <span>networking task
+  source</span>.</p>
+
+  <hr>
+
+  <p>When a <code>GeneratedStream</code> object is created, the user
+  agent must generate a globally unique identifier string, and must
+  initialize the object's <code title="dom-stream-label">label</code>
+  attribute to that string. Such strings must only use characters in
+  the ranges U+0021, U+0023 to U+0027, U+002A to U+002B, U+002D to
+  U+002E, U+0030 to U+0039, U+0041 to U+005A, U+005E to U+007E, and
+  must be 36 characters long.</p> <!-- UUIDs have 36 characters
+  including hyphens; the ranges above comes from RFC4574 (the a=label:
+  thing in SDP) -->
+
+  <p>When a <code>Stream</code> is created to represent a stream
+  obtained from a remote peer, the <code
+  title="dom-stream-label">label</code> attribute is initialized from
+  information provided by the remote source.</p> <!-- described below
+  -->
+
+  <p>The <dfn title="dom-stream-label"><code>label</code></dfn>
+  attribute must return the value to which it was initialized when the
+  object was created.</p>
+
+  <hr>
+
+  <p>When the <dfn
+  title="dom-stream-record"><code>record()</code></dfn> method is
+  invoked, the user agent must return a new
+  <code>StreamRecorder</code> object associated with the stream.</p>
+
+  <hr>
+
+  <p>When a <code>GeneratedStream</code> object's <dfn
+  title="dom-stream-stop"><code>stop()</code></dfn> method is invoked,
+  the user agent must <span>queue a task</span> that runs the
+  following steps:</p>
+
+  <ol>
+
+   <li><p>If the object's <code
+   title="dom-stream-readyState">readyState</code> attribute is in the
+   <code title="dom-stream-ENDED">ENDED</code> (2) state, then abort
+   these steps.</p></li>
+
+   <li><p>Permanently stop the generation of data for the stream. If
+   the data is being generated from a live source (e.g. a microphone
+   or camera), and no other stream is being generated from a live
+   source, then the user agent should remove any active "on-air"
+   indicator. If the data is being generated from a prerecorded source
+   (e.g. a video file), any remaining content in the file is
+   ignored.</p></li>
+
+   <li><p>Set the object's <code
+   title="dom-stream-readyState">readyState</code> attribute to <code
+   title="dom-stream-ENDED">ENDED</code> (2).</p></li>
+
+   <li><p><span>Fire a simple event</span> named <code
+   title="event-readystatechange">readystatechange</code> at the
+   object.</p></li>
+
+   <li><p><span>Fire a simple event</span> named <code
+   title="event-stream-ended">ended</code> at the object.</p></li>
+
+  </ol>
+
+  <hr>
+
+  <p>When a <code>GeneratedStream</code> object's <dfn
+  title="dom-stream-pause"><code>pause()</code></dfn> method is
+  invoked, the user agent must <span>queue a task</span> that runs the
+  following steps:</p>
+
+  <ol>
+
+   <li><p>If the object's <code
+   title="dom-stream-readyState">readyState</code> attribute is not in
+   the <code title="dom-stream-LIVE">LIVE</code> (1) state, then abort
+   these steps.</p></li>
+
+   <li><p>Pause the generation of data for the stream. If the data is
+   being generated from a live source (e.g. a microphone or camera),
+   then data collected for this stream while the stream is paused must
+   be discarded. If the data is being generated from a prerecorded
+   source (e.g. a video file), the user agent should follow user
+   preferences for handling a pause (either skipping over data in real
+   time or resuming from the same point when the stream is later
+   resumed).</p></li>
+
+   <li><p>Set the object's <code
+   title="dom-stream-readyState">readyState</code> attribute to <code
+   title="dom-stream-PAUSED">PAUSED</code> (3).</p></li>
+
+   <li><p><span>Fire a simple event</span> named <code
+   title="event-readystatechange">readystatechange</code> at the
+   object.</p></li>
+
+   <li><p><span>Fire a simple event</span> named <code
+   title="event-stream-pause">pause</code> at the object.</p></li>
+
+  </ol>
+
+  <p>When a <code>GeneratedStream</code> object's <dfn
+  title="dom-stream-resume"><code>resume()</code></dfn> method is
+  invoked, the user agent must <span>queue a task</span> that runs the
+  following steps:</p>
+
+  <ol>
+
+   <li><p>If the object's <code
+   title="dom-stream-readyState">readyState</code> attribute is not in
+   the <code title="dom-stream-PAUSED">PAUSED</code> (3) state, then
+   abort these steps.</p></li>
+
+   <li><p>Resume the generation of data for the stream.</p></li>
+
+   <li><p>Set the object's <code
+   title="dom-stream-readyState">readyState</code> attribute to <code
+   title="dom-stream-LIVE">LIVE</code> (1).</p></li>
+
+   <li><p><span>Fire a simple event</span> named <code
+   title="event-readystatechange">readystatechange</code> at the
+   object.</p></li>
+
+   <li><p><span>Fire a simple event</span> named <code
+   title="event-stream-play">play</code> at the object.</p></li>
+
+  </ol>
+
+  <hr>
+
+  <p>The <span>task source</span> for the <span
+  title="concept-task">tasks</span> queued for the <code
+  title="dom-stream-stop">stop()</code>, <code
+  title="dom-stream-pause">pause()</code>, and <code
+  title="dom-stream-resume">resume()</code> methods is the <span>DOM
+  manipulation task source</span>.</p>
+
+  <hr>
+
+  <p>The following are the <span>event handlers</span> (and their
+  corresponding <span title="event handler event type">event handler
+  event types</span>) that must be supported, as IDL attributes, by
+  all objects implementing the <code>Stream</code> interface:</p>
+
+  <table>
+   <thead>
+    <tr><th><span title="event handlers">Event handler</span> <th><span>Event handler event type</span>
+   <tbody>
+    <tr><td><dfn title="handler-stream-onreadystatechange"><code>onreadystatechange</code></dfn> <td> <code title="event-stream-readystatechange">readystatechange</code>
+    <tr><td><dfn title="handler-stream-onended"><code>onended</code></dfn> <td> <code title="event-stream-ended">ended</code>
+  </table>
+
+  <p>The following are the additional <span>event handlers</span> (and
+  their corresponding <span title="event handler event type">event
+  handler event types</span>) that must be supported, as IDL
+  attributes, by all objects implementing the
+  <code>GeneratedStream</code> interface:</p>
+
+  <table>
+   <thead>
+    <tr><th><span title="event handlers">Event handler</span> <th><span>Event handler event type</span>
+   <tbody>
+    <tr><td><dfn title="handler-stream-onpause"><code>onpause</code></dfn> <td> <code title="event-stream-pause">pause</code>
+    <tr><td><dfn title="handler-stream-onplay"><code>onplay</code></dfn> <td> <code title="event-stream-play">play</code>
+  </table>
+
+  </div>
+
+  <div class="example">
+
+   <p>This sample code exposes a button. When clicked, the button is
+   disabled and the user is prompted to offer a stream. The user can
+   cause the button to be re-enabled by providing a stream (e.g.
+   giving the page access to the local camera) and then disabling the
+   stream (e.g. revoking that access).</p>
+
+   <pre>
+&lt;input type="button" value="Start" onclick="start()" id="startBtn">
+&lt;script>
+ var startBtn = document.getElementById('startBtn');
+ function start() {
+   navigator.getUserMedia('audio,video', gotStream);
+   startBtn.disabled = true;
+ }
+ function gotStream(stream) {
+   stream.onended = function () {
+     startBtn.disabled = false;
+   }
+ }
+&lt;/script></pre>
+
+  </div>
+
+  <pre class="idl">interface <dfn>StreamRecorder</dfn> {
+  <span>Blob</span> <span title="dom-StreamRecorder-getRecordedData">getRecordedData</span>(in <span>BlobCallback</span> callback);
+};
+
+[Callback=FunctionOnly, NoInterfaceObject]
+interface <dfn>BlobCallback</dfn> {
+  void <span title="dom-BlobCallback-handleEvent">handleEvent</span>(in <span>Blob</span> blob);
+};</pre>
+
+  <dl class="domintro">
+
+   <dt><var title="">recorder</var> . <code title="dom-StreamRecorder-getRecordedData">getRecordedData</code>(<var title="">callback</var>)</dt>
+
+   <dd>
+
+    <p>Creates a <code>Blob</code> of the recorded data, and invokes
+    the provided callback with that <code>Blob</code>.</p>
+
+   </dd>
+
+  </dl>
+
+  <div class="impl">
+
+  <p>When the <dfn
+  title="dom-StreamRecorder-getRecordedData"><code>getRecordedData()</code></dfn>
+  method is called, the user agent must run the following steps:</p>
+
+  <ol>
+
+   <li><p>Let <var title="">callback</var> be the callback
+   indicated by the method's first argument.</p></li>
+
+   <li><p>If <var title="">callback</var> is null, abort these
+   steps.</p></li> <!-- we could throw an exception instead (that's
+   why the method doesn't return until later: so that we can add an
+   exception here without changing the algorithm) -->
+
+   <li><p>Let <var title="">data</var> be the data that was streamed
+   by the <code>Stream</code> object from which the
+   <code>StreamRecorder</code> was created since the creation of the
+   <code>StreamRecorder</code> object.</li>
+
+   <li><p>Return, and run the remaining steps asynchronously.</p></li>
+
+   <li><p>Generate a file that containing <var title="">data</var> in
+   a format supported by the user agent for use in <code>audio</code>
+   and <code>video</code> elements.</p></li>
+
+   <li><p>Let <var title="">blob</var> be a <code>Blob</code> object
+   representing the contents of the file generated in the previous
+   step. <a href="#refsFILEAPI">[FILEAPI]</a></p>
+
+   <li><p><span>Queue a task</span> to invoke <var
+   title="">callback</var> with <var title="">blob</var> as its
+   argument.</p></li>
+
+  </ol>
+
+  <p class="note">The <code
+  title="dom-StreamRecorder-getRecordedData">getRecordedData()</code>
+  method can be called multiple times on one
+  <code>StreamRecorder</code> object; each time, it will create a new
+  file as if this was the first time the method was being called. In
+  particular, the method does not stop or reset the recording when the
+  method is called.</p>
+
+  </div>
+
+  <div class="example">
+
+   <p>This example allows people to record a short audio message and
+   upload it to the server. This example even shows rudimentary error
+   handling.</p>
+
+   <pre>&lt;input type="button" value="&#x26AB;" onclick="msgRecord()" id="recBtn">
+&lt;input type="button" value="&#x25FC;" onclick="msgStop()" id="stopBtn" disabled>
+&lt;p id="status">To start recording, press the &#x26AB; button.&lt;/p>
+&lt;script>
+ var recBtn = document.getElementById('recBtn');
+ var stopBtn = document.getElementById('stopBtn');
+ function report(s) {
+   document.getElementById('status').textContent = s;
+ }
+ function msgRecord() {
+   report('Attempting to access microphone...');
+   navigator.getUserMedia('audio', gotStream, noStream);
+   recBtn.disabled = true;
+ }
+ var msgStream;
+ function gotStream(stream) {
+   report('Recording... To stop, press to &#x25FC; button.');
+   msgStream = stream;
+   stopBtn.disabled = false;
+   stream.onended = function () {
+     msgStop();     
+   }
+ }
+ function msgStop() {
+   report('Creating file...');
+   stopBtn.disabled = true;
+   stream.onended = null;
+   stream.stop();
+   stream.getRecordedData(msgSave);
+ }
+ function msgSave(blob) {
+   report('Uploading file...');
+   var x = new XMLHttpRequest();
+   x.open('POST', 'uploadMessage');
+   x.send(blob);
+   x.onload = function () {
+     report('Done! To record a new message, press the &#x26AB; button.');
+     recBtn.disabled = false;
+   };
+   x.onerror = function () {
+     report('Failed to upload message. To try recording a message again, press the &#x26AB; button.');
+     recBtn.disabled = false;
+   };
+ }
+ funciton noStream() {
+   report('Could not obtain access to your microphone. To try again, press the &#x26AB; button.');
+   recBtn.disabled = false;
+ }
+&lt;/script></pre>
+
+  </div>
+
+  <pre class="idl">[Supplemental]
+interface <dfn title="dom-URL">URL</dfn> {
+  static DOMString <span title="dom-URL-createObjectURL">createObjectURL</span>(in <span>Stream</span> stream);
+};</pre>
+
+  <dl class="domintro">
+
+   <dt><var title="">window</var> . <code title="dom-URL">URL</code> . <code title="dom-URL-createObjectURL">createObjectURL</code>(<var title="">stream</var>)</dt>
+
+   <dd>
+
+    <p>Mints a <span>Blob URL</span> to refer to the given <code>Stream</code>.</p>
+
+   </dd>
+
+  </dl>
+
+  <div class="impl">
+
+  <p>When the <dfn
+  title="dom-URL-createObjectURL"><code>createObjectURL()</code></dfn>
+  method is called with a <code>Stream</code> argument, the user agent
+  must return a unique <span>Blob URL</span> for the given
+  <code>Stream</code>. <a href="#refsFILEAPI">[FILEAPI]</a></p>
+
+  <p>For audio and video streams, the data exposed on that stream must
+  be in a format supported by the user agent for use in
+  <code>audio</code> and <code>video</code> elements.</p>
+
+  <p class="bookkeeping">A <dfn>Blob URL</dfn> is the same as what the
+  File API specification calls a <span>Blob URI</span>, except that
+  anything in the definition of that feature that refers to
+  <code>File</code> and <code>Blob</code> objects is hereby extended
+  to also apply to <code>Stream</code> and
+  <code>GeneratedStream</code> objects.</p>
+
+  </div>
+
+  <div class="example">
+
+   <p>This example allows people to take photos of themselves from the
+   local video camera.</p>
+
+   <pre>&lt;article>
+ &lt;style scoped>
+  video { transform: scaleX(-1); }
+  p { text-align: center; }
+ &lt;/style>
+ &lt;h1>Snapshot Kiosk&lt;/h1>
+ &lt;section id="splash">
+  &lt;p id="errorMessage">Loading...&lt;/p>
+ &lt;/section>
+ &lt;section id="app" hidden>
+  &lt;p>&lt;video id="monitor">&lt;/video> &lt;canvas id="photo">&lt;/canvas>
+  &lt;p>&lt;input type=button value="&amp;#x1F4F7;" onclick="snapshot()">
+ &lt;/section>
+ &lt;script>
+  navigator.getUserMedia('video', gotStream, noStream);
+  var video = document.getElementById('monitor');
+  var canvas = document.getElementById('photo');
+  function gotStream(stream) {
+    video.src = URL.getObjectURL(stream);
+    video.onerror = function () {
+      stream.stop();
+      noStream();
+    }
+    video.onloadedmetadata = function () {
+      canvas.width = video.videoWidth;
+      canvas.height = video.videoHeight;
+      document.getElementById('splash').hidden = true;
+      document.getElementById('app').hidden = false;
+    }
+  }
+  function noStream() {
+    document.getElementById('errorMessage').textContent = 'No camera available.';
+  }
+  function snapshot() {
+    canvas.getContext('2d').drawImage(video, 0, 0);
+  }
+ &lt;/script>
+&lt;/article></pre>
+
+  </div>
+
+
+
+  <h4>Peer-to-peer connections</h4>
+
+  <pre class="idl">[<span title="dom-PeerConnection">Constructor</span>(in DOMString configuration, in <span>SignalingCallback</span> signalingCallback)]
+interface <dfn>PeerConnection</dfn> {
+  void <span title="dom-PeerConnection-signalingMessage">signalingMessage</span>(in DOMString message);
+
+  // <span class="XXX">readyState, etc</span>
+
+  void <span title="dom-PeerConnection-send">send</span>(in DOMString text);
+  void <span title="dom-PeerConnection-addStream">addStream</span>(in <span>Stream</span> stream);
+  void <span title="dom-PeerConnection-removeStream">removeStream</span>(in <span>Stream</span> stream);
+  readonly attribute <span>Stream</span>[] <span title="dom-PeerConnection-localStreams">localStreams</span>;
+  readonly attribute <span>Stream</span>[] <span title="dom-PeerConnection-remoteStreams">remoteStreams</span>;
+
+  // <span class="XXX">connection quality information</span>
+
+           attribute <span>Function</span> <span title="handler-PeerConnection-ontext">ontext</span>;
+           attribute <span>Function</span> <span title="handler-PeerConnection-onaddstream">onaddstream</span>;
+           attribute <span>Function</span> <span title="handler-PeerConnection-onremovestream">onremovestream</span>;
+};
+<span>PeerConnection</span> implements <span>EventTarget</span>;
+
+[Callback=FunctionOnly, NoInterfaceObject]
+interface <dfn>SignalingCallback</dfn> {
+  void <span title="dom-SignalingCallback-handleEvent">handleEvent</span>(in <span>PeerConnection</span> source, in DOMString message);
+};</pre>
+
+  <p>A <code>PeerConnection</code> allows two users to communicate
+  directly, browser-to-browser. Communications are coordinated via a
+  signaling channel provided by script in the page via the server,
+  e.g. using <code>XMLHttpRequest</code>.</p>
+
+  <dl class="domintro">
+
+   <dt><var title="">connection</var> = new <code title="dom-PeerConnection">PeerConnection</code>(<var title="">configuration</var>, <var title="">signalingCallback</var>)</dt>
+
+   <dd>
+
+    <p>Creates a <code>PeerConnection</code> object.</p>
+
+    <p>The <var title="">configuration</var> string gives the address
+    of a STUN or TURN server to use to establish the connection. <a
+    href="#refsSTUN">[STUN]</a> <a href="#refsTURN">[TURN]</a></p>
+
+    <p>The allowed formats for this string are:</p>
+
+    <dl>
+
+     <dt>"<code title=""><var title="">TYPE</var> 203.0.113.2:3478</code>"
+     <dd>
+      <p>Indicates a specific IP address and port for the server.</p>
+     </dd>
+
+     <dt>"<code title=""><var title="">TYPE</var> relay.example.net:3478</code>"
+     <dd>
+      <p>Indicates a specific host and port for the server; the user agent will look up the IP address in DNS.</p>
+     </dd>
+
+     <dt>"<code title=""><var title="">TYPE</var> example.net</code>"
+     <dd>
+      <p>Indicates a specific domain for the server; the user agent will look up the IP address and port in DNS.</p>
+     </dd>
+
+    </dl>
+
+    <p>The "<code title=""><var title="">TYPE</var></code>" is one of:</p>
+
+    <dl>
+
+     <dt><code title="">STUN</code></dt>
+     <dd>Indicates a STUN server
+
+     <dt><code title="">STUNS</code></dt>
+     <dd>Indicates a STUN server that is to be contacted using a TLS session.
+
+     <dt><code title="">TURN</code></dt>
+     <dd>Indicates a TURN server
+
+     <dt><code title="">TURNS</code></dt>
+     <dd>Indicates a TURN server that is to be contacted using a TLS session.
+
+    </dl>
+
+    <p>The <var title="">signalingCallback</var> argument is a method
+    that will be invoked when the user agent needs to send a message
+    to the other host over the signaling channel. When the callback
+    is invoked, convey its argument (a string) to the other peer using
+    whatever method is being used by the Web application to relay
+    signaling messages. (Messages returned from the other peer are
+    provided back to the user agent using the <code
+    title="dom-PeerConnection-signalingMessage">signalingMessage()</code>
+    method.)</p>
+
+   </dd>
+
+
+   <dt><var title="">connection</var> . <code title="dom-PeerConnection-signalingMessage">signalingMessage</code>(<var title="">message</var>)</dt>
+
+   <dd>
+
+    <p>When a message is relayed from the remote peer over the
+    signaling channel is received by the Web application, pass it to
+    the user agent by calling the <code
+    title="dom-PeerConnection-signalingMessage">signalingMessage()</code>
+    method.</p>
+
+    <p>The order of messages is important. Passing messages to the
+    user agent in a different order than they were generated by the
+    remote peer's user agent can prevent a successful connection from
+    being established or degrade the connection's quality if one is
+    established.</p>
+
+   </dd>
+
+   <dt><var title="">connection</var> . <code title="dom-PeerConnection-send">send</code>(<var title="">text</var>)</dt>
+
+   <dd>
+
+    <p>Attempts to send the given text to the remote peer. This uses
+    UDP, which is inherently unreliable; there is no guarantee that
+    every message will be received.</p>
+
+    <p>When a message sent in this manner from the other peer is
+    received, a <code title="event-PeerConnection-text">text</code>
+    event is dispatched at the <code>PeerConnection</code> object.</p>
+
+   </dd>
+
+   <dt><var title="">connection</var> . <code title="dom-PeerConnection-addStream">addStream</code>(<var title="">stream</var>)</dt>
+
+   <dd>
+
+    <p>Attempts to starting sending the given stream to the remote
+    peer.</p>
+
+    <p>When the other peer starts sending a stream in this manner, an
+    <code title="event-PeerConnection-addstream">addstream</code>
+    event is dispatched at the <code>PeerConnection</code> object.</p>
+
+   </dd>
+
+   <dt><var title="">connection</var> . <code title="dom-PeerConnection-removeStream">removeStream</code>(<var title="">stream</var>)</dt>
+
+   <dd>
+
+    <p>Steps sending the given stream to the remote peer.</p>
+
+    <p>When the other peer stops sending a stream in this manner, a
+    <code
+    title="event-PeerConnection-removestream">removestream</code>
+    event is dispatched at the <code>PeerConnection</code> object.</p>
+
+   </dd>
+
+   <dt><var title="">connection</var> . <code title="dom-PeerConnection-localStreams">localStreams</code></dt>
+
+   <dd>
+
+    <p>Returns a live array containing the streams that the user agent
+    is currently attempting to transmit to the remote peer (those that
+    were added with <code
+    title="dom-PeerConnection-addStream">addStream()</code>).</p>
+
+   </dd>
+
+   <dt><var title="">connection</var> . <code title="dom-PeerConnection-remoteStreams">remoteStreams</code></dt>
+
+   <dd>
+
+    <p>Returns a live array containing the streams that the user agent
+    is currently receiving from the remote peer.</p>
+
+    <p>This array is updated when <code
+    title="event-PeerConnection-addstream">addstream</code> and <code
+    title="event-PeerConnection-removestream">removestream</code>
+    events are fired.</p>
+
+   </dd>
+
+  </dl>
+
+  <div class="impl">
+
+  <p>A <code>PeerConnection</code> object has an associated
+  <dfn><code>PeerConnection</code> signaling callback</dfn>, a
+  <dfn><code>PeerConnection</code> ICE Agent</dfn>, a
+  <dfn><code>PeerConnection</code> data UDP media stream</dfn> and an
+  <dfn>ICE started flag</dfn>. These are initialized when the object
+  is created.</p>
+
+  <p>When the <dfn
+  title="dom-PeerConnection"><code>PeerConnection()</code></dfn>
+  constructor is invoked, the user agent must run the following steps.
+  This algorithm has a <span>synchronous section</span> (which is
+  triggered as part of the <span>event loop</span> algorithm). Steps
+  in the <span>synchronous section</span> are marked with
+  &#x231B;.</p>
+
+  <ol>
+
+   <li><p>Let <var title="">serverConfiguration</var> be the constructor's
+   first argument.</p></li>
+
+   <li><p>Let <var title="">signalingCallback</var> be the
+   constructor's second argument.</p></li>
+
+   <li><p>If <var title="">signalingCallback</var> is null, throw a
+   <code>TypeError</code> exception and abort these steps.</p></li>
+
+   <li><p>Let <var title="">connection</var> be a newly created
+   <code>PeerConnection</code> object.</p></li>
+
+   <li><p>Create an ICE Agent and let <var title="">connection</var>'s
+   <span><code>PeerConnection</code> ICE Agent</span> be that ICE
+   Agent. <a href="#refsICE">[ICE]</a></p></li>
+
+   <li><p>If <var title="">serverConfiguration</var> contains a U+000A LINE
+   FEED (LF) character or a U+000D CARRIAGE RETURN (CR) character (or
+   both), remove all characters from <var title="">serverConfiguration</var>
+   after the first such character.</p></li>
+
+   <li><p><span title="split a string on spaces">Split <var
+   title="">serverConfiguration</var> on spaces</span> to obtain <var
+   title="">configuration components</var>.</p></li>
+
+   <li>
+
+    <p>If <var title="">configuration components</var> has two or more
+    components, and the first component is a
+    <span>case-sensitive</span> match for one of the following
+    strings:</p>
+
+    <ul class="brief">
+     <li>"<code title="">STUN</code>"
+     <li>"<code title="">STUNS</code>"
+     <li>"<code title="">TURN</code>"
+     <li>"<code title="">TURNS</code>"
+    </ul>
+
+    <p>...then run the following substeps:</p>
+
+    <ol>
+
+     <li><p>Let <var title="">server type</var> be STUN if the first
+     component of <var title="">configuration components</var> is
+     "<code title="">STUN</code>" or "<code title="">STUNS</code>",
+     and TURN otherwise (the first component of <var
+     title="">configuration components</var> is "<code
+     title="">TURN</code>" or "<code title="">TURNS</code>").</p>
+
+     <li><p>Let <var title="">secure</var> be true if the first
+     component of <var title="">configuration components</var> is
+     "<code title="">STUNS</code>" or "<code title="">TURNS</code>",
+     and false otherwise.</p>
+
+     <li><p>Let <var title="">host</var> be the contents of the second
+     component of <var title="">configuration components</var> up to
+     the character before the first U+003A COLON character (:), if
+     any, or the entire string otherwise.</p></li>
+
+     <li><p>Let <var title="">port</var> be the contents of the second
+     component of <var title="">configuration components</var> from
+     the character after the first U+003A COLON character (:) up to
+     the end, if any, or the empty string otherwise.</p></li>
+
+     <li>
+
+      <p>Configure the <span><code>PeerConnection</code> ICE
+      Agent</span>'s STUN or TURN server as follows:</p>
+
+      <ul>
+
+       <li>If <var title="">server type</var> is STUN, the server is a
+       STUN server. Otherwise, <var title="">server type</var> is TURN
+       and the server is a TURN server.</li>
+
+       <li>If <var title="">secure</var> is true, the server is to be
+       contacted using TLS-over-TCP, otherwise, it is to be contacted
+       using UDP.</li>
+
+       <li>The IP address, host name, or domain name of the server is
+       <var title="">host</var>.</li>
+
+       <li>The port to use is <var title="">port</var>. If this is the
+       empty string, then only a domain name is configured (and the
+       ICE Agent will use DNS SRV requests to determine the IP address
+       and port).</li>
+
+       <li>The long-term username for the the STUN or TURN server is
+       the <span title="ASCII serialization of an origin">ASCII
+       serialization</span> of the <span>entry script</span>'s
+       <span>origin</span>; the long-term password is the empty
+       string.</li>
+
+      </ul>
+
+      <p>If the given IP address, host name, domain name, or port are
+      invalid, then the user agent must act as if no STUN or TURN
+      server is configured.</p>
+
+     </li>
+
+    </ol>
+
+   </li>
+
+   <li><p>Let the <var title="">connection</var>'s
+   <span><code>PeerConnection</code> signaling callback</span> be
+   <var title="">signalingCallback</var>.</p></li>
+
+   <li><p>Set <var title="">connection</var>'s <span>ICE started
+   flag</span> to false.</p></li>
+
+   <li><p>Let <var title="">connection</var>'s
+   <span><code>PeerConnection</code> data UDP media stream</span> be a
+   new <span>data UDP media stream</span>.</p></li>
+
+   <li><p>Let <var title="">connection</var>'s <code
+   title="dom-PeerConnection-localStreams">localStreams</code>
+   attribute be an empty read-only <code>Stream</code> array. <a
+   href="#refsWEBIDL">[WEBIDL]</a></p></li>
+
+   <li><p>Let <var title="">connection</var>'s <code
+   title="dom-PeerConnection-remoteStreams">remoteStreams</code>
+   attribute be an empty read-only <code>Stream</code> array. <a
+   href="#refsWEBIDL">[WEBIDL]</a></p></li>
+
+   <li><p>Return <var title="">connection</var>, but continue these
+   steps asynchronously.</p></li>
+
+   <li><p><span>Await a stable state</span>. The <span>synchronous
+   section</span> consists of the remaining steps of this
+   algorithm. (Steps in <span title="synchronous section">synchronous
+   sections</span> are marked with &#x231B;.)</p></li>
+
+   <li><p>&#x231B; If <var title="">connection</var>'s <span>ICE
+   started flag</span> is still false, start the
+   <span><code>PeerConnection</code> ICE Agent</span> and send the
+   initial offer. The initial offer must include a media description
+   for the <span><code>PeerConnection</code> data UDP media
+   stream</span> and for all the streams in <code
+   title="dom-PeerConnection-localStreams">localStreams</code>. <a
+   href="#refsICE">[ICE]</a></p></li>
+
+   <li><p>&#x231B; Let <var title="">connection</var>'s <span>ICE
+   started flag</span> be true.</p></li>
+
+  </ol>
+
+  <p>When a <span><code>PeerConnection</code> ICE Agent</span> is
+  required to send SDP offers or answers, the user agent must follow
+  these steps:</p>
+
+  <ol>
+
+   <li><p>Let <var title="">sdp</var> be the SDP offer or answer to be
+   sent. <a href="#refsSDPOFFERANSWER">[SDPOFFERANSWER]</a></p></li>
+
+   <li><p>Let <var title="">message</var> be the concatenation of the
+   string "<code title="">SDP</code>", a U+000A LINE FEED (LF)
+   character, and <var title="">sdp</var>, in that order.</p></li>
+
+   <li><p><span>Queue a task</span> to invoke that
+   <span><code>PeerConnection</code> ICE Agent</span>'s
+   <span><code>PeerConnection</code> signaling callback</span> with
+   <var title="">message</var> as its argument.</p></li>
+
+  </ol>
+
+  <p>All SDP media descriptions for streams represented by
+  <code>Stream</code> objects must include a label attribute ("<code
+  title="">a=label:</code>") whose value is the value of the
+  <code>Stream</code> object's <code
+  title="dom-stream-label">label</code> attribute. <a
+  href="#refsSDP">[SDP]</a> <a href="#refsSDPLABEL">[SDPLABEL]</a></p>
+
+  <p><span title="PeerConnection ICE
+  Agent"><code>PeerConnection</code> ICE Agents</span> must not
+  generate any candidates for media streams whose media descriptions
+  do not have a label attribute ("<code title="">a=label:</code>"). <a
+  href="#refsICE">[ICE]</a> <a href="#refsSDP">[SDP]</a> <a
+  href="#refsSDPLABEL">[SDPLABEL]</a></p>
+
+  <p>When a user agent starts receiving media for a component an a
+  candidate provided for that component by a
+  <span><code>PeerConnection</code> ICE Agent</span>, the user agent
+  must follow these steps:</p>
+
+  <ol>
+
+   <li><p>Let <var title="">connection</var> be the
+   <code>PeerConnection</code> whose ICE Agent is expecting this
+   media.</p></li>
+
+   <li><p>If there is already a <code>Stream</code> object for the
+   media stream to which this component belongs, then associate the
+   component with that media stream and abort these steps. (Some media
+   streams have multiple components; this API does not expose the
+   role of these individual components in ICE.)</p></li>
+
+   <li><p>Create a <code>Stream</code> object to represent the media
+   stream. Set its <code title="attr-stream-label">label</code>
+   attribute to the value of the SDP Label attribute for that
+   component's media stream.</p></li>
+
+   <li><p><span>Queue a task</span> to add the newly created
+   <code>Stream</code> object to the end of <var
+   title="">connection</var>'s <code
+   title="dom-PeerConnection-remoteStreams">remoteStreams</code>
+   array, then <span>fire a stream event</span> named <code
+   title="event-stream-addstream">addstream</code> with the newly
+   created <code>Stream</code> object at the <var
+   title="">connection</var> object.</p></li>
+
+  </ol>
+
+  <p>When a <span><code>PeerConnection</code> ICE Agent</span> finds
+  that a stream from the remote peer has been removed (its port has
+  been set to zero in a media description sent on the signaling
+  channel), the user agent must follow these steps:</p>
+
+  <ol>
+
+   <li><p>Let <var title="">connection</var> be the
+   <code>PeerConnection</code> whose <span><code>PeerConnection</code>
+   ICE Agent</span> has determined that a stream is being removed.</p></li>
+
+   <li><p>Let <var title="">stream</var> be the <code>Stream</code>
+   object that represents the media stream being removed, if any. If
+   there isn't one, then abort these steps.</p></li>
+
+   <li><p><span>Queue a task</span> to remove <var
+   title="">stream</var> from <var title="">connection</var>'s <code
+   title="dom-PeerConnection-remoteStreams">remoteStreams</code>
+   array, then <span>fire a stream event</span> named <code
+   title="event-stream-removestream">removestream</code> with <var
+   title="">stream</var> at the <var title="">connection</var>
+   object.</p></li>
+
+  </ol>
+
+  <p>When the <dfn title="dom-PeerConnection-signalingMessage"><code
+  title="">signalingMessage()</code></dfn> method is invoked, the
+  user agent must run the following steps:</p>
+
+  <ol>
+
+   <li><p>Let <var title="">message</var> be the method's
+   argument.</p></li>
+
+   <li>
+
+    <p>If the first four characters of <var title="">message</var> are
+    not "<code title="">SDP</code>" followed by a U+000A LINE FEED
+    (LF) character, then abort these steps. (This indicates an error
+    in the signaling channel implementation. User agents may report
+    such errors to their developer consoles to aid debugging.)</p>
+
+    <p class="note">Future extensions to the
+    <code>PeerConnection</code> interface might use other prefix
+    values to implement additional features.</p>
+
+   </li>
+
+   <li><p>Let <var title="">sdp</var> be the string consisting of all
+   but the first four characters of <var
+   title="">message</var>.</p></li>
+
+   <li>
+
+    <p>If <var title="">connection</var>'s <span>ICE started
+    flag</span> is still false, start the
+    <span><code>PeerConnection</code> ICE Agent</span> and pass it
+    <var title="">sdp</var> as the initial offer from the other peer;
+    the ICE Agent will then (asynchronously) construct the initial
+    answer and transmit it as described above. The initial answer must
+    include a media description for the
+    <span><code>PeerConnection</code> data UDP media stream</span> and
+    for all the streams in <code
+    title="dom-PeerConnection-localStreams">localStreams</code>. <a
+    href="#refsICE">[ICE]</a></p>
+
+    <p>If <var title="">connection</var>'s <span>ICE started
+    flag</span> is true, then pass <var title="">sdp</var> to the
+    <span><code>PeerConnection</code> ICE Agent</span> as a subsequent
+    offer or answer, to be interpreted as appropriate given the
+    current state of the ICE Agent. <a href="#refsICE">[ICE]</a></p>
+
+   </li>
+
+   <li><p>Let <var title="">connection</var>'s <span>ICE started
+   flag</span> be true.</p></li>
+
+  </ol>
+
+  <p>When the <dfn title="dom-PeerConnection-send"><code
+  title="">send()</code></dfn> method is invoked, the
+  user agent must run the following steps:</p>
+
+  <ol>
+
+   <li><p>Let <var title="">message</var> be the method's first
+   argument.</p></li>
+
+   <li><p>Let <var title="">data</var> be <var title="">message</var>
+   encoded as UTF-8. <a href="#refsRFC3629">[RFC3629]</a></p></li>
+
+   <li><p>If <var title="">data</var> is longer than 65470 bytes,
+   throw an <code>INVALID_ACCESS_ERR</code> exception and abort these
+   steps.</p></li>
+   <!-- 65470 = 65535 (64K, max IP size) - 40 (IP header) - 8 (UDP header) - 16 (nonce) - 1 (payload type byte) -->
+
+   <li><p>If the <code>PeerConnection</code>'s
+   <span><code>PeerConnection</code> data UDP media stream</span> is
+   not an <span>active data UDP media stream</span>, abort these
+   steps. No message is sent.</p></li>
+
+   <li><p><span>Transmit a data packet to a peer</span> using the
+   <code>PeerConnection</code>'s <span><code>PeerConnection</code>
+   data UDP media stream</span> with <var title="">data</var> as the
+   message.</p></li>
+
+  </ol>
+
+  <p>When the <dfn title="dom-PeerConnection-addStream"><code
+  title="">addStream()</code></dfn> method is invoked, the user agent
+  must run the following steps:</p>
+
+  <ol>
+
+   <li><p>Let <var title="">stream</var> be the method's
+   argument.</p></li>
+
+   <li><p>If <var title="">stream</var> is null, throw a
+   <code>TypeError</code> exception and abort these steps.</p></li>
+
+   <li><p>If <var title="">stream</var> is already in the
+   <code>PeerConnection</code> object's <code
+   title="dom-PeerConnection-localStreams">localStreams</code> object,
+   then abort these steps.</p></li>
+
+   <li><p>Add <var title="">stream</var> to the end of the
+   <code>PeerConnection</code> object's <code
+   title="dom-PeerConnection-localStreams">localStreams</code>
+   object.</p></li>
+
+   <li><p>If the <code>PeerConnection</code>'s <span>ICE
+   started flag</span> is false, then abort these steps.</p></li>
+
+   <li><p>Have the <code>PeerConnection</code>'s
+   <span><code>PeerConnection</code> ICE Agent</span> add a media
+   stream for <var title="">stream</var>. <a
+   href="#refsICE">[ICE]</a></p></li> <!-- section 9.1.1.3 -->
+
+  </ol>
+  
+  <p>When the <dfn title="dom-PeerConnection-removeStream"><code
+  title="">removeStream()</code></dfn> method is invoked, the user agent
+  must run the following steps:</p>
+
+  <ol>
+
+   <li><p>Let <var title="">stream</var> be the method's
+   argument.</p></li>
+
+   <li><p>If <var title="">stream</var> is null, throw a
+   <code>TypeError</code> exception and abort these steps.</p></li>
+
+   <li><p>If <var title="">stream</var> is not in the
+   <code>PeerConnection</code> object's <code
+   title="dom-PeerConnection-localStreams">localStreams</code> object,
+   then abort these steps.</p></li>
+
+   <li><p>Remove <var title="">stream</var> from the
+   <code>PeerConnection</code> object's <code
+   title="dom-PeerConnection-localStreams">localStreams</code>
+   object.</p></li>
+
+   <li><p>If the <code>PeerConnection</code>'s <span>ICE
+   started flag</span> is false, then abort these steps.</p></li>
+
+   <li><p>Have the <code>PeerConnection</code>'s
+   <span><code>PeerConnection</code> ICE Agent</span> remove the media
+   stream for <var title="">stream</var>. <a
+   href="#refsICE">[ICE]</a></p></li> <!-- section 9.1.1.2 -->
+
+  </ol>
+
+  <p>The <dfn
+  title="dom-PeerConnection-localStreams"><code>localStreams</code></dfn>
+  and <dfn
+  title="dom-PeerConnection-remoteStreams"><code>remoteStreams</code></dfn>
+  attributes must return the read-only <code>Stream</code> arrays that
+  the attributes were respectively set to when the
+  <code>PeerConnection</code>'s constructor ran.</p>
+
+  <hr>
+
+  <p>The following are the <span>event handlers</span> (and their
+  corresponding <span title="event handler event type">event handler
+  event types</span>) that must be supported, as IDL attributes, by
+  all objects implementing the <code>PeerConnection</code>
+  interface:</p>
+
+  <table>
+   <thead>
+    <tr><th><span title="event handlers">Event handler</span> <th><span>Event handler event type</span>
+   <tbody>
+    <tr><td><dfn title="handler-PeerConnection-ontext"><code>ontext</code></dfn> <td> <code title="event-stream-text">text</code>
+    <tr><td><dfn title="handler-PeerConnection-onaddstream"><code>onaddstream</code></dfn> <td> <code title="event-stream-addstream">addstream</code>
+    <tr><td><dfn title="handler-PeerConnection-onremovestream"><code>onremovestream</code></dfn> <td> <code title="event-stream-removestream">removestream</code>
+  </table>
+
+  <hr>
+
+  <p>The <span>task source</span> for the <span
+  title="concept-task">tasks</span> listed in this section is the
+  <span>networking task source</span>.</p>
+
+  </div>
+
+  <div class="example">
+
+   <p>When two peers decide they are going to set up a connection to
+   each other, they both go through these steps. The STUN/TURN server
+   configuration describes a server they can use to get things like
+   their public IP address or to set up NAT traversal. They also have
+   to send data for the signaling channel to each other using the same
+   out-of-band mechanism they used to establish that they were going
+   to communicate in the first place.</p>
+
+   <pre>// the first argument describes the STUN/TURN server configuration
+var local = new PeerConnection('TURNS example.net', sendSignalingChannel);
+local.signalingChannel(...); // if we have a message from the other side, pass it along here
+
+// (aLocalStream is some GeneratedStream object)
+local.addStream(aLocalStream); // start sending video
+
+function sendSignalingChannel(message) {
+  ... // send message to the other side via the signaling channel
+}
+
+function receiveSignalingChannel (message) {
+  // call this whenever we get a message on the signaling channel
+  local.signalingChannel(message);
+}
+
+local.onaddstream = function (event) {
+  // (videoElement is some &lt;video> element)
+  videoElement.src = URL.getObjectURL(event.stream);
+};</pre>
+
+  </div>
+
+  <p class="warning">To prevent network sniffing from allowing a
+  fourth party to establish a connection to a peer using the
+  information sent out-of-band to the other peer and thus spoofing the
+  client, the configuration information should always be transmitted
+  using an encrypted connection.</p>
+
+
+
+  <h4>The data stream</h4>
+
+  <p>All <code>PeerConnection</code> connections include a <dfn>data
+  UDP media stream</dfn>, which is used to send data packets
+  peer-to-peer, for instance game control packets. This data channel
+  is unreliable (packets are not guaranteed to be delivered, and are
+  not guaranteed to be delivered in the right order).</p>
+
+  <p>All SDP media descriptions for <span title="data UDP media
+  stream">data UDP media streams</span> must include a label attribute
+  ("<code title="">a=label:</code>") whose value is the string "<code
+  title="">data</code>". <a href="#refsSDP">[SDP]</a> <a
+  href="#refsSDPLABEL">[SDPLABEL]</a></p>
+
+  <p>All SDP media descriptions for <span title="data UDP media
+  stream">data UDP media streams</span> must also include a key field
+  ("<code title="">k=</code>"), with the value being a base64-encoded
+  representation of 16 cryptographically random bytes determined on a
+  per-ICE-Agent basis. <a href="#refsSDP">[SDP]</a></p>
+
+  <p><span title="PeerConnection ICE
+  Agent"><code>PeerConnection</code> ICE Agents</span> must attempt to
+  establish a connection for their <span><code>PeerConnection</code>
+  data UDP media stream</span> during the initial offer/answer
+  exchange, and must maintain that UDP media stream for the ICE
+  Agents' whole lifetime.</p>
+
+  <p>A <span>data UDP media stream</span> is an <dfn>active data UDP
+  media stream</dfn> if the <span><code>PeerConnection</code> ICE
+  Agent</span> has selected a destination for it. A <span>data UDP
+  media stream</span> can change active status many times during the
+  lifetime of its <code>PeerConnection</code> object (e.g. any time
+  the network topology changes and the ICE Agent performs an ICE
+  Restart). <a href="#refsICE">[ICE]</a></p>
+
+  <p>Bytes transmitted on a <span>data UDP media stream</span> are
+  masked so as to prevent cross-protocol attacks (<span>data UDP media
+  stream</span> always appear to contain random noise to other
+  protocols). For the purposes of masking, the <dfn>data UDP media
+  stream salt</dfn> is defined to be the following 16 bytes, described
+  here as hexadecimal numbers: DB 68 B5 FD 17 0E 15 77 56 AF 7A 3A 1A
+  57 75 02</p> <!-- obtained thusly: head -c 16 /dev/urandom |
+  hexdump -C -->
+
+  <p>When the user agent is to <dfn>transmit a data packet to a
+  peer</dfn> using a <span>data UDP media stream</span> and with a
+  byte string payload <var title="">data</var>, the user agent must
+  run the following steps:</p>
+
+  <ol>
+
+   <li><p>Let <var title="">nonce</var> be 16 cryptographically random
+   bytes.</p></li>
+
+   <li><p>Let <var title="">ice-key</var> be the 16 bytes given as the
+   encryption key for the <span>data UDP media stream</span> in its
+   media description, as defined above.</p></li>
+
+   <li><p>Let <var title="">key</var> be the first 16 bytes of the
+   HMAC-SHA1 of the 16 <var title="">nonce</var> bytes concatenated
+   with the 16 <var title="">ice-key</var> bytes concatenated with the
+   16 <span>data UDP media stream salt</span> bytes. <a
+   href="#refsHMAC">[HMAC]</a> <a href="#refsSHA1">[SHA1]</a></p></li>
+
+   <li><p>Let <var title="">message</var> be a 0x01 byte followed by
+   <var title="">data</var>.</p></li>
+
+   <li><p>Let <var title="">masked message</var> be the result of
+   encrypting <var title="">message</var> using AES-128-CTR keyed with
+   <var title="">key</var>. <a
+   href="#refsAES128CTR">[AES128CTR]</a></p></li>
+
+   <li><p>Send the concatenation of <var title="">nonce</var> and <var
+   title="">masked message</var> in a UDP packet to the destination
+   that the relevant <span><code>PeerConnection</code> ICE
+   Agent</span> has selected a destination for the <span>data UDP
+   media stream</span>.</p></li>
+
+  </ol>
+
+  <p>A <dfn>remote data UDP media stream</dfn> is the first UDP media
+  stream whose sender is the remote peer, whose label attribute
+  ("<code title="">a=label:</code>") has the value "<code
+  title="">data</code>", and for which a
+  <span><code>PeerConnection</code> ICE Agent</span> has selected a
+  destination, if that media stream has an encryption key advertised
+  in its media description, and if that encryption key is 16 bytes
+  long. A <span>remote data UDP media stream</span> is associated with
+  the <code>PeerConnection</code> object for which the
+  <span><code>PeerConnection</code> ICE Agent</span> in question is
+  operating.</p>
+
+  <p>When a packet from a <span>remote data UDP media stream</span> is
+  received, the user agent must run the following steps:</p>
+
+  <ol>
+
+   <li><p>Let <var title="">data</var> be the UDP packet's data.</p></li>
+
+   <li><p>If <var title="">data</var> is shorter than 17 bytes, then
+   abort these steps.</p></li>
+
+   <li><p>Let <var title="">nonce</var> be the first 16 bytes of the
+   <var title="">data</var>.</p></li>
+
+   <li><p>Let <var title="">ice-key</var> be the 16 bytes given as the
+   encryption key for the <span>remote data UDP media stream</span> in
+   the media description for this media stream. <a
+   href="#refsSDP">[SDP]</a></p></li>
+
+   <li><p>Let <var title="">key</var> be the first 16 bytes of the
+   HMAC-SHA1 of the 16 <var title="">nonce</var> bytes concatenated
+   with the 16 <var title="">ice-key</var> bytes concatenated with the
+   16 <span>data UDP media stream salt</span> bytes. <a
+   href="#refsHMAC">[HMAC]</a> <a href="#refsSHA1">[SHA1]</a></li>
+
+   <li><p>Let <var title="">unmasked data</var> be the result of
+   decrypting <var title="">message</var> using AES-128-CTR keyed with
+   <var title="">key</var>. <a
+   href="#refsAES128CTR">[AES128CTR]</a></p></li>
+
+   <li><p>If the first byte of <var title="">unmasked data</var> is
+   not 0x01, then abort these steps.</p></li>
+
+   <li><p>Let <var title="">raw message</var> be the string consisting
+   of all but the first character of <var title="">unmasked
+   message</var>.</p></li>
+
+   <li><p>Let <var title="">message</var> be <var title="">raw
+   message</var> <span>decoded as UTF-8, with error
+   handling</span>.</p></li>
+
+   <li><p>Create an event that uses the <code>MessageEvent</code>
+   interface, with the name <code title="event-text">text</code>,
+   which does not bubble, is not cancelable, has no default action,
+   and has a <code title="dom-MessageEvent-data">data</code> attribute
+   whose value is <var title="">message</var>, and <span>queue a
+   task</span> to dispatch the event at the
+   <code>PeerConnection</code> object that the <span>remote data UDP
+   media stream</span> is associated with.</p></li>
+
+  </ol>
+
+
+  <h4>Event definitions</h4>
+
+  <p>The <code title="event-stream-addstream">addstream</code> and
+  <code title="event-stream-removestream">removestream</code> events
+  use the <code>StreamEvent</code> interface:</p>
+
+  <pre class="idl">interface <dfn>StreamEvent</dfn> : <span>Event</span> {
+  readonly attribute <span>Stream</span> <span title="dom-StreamEvent-stream">stream</span>;
+  void <span title="dom-CloseEvent-initCloseEvent">initCloseEvent</span>(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in <span>Stream</span> streamArg);
+};</pre>
+
+  <p>The <dfn
+  title="dom-StreamEvent-initStreamEvent"><code>initStreamEvent()</code></dfn>
+  method must initialize the event in a manner analogous to the
+  similarly-named method in the DOM Events interfaces. <a
+  href="#refsDOMEVENTS">[DOMEVENTS]</a></p>
+
+  <p>The <dfn title="dom-StreamEvent-stream"><code>stream</code></dfn>
+  attribute represents the <code>Stream</code> object associated with
+  the event.</p>
+
+  <p><dfn title="fire a stream event">Firing a stream event named <var
+  title="">e</var></dfn> with a <code>Stream</code> <var
+  title="">stream</var> means that an event with the name <var
+  title="">e</var>, which does not bubble (except where otherwise
+  stated) and is not cancelable (except where otherwise stated), and
+  which uses the <code>StreamEvent</code> interface with the <code
+  title="dom-StreamEvent-stream">stream</code> attribute set to <var
+  title="">stream</var>, must be dispatched at the given target.</p>
+
+
+  <h4>Event Summary</h4>
+
+  <p class="XXX">...will add event summary for streams here...</p>
+
+</div>
+
+<!--END html--><!--END dev-html-->
+
+
+
+
+
+
   <div data-component="Web Workers (editor: Ian Hickson)">
 
   <h2 id="workers">Web workers</h2>
@@ -81261,7 +82714,7 @@
 
   <p>The bulk of this code is simply an unoptimized search for a prime
   number. To send a message back to the page, the <code
-  title="dom-DedicatedWorkerGlobalScope-postMessage">postMessage()</code>
+  title="dom-DedicatedWorkerGlobalScope-send">send()</code>
   method is used to post a message when a prime is found.</p>
 
   <p><a href="http://www.whatwg.org/demos/workers/primes/page.html">View this example online</a>.</p>
@@ -99096,7 +100549,7 @@
   <hr>
 
   <p>All animated images with the same <span>absolute URL</span> and
-  the same image data are expected to be rendered synchronised to the
+  the same image data are expected to be rendered synchronized to the
   same timeline as a group, with the timeline starting at the time of
   the most recent addition to the group.</p>
 
@@ -106877,6 +108330,9 @@
    href="http://tools.ietf.org/html/draft-holsten-about-uri-scheme">The
    'about' URI scheme</a></cite>, J. Holsten, L. Hunt. IETF.</dd>
 
+   <dt id="refsAES128CTR">[AES128CTR]</dt>
+   <dd><cite><a href="http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf">Advanced Encryption Standard (AES)</a></cite>. NIST.</dd>
+
    <dt id="refsARIA">[ARIA]</dt>
    <dd><cite><a href="http://www.w3.org/WAI/PF/aria/">Accessible Rich
    Internet Applications (WAI-ARIA)</a></cite>, J. Craig, M. Cooper, L. Pappas,
@@ -107110,6 +108566,9 @@
    href="http://microformats.org/wiki/hatom">hAtom</a></cite>, D
    Janes. Microformats.</dd>
 
+   <dt id="refsHMAC">[HMAC]</dt>
+   <dd><cite><a href="http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf">The Keyed-Hash Message Authentication Code (HMAC)</a></cite>. NIST.</dd>
+
    <dt id="refsHTML4">[HTML4]</dt>
    <dd>(Non-normative) <cite><a
    href="http://www.w3.org/TR/html4/">HTML 4.01
@@ -107158,6 +108617,9 @@
    href="http://www.iana.org/assignments/message-headers/perm-headers.html">Permanent
    Message Header Field Names</a></cite>. IANA.</dd>
 
+   <dt id="refsICE">[ICE]</dt>
+   <dd><cite><a href="http://tools.ietf.org/html/rfc5245">Interactive Connectivity Establishment (ICE): A Protocol for Network Address Translator (NAT) Traversal for Offer/Answer Protocols</a></cite>, J. Rosenberg. IETF.</dd>
+
    <dt id="refsIEEE754">[IEEE754]</dt>
    <dd><cite><a
    href="http://ieeexplore.ieee.org/servlet/opac?punumber=4610933">IEEE
@@ -107463,12 +108925,24 @@
    Compression Scheme For Unicode</a></cite>, M. Wolf, K. Whistler,
    C. Wicksteed, M. Davis, A. Freytag, M. Scherer. Unicode Consortium.</dd>
 
+   <dt id="refsSDP">[SDP]</dt>
+   <dd><cite><a href="http://tools.ietf.org/html/rfc4566">SDP: Session Description Protocol</a></cite>, M. Handley, V. Jacobson, C. Perkins. IETF.</dd>
+
+   <dt id="refsSDPLABEL">[SDPLABEL]</dt>
+   <dd><cite><a href="http://tools.ietf.org/html/rfc4574">The Session Description Protocol (SDP) Label Attribute</a></cite>, O. Levin, G. Camarillo. IETF.</dd>
+
+   <dt id="refsSDPOFFERANSWER">[SDPOFFERANSWER]</dt>
+   <dd><cite><a href="http://tools.ietf.org/html/rfc3264">An Offer/Answer Model with the Session Description Protocol (SDP)</a></cite>, J. Rosenberg, H. Schulzrinne. IETF.</dd>
+
    <dt id="refsSELECTORS">[SELECTORS]</dt>
    <dd><cite><a
    href="http://www.w3.org/TR/css3-selectors">Selectors</a></cite>,
    T. &Ccedil;elik, E. Etemad, D.  Glazman, I. Hickson, P. Linss,
    J. Williams. W3C.</dd>
 
+   <dt id="refsSHA1">[SHA1]</dt>
+   <dd><cite><a href="http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf">Secure Hash Standard</a></cite>. NIST.</dd>
+
    <dt id="refsSHIFTJIS">[SHIFTJIS]</dt>
    <dd><cite>JIS X0208: 7-bit and 8-bit double byte coded KANJI sets
    for information interchange</cite>. Japanese Industrial Standards Committee.</dd>
@@ -107480,6 +108954,9 @@
    and management &mdash; Part 2-1: Colour management &mdash; Default RGB colour
    space &mdash; sRGB</a></cite>. IEC.</dd>
 
+   <dt id="refsSTUN">[STUN]</dt>
+   <dd><cite><a href="http://tools.ietf.org/html/rfc5389">Session Traversal Utilities for NAT (STUN)</a></cite>, J. Rosenberg, R. Mahy, P. Matthews, D. Wing. IETF.</dd>
+
    <dt id="refsSVG">[SVG]</dt>
    <dd><cite><a href="http://www.w3.org/TR/SVGTiny12/">Scalable Vector
    Graphics (SVG) Tiny 1.2 Specification</a></cite>, O. Andersson,
@@ -107495,6 +108972,9 @@
    Ministry of Industry, Royal Thai Government. ISBN
    974-606-153-4.</dd>
 
+   <dt id="refsTURN">[TURN]</dt>
+   <dd><cite><a href="http://tools.ietf.org/html/rfc5766">Traversal Using Relays around NAT (TURN): Relay Extensions to Session Traversal Utilities for NAT (STUN)</a></cite>, R. Mahy, P. Matthews, J. Rosenberg. IETF.</dd>
+
    <dt id="refsUAAG">[UAAG]</dt>
    <dd>(Non-normative) <cite><a
    href="http://www.w3.org/TR/UAAG20/">Web Content Accessibility

|