<!DOCTYPE html>
<!--
    To publish this document, see instructions in README
  -->

<html lang="en">
<head>
  <meta charset="utf-8">
  <link href="webrtc.css" rel="stylesheet">
  <title>WebRTC 1.0: Real-time Communication Between Browsers</title>
  <script class="remove" src="http://www.w3.org/Tools/respec/respec-w3c-common"
  type="text/javascript">
// // keep this comment //
  </script>
  <script class="remove" src="webrtc.js" type="text/javascript">
// // keep
    this comment //
  </script>
</head>

<body>
  <section id="abstract">
    <p>This document defines a set of ECMAScript APIs in WebIDL to allow media
    to be sent to and received from another browser or device implementing the
    appropriate set of real-time protocols. This specification is being
    developed in conjunction with a protocol specification developed by the
    IETF RTCWEB group and an API specification to get access to local media
    devices developed by the Media Capture Task Force.</p>
  </section>

  <section id="sotd">
    <p>This document is neither complete nor stable, and as such is not yet
    suitable for commercial implementation. However, early experimentation is
    encouraged. The API is based on preliminary work done in the WHATWG. The
    Web Real-Time Communications Working Group expects this specification to
    evolve significantly based on:</p>

    <ul>
      <li>The outcome of ongoing exchanges in the companion RTCWEB group at
      IETF to define the set of protocols that, together with this document,
      will enable real-time communications in Web browsers.</li>

      <li>Privacy issues that arise when exposing local capabilities and local
      streams.</li>

      <li>Technical discussions within the group.</li>

      <li>Experience gained through early experimentations.</li>

      <li>Feedback received from other groups and individuals.</li>
    </ul>
  </section>

  <section class="informative" id="intro">
    <h2>Introduction</h2>

    <p>There are a number of facets to video-conferencing in HTML covered by
    this specification:</p>

    <ul>
      <li>Connecting to remote peers using NAT-traversal technologies such as
      ICE, STUN, and TURN.</li>

      <li>Sending the locally-produced tracks to remote peers and receiving
      tracks from remote peers.</li>

      <li>Sending arbitrary data directly to remote peers.</li>
    </ul>

    <p>This document defines the APIs used for these features. This
    specification is being developed in conjunction with a protocol
    specification developed by the <a href=
    "https://datatracker.ietf.org/wg/rtcweb/">IETF RTCWEB group</a> and an API
    specification to get access to local media devices
    [[!GETUSERMEDIA]] developed by the <a href=
    "https://www.w3.org/wiki/Media_Capture">Media Capture Task Force</a>. An
    overview of the system can be found in [[RTCWEB-OVERVIEW]] and
    [[RTCWEB-SECURITY]].</p>
  </section>

  <section id="conformance">
    <p>This specification defines conformance criteria that apply to a single
    product: the <dfn>user agent</dfn> that implements the interfaces that it
    contains with the exception of the <code><a>RTCIdentityProvider</a></code>
    interface which is used by the
    user agent but not implemented by the user agent.</p>

    <p>It also defines conformance criteria for identity providers which provide
    implementations of the <code><a>RTCIdentityProvider</a></code>
    interface.</p>

    <p>Conformance requirements phrased as algorithms or specific steps may be
    implemented in any manner, so long as the end result is equivalent. (In
    particular, the algorithms defined in this specification are intended to be
    easy to follow, and not intended to be performant.)</p>

    <p>Implementations that use ECMAScript to implement the APIs defined in
    this specification MUST implement them in a manner consistent with the
    ECMAScript Bindings defined in the Web IDL specification [[!WEBIDL]], as
    this specification uses that specification and terminology.</p>
  </section>

  <section>
    <h2>Terminology</h2>

    <p>The <code><a href=
    "http://dev.w3.org/html5/spec/webappapis.html#eventhandler">EventHandler</a></code>
    interface represents a callback used for event handlers as defined in
    [[!HTML5]].</p>

    <p>The concepts <dfn><a href=
    "http://dev.w3.org/html5/spec/webappapis.html#queue-a-task">queue a
    task</a></dfn> and <dfn><a href=
    "http://dev.w3.org/html5/spec/webappapis.html#fire-a-simple-event">fire a
    simple event</a></dfn> are defined in [[!HTML5]].</p>

    <p>The terms <dfn>event</dfn>, <dfn><a href=
    "http://dev.w3.org/html5/spec/webappapis.html#event-handlers">event
    handlers</a></dfn> and <dfn><a href=
    "http://dev.w3.org/html5/spec/webappapis.html#event-handler-event-type">event
    handler event types</a></dfn> are defined in [[!HTML5]].</p>

    <p>The terms <dfn>MediaStream</dfn>, <dfn>MediaStreamTrack</dfn>, and
    <dfn>MediaStreamConstraints</dfn> are defined in [[!GETUSERMEDIA]].</p>

    <p>The term <dfn>media description</dfn> is defined in [[!RFC4566]].</p>
  </section>

  <section>
    <h2>Peer-to-peer connections</h2>

    <section>
      <h3>Introduction</h3>

      <p>An <code><a>RTCPeerConnection</a></code> instance allows to establish
      peer to peer communications. Communications are coordinated
      via a signaling channel which is provided by unspecified means, but
      generally by a script in the page via the server, e.g. using
      <code>XMLHttpRequest</code> [[XMLHttpRequest]] or Web Sockets
      [[WEBSOCKETS-API]].</p>
    </section>

    <section>
      <h3>Configuration</h3>

      <section>
        <h4>RTCConfiguration Dictionary</h4>

        <p>The <code>RTCConfiguration</code> defines a set of parameters to
        configure how the peer to peer communication established via
        <code><a>RTCPeerConnection</a></code> is established or
        re-established.</p>

        <dl class="idl" title="dictionary RTCConfiguration">
          <dt>sequence&lt;RTCIceServer&gt; iceServers</dt>

          <dd>
            <p>An array of objects describing servers available to be used by ICE,
            such as STUN and TURN server.</p>
          </dd>

          <dt>RTCIceTransportPolicy iceTransportPolicy = "all"</dt>

          <dd>
            <p>Indicates which candidates the <a>ICE agent</a> is allowed to use.</p>
          </dd>

          <dt>RTCBundlePolicy bundlePolicy = "balanced"</dt>

          <dd>
            <p>Indicates which <a href="#target-bundle-policy">media-bundling policy</a> to use when gathering ICE candidates. </p>
          </dd>

          <dt>RTCRtcpMuxPolicy rtcpMuxPolicy = "require"</dt>

          <dd>
            <p>Indicates which <a href="#target-rtcp-mux-policy">rtcp-mux policy</a> to use when gathering ICE candidates. </p>
          </dd>

          <dt>DOMString peerIdentity</dt>

          <dd>
            <p>Sets the <a href="#target-peer-identity">target peer
            identity</a> for the <a>RTCPeerConnection</a>. The
            <a>RTCPeerConnection</a> will not establish a connection to a remote
            peer unless it can be successfully authenticated with the provided
            name.</p>
          </dd>

          <dt>sequence&lt;RTCCertificate&gt; certificates</dt>

          <dd>
            <p>A set of certificates that
            the <a><code>RTCPeerConnection</code></a> uses to authenticate.</p>

            <p>Valid values for this parameter are created through calls to
            the <a href="#widl-RTCPeerConnection-generateCertificate-Promise-RTCCertificate--AlgorithmIdentifier-keygenAlgorithm"><code>generateCertificate</code></a>
            function.</p>

            <p>Although any given DTLS connection will use only one certificate,
            this attribute allows the caller to provide multiple certificates
            that support different algorithms.  The final certificate will be
            selected based on the DTLS handshake, which establishes which
            certificates are allowed.  The <code>RTCPeerConnection</code>
            implementation selects which of the certificates is used for a given
            connection; how certificates are selected is outside the scope of
            this specification.</p>

            <p>If this value is absent, then a set of certificates are generated
            for each <a><code>RTCPeerConnection</code></a> instance.</p>

            <p>This option allows applications to establish key continuity.
            An <code>RTCCertificate</code> can be persisted in [[INDEXEDDB]] and
            reused.  Persistence and reuse also avoids the cost of key
            generation.</p>

            <p>The value for this configuration option cannot change after its
            value is initially selected.  Attempts to change this value MUST be
            rejected.</p>
          </dd>

          <dt>unsigned short iceCandidatePoolSize = 0</dt>

          <dd>
            <p>Size of the prefetched ICE pool as defined in <span data-jsep="ice-candidate-pool constructor">[[!JSEP]]</span></p>
          </dd>
           
        </dl>
      </section>

      <section>
        <h4>RTCIceCredentialType Enum</h4>
        <dl class="idl" title="enum RTCIceCredentialType">
          <dt>password</dt>

          <dd>The credential is a long-term authentication password, as
            described in [[!RFC5389]], Section 10.2.
          </dd>

          <dt>token</dt>

          <dd>The credential is an access token, as described in
          [[!TRAM-TURN-THIRD-PARTY-AUTHZ]], Section 6.2.</dd>
        </dl>
      </section>

      <section>
        <h4>RTCIceServer Dictionary</h4>

        <p>The <code>RTCIceServer</code> dictionary is used to describe the
        STUN and TURN servers that can be used by the <a>ICE agent</a> to
        establish a connection with a peer.</p>

        <dl class="idl" title="dictionary RTCIceServer">
          <dt>required (DOMString or sequence&lt;DOMString&gt;) urls</dt>

          <dd>
            <p>STUN or TURN URI(s) as defined in [[!RFC7064]] and [[!RFC7065]]
            or other URI types.</p>
          </dd>

          <dt>DOMString username</dt>

          <dd>
            <p>If this <code><a>RTCIceServer</a></code> object represents a
            TURN server, then this attribute specifies the username to use with
            that TURN server.</p>
          </dd>

          <dt>DOMString credential</dt>

          <dd>
            <p>If this <code><a>RTCIceServer</a></code> object represents a
            TURN server, then this attribute specifies the credential to use
            with that TURN server.</p>
          </dd>

          <dt>RTCIceCredentialType credentialType = "password"</dt>

          <dd>
            <p>If this <code><a>RTCIceServer</a></code> object represents a
            TURN server, then this attribute specifies how <var>credential</var>
            should be used when that TURN server requests authorization.</p>
          </dd>
        </dl>

        <p>An example array of RTCIceServer objects is:</p>

        <pre class="example highlight"><code>[
     { "urls": "stun:stun1.example.net" },
     { "urls": ["turns:turn.example.org", "turn:turn.example.net"],
       "username": "user",
       "credential": "myPassword",
       "credentialType": "password" }
]</code></pre>
      </section>

      <section>
        <h4>RTCIceTransportPolicy Enum</h4>

        <dl class="idl" title="enum RTCIceTransportPolicy">
          <dt>none</dt>

          <dd>The <a>ICE agent</a> MUST not send or receive any packets at this
          point.</dd>

          <dt>relay</dt>

          <dd>The <a>ICE agent</a> MUST only use media relay candidates such as
          candidates passing through a TURN server. This can be used to reduce
          leakage of IP addresses in certain use cases.</dd>

          <dt>all</dt>

          <dd>The <a>ICE agent</a> may use any type of candidates when this value is
          specified.</dd>
        </dl>
      </section>

      <section>
        <h4>RTCBundlePolicy Enum</h4>

        <p>As described in <span data-jsep="constructor">[[!JSEP]]</span>, BUNDLE policy
        affects which media tracks are negotiated if
        the remote endpoint is not BUNDLE-aware, and what ICE
        candidates are gathered.  If the remote endpoint is
        BUNDLE-aware, all media tracks and data channels are BUNDLEd
        onto the same transport.</p>

        <dl class="idl" title="enum RTCBundlePolicy" id="target-bundle-policy">
          <dt>balanced</dt>

          <dd>Gather ICE candidates for each media type in use (audio,
          video, and data).  If the remote endpoint is not
          BUNDLE-aware, negotiate only one audio and video track on
          separate transports.</dd>

          <dt>max-compat</dt>

          <dd>Gather ICE candidates for each track. If the remote
          endpoint is not BUNDLE-aware, negotiate all media tracks on
          separate transports.</dd>

          <dt>max-bundle</dt>

          <dd>Gather ICE candidates for only one track.  If the remote
          endpoint is not BUNDLE-aware, negotiate only one media
          track.</dd>
        </dl>
      </section>

      <section>
        <h4>RTCRtcpMuxPolicy Enum</h4>

        <p>Defined in <span data-jsep="constructor">[[!JSEP]]</span>.  The following is a
        non-normative summary for convenience.</p>

        <p>The RtcpMuxPolicy affects what ICE candidates are gathered
        to support non-multiplexed RTCP.</p>

        <dl class="idl" title="enum RTCRtcpMuxPolicy" id="target-rtcp-mux-policy">
          <dt>negotiate</dt>

          <dd>Gather ICE candidates for both RTP and RTCP candidates.
          If the remote-endpoint is capable of multiplexing RTCP,
          multiplex RTCP on the RTP candidates.  If it is not, use
          both the RTP and RTCP candidates separately.</dd>

          <dt>require</dt>

          <dd>Gather ICE candidates only for RTP and multiplex RTCP on
          the RTP candidates.  If the remote endpoint is not capable
          of rtcp-mux, session negotiation will fail.</dd>
        </dl>
      </section>

      <section>
        <h4>Offer/Answer Options</h4>

        <p>These dictionaries describe the options that can be used to control
        the offer/answer creation process.</p>

        <dl class="idl" title="dictionary RTCOfferAnswerOptions">
          <dt>boolean voiceActivityDetection = true</dt>

          <dd>
            <p>Many codecs and systems are capable of detecting "silence" and
            changing their behavior in this case by doing things such as not
            transmitting any media. In many cases, such as when dealing with
            emergency calling or sounds other than spoken voice, it is
            desirable to be able to turn off this behavior. This option allows
            the application to provide information about whether it wishes this
            type of processing enabled or disabled.</p>
          </dd>
        </dl>

        <dl class="idl" title="dictionary RTCOfferOptions : RTCOfferAnswerOptions">
          <dt>boolean iceRestart = false</dt>

          <dd>
            <p>When the value of this dictionary member is true, the generated
            description will have ICE credentials that are different from the
            current credentials (as visible in the
            <code><a>localDescription</a></code> attribute's SDP). Applying the
            generated description will restart ICE.</p>

            <p>When the value of this dictionary member is false, and the
            <code><a>localDescription</a></code> attribute has valid ICE
            credentials, the generated description will have the same ICE
            credentials as the current value from the
            <code><a>localDescription</a></code> attribute.</p>
          </dd>
        </dl>

        <dl class="idl" title="dictionary RTCAnswerOptions : RTCOfferAnswerOptions">
        </dl>

      </section>
    </section>

    <section>
      <h3>RTCPeerConnection Interface</h3>

      <p>The general operation of the RTCPeerConnection is described in
      [[!JSEP]].</p>

      <section>
        <h4>Operation</h4>

        <p>Calling <code>new <a>RTCPeerConnection</a>(<var>configuration</var>
        )</code> creates an <code><a>RTCPeerConnection</a></code> object.</p>

        <p>The <var>configuration</var> has the information to find and access
        the servers used by ICE. There may be multiple servers of each type and
        any TURN server also acts as a STUN server.</p>

        <p>An <code><a>RTCPeerConnection</a></code> object has an associated
        <dfn id="rtcpeerconnection-ice-agent">ICE agent</dfn> [[!ICE]],
        RTCPeerConnection signaling state, ICE gathering state, and ICE
        connection state. These are initialized when the object is created.</p>

        <p>When the <dfn id=
        "dom-peerconnection"><code>RTCPeerConnection()</code></dfn> constructor
        is invoked, the user agent MUST run the following steps:</p>

        <ol>
          <li>
            <p>Let <var>connection</var> be a newly created
            <code><a>RTCPeerConnection</a></code> object.</p>
          </li>

          <li>
            <p><a href="#set-pc-configuration">Set the configuration</a>
            specified by the constructor's first argument.</p>
          </li>

          <li>
            <p>Create an ICE Agent as defined in [[!ICE]] and let
            <var>connection</var>'s <code>RTCPeerConnection</code> ICE Agent be
            that ICE Agent. The ICE Agent will
            proceed with gathering as soon as the <a href=
            "#ice-transports-setting">ICE transports setting</a> is not set to
            <code>none</code>. At this point the ICE Agent does not know how
            many ICE components it needs (and hence the number of candidates to
            gather), but it can make a reasonable assumption such as 2. As the
            <code>RTCPeerConnection</code> object gets more information, the
            ICE Agent can adjust the number of components.</p>
          </li>

          <li>
            <p>Set <var>connection</var>'s <a href=
            "#dom-peerconnection-signaling-state"><code>RTCPeerConnection</code>
            signalingState</a> to <code>stable</code>.</p>
          </li>

          <li>
            <p>Set <var>connection</var>'s <a href=
            "#dom-peerconnection-ice-connection-state"><code>RTCPeerConnection</code>
            ice connection state</a> to <code>new</code>.</p>
          </li>

          <li>
            <p>Set <var>connection</var>'s <a href=
            "#dom-peerconnection-ice-gathering-state"><code>RTCPeerConnection</code>
            ice gathering state</a> to <code>new</code>.</p>
          </li>

          <li>
            <p>Set <var>connection</var>'s
            <code><a href=
            "#dom-peerconnection-pendinglocaldesc">pendingLocalDescription</a></code>,
            <code><a href=
            "#dom-peerconnection-currentlocaldesc">currentLocalDescription</a></code>,
            <code><a href=
            "#dom-peerconnection-pendingremotedesc">pendingRemoteDescription</a></code>
            and <code><a href=
            "#dom-peerconnection-currentremotedesc">currentRemoteDescription</a></code>
            to null.
            </p>
          </li>

          <li>
            <p>Initialize an internal variable <var>operations</var> to represent a queue of
            operations with an empty array.</p>
          </li>

          <li>
            <p>If the <code>certificates</code> value in
            the <code>RTCConfiguration</code> structure is non-empty, check that
            the <code>expires</code> on each value is in the future.  If a
            certificate has expired, throw an <code>InvalidParameter</code>
            exception and abort these steps; otherwise, store the certificates.
            If no <code>certificates</code> value was specified, one or more
            new <code>RTCCertificate</code> instances are generated for use with
            this <code>RTCPeerConnection</code> instance.</p>
          </li>

          <li>
            <p>Return <var>connection</var>.</p>
          </li>
        </ol>

        <p>Once the RTCPeerConnection object has been initialized, for every
        call to <code>createOffer</code>, <code>setLocalDescription</code>,
        <code>createAnswer</code>, <code>setRemoteDescription</code>,
        and <code>addIceCandidate</code>,
        execute the following steps:</p>

        <ol>
          <li>
            <p>Let <var>p</var> be a new promise.</p>
          </li>

          <li>
            <p>Append an object representing the current call being handled
            (i.e. function name and corresponding arguments) to the
            <var>operations</var> array.</p>
          </li>

          <li>
            <p>If the length of the <var>operations</var> array is exactly 1,
            execute the object from the front of the queue.</p>
          </li>

          <li>
            <p>Upon fulfillment or rejection of the promise returned
            by the function, fulfill or reject <var>p</var> with the
            corresponding value or reason.  Upon fulfillment or
            rejection of <var>p</var>, execute the following
            steps:</p>
            <ol>
              <li><p>Remove the corresponding object from
                the <var>operations</var> array.</p></li>
              <li><p>If the array is non-empty, execute the first
                object queued.</p></li>
            </ol>
          </li>

          <li>
            <p>Return <var>p</var>.</p>
          </li>
        </ol>

        <p>The general idea is to have only one among <code>createOffer</code>,
        <code>setLocalDescription</code>, <code>createAnswer</code> and
        <code>setRemoteDescription</code>
        and <code>addIceCandidate</code> executing at any given
        time. If subsequent calls are made while the returned promise
        of a previous call is still unsettled, they are added to a
        queue and executed when all the previous calls are executed
        and their promises are settled.</p>

        <p>Additionally, during the lifetime of the RTCPeerConnection object,
        the following procedures are followed when an ICE event occurs:</p>

        <ol>
          <li>
            <p>If the <a href=
            "#dom-peerconnection-ice-gathering-state"><code>RTCPeerConnection</code>
            ice gathering state</a> is <code>new</code> and the <a href=
            "#ice-transports-setting">ICE transports setting</a> is not set to
            <code>none</code>, the user agent MUST queue a task to start
            gathering ICE addresses and set the <a href=
            "#dom-peerconnection-ice-gathering-state">ice gathering state</a>
            to <code>gathering</code>.</p>
          </li>

          <li>
            <p>If the ICE Agent has found one or more candidate pairs for each
            <code>MediaStreamTrack</code> that forms a valid connection, the ICE connection
            state is changed to <code>connected</code>.</p>
          </li>

          <li>
            <p>When the ICE Agent finishes checking all candidate pairs, if at
            least one connection has been found for each <a>media description</a>, the
            <a href=
            "#dom-peerconnection-ice-connection-state"><code>RTCPeerConnection</code>
            ice connection state</a> is changed to <code>completed</code>; otherwise
            <code>failed</code>.</p>
          </li>
        </ol>

        <p>When a new ICE candidate is available or when the ICE gathering process is done
        , the user agent MUST queue a task to run the
        following steps:</p>

        <ol>
          <li>
            <p>Let <var>connection</var> be the
            <code><a>RTCPeerConnection</a></code> object associated with this
            ICE Agent.</p>
          </li>

          <li>
            <p>If <var>connection</var>'s <a href=
            "#dom-peerconnection-signaling-state"><code>RTCPeerConnection</code>
            signalingState</a> is <code>closed</code>, abort these steps.</p>
          </li>

          <li>
            <p>If the intent of the ICE Agent is to notify the script that:</p>

            <ul>
              <li>
                <p>A new candidate is available.</p>

                <p>Add the candidate to <var>connection</var>'s
                <code><a>localDescription</a></code> and create a
                <code><a>RTCIceCandidate</a></code> instance to represent the
                candidate. Let <var>newCandidate</var> be that object.</p>
              </li>

              <li>
                <p>The gathering process is done.</p>

                <p>Set <var>connection</var>'s <a href=
                "#dom-peerconnection-ice-gathering-state">ice gathering
                state</a> to <code>completed</code> and let
                <var>newCandidate</var> be null.</p>
              </li>
            </ul>
          </li>

          <li>
            <p>Fire an event named <code><a href=
            "#event-icecandidate">icecandidate</a></code> with
            <var>newCandidate</var> at <var>connection</var>.</p>
          </li>
        </ol>

        <p>To <dfn id=
        "update-ice-gathering-state">update the ice gathering state</dfn> of an
        <code><a>RTCPeerConnection</a></code> instance <var>connection</var> to
        <var>newState</var>, the User Agent MUST queue a task that sets
        <var>connection</var>'s <a href=
        "#dom-peerconnection-ice-gathering-state">iceGatheringState</a>
        attribute to <var>newState</var> and fires a simple event named
        <code><a href=
        "#event-icegatheringstatechange">icegatheringstatechange</a></code> at
        <var>connection</var>.</p>

        <p>To <dfn id=
        "update-ice-connection-state">update the ice connection state</dfn> of an
        <code><a>RTCPeerConnection</a></code> instance <var>connection</var> to
        <var>newState</var>, the User Agent MUST queue a task that sets
        <var>connection</var>'s <a href=
        "#dom-peerconnection-ice-connection-state">iceConnectionState</a>
        attribute to <var>newState</var> and fires a simple event named
        <code><a href=
        "#event-iceconnectionstatechange">icegatheringstatechange</a></code> at
        <var>connection</var>.</p>

        <p>To <dfn id="set-description">set an RTCSessionDescription</dfn>
        <var>description</var> on an <code><a>RTCPeerConnection</a></code>
        object <var>connection</var>, run the following steps:</p>

        <ol>
          <li>
            <p>If <var>connection</var>'s
            <a href="#dom-peerconnection-signaling-state">signaling
            state</a> is <code>closed</code>, the user agent MUST return a
            promise rejected with an <code>InvalidStateError</code>.</p>
          </li>

          <li>
            <p>Let <var>p</var> be a new promise.</p>
          </li>

          <li>
            <p>In parallel, start the process to apply <var>description</var> as
            described in <span data-jsep="processing-a-local-desc processing-a-remote-desc">[[!JSEP]]</span>.</p>

            <ol>
              <li>
                <p>If the process to apply <var>description</var> fails for
                any reason, then user agent MUST queue a task runs the
                following steps:</p>

                <ol>
                  <li>
                    <p>If <var>connection</var>'s <a href=
                    "#dom-peerconnection-signaling-state">signaling state</a>
                    is <code>closed</code>, then abort these steps.</p>
                  </li>

                  <li>
                    <p>If the content of <var>description</var> is invalid or if
                    <var>description</var>'s <code><a href=
                    "#widl-RTCSessionDescription-type">type</a></code> is wrong for
                    the current <a href=
                    "#dom-peerconnection-signaling-state">signaling state</a> of
                    <var>connection</var>, then reject <var>p</var> with an
                    <code>InvalidSessionDescriptionError</code> and abort these
                    steps.</p>
                  </li>

                  <li>
                    <p>If <var>description</var> cannot be applied at the media
                    layer, but the User Agent recovered, possibly by rolling back
                    to the previous configuration, then reject <var>p</var> with
                    <code>IncompatibleSessionDescriptionError</code> and abort
                    these steps.</p>

                    <p>This occurs, for example, when the version of
                    <var>description</var> is older than the one currently
                    being used.</p>
                  </li>

                  <li>
                    <p>Otherwise, set <var>connection</var>'s <a href=
                    "#dom-peerconnection-signaling-state">signaling state</a> to
                    <code>closed</code>.</p>
                  </li>

                  <li>
                    <p>Fire a simple event named <code><a href=
                    "#event-signalingstatechange">signalingstatechange</a></code>
                    at <var>connection</var>.</p>
                  </li>

                  <li>
                    <p>Reject <var>p</var> with <code>InternalError</code>.</p>
                  </li>
                </ol>
              </li>

              <li>
                <p>If <var>description</var> is applied successfully, the user
                agent MUST queue a task that runs the following steps:</p>

                <ol>
                  <li>
                    <p>If <var>connection</var>'s <a href=
                    "#dom-peerconnection-signaling-state">signaling state</a>
                    is <code>closed</code>, then abort these steps.</p>
                  </li>

                  <li>
                    <p>If <var>description</var> is set as a local description, and
                    its content matches the state of all tracks and data channels,
                    <a href="#clearing-negotiation-needed">as defined below</a>,
                    clear the negotiation-needed flag.
                    </p>

                    <p class="issue">NOTE: The principles of pending and current SDP
                    were agreed by the WG but the details in the next steps have not
                    yet been fully reviewed. TODO - review this.</p>
                  </li>

                  <li>
                    <p>If <var>description</var> is set as a local description,
                    then run one of the following steps:</p>

                    <ul>
                      <!-- A) transition stable to haveLocalOffer -->
                      <li>
                        <p>If <var>description</var> is of type "offer",
                        set <var>connection</var>'s <code><a href=
                        "#dom-peerconnection-pendinglocaldesc">pendingLocalDescription</a></code>
                        attribute to <var>description</var> and <a href=
                        "#dom-peerconnection-signaling-state">signaling state</a>
                        to <code>have-local-offer</code>.</p>
                      </li>

                      <!-- C) transition haveRemoteOffer or haveLocalProvAnswer to
                      stable -->
                      <li>
                        <p>If <var>description</var> is
                        of type "answer", then this completes an offer answer
                        negotiation. Set <var>connection</var>'s <code><a href=
                        "#dom-peerconnection-currentlocaldesc">currentLocalDescription</a></code>
                        to <var>description</var> and <code><a href=
                        "#dom-peerconnection-currentremotedesc">currentRemoteDescription</a></code>
                        to the value of <code><a href=
                        "#dom-peerconnection-pendingremotedesc">pendingRemoteDescription</a></code>.
                        Set both <code><a href=
                        "#dom-peerconnection-pendingremotedesc">pendingRemoteDescription</a></code>
                        and <code><a href=
                        "#dom-peerconnection-pendinglocaldesc">pendingLocalDescription</a></code>
                        to null. Finally set <var>connection</var>'s <a href=
                        "#dom-peerconnection-signaling-state">signaling state</a>
                        to <code>stable</code></p>
                      </li>

                      <!-- B) transition rollback to haveLocalOffer to stable -->
                      <li>
                        <p>If <var>description</var> is
                        of type "rollback", then this is a rollback. Set
                        <var>connection</var>'s <code><a href=
                        "#dom-peerconnection-pendinglocaldesc">pendingLocalDescription</a></code>
                        to null and <a href=
                        "#dom-peerconnection-signaling-state">signaling state</a>
                        to <code>stable</code>.</p>
                      </li>

                      <!-- G) transition haveRemoteOffer to haveLocalProvAnswer -->
                      <li>
                        <p>If <var>description</var> is
                        of type "pranswer", then set <var>connection</var>'s
                        <code><a href=
                        "#dom-peerconnection-pendinglocaldesc">pendingLocalDescription</a></code>
                        to <var>description</var> and <a href=
                        "#dom-peerconnection-signaling-state">signaling state</a>
                        to <code>have-local-pranswer</code>.</p>
                      </li>
                    </ul>
                  </li>

                  <li>
                    <p>Otherwise, if <var>description</var> is set as a remote
                    description, then run one of the following steps:</p>

                    <ul>
                      <!-- D) transition stable to haveRemoteOffer -->
                      <li>
                        <p>If <var>description</var> is
                        of type "offer",
                        set <var>connection</var>'s <code><a href=
                        "#dom-peerconnection-pendingremotedesc">pendingRemoteDescription</a></code>
                        attribute to <var>description</var> and <a href=
                        "#dom-peerconnection-signaling-state">signaling state</a>
                        to <code>have-remote-offer</code>.</p>
                      </li>

                      <!-- F) transition haveRemoteOffer or haveLocalProvAnswer to
                      stable -->
                      <li>
                        <p>If <var>description</var> is
                        of type "answer", then this completes an offer answer
                        negotiation. Set <var>connection</var>'s <code><a href=
                        "#dom-peerconnection-currentremotedesc">currentRemoteDescription</a></code>
                        to <var>description</var> and <code><a href=
                        "#dom-peerconnection-currentlocaldesc">currentLocalDescription</a></code>
                        to the value of <code><a href=
                        "#dom-peerconnection-pendinglocaldesc">pendingLocalDescription</a></code>.
                        Set both <code><a href=
                        "#dom-peerconnection-pendingremotedesc">pendingRemoteDescription</a></code>
                        and <code><a href=
                        "#dom-peerconnection-pendinglocaldesc">pendingLocalDescription</a></code>
                        to null. Finally set <var>connection</var>'s <a href=
                        "#dom-peerconnection-signaling-state">signaling state</a>
                        to <code>stable</code></p>
                      </li>

                      <!-- E) transition rollback to haveRemoteOffer to stable -->
                      <li>
                        <p>If <var>description</var> is
                        of type "rollback", then this is a rollback. Set
                        <var>connection</var>'s <code><a href=
                        "#dom-peerconnection-pendingremotedesc">pendingRemoteDescription</a></code>
                        to null and <a href=
                        "#dom-peerconnection-signaling-state">signaling state</a>
                        to <code>stable</code>.</p>
                      </li>

                      <!-- H) transition haveRemoteOffer to haveLocalProvAnswer -->
                      <li>
                        <p>If <var>description</var> is
                        of type "pranswer", then set <var>connection</var>'s
                        <code><a href=
                        "#dom-peerconnection-pendingremotedesc">pendingRemoteDescription</a></code>
                        to <var>description</var> and <a href=
                        "#dom-peerconnection-signaling-state">signaling state</a>
                        to <code>have-remote-pranswer</code>.</p>
                      </li>
                    </ul>
                  </li>

                  <li>
                    <p>If <var>connection</var>'s <a href=
                    "#dom-peerconnection-signaling-state">signaling state</a>
                    changed above, fire a simple event named <code><a href=
                    "#event-signalingstatechange">signalingstatechange</a></code>
                    at <var>connection</var>.</p>
                  </li>

                  <li>
                    <p>If <var>description</var> is set as a local description,
                    <var>connection</var>'s <a href=
                    "#dom-peerconnection-ice-gathering-state">ice gathering
                    state</a> is <code>new</code>, and <var>description</var>
                    contains media, then <a href=
                    "#update-ice-gathering-state">update <var>connection</var>'s
                    ice gathering state</a> to <code>gathering</code>.</p>
                  </li>

                  <li>
                    <p>If the process to apply <var>description</var> resulted
                    in an ICE restart <span data-jsep="applying-a-local-desc applying-a-remote-desc">[[!JSEP]]</span>, then run the following
                    steps:</p>

                    <ol>
                      <li>
                        <p>If <var>connection</var> is not already gathering,
                        <a href="#update-ice-gathering-state">update
                        <var>connection</var>'s ice gathering state</a> to
                        <code>gathering</code>.</p>
                      </li>

                      <li>
                        <p>If <var>connection</var>'s <a href=
                        "#dom-peerconnection-ice-connection-state">ice connection state</a>
                        is <code>completed</code>, <a href=
                        "#update-ice-connection-state">update
                        <var>connection</var>'s ice connection state</a> to
                        <code>connected</code>.</p>
                      </li>
                    </ol>
                  </li>

                  <li>
                    <p>If <var>description</var> is set as a remote description
                    with new media descriptions [[!JSEP]], the User Agent
                    MUST <a href="#dispatch-receiver">dispatch a receiver</a> for
                    all new media descriptions.</p>
                  </li>

                  <li>
                    <p>If <var>connection</var>'s <a href=
                    "#dom-peerconnection-signaling-state">signalingState</a> is
                    now <code>stable</code>, and the negotiation-needed flag is
                    set, the User Agent MUST queue a task to fire a simple event
                    named <code><a href=
                    "#event-negotiation">negotiationneeded</a></code> at
                    <var>connection</var> and clear the negotiation-needed flag.</p>
                  </li>

                  <li>
                    <p>Resolve <var>p</var> with <var>undefined</var>.</p>
                  </li>
                </ol>
              </li>
            </ol>
          </li>

          <li>
            <p>Return <var>p</var>.</p>
          </li>
        </ol>

        <p>The task source for the <span title="concept-task">tasks</span>
        listed in this section is the networking task source.</p>

        <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>
      </section>

      <section>
        <h3>Interface Definition</h3>

        <p>The <code><a>RTCPeerConnection</a></code> interface presented in this
        section is extended by several partial
        interfaces throughout this specification. Notably, the <a href=
        "#rtcpeerconnection-interface-extensions">RTP Media section</a>, that
        adds the APIs to send and receive <code><a>MediaStreamTrack</a></code>
        objects.</p>

        <dl class="idl" title="interface RTCPeerConnection : EventTarget ">
          <dt>Constructor (optional RTCConfiguration configuration)</dt>

          <dd>
            See the <a href="#dom-peerconnection">RTCPeerConnection constructor
            algorithm</a>.
          </dd>

          <dt>Promise&lt;RTCSessionDescription&gt; createOffer (
            optional RTCOfferOptions options)</dt>

          <dd>
            <p>The createOffer method generates a blob of SDP that contains an
            RFC 3264 offer with the supported configurations for the session,
            including descriptions of the local <code>MediaStreamTrack</code>s
            attached to this <code>RTCPeerConnection</code>, the codec/RTP/RTCP
            options supported by this implementation, and any candidates that
            have been gathered by the ICE Agent. The <code>options</code> parameter may be
            supplied to provide additional control over the offer
            generated.</p>

            <p>As an offer, the generated SDP will contain the full set of
            capabilities supported by the session (as opposed to an answer,
            which will include only a specific negotiated subset to use); for
            each SDP line, the generation of the SDP MUST follow the
            appropriate process for generating an offer. In the event
            <code>createOffer</code> is called after the session is established, <code>createOffer</code>
            will generate an offer that is compatible with the current session,
            incorporating any changes that have been made to the session since
            the last complete offer-answer exchange, such as addition or
            removal of tracks. If no changes have been made, the offer will
            include the capabilities of the current local description as well
            as any additional capabilities that could be negotiated in an
            updated offer.</p>

            <p>Session descriptions generated by <code>createOffer</code> MUST be
            immediately usable by <code>setLocalDescription</code> without causing an error
            as long as <code>setLocalDescription</code> is called reasonably soon.
            If a system has limited resources (e.g. a finite number
            of decoders), <code>createOffer</code> needs to return an offer that reflects
            the current state of the system, so that <code>setLocalDescription</code> will
            succeed when it attempts to acquire those resources. The session
            descriptions MUST remain usable by <code>setLocalDescription</code> without
            causing an error until at least the end of the fulfillment callback of the
            returned promise. Calling this method is needed to get the ICE user name
            fragment and password.</p>

            <p>The value for <code>certificates</code> in
            the <code><a>RTCConfiguration</a></code> for
            the <code>RTCPeerConnection</code> is used to produce a set of
            certificate fingerprints.  These certificate fingerprints are used
            in the construction of SDP and as input to requests for identity
            assertions.</p>

            <p>If the <code>RTCPeerConnection</code> is configured to generate
            Identity assertions by calling <code>setIdentityProvider</code>, then the
            session description SHALL contain an appropriate assertion.  If the
            identity provider is unable to produce an identity assertion, the
            call to <code>createOffer</code> MUST be rejected with a
            <code>DOMError</code> that has a name of <code>IdpError</code>.</p>

            <p>If this <code>RTCPeerConnection</code> object is closed before
            the SDP generation process completes, the user agent MUST suppress
            the result and not resolve or reject the returned promise.</p>

            <p>If the SDP generation process completed successfully, the user
            agent MUST resolve the returned promise with a
            newly created <code><a>RTCSessionDescription</a></code> object,
            representing the generated offer.</p>

            <p>If the SDP generation process failed for any other reason, the
            user agent MUST reject the returned promise with an
            <code>DOMError</code> object of type TBD as its argument.</p>

            <p data-number="265" class="issue">To Do: Discuss privacy aspects of this from a fingerprinting
            point of view - it's probably around as bad as access to a canvas
            :-)</p>
          </dd>

          <dt>Promise&lt;RTCSessionDescription&gt; createAnswer (optional
          RTCAnswerOptions options)</dt>

          <dd>
            <p>The <code>createAnswer</code> method generates an [[!SDP]] answer with the
            supported configuration for the session that is compatible with the
            parameters in the remote configuration. Like <code>createOffer</code>, the
            returned blob contains descriptions of the local <code>MediaStreamTrack</code>s
            attached to this <code>RTCPeerConnection</code>, the codec/RTP/RTCP options
            negotiated for this session, and any candidates that have been
            gathered by the ICE Agent. The <code>options</code> parameter may be supplied to
            provide additional control over the generated answer.</p>

            <p>As an answer, the generated SDP will contain a specific
            configuration that, along with the corresponding offer, specifies
            how the media plane should be established. The generation of the
            SDP MUST follow the appropriate process for generating an
            answer.</p>

            <p>Session descriptions generated by createAnswer MUST be
            immediately usable by <code>setLocalDescription</code> without causing an
            error as long as <code>setLocalDescription</code> is called reasonably soon.
            Like <code>createOffer</code>, the returned description SHOULD reflect
            the current state of the system. The session descriptions MUST
            remain usable by <code>setLocalDescription</code> without causing an error until
            at least the end of the fulfillment callback of the returned promise. Calling this
            method is needed to get the ICE user name fragment and
            password.</p>

            <p>An answer can be marked as provisional, as described in
            <span data-jsep="use-of-provisional-answer">[[!JSEP]]</span>, by setting the <code><a href=
            "#widl-RTCSessionDescription-type">type</a></code> to
            <code>pranswer</code>.</p>

            <p>If the <code>RTCPeerConnection</code> is configured to generate
            Identity assertions by calling <a>setIdentityProvider</a>, then the
            session description SHALL contain an appropriate assertion.  If the
            identity provider is unable to produce an identity assertion, the
            call to <code>createAnswer</code> MUST be rejected with a
            <code>DOMError</code> that has a name of <code>IdpError</code>.</p>

            <p>If this <code>RTCPeerConnection</code> object is closed before
            the SDP generation process completes, the user agent MUST suppress
            the result and not resolve or reject the returned promise.</p>

            <p>If the SDP generation process completed successfully, the user
            agent MUST resolve the returned promise with a
            newly created <code><a>RTCSessionDescription</a></code> object,
            representing the generated answer.</p>

            <p>If the SDP generation process failed for any reason, the user
            agent MUST reject the returned promise with a <code>DOMError</code>
            object of type TBD.</p>
            <p data-number="319" class="issue">TODO: define type of error for SDP generation</p>
          </dd>

          <dt>Promise&lt;void&gt; setLocalDescription (
            RTCSessionDescriptionInit description)</dt>

          <dd>
            <p>The <dfn id=
            "dom-peerconnection-setlocaldescription"><code>setLocalDescription()</code></dfn>
            method instructs the <code><a>RTCPeerConnection</a></code> to apply
            the supplied <code><a>RTCSessionDescriptionInit</a></code> as the local
            description.</p>

            <p>This API changes the local media state. In order to successfully
            handle scenarios where the application wants to offer to change
            from one media format to a different, incompatible format, the
            <code><a>RTCPeerConnection</a></code> MUST be able to
            simultaneously support use of both the current and pending local
            descriptions (e.g. support codecs that exist in both descriptions)
            until a final answer is received, at which point the
            <code><a>RTCPeerConnection</a></code> can fully adopt the pending local
            description, or rollback to the current description if the remote side
            rejected the change. </p>

            <p>When the method is invoked, the user agent must <a
            href="#set-description">set the RTCSessionDescription</a> indicated
            by the method's first argument.

            <p data-number="338" class="issue">To Do: specify what parts of the SDP can be changed between the
            createOffer and setLocalDescription</p>
          </dd>

          <dt>readonly attribute RTCSessionDescription? localDescription</dt>

          <dd>
            <p>The <dfn id=
            "dom-peerconnection-localdescription"><code>localDescription</code></dfn>
            attribute MUST return <code><a href=
            "#dom-peerconnection-pendinglocaldesc">pendingLocalDescription</a></code>
            if it is not null and otherwise it MUST return <code><a href=
            "#dom-peerconnection-currentlocaldesc">currentLocalDescription</a></code>. </p>
          </dd>


          <dt>readonly attribute RTCSessionDescription? currentLocalDescription</dt>

          <dd>
            <p>The <code><a href=
            "#dom-peerconnection-currentlocaldesc">currentLocalDescription</a></code>
            attribute represents the local <code><a>RTCSessionDescription</a></code>
            that was successfully negotiated the last time the<code>RTCPeerConnection</code> transitioned into
            the stable state plus any local candidates that have been generated by the ICE
            Agent since the offer or answer was created. This attribute is updated by <code><a href=
            "#dom-peerconnection-setlocaldescription">setLocalDescription()</a></code>.</p>

            <p>The <dfn id=
            "dom-peerconnection-currentlocaldesc"><code>currentLocalDescription</code></dfn>
            attribute MUST return the last value that algorithms in this
            specification set it to, completed with any local candidates that have been
            generated by the ICE Agent since the offer or answer was created.
            Prior to being set, it returns null.
            </p>
          </dd>

          <dt>readonly attribute RTCSessionDescription? pendingLocalDescription</dt>

          <dd>
            <p>The <code><a href=
            "#dom-peerconnection-pendinglocaldesc">pendingLocalDescription</a></code>
            attribute represents a local
            <code><a>RTCSessionDescription</a></code> that is in the process of
            being negotiated plus any local candidates that have been generated
            by the ICE Agent since the offer or answer was created. If the
           <code>RTCPeerConnection</code> is in the stable state, the value is null.
            This attribute is updated by <code><a href=
            "#dom-peerconnection-setlocaldescription">setLocalDescription()</a></code>.
            </p>

            <p>The <dfn id=
            "dom-peerconnection-pendinglocaldesc"><code>pendingLocalDescription</code></dfn>
            attribute MUST return the last value that algorithms in this
            specification set it to, completed with any local candidates that have been
            generated by the ICE Agent since the offer or answer was created.
            Prior to being set, it returns null.
            </p>
          </dd>


          <dt>Promise&lt;void&gt; setRemoteDescription (
            RTCSessionDescriptionInit description)</dt>

          <dd>
            <p>The <dfn id=
            "dom-peerconnection-setremotedescription"><code>setRemoteDescription()</code></dfn>
            method instructs the <code><a>RTCPeerConnection</a></code> to apply
            the supplied <code><a>RTCSessionDescriptionInit</a></code> as the
            remote offer or answer. This API changes the local media state.</p>

            <p>When the method is invoked, the user agent must <a
            href="#set-description">set the RTCSessionDescription</a> indicated
            by the method's first argument.
            In addition, a remote description is processed to determine and
            verify the identity of the peer.</p>

            <p>If an <code>a=identity</code> attribute is present in the session
            description, the browser <a href=
            "#sec.identity-verify-assertion">validates the identity
            assertion.</a>.</p>

            <p>If the "peerIdentity" configuration is applied to the
            <code><a>RTCPeerConnection</a></code>, this establishes a <dfn
            id="target-peer-identity">target peer identity</dfn> of the provided
            value.  Alternatively, if the <code><a>RTCPeerConnection</a></code>
            has previously authenticated the identity of the peer (that is,
            there is a current value for <code><a href=
            "#widl-RTCPeerConnection-peerIdentity">peerIdentity</a></code> ),
            then this also establishes a <a href= "#target-peer-identity">target
            peer identity</a>.</p>

            <p>The <a href="#target-peer-identity">target peer identity</a>
            cannot be changed once set. Once set, if a different value is
            provided, the user agent MUST reject the returned promise with
            <code>IncompatibleSessionDescriptionError</code> and abort this
            operation. The <code><a>RTCPeerConnection</a></code> MUST be closed
            if the validated peer identity does not match the <a href=
            "#target-peer-identity">target peer identity</a>.</p>

            <p>If there is no <a href="#target-peer-identity">target peer
            identity</a>, then <code>setRemoteDescription</code> does not await
            the completion of identity validation.</p>
          </dd>

          <dt>readonly attribute RTCSessionDescription? remoteDescription</dt>

          <dd>
            <p>The <dfn id=
            "dom-peerconnection-remotedescription"><code>remoteDescription</code></dfn>
            attribute  MUST return <code><a href=
            "#dom-peerconnection-pendingremotedesc">pendingRemoteDescription</a></code>
            if it is not null and otherwise it MUST return <code><a href=
            "#dom-peerconnection-currentremotedesc">currentRemoteDescription</a></code>. </p>
          </dd>

          <dt>readonly attribute RTCSessionDescription? currentRemoteDescription</dt>

          <dd>
            <p>The <code><a href=
            "#dom-peerconnection-currentremotedesc">currentRemoteDescription</a></code>
            attribute represents the last remote
            <code><a>RTCSessionDescription</a></code> that was successfully
            negotiated the last time the<code>RTCPeerConnection</code> transitioned into the
            stable state plus any remote candidates that have been supplied via
            <code><a href=
            "#dom-peerconnection-addicecandidate">addIceCandidate()</a></code>
            since the offer or answer was created. This attribute is updated by
            <code><a href=
            "#dom-peerconnection-setremotedescription">setRemoteDescription()</a></code>.
            </p>

            <p>The <dfn id=
            "dom-peerconnection-currentremotedesc"><code>currentRemoteDescription</code></dfn>
            attribute MUST return the value that algorithms in this
            specification set it to, completed with any remote candidates that have been
            supplied via <code><a href=
            "#dom-peerconnection-addicecandidate">addIceCandidate()</a></code>
            since the offer or answer was created. Prior to being set, it returns null.
</p>
          </dd>

          <dt>readonly attribute RTCSessionDescription? pendingRemoteDescription</dt>

          <dd>
            <p>The <code><a href=
            "#dom-peerconnection-pendingremotedesc">pendingRemoteDescription</a></code>
            attribute represents a remote
            <code><a>RTCSessionDescription</a></code> that is in the process of
            being negotiated, completed with any remote candidates that have been supplied
            via <code><a href=
            "#dom-peerconnection-addicecandidate">addIceCandidate()</a></code>
            since the offer or answer was created. If the
           <code>RTCPeerConnection</code> is in the stable state, the value is null.
            This attribute is updated by <code><a href=
            "#dom-peerconnection-setlocaldescription">setLocalDescription()</a></code>.
            </p>

            <p>The <dfn id=
            "dom-peerconnection-pendingremotedesc"><code>pendingRemoteDescription</code></dfn>
            attribute MUST return the value that algorithms in this
            specification set it to, completed with any remote candidates that have been
            supplied via <code><a href=
            "#dom-peerconnection-addicecandidate">addIceCandidate()</a></code>
            since the offer or answer was created. Prior to being set, it returns null.
</p>
          </dd>

          <dt>Promise&lt;void&gt; addIceCandidate (RTCIceCandidate candidate)</dt>

          <dd>
            <p>The <dfn id=
            "dom-peerconnection-addicecandidate"><code>addIceCandidate()</code></dfn>
            method provides a remote candidate to the ICE Agent. In addition to
            being added to the remote description, connectivity checks will be
            sent to the new candidates as long as the <a href=
            "#ice-transports-setting">ICE Transports setting</a> is not set to
            <code>none</code>. This call will result in a change to the
            connection state of the ICE Agent, and may result in a change to
            media state if it results in different connectivity being
            established. The only members of the candidate attribute
            used by this method are <var>candidate</var>, <var>sdpMid</var> and
            <var>sdpMLineIndex</var>; the rest are ignored.</p>

            <ol>
              <li>
                <p>Let <var>p</var> be a new promise.</p>
              </li>

              <li>
                <p>If this <code><a>RTCPeerConnection</a></code> object's
                <a href="#dom-peerconnection-signaling-state">signaling
                state</a> is <code>closed</code>, the user agent MUST reject
                <var>p</var> with <code>InvalidStateError</code>, and
                jump to the step labeled <em>Return</em>.</p>
              </li>

              <li>
                <p>If the candidate could not be successfully applied, reject
                <var>p</var> with a <code>DOMError</code> object whose
                <code>name</code> attribute has the value TBD
                and jump to the step
                labeled <em>Return</em>.</p>
                <p class="issue">TODO: define names for DOMError (
                InvalidCandidate and InvalidMidIndex (see also <a href="https://github.com/w3c/webrtc-pc/issues/319">Issue 319</a>)</p>
              </li>

              <li>
                <p>If the candidate is successfully applied, resolve
                <var>p</var> with <code>undefined</code>.</p>
              </li>

              <li>
                <p><em>Return:</em> Return <var>p</var>.</p>
              </li>
            </ol>

            <div class="issue">
              What errors do we need here? Should we reuse the
              *SessionDescriptionError names or invent new ones for candidates?
              Should this method be queued? (see also <a href="https://github.com/w3c/webrtc-pc/issues/319">Issue 319</a>)
            </div>
          </dd>

          <dt>readonly attribute RTCSignalingState signalingState</dt>

          <dd>
            <p>The <dfn id=
            "dom-peerconnection-signaling-state"><code>signalingState</code></dfn>
            attribute MUST return the <code><a href=
            "#dom-peerconnection-signaling-state">RTCPeerConnection</a></code>
            object's <a href=
            "#dom-peerconnection-signaling-state"><code>RTCPeerConnection</code>
            signaling state</a>.</p>
          </dd>

          <dt>readonly attribute RTCIceGatheringState iceGatheringState</dt>

          <dd>
            <p>The <dfn id=
            "dom-peerconnection-ice-gathering-state"><code>iceGatheringState</code></dfn>
            attribute MUST return the gathering state of the <a href=
            "#rtcpeerconnection-ice-agent"><code>RTCPeerConnection</code> ICE
            Agent</a>.</p>
          </dd>

          <dt>readonly attribute RTCIceConnectionState iceConnectionState</dt>

          <dd>
            <p>The <dfn id=
            "dom-peerconnection-ice-connection-state"><code>iceConnectionState</code></dfn>
            attribute MUST return the <a href=
            "#rtcpeerconnection-ice-agent">connection state of the <code>RTCPeerConnection</code> ICE
            Agent</a>.</p>
          </dd>

          <dt>readonly attribute RTCPeerConnectionState connectionState</dt>

          <dd>
            <p>The <dfn id=
            "dom-peerconnection-connection-state"><code>connectionState</code></dfn>
            attribute MUST return the aggregate of the states of
            the <a><code>DtlsTransport</code></a>s
            and <a><code>IceTransport</code></a>s of
            the <a><code>RTCPeerConnection</code></a>, as describe in the
            values of the <a><code>RTCPeerConnectionState</code></a> enum.

              </p>
          </dd>

          <dt>readonly attribute boolean? canTrickleIceCandidates</dt>

          <dd>
            <p>This attribute indicates whether the remote peer is able to
            accept trickled ICE candidates [[TRICKLE-ICE]].  The value is
            determined based on whether a remote description indicates support
            for trickle ICE, as defined in <span data-jsep="cantrickle">[[!JSEP]]</span>.  Prior to
            the completion
            of <a href="#dom-peerconnection-setremotedescription"><code>setRemoteDescription</code></a>,
            this value is <code>null</code>.
          </dd>

          <dt>static readonly attribute FrozenArray&lt;RTCIceServer&gt; defaultIceServers</dt>

          <dd>
            <p>The <code>defaultIceServers</code> attribute provides a list of
            ICE servers that are configured into the browser.  A browser might
            be configured to use local or private STUN or TURN servers.  This
            method allows an application to learn about these servers and
            optionally use them.
            </p>
          </dd>

          <dt>RTCConfiguration getConfiguration()</dt>

          <dd>
            <p>Returns a <code><a>RTCConfiguration</a></code> object
            representing the current configuration of this
            <code><a>RTCPeerConnection</a></code> object.</p>

            <p>When this method is call, the user agent MUST a construct new
            <code><a>RTCConfiguration</a></code> object to be returned, and
            initialize it using the ICE Agent's <a href=
            "#ice-transports-setting">ICE transports setting</a> and <a href=
            "#ice-servers-list">ICE servers list</a>.</p>

            <p>The returned configuration MUST include
            a <code>certificates</code> attribute containing the candidate set
            of certificates used for connecting to peers.  This attribute
            contains the certificates chosen by the application, or the
            certificates generated by the <a>user agent</a> for use with this
            <code>RTCPeerConnection</code> instance.</p>
          </dd>

          <dt>void setConfiguration (RTCConfiguration configuration)</dt>

          <dd>
            <p>The <code>setConfiguration</code> method updates the ICE Agent process of gathering
            local candidates and pinging remote candidates.</p>

            <p>This call may result in a change to the state of the ICE Agent,
            and may result in a change to media state if it results in
            connectivity being established.</p>

            <p>When the <dfn id=
            "dom-peerconnection-setconfiguration"><code>setConfiguration()</code></dfn>
            method is invoked, the user agent MUST <a href=
            "#set-pc-configuration">set the configuration</a> specified by the
            methods argument.</p>

            <p>To <dfn id="set-pc-configuration">set a configuration</dfn>, run
            the following steps:</p>

            <ol>
              <li>Let <var>configuration</var> be the
              <code><a>RTCConfiguration</a></code> dictionary to be processed.</li>

              <li>
                <p>Let the value of <code><var>configuration</var>.<a href=
                "#widl-RTCConfiguration-iceTransportPolicy">iceTransportPolicy</a></code>
                be the ICE Agent's <dfn id=
                "ice-transports-setting">ICE transports setting</dfn>.</p>
              </li>

              <li>
                <p>Let the value of <code><var>configuration</var>.<a href=
                "#widl-RTCConfiguration-bundlePolicy">bundlePolicy</a></code>
                be the user agent's bundle policy.</p>
              </li>

              <li>
                <p>Let the value of <code><var>configuration</var>.<a href=
                "#widl-RTCConfiguration-iceCandidatePoolSize">iceCandidatePoolSize</a></code>
                be the user agent's prefetched ICE
                candidate pool size as defined in <span data-jsep="setconfiguration">[[!JSEP]]</span>.</p>
              </li>
              
              <li>
                <p>Let <var>validatedServers</var> be an empty list.</p>
              </li>

              <li>
                <p>If <code><var>configuration</var>.<a href=
                "#widl-RTCConfiguration-iceServers">iceServers</a></code>
                is defined, then run the following steps for each
                element:</p>

                <ol>
                  <li>
                    <p>Let <var>server</var> be the current list element.</p>
                  </li>

                  <li>
                    <p>If <code><var>server</var>.urls</code> is a string, let
                    <code><var>server</var>.urls</code> be a list consisting of just that
                    string.</p>
                  </li>

                  <li>
                    <p>For each <var>url</var> in <code><var>server</var>.urls</code>, parse <var>url</var> and
                    obtain <var>scheme name</var>. If the parsing fails or if
                    <var>scheme name</var> is not implemented by the browser,
                    throw a <code>SyntaxError</code> and abort these steps.</p>
                  </li>

                  <li>
                    <p>If <var>scheme name</var> is <code>turn</code> or <code>turns</code>, and either of 
                    <code><var>server</var>.username</code> or
                    <code><var>server</var>.credential</code> are omitted, then throw an
                    <code>InvalidAccessError</code> and abort these steps.</p>
                  </li>

                  <li>
                    <p>Append<var>server</var> to <var>validatedServers</var>.
                    </p>
                  </li>
                </ol>

                <p>Let <var>validatedServers</var> be the ICE Agent's
                <dfn id="ice-servers-list">ICE servers list</dfn>.</p>

                <p>If a new list of servers replaces the ICE Agent's existing
                ICE servers list, no action will be taken until the
                <code><a>RTCPeerConnection</a></code>'s <a href=
                "#dom-peerconnection-ice-gathering-state">ice gathering
                state</a> transitions to <code>gathering</code>. If a script
                wants this to happen immediately, it should do an ICE
                restart.</p>
              </li>
            </ol>

            <div class="issue">
              The exception types throw in the above algorithm are provisional
              (until we decide what to do in each case). See also <a href="https://github.com/w3c/webrtc-pc/issues/319">Issue 319</a>
            </div>
          </dd>

          <dt>void close ()</dt>

          <dd>
            <p>When the <dfn id="dom-peerconnection-close"><code title=
            "">RTCPeerConnection close()</code></dfn> method is invoked, the
            user agent MUST run the following steps:</p>

            <ol>
              <li>If the <code>RTCPeerConnection</code> object's
              <code>RTCPeerConnection</code> <code>signalingState</code> is
              <code>closed</code>, abort these steps.</li>

              <li>
                <p>Destroy the <a href=
                "#rtcpeerconnection-ice-agent"><code>RTCPeerConnection</code>
                ICE Agent</a>, abruptly ending any active ICE processing and
                any active streaming, and releasing any relevant resources
                (e.g. TURN permissions).</p>
              </li>

              <li>
                <p>Set the object's <a href=
                "#dom-peerconnection-signaling-state"><code>RTCPeerConnection</code>
                signalingState</a> to <code>closed</code>.</p>
              </li>
            </ol>
          </dd>

          <dt>attribute EventHandler onnegotiationneeded</dt>

          <dd>The event type of this event handler is <code><a href=
          "#event-negotiation">negotiationneeded</a></code>.</dd>

          <dt>attribute EventHandler onicecandidate</dt>

          <dd>The event type of this event handler is <code><a href=
          "#event-icecandidate">icecandidate</a></code>.</dd>

          <dt>attribute EventHandler onicecandidateerror</dt>

          <dd>The event type of this event handler is <code><a href=
          "#event-icecandidateerror">icecandidateerror</a></code>.</dd>

          <dt>attribute EventHandler onsignalingstatechange</dt>

          <dd>The event type of this event handler is <code><a href=
          "#event-signalingstatechange">signalingstatechange</a></code>. It is called any
          time the <a href="#dom-peerconnection-signaling-state">
          <code>RTCPeerConnection</code> signaling state</a> changes, i.e., from a call to
          <code>setLocalDescription</code>, a call to
          <code>setRemoteDescription</code>, or code. It does not fire for the
          initial state change into <code>new</code>.</dd>

          <dt>attribute EventHandler oniceconnectionstatechange</dt>

          <dd>
            The event type of this event handler is <code><a href=
            "#event-iceconnectionstatechange">iceconnectionstatechange</a></code>. It is called any
            time the <a href=
            "#dom-peerconnection-ice-connection-state"><code>RTCPeerConnection</code>
            ice connection state</a> changes.
          </dd>

          <dt>attribute EventHandler onicegatheringstatechange</dt>

          <dd>
            The event type of this event handler is <code><a href=
            "#event-icegatheringstatechange">icegatheringstatechange</a></code>. It is called any
            time
            the <a href="#dom-peerconnection-ice-gathering-state"><code>RTCPeerConnection</code>
            ice gathering state</a> changes.
          </dd>

          <dt>attribute EventHandler onconnectionstatechange</dt>

          <dd>
            The event type of this event handler is <code><a href=
            "#event-connectionstatechange">connectionstatechange</a></code>.
          </dd>
        </dl>
      </section>

      <section>
        <h3>Legacy Interface Extensions</h3>

        <div class="note">These methods are kept on <code>
            <a>RTCPeerConnection</a>
          </code> for legacy purposes.</div>

        <dl class="idl" title="partial interface RTCPeerConnection">

          <dt>void createOffer (RTCSessionDescriptionCallback successCallback,
          RTCPeerConnectionErrorCallback failureCallback, optional
          RTCOfferOptions options)</dt>

          <dd>
            <p>When the <code>createOffer</code> method is called, the user
            agent MUST run the following steps:</p>

            <ol>
              <li>
                <p>Let <var>successCallback</var> be the method's first
                argument.</p>
              </li>
              <li>
                <p>Let <var>failureCallback</var> be the callback indicated by
                the method's second argument.</p>
              </li>
              <li>
                <p>Let <var>options</var> be the callback indicated by
                the method's third argument.</p>
              </li>
              <li>
                <p>Run the steps specified by <code>
                <a>RTCPeerConnection</a></code>'s <a href=
                "#widl-RTCPeerConnection-createOffer-Promise-RTCSessionDescription--RTCOfferOptions-options">createOffer()</a>
                method with <var>options</var> as the sole argument, and let
                <var>p</var> be the resulting promise.</p>
              </li>
            </ol>

            <p>Upon fulfillment of <var>p</var> with value <var>offer</var>,
            invoke <var>successCallback</var> with <var>offer</var> as the
            argument.</p>

            <p>Upon rejection of <var>p</var> with reason <var>r</var>,
            invoke <var>failureCallback</var> with <var>r</var> as the
            argument.</p>
          </dd>

          <dt>void setLocalDescription (RTCSessionDescriptionInit description,
          VoidFunction successCallback, RTCPeerConnectionErrorCallback
          failureCallback)</dt>

          <dd>
            <p>When the <code>setLocalDescription</code> method is called, the
            user agent MUST run the following steps:</p>

            <ol>
              <li>
                <p>Let <var>description</var> be the method's first
                argument.</p>
              </li>
              <li>
                <p>Let <var>successCallback</var> be the callback indicated by
                the method's second argument.</p>
              </li>
              <li>
                <p>Let <var>failureCallback</var> be the callback indicated by
                the method's third argument.</p>
              </li>
              <li>
                <p>Run the steps specified by <code>
                <a>RTCPeerConnection</a></code>'s <a href=
                "#dom-peerconnection-setlocaldescription">setLocalDescription()</a>
                method with <var>description</var> as the sole argument, and let
                <var>p</var> be the resulting promise.</p>
              </li>
            </ol>

            <p>Upon fulfillment of <var>p</var>,
            invoke <var>successCallback</var> with <code>undefined</code> as the
            argument.</p>

            <p>Upon rejection of <var>p</var> with reason <var>r</var>,
            invoke <var>failureCallback</var> with <var>r</var> as the
            argument.</p>
          </dd>

          <dt>void createAnswer (RTCSessionDescriptionCallback successCallback,
          RTCPeerConnectionErrorCallback failureCallback)</dt>

          <dd>
            <p>When the <code>createAnswer</code> method is called, the user
            agent MUST run the following steps:</p>

            <ol>
              <li>
                <p>Let <var>successCallback</var> be the method's first
                argument.</p>
              </li>
              <li>
                <p>Let <var>failureCallback</var> be the callback indicated by
                the method's second argument.</p>
              </li>
              <li>
                <p>Run the steps specified by <code>
                <a>RTCPeerConnection</a></code>'s <a href=
                "#widl-RTCPeerConnection-createAnswer-Promise-RTCSessionDescription--RTCAnswerOptions-options">createAnswer()</a>
                method with no arguments, and let <var>p</var> be the resulting
                promise.</p>
              </li>
            </ol>

            <p>Upon fulfillment of <var>p</var> with value <var>answer</var>,
            invoke <var>successCallback</var> with <var>answer</var> as the
            argument.</p>

            <p>Upon rejection of <var>p</var> with reason <var>r</var>,
            invoke <var>failureCallback</var> with <var>r</var> as the
            argument.</p>
          </dd>

          <dt>void setRemoteDescription (RTCSessionDescriptionInit description,
          VoidFunction successCallback, RTCPeerConnectionErrorCallback
          failureCallback)</dt>

          <dd>
            <p>When the <code>setRemoteDescription</code> method is called, the
            user agent MUST run the following steps:</p>

            <ol>
              <li>
                <p>Let <var>description</var> be the method's first
                argument.</p>
              </li>
              <li>
                <p>Let <var>successCallback</var> be the callback indicated by
                the method's second argument.</p>
              </li>
              <li>
                <p>Let <var>failureCallback</var> be the callback indicated by
                the method's third argument.</p>
              </li>
              <li>
                <p>Run the steps specified by <code>
                <a>RTCPeerConnection</a></code>'s <a href=
                "#dom-peerconnection-setremotedescription">setRemoteDescription()</a>
                method with <var>description</var> as the sole argument, and let
                <var>p</var> be the resulting promise.</p>
              </li>
            </ol>

            <p>Upon fulfillment of <var>p</var>,
            invoke <var>successCallback</var> with <code>undefined</code> as the
            argument.</p>

            <p>Upon rejection of <var>p</var> with reason <var>r</var>,
            invoke <var>failureCallback</var> with <var>r</var> as the
            argument.</p>
          </dd>

          <dt>void addIceCandidate (RTCIceCandidate candidate, VoidFunction
          successCallback, RTCPeerConnectionErrorCallback failureCallback)</dt>

          <dd>
            <p>When the <code>addIceCandidate</code> method is called, the
            user agent MUST run the following steps:</p>

            <ol>
              <li>
                <p>Let <var>candidate</var> be the method's first argument.</p>
              </li>
              <li>
                <p>Let <var>successCallback</var> be the callback indicated by
                the method's second argument.</p>
              </li>
              <li>
                <p>Let <var>failureCallback</var> be the callback indicated by
                the method's third argument.</p>
              </li>
              <li>
                <p>Run the steps specified by <code>
                <a>RTCPeerConnection</a></code>'s <a href=
                "#dom-peerconnection-addicecandidate">addIceCandiddate()</a>
                method with <var>candidate</var> as the sole argument, and let
                <var>p</var> be the resulting promise.</p>
              </li>
            </ol>

            <p>Upon fulfillment of <var>p</var>,
            invoke <var>successCallback</var> with <code>undefined</code> as the
            argument.</p>

            <p>Upon rejection of <var>p</var> with reason <var>r</var>,
            invoke <var>failureCallback</var> with <var>r</var> as the
            argument.</p>
          </dd>

          <dt>void getStats(MediaStreamTrack? selector, RTCStatsCallback
          successCallback, RTCPeerConnectionErrorCallback failureCallback)</dt>

          <dd>
            <p>When the <code>getStats</code> method is called, the
            user agent MUST run the following steps:</p>

            <ol>
              <li>
                <p>Let <var>selector</var> be the method's first argument.</p>
              </li>
              <li>
                <p>Let <var>successCallback</var> be the callback indicated by
                the method's second argument.</p>
              </li>
              <li>
                <p>Let <var>failureCallback</var> be the callback indicated by
                the method's third argument.</p>
              </li>
              <li>
                <p>Run the steps specified by <code>
                <a>RTCPeerConnection</a></code>'s <a href=
                "#widl-RTCPeerConnection-getStats-Promise-RTCStatsReport--MediaStreamTrack-selector">getStats()</a>
                method with <var>selector</var> as the sole argument, and let
                <var>p</var> be the resulting promise.</p>
              </li>
            </ol>

            <p>Upon fulfillment of <var>p</var> with value <var>report</var>,
            invoke <var>successCallback</var> with <var>report</var> as the
            argument.</p>

            <p>Upon rejection of <var>p</var> with reason <var>r</var>,
            invoke <var>failureCallback</var> with <var>r</var> as the
            argument.</p>
          </dd>

        </dl>
      </section>

      <section>
        <h2>Garbage collection</h2>

        <p>An <code><a>RTCPeerConnection</a></code> object MUST not be garbage
        collected as long as any event can cause an event handler to be
        triggered on the object. When the object's <a href=
        "#dom-peerconnection-signaling-state"><code>RTCPeerConnection</code>
        signalingState</a> is <code>closed</code>, no such event handler can be
        triggered and it is therefore safe to garbage collect the object.</p>

        <p>All <code><a>RTCDataChannel</a></code> and
        <code><a>MediaStreamTrack</a></code> objects that are connected to a
        <code><a>RTCPeerConnection</a></code> have a strong
        reference to the <code><a>RTCPeerConnection</a></code> object.</p>
      </section>
    </section>

    <section>
      <h3>State Definitions</h3>

      <section>
        <h4>RTCSignalingState Enum</h4>

        <dl class="idl" title="enum RTCSignalingState">
          <dt>stable</dt>

          <dd>There is no offer&shy;answer exchange in progress. This is also
          the initial state in which case the local and remote descriptions are
          empty.</dd>

          <dt>have-local-offer</dt>

          <dd>A local description, of type "offer", has been successfully
          applied.</dd>

          <dt>have-remote-offer</dt>

          <dd>A remote description, of type "offer", has been successfully
          applied.</dd>

          <dt>have-local-pranswer</dt>

          <dd>A remote description of type "offer" has been successfully
          applied and a local description of type "pranswer" has been
          successfully applied.</dd>

          <dt>have-remote-pranswer</dt>

          <dd>A local description of type "offer" has been successfully applied
          and a remote description of type "pranswer" has been successfully
          applied.</dd>

          <dt>closed</dt>

          <dd>The connection is closed.</dd>
        </dl>

        <figure><img alt=
        "signalling state transition diagram" src=
        "images/peerstates.svg" width="600"><figcaption>Non-normative signalling state transitions diagram</figcaption></figure>

        <p>An example set of transitions might be:</p>
        <dl>
        <dt>Caller transition:</dt>

        <dd><ul>
          <li>new RTCPeerConnection(): <code>stable</code></li>

          <li>setLocal(offer): <code>have-local-offer</code></li>

          <li>setRemote(pranswer): <code>have-remote-pranswer</code></li>

          <li>setRemote(answer): <code>stable</code></li>

          <li>close(): <code>closed</code></li>
        </ul></dd>

        <dt>Callee transition:</dt>

        <dd><ul>
          <li>new RTCPeerConnection(): <code>stable</code></li>

          <li>setRemote(offer): <code>have-remote-offer</code></li>

          <li>setLocal(pranswer): <code>have-local-pranswer</code></li>

          <li>setLocal(answer): <code>stable</code></li>

          <li>close(): <code>closed</code></li>
        </ul></dd>
        </dl>
      </section>

      <section>
        <h4>RTCIceGatheringState Enum</h4>

        <dl class="idl" title="enum RTCIceGatheringState">
          <dt>new</dt>

          <dd>The object was just created, and no networking has occurred
          yet.</dd>

          <dt>gathering</dt>

          <dd>The <a>ICE agent</a> is in the process of gathering candidates for this
          RTCPeerConnection.</dd>

          <dt>complete</dt>

          <dd>The <a>ICE agent</a> has completed gathering. Events such as adding a
          new interface or a new TURN server will cause the state to go back to
          gathering.</dd>

        </dl>
      </section>

      <section>
        <h4>RTCPeerConnectionState Enum</h4>

        <dl class="idl" title="enum RTCPeerConnectionState">
          <dt>new</dt>

          <dd>Any of the <code><a>RTCIceTransport</a></code>s or
            <code><a>RTCDtlsTransport</a></code>s are in
            the <code>new</code> state and none of the transports are
            in the <code>connecting</code>, <code>checking</code>,
            <code>failed</code> or <code>disconnected</code> state,
            or all transports are in the <code>closed</code> state.

          <dt>connecting</dt>

          <dd>Any of the <code><a>RTCIceTransport</a></code>s
            or <code><a>RTCDtlsTransport</a></code>s are in
            the <code>connecting</code> or <code>checking</code> state
            and none of them is in the <code>failed</code> state.

          <dt>connected</dt>

          <dd>All <code><a>RTCIceTransport</a></code>s
          and <code><a>RTCDtlsTransport</a></code>s are in
          the <code>connected</code>, <code>completed</code> or
          <code>closed</code> state and at least of them is in
          the <code>connected</code> or <code>completed</code>
          state. </dd>

          <dt>disconnected</dt>

          <dd>Any of the <code><a>RTCIceTransport</a></code>s
            or <code><a>RTCDtlsTransport</a></code>s are in
            the <code>disconnected</code> state and none of them are in
            the <code>failed</code> or <code>connecting</code>
            or <code>checking</code> state.

          <dt>failed</dt>

          <dd>Any of the <code><a>RTCIceTransport</a></code>s
            or <code><a>RTCDtlsTransport</a></code>s are in
            a <code>failed</code> state.</dd>

        </dl>
      </section>

      <section>
        <h4>RTCIceConnectionState Enum</h4>

        <dl class="idl" title="enum RTCIceConnectionState">
          <dt>new</dt>

          <dd>The ICE Agent is gathering addresses and/or waiting for remote
          candidates to be supplied.</dd>

          <dt>checking</dt>

          <dd>The ICE Agent has received remote candidates on at least one
          component, and is checking candidate pairs but has not yet found a
          connection. In addition to checking, it may also still be
          gathering.</dd>

          <dt>connected</dt>

          <dd>The ICE Agent has found a usable connection for all components
          but is still checking other candidate pairs to see if there is a
          better connection. It may also still be gathering.</dd>

          <dt>completed</dt>

          <dd>The ICE Agent has finished gathering and checking and found a
            connection for all components.
            Details on how the completed state in ICE is reached are covered in
            [[!ICE]].  </dd>

          <dt>failed</dt>

          <dd>The ICE Agent is finished checking all candidate pairs and failed
          to find a connection for at least one component. Connections may have
          been found for some components.</dd>

          <dt>disconnected</dt>

          <dd>Liveness checks have failed for one or more components. This is
          more aggressive than <code>failed</code>, and may trigger
          intermittently (and resolve itself without action) on a flaky
          network.</dd>

          <dt>closed</dt>

          <dd>The ICE Agent has shut down and is no longer responding to STUN
          requests.</dd>
        </dl>

        <p>States take either the value of any component or all components, as
        outlined below:</p>

        <ul>
          <li><code>checking</code> occurs if ANY component has received a
          candidate and can start checking</li>

          <li><code>connected</code> occurs if ALL components have established
          a working connection</li>

          <li><code>completed</code> occurs if ALL components have finalized
          the running of their ICE processes</li>

          <li><code>failed</code> occurs if ANY component has given up trying
          to connect</li>

          <li><code>disconnected</code> occurs if ANY component has failed
          liveness checks</li>

          <li><code>closed</code> occurs only if
          <code>RTCPeerConnection.close()</code> has been called.</li>
        </ul>

        <p>If a component is discarded as a result of signaling (e.g. RTCP mux
        or BUNDLE), the state may advance directly from <code>checking</code>
        to <code>completed</code>.</p>

        <p>Some example transitions might be:</p>

        <ul>
          <li>new RTCPeerConnection(): <code>new</code></li>

          <li>(<code>new</code>, remote candidates received):
          <code>checking</code></li>

          <li>(<code>checking</code>, found usable connection):
          <code>connected</code></li>

          <li>(<code>checking</code>, gave up): <code>failed</code></li>

          <li>(<code>connected</code>, finished all checks):
          <code>completed</code></li>

          <li>(<code>completed</code>, lost connectivity):
          <code>disconnected</code></li>

          <li>(any state, ICE restart occurs): <code>new</code></li>

          <li>close(): <code>closed</code></li>
        </ul>

        <figure><img alt=
        "ICE state transition diagram" src=
        "images/icestates.svg" width="600">
          <figcaption>Non-normative ICE state transition diagram</figcaption></figure>
      </section>
    </section>

    <section>
      <h3>Callback Definitions</h3>

      <section>
        <h4>RTCPeerConnectionErrorCallback</h4>

        <dl class="idl" title="callback RTCPeerConnectionErrorCallback = void">
          <dt>DOMError error</dt>

          <dd>An error object encapsulating information about what went
          wrong.</dd>
        </dl>
      </section>

      <section>
        <h4>RTCSessionDescriptionCallback</h4>

        <dl class="idl" title="callback RTCSessionDescriptionCallback = void">
          <dt>RTCSessionDescription sdp</dt>

          <dd>The object containing the SDP [[!SDP]].</dd>
        </dl>
      </section>
    </section>

    <section>
      <h3>Error Handling</h3>

      <section>
        <h4>General Principles</h4>

        <p>All methods that return promises are governed by the standard error
        handling rules of promises. Methods that do not return promises may throw
        exceptions to indicate errors.</p>

        <p>Legacy-methods may only throw exceptions to indicate invalid state
        and other programming errors. For example, when a legacy-method is
        called when the <code><a>RTCPeerConnection</a></code> is in an invalid
        state or a state in which that particular method is not allowed to be
        executed, it will throw an exception. In all other cases, legacy methods
        MUST provide an error object to the error callback.</p>
      </section>

      <section>
        <h4>RTCSdpError</h4>

        <dl class="idl" title="interface RTCSdpError : DOMError">
          <dt>readonly attribute unsigned long sdpLineNumber</dt>

          <dd>The line number of an <code><a>RTCSessionDescriptionInit</a></code>
          at which the error was encountered.</dd>
        </dl>

        <div class="issue">
          <p>(see also <a href="https://github.com/w3c/webrtc-pc/issues/319">Issue 319</a>)</p>
          <p>Ask the DOM team to extend their list with the following errors.
          The error names and their descriptions are directly copied from the
          old RTCErrorName enum and might need some adjustment before being
          added to the public list of errors.</p>

          <ul>
            <li>InvalidSessionDescriptionError: The provided
            RTCSessionDescriptionInit contained invalid SDP, or the type was wrong
            for the current state of the RTCPeerConnection. User agents SHOULD
            provide as much additional information in the error message as
            possible, including the sdpLineNumber, if appropriate.</li>

            <li>IncompatibleSessionDescriptionError: The provided
            RTCSessionDescriptionInit contained SDP that could not be correctly
            applied to the RTCPeerConnection due to its current state. User
            agents SHOULD provide as much additional information in the error
            message as possible, including the sdpLineNumber, if
            appropriate.</li>

            <li>IncompatibleConstraintsError: The provided MediaConstraints
            could not be correctly applied to the RTCPeerConnection due to its
            current state. User agents SHOULD provide as much additional
            information in the error message as possible.</li>

            <li>InternalError: The RTCPeerConnection encountered an error that
            it could not recover from.</li>
          </ul>
        </div>
      </section>
    </section>

    <section>
      <h3>Session Description Model</h3>

      <section>
        <h4>RTCSdpType</h4>

        <p>The RTCSdpType enum describes the type of an
        <code><a>RTCSessionDescriptionInit</a></code> or
        <code><a>RTCSessionDescription</a></code> instance.</p>

        <dl class="idl" title="enum RTCSdpType">
          <dt>offer</dt>

          <dd>
            <p>An <code>RTCSdpType</code> of <code>offer</code> indicates that a description MUST be
            treated as an [[!SDP]] offer.</p>
          </dd>

          <dt>pranswer</dt>

          <dd>
            <p>An <code>RTCSdpType</code> of <code>pranswer</code> indicates that a description MUST
            be treated as an [[!SDP]] answer, but not a final answer. A
            description used as an SDP <code>pranswer</code> may be applied as a response
            to an SDP offer, or an update to a previously sent SDP
            pranswer.</p>
          </dd>

          <dt>answer</dt>

          <dd>
            <p>An <code>RTCSdpType</code> of <code>answer</code> indicates that a description MUST be
            treated as an [[!SDP]] final answer, and the offer-answer exchange
            MUST be considered complete. A description used as an SDP answer
            may be applied as a response to an SDP offer or as an update to a
            previously sent SDP pranswer.</p>
          </dd>

          <dt>rollback</dt>

          <dd>
            <p>An <code>RTCSdpType</code> of <code>rollback</code> indicates that a description MUST be
            treated as an canceling the current SDP negotiation and moving back
            to the SDP [[!SDP]] offer and answer back to what it was in the previous stable
            state. Note the local or remote SDP descriptions in the
	    previous stable state could be null if there has
            not yet been a successful offer-answer negotiation.</p>
          </dd>

        </dl>
      </section>

      <section>
        <h4>RTCSessionDescription Class</h4>

        <p>The <code>RTCSessionDescription</code> class is used by
        <code><a>RTCPeerConnection</a></code> to expose local and remote session
        descriptions.  Attributes on this interface are mutable for legacy
        reasons.</p>

        <dl class="idl" data-merge="RTCSessionDescriptionInit" title=
        "interface RTCSessionDescription">
          <dt>Constructor (RTCSessionDescriptionInit descriptionInitDict)</dt>

          <dd>The <dfn id=
          "dom-sessiondescription"><code>RTCSessionDescription()</code></dfn>
          constructor takes a dictionary argument,
          <var>descriptionInitDict</var>, whose content is used to initialize
          the new <code><a>RTCSessionDescription</a></code> object.  This
          constructor is deprecated; it exists for legacy compatibility reasons
          only.</dd>

          <dt>attribute RTCSdpType type</dt>

          <dd>The type of this RTCSessionDescription.</dd>

          <dt>attribute DOMString? sdp</dt>

          <dd>The string representation of the SDP [[!SDP]] or
          a <code>null</code> value.</dd>

          <dt>serializer = { attribute }</dt>
        </dl>

        <dl class="idl" title="dictionary RTCSessionDescriptionInit">
          <dt>required RTCSdpType type</dt>

          <dt>DOMString? sdp = null</dt>
        </dl>
      </section>
    </section>
    <section>
      <h3>Session Negotiation Model</h3>
      <p>Many changes to state of an <code><a>RTCPeerConnection</a></code> will
        require communication with
        the remote side via the signaling channel, in order to have the desired
        effect. The app can be kept informed as to when it needs to do signaling,
        by listening to the <code>negotiationneeded</code> event.</p>
      <section>
        <h4>Setting Negotiation-Needed</h4>
        <p>If an operation is performed on an <code><a>RTCPeerConnection</a></code>
          that requires signaling,
          the connection will be marked as needing negotiation. Examples of such
          operations include adding or stopping a track, or adding the first
          data channel.</p>
        <p>Internal changes within the implementation can also result in the
          connection being marked as needing negotiation. For example, if a
          <code><a>MediaStreamTrack</a></code> enters the ended state because
          its source device became unavailable.
        </p>
      </section>
      <section>
        <h4>Clearing Negotiation-Needed</h4>
        <p>The negotiation-needed flag is cleared when
          <code>setLocalDescription</code> is
          called (either for an offer or answer), and the supplied description
          matches the state of the tracks/datachannels that currenly exist on the
          <code><a>RTCPeerConnection</a></code>. Specifically, this means that
          all live tracks have an associated section in the local description
          with their MSID, all ended tracks have been removed from the local
          description, and, if any data channels have been created, a data
          section exists in the local description.</p>
        <p>Note that <code>setLocalDescription(answer)</code> will clear the
          negotiation-needed flag only if the offer had a corresponding section for
          all the tracks/datachannels on the answerer side. Otherwise, a new offer by
          the answerer is still needed, and so the state is not cleared.</p>
      </section>
      <section>
        <h4>Firing An Event</h4>
        <p>When the <code><a>RTCPeerConnection</a></code> <var>connection</var>
           is marked as negotiation-needed, and it was not already marked as such:</p>
        <ul>
          <li>If the signaling state is <code>stable</code>, schedule a task to check the
            negotiation-needed flag and, if still set, fire a
            <a href="#event-negotiation">negotiationneeded</a> event on
            <var>connection</var>.</li>
          <li>Otherwise, do nothing. If necessary, an event will be fired during
            <code>setLocalDescription</code> or
            <code>setRemoteDescription</code> processing, as described above.</li>
        </ul>
      </section>
    </section>

    <section>
      <h3>Interfaces for Connectivity Establishment</h3>

      <section>
        <h4>RTCIceCandidate Dictionary</h4>

        <p>This describes an ICE candidate. Though not explicitly required,
        values for <var>candidate</var> and either <var>sdpMid</var>
        or <var>sdpMLineIndex</var> MUST be provided.</p>

        <dl class="idl" title="[Constructor(RTCIceCandidate copy)] dictionary RTCIceCandidate">
          <dt>required DOMString candidate</dt>

          <dd>This carries the <code>candidate-attribute</code> as defined in
          section 15.1 of [[!ICE]].</dd>

          <dt>DOMString sdpMid</dt>

          <dd>If present, this contains the identifier of the "media stream
          identification" as defined in [[!RFC5888]] for the media component this
          candidate is associated with.</dd>

          <dt>unsigned short sdpMLineIndex</dt>

          <dd>This indicates the index (starting at zero) of the <a>media description</a> in the
          SDP this candidate is associated with.</dd>

          <dt>DOMString foundation</dt>

          <dd>A unique identifier that allows ICE to correlate candidates that
          appear on multiple <code><a>RTCIceTransport</a></code>s.</dd>

          <dt>unsigned long priority</dt>

          <dd>The assigned priority of the candidate. This is automatically
          populated by the browser.</dd>

          <dt>DOMString ip</dt>

          <dd>The IP address of the candidate.</dd>

          <dt>RTCIceProtocol protocol</dt>

          <dd>The protocol of the candidate (<code>udp</code>/<code>tcp</code>).</dd>

          <dt>unsigned short port</dt>

          <dd>The port of the candidate.</dd>

          <dt>RTCIceCandidateType type</dt>

          <dd>The type of candidate.</dd>

          <dt>RTCIceTcpCandidateType tcpType</dt>

          <dd>If <code>protocol</code> is <code>tcp</code>, <code>tcpType</code> represents
          the type of TCP candidate. Otherwise, <code>tcpType</code> is not present in the
          dictionary.</dd>

          <dt>DOMString relatedAddress</dt>

          <dd>For a candidate that is derived from another, such as a relay or reflexive
          candidate, the <dfn>relatedAddress</dfn> is the IP address of the candidate that
          it is derived from. For host candidates, the <code>relatedAddress</code>
          is not present in the dictionary.</dd>

          <dt>unsigned short relatedPort</dt>

          <dd>For a candidate that is derived from another, such as a relay or reflexive
          candidate, the <dfn>relatedPort</dfn> is the port of the candidate that
          it is derived from. For host candidates, the <code>relatedPort</code>
          is not present in the dictionary.</dd>
        </dl>
        <div class="note">
          <p>The constructor on <code><a>RTCIceCandidate</a></code> exists
          for legacy compatibility reasons only.</p>
        </div>

        <section>
          <h4>The RTCIceProtocol</h4>

          <p>The <dfn>RTCIceProtocol</dfn> represents the protocol of the ICE candidate.</p>

          <dl class="idl" title="enum RTCIceProtocol">
            <dt>udp</dt>

            <dd>A UDP candidate, as described in [[!ICE]].</dd>

            <dt>tcp</dt>

            <dd>A TCP candidate, as described in [[!RFC6544]].</dd>
          </dl>
        </section>

        <section>
          <h4>The RTCIceTcpCandidateType</h4>

          <p>The <dfn>RTCIceTcpCandidateType</dfn> represents the type of the ICE TCP
          candidate, as defined in [[!RFC6544]].</p>

          <dl class="idl" title="enum RTCIceTcpCandidateType">
            <dt>active</dt>

            <dd>An <code>active</code> TCP candidate is one for which the transport will
            attempt to open an outbound connection but will not receive incoming
            connection requests.</dd>

            <dt>passive</dt>

            <dd>A <code>passive</code> TCP candidate is one for which the transport
            will receive incoming connection attempts but not attempt a connection.</dd>

            <dt>so</dt>

            <dd>An <code>so</code> candidate is one for which the transport will attempt
             to open a connection simultaneously with its peer.</dd>
          </dl>
        </section>

        <section>
          <h4>The RTCIceCandidateType</h4>

          <p>The <dfn>RTCIceCandidateType</dfn> represents the type of the ICE candidate,
          as defined in [[!ICE]].</p>

          <dl class="idl" title="enum RTCIceCandidateType">
            <dt>host</dt>

            <dd>A host candidate.</dd>

            <dt>srflx</dt>

            <dd>A server reflexive candidate.</dd>

            <dt>prflx</dt>

            <dd>A peer reflexive candidate.</dd>

            <dt>relay</dt>

            <dd>A relay candidate.</dd>
          </dl>
        </section>
      </section>

      <section>
        <h4>RTCPeerConnectionIceEvent</h4>

        <p>The <code>icecandidate</code> event of the RTCPeerConnection uses
        the <code><a>RTCPeerConnectionIceEvent</a></code> interface.</p>

        <p><dfn data-lt="Fire an ice candidate event">Firing an
        <code><a>RTCPeerConnectionIceEvent</a></code> event named
        <var>e</var></dfn> with an <code><a>RTCIceCandidate</a></code>
        <var>candidate</var> means that an event with the name <var>e</var>,
        which does not bubble (except where otherwise stated) and is not
        cancelable (except where otherwise stated), and which uses the
        <code>RTCPeerConnectionIceEvent</code> interface with the
        <code>candidate</code> attribute set to the new ICE candidate, MUST be
        created and dispatched at the given target.</p>

        <p>When firing an <code><a>RTCPeerConnectionIceEvent</a></code> event
        that contains a <code><a>RTCIceCandidate</a></code> object, it MUST
        include values for
        both <a href="#widl-RTCIceCandidate-sdpMid"><code>sdpMid</code></a>
        and <a href="#widl-RTCIceCandidate-sdpMLineIndex"><code>sdpMLineIndex</code></a>.
        If the <code><a>RTCIceCandidate</a></code> is of type <code>srflx</code>
        or type <code>relay</code>, the <code>url</code> property of the event MUST be
        set to the URL of the ICE server from which the candidate was obtained.</p>

        <dl class="idl" data-merge="RTCPeerConnectionIceEventInit" title=
        "interface RTCPeerConnectionIceEvent : Event">
          <dt>Constructor(DOMString type, RTCPeerConnectionIceEventInit
          eventInitDict)</dt>

          <dt>readonly attribute RTCIceCandidate? candidate</dt>

          <dd>
            <p>The <code>candidate</code> attribute is the
            <code><a>RTCIceCandidate</a></code> object with the new ICE
            candidate that caused the event.</p>

            <p>This attribute is set to <code>null</code> when an event is
            generated to indicate the end of candidate gathering.</p>

            <p class="note">Even where there are multiple media components, only
            one event containing a <code>null</code> candidate is fired.</p>
          </dd>

          <dt>readonly attribute DOMString? url</dt>

          <dd>
            <p>The <code>url</code> attribute is the STUN or TURN URL that
            identifies the STUN or TURN server used to gather this candidate.
            If the candidate was not gathered from a STUN or TURN server, this
            parameter will be set to <code>null</code>.</p>
          </dd>
        </dl>

        <dl class="idl" title=
        "dictionary RTCPeerConnectionIceEventInit : EventInit">
          <dt>RTCIceCandidate candidate</dt>

          <dd>
            <p>See <a href="#widl-RTCPeerConnectionIceEvent-candidate">the <code>candidate</code> attribute of the <code>RTCPeerConnectionIceEvent</code> interface</a>.</p>
          </dd>

          <dt>DOMString url</dt>
        </dl>
      </section>

      <section>
        <h4>RTCPeerConnectionIceErrorEvent</h4>

        <p>The <code>icecandidateerror</code> event of the RTCPeerConnection uses
        the <code><a>RTCPeerConnectionIceErrorEvent</a></code> interface.</p>

        <dl class="idl" data-merge="RTCPeerConnectionIceErrorEventInit" title=
        "interface RTCPeerConnectionIceErrorEvent : Event">
          <dt>Constructor(DOMString type, RTCPeerConnectionIceErrorEventInit
          eventInitDict)</dt>

          <dt>readonly attribute DOMString hostCandidate</dt>

          <dd>
            <p>The <code>hostCandidate</code> attribute is the local IP address and
            port used to communicate with the STUN or TURN server.</p>
            <p> On a multihomed system, multiple interfaces may be used to contact the
            server, and this attribute allows the application to figure out
            on which one the failure occurred.</p>
            <p>If use of multiple interfaces has been prohibited for privacy
            reasons, this attribute will be set to 0.0.0.0:0 or [::]:0, as
            appropriate.</p>
          </dd>

          <dt>readonly attribute DOMString url</dt>

          <dd>
            <p>The <code>url</code> attribute is the STUN or TURN URL that
            identifies the STUN or TURN server for which the
            failure occurred.</p>
          </dd>

          <dt>readonly attribute unsigned short errorCode</dt>

          <dd>
            <p>The <code>errorCode</code> attribute is the numeric STUN
            error code returned by the STUN or TURN server.</p>
            <p>If the server could not be reached, <code>errorCode</code> will
            be set to a TBD value in the 7XX range, as this does not conflict
            with the STUN error code range.</p>
            <p class="issue">Error code to be defined</p>
          </dd>

          <dt>readonly attribute USVString errorText</dt>

          <dd>
            <p>The <code>errorText</code> attribute is the STUN reason text
            returned by the STUN or TURN server.</p>
            <p>If the server could not be reached, <code>errorText</code> will
            be set to an implementation-specific value providing details about
            the error.</p>
          </dd>
        </dl>

        <dl class="idl" title=
        "dictionary RTCPeerConnectionIceErrorEventInit : EventInit">
          <dt>DOMString hostCandidate</dt>

          <dt>DOMString url</dt>

          <dt>unsigned short errorCode</dt>

          <dt>USVString statusText</dt>
        </dl>
      </section>

    </section>

    <section>
      <h2>Priority and QoS Model</h2>

      <p> Many applications have multiple media flows of the same
        data type and often some of the flows are more important than
        others.  WebRTC uses the priority and Quality of Service (QoS) framework
        described in [[!RTCWEB-TRANSPORT]] and [[!TSVWG-RTCWEB-QOS]]
        to provide priority and DSCP marking for packets that will
        help provide QoS in some networking environments. The
        priority setting can be used to indicate the relative priority
        of various flows. The priority API allows the JavaScript
        applications to tell the browser whether a particular media
        flow is high, medium, low or of very low importance to the
        application by setting the <code>priority</code> property
        of <code><a>RTCRtpEncodingParameters</a></code> objects to one of the following values.</p>

      <section>
        <h4>RTCPriorityType Enum</h4>
        <dl class="idl" title="enum RTCPriorityType">
          <dt>very-low</dt> <dd>See [[!RTCWEB-TRANSPORT]], Section 4.</dd>
          <dt>low</dt> <dd>See [[!RTCWEB-TRANSPORT]], Section 4.</dd>
          <dt>medium</dt> <dd>See [[!RTCWEB-TRANSPORT]], Section 4.</dd>
          <dt>high</dt> <dd>See [[!RTCWEB-TRANSPORT]], Section 4.</dd>
        </dl>
      </section>

      <p>
        Applications that use this API should be aware that often
        better overall user experience is obtained by lowering the
        priority of things that are not as important rather than
        raising the the priority of the things that are.
      </p>
    </section>

    <section>
      <h2 id="sec.cert-mgmt">Certificate Management</h2>
      <p>
        The certificates that <code>RTCPeerConnection</code> instances use to
        authenticate with peers use the <a><code>RTCCertificate</code></a>
        interface.  These objects can be explicitly generated by applications
        using <code>RTCPeerConnection.generateCertificate</code> and provided in
        the <a><code>RTCConfiguration</code></a> when constructing a
        new <code>RTCPeerConnection</code> instance.
      </p>
      <p>
        The explicit certificate management functions provided here are
        optional.  If an application does not provide
        the <code>certificates</code> configuration option when constructing
        an <code>RTCPeerConnection</code> a new set of certificates MUST be
        generated by the <a>user agent</a>.  That set MUST include an ECDSA
        certificate with a private key on the P-256 curve and a signature with a
        SHA-256 hash.
      </p>

      <dl class="idl" title="partial interface RTCPeerConnection">
        <dt>static Promise&lt;RTCCertificate&gt; generateCertificate
          (AlgorithmIdentifier keygenAlgorithm)</dt>
        <dd>
          <p>The <code>generateCertificate</code> function causes the <a>user
          agent</a> to create and store an X.509 certificate [[!X509V3]] and
          corresponding private key.  A handle to information is provided in the
          form of the <code>RTCCertificate</code> interface.  The
          returned <code>RTCCertificate</code> can be used to control the
          certificate that is offered in the DTLS sessions established
          by <code>RTCPeerConnection</code>.</p>

          <p>The <var>keygenAlgorithm</var> argument is used to control how the
          private key associated with the certificate is generated.
          The <var>keygenAlgorithm</var> argument uses the WebCrypto
          [[!WebCryptoAPI]] <a href="https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#dfn-AlgorithmIdentifier"><code>AlgorithmIdentifier</code></a>
          type.  The <var>keygenAlgorithm</var> value MUST be a valid argument
          to <a href="https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#SubtleCrypto-method-generateKey"><code>window.crypto.subtle.generateKey</code></a>;
          that is, the value MUST produce a non-error result when normalized
          according to the
          WebCrypto <a href="https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#algorithm-normalization">algorithm
          normalization process</a> [[!WebCryptoAPI]] with an operation name
          of <code>generateKey</code> and a
          [[<a href="https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#dfn-supportedAlgorithms">supportedAlgorithms</a>]]
          value specific to production of certificates
          for <code>RTCPeerConnection</code>.  If the algorithm normalization
          process produces an error, the call
          to <code>generateCertificate</code> MUST be rejected with that
          error.</p>

          <p>Signatures produced by the generated key are used to authenticate
          the DTLS connection. The identified algorithm (as identified by
          the <code>name</code> of the
          normalized <code>AlgorithmIdentifier</code>) MUST be an asymmetric
          algorithm that can be used to produce a signature.</p>

          <p>The certificate produced by this process also contains a signature.
          The validity of this signature is only relevant for compatibility
          reasons.  Only the public key and the resulting certificate
          fingerprint are used by <code>RTCPeerConnection</code>, but it is more
          likely that a certificate will be accepted if the certificate is well
          formed.  The browser selects the algorithm used to sign the
          certificate; a browser SHOULD select SHA-256 [[!FIPS-180-4]] if a hash
          algorithm is needed.</p>

          <p>The resulting certificate MUST NOT include information that can be
          linked to a user or <a>user agent</a>.  Randomized values for
          distinguished name and serial number SHOULD be used.</p>

          <p>A <a>user agent</a> MUST reject a call
          to <code>generateCertificate()</code> with a <code>DOMError</code> of
          type <code>NotSupportedError</code> if the <var>keygenAlgorithm</var>
          parameter identifies an algorithm that the <a>user agent</a> cannot or
          will not use to generate a certificate
          for <code>RTCPeerConnection</code>.</p>

          <p>The following values MUST be supported by a <a>user agent</a>:
            <code>{ name:
            "<a href="https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#rsassa-pkcs1">RSASSA-PKCS1-v1_5</a>",
            modulusLength: 2048, publicExponent: new Uint8Array([1, 0, 1]), hash: "SHA-256" }</code>, and <code>{
            name:
            "<a href="https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#ecdsa">ECDSA</a>",
            namedCurve:
            "<a href="https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#dfn-NamedCurve">P-256</a>"
            }</code>.</p>

          <p class="note">It is expected that a <a>user agent</a> will have a
          small or even fixed set of values that it will accept.</p>
        </dd>
      </dl>

      <section>
        <h2>RTCCertificate Interface</h2>

        <p>The <dfn><code>RTCCertificate</code></dfn> interface represents a
        certificate used to authenticate WebRTC communications.  In addition to
        the visible properties, internal slots contain a handle to the generated
        private keying materal
        ([[<dfn id="RTCCertificate-handle">handle</dfn>]]) and a certificate
        ([[<dfn id="RTCCertificate-certificate">certificate</dfn>]])
        that <code>RTCPeerConnection</code> uses to authenticate with a
        peer.</p>

        <dl class="idl" title="interface RTCCertificate">
          <dt>readonly attribute DOMTimeStamp expires</dt>
          <dd>
            <p>The <var>expires</var> attribute indicates the date and time
            in milliseconds relative to 1970-01-01T00:00:00Z
            after which the certificate will be considered invalid by the
            browser.  After this time, attempts to construct
            an <code>RTCPeerConnection</code> using this certificate fail.</p>
            <p>Note that this value might not be reflected in
            a <code>notAfter</code> parameter in the certificate itself.</p>
          </dd>
        </dl>

        <p>For the purposes of this API, the
        [[<a href="#RTCCertificate-certificate">certificate</a>]] slot contains
        unstructured binary data.</p>

        <p>Note that a <code>RTCCertificate</code> might not directly hold
        private keying material, this might be stored in a secure module.</p>

        <p>The <code>RTCCertificate</code> object can be stored and retrieved
        from persistent storage by an application.  When a <a>user agent</a> is
        required to obtain a structured clone [[!HTML]] of
        a <code>RTCCertificate</code> object, it performs the following
        steps:</p>
        <ol>
          <li>Let <var>input</var> and <var>memory</var> be the corresponding
          inputs defined by the internal structured cloning algorithm,
          where <var>input</var> represents a <code>RTCCertificate</code> object
          to be cloned.</li>

          <li>Let <var>output</var> be a newly
          constructed <code>RTCCertificate</code> object.</li>

          <li>Copy the value of the <code>expires</code> attribute
          from <var>input</var> to <var>output</var>.</li>

          <li>Let the [[<a href="#RTCCertificate-certificate">certificate</a>]]
          internal slot of <var>output</var> be set to the result of invoking
          the internal structured clone algorithm recursively on the
          corresponding internal slots of <var>input</var>, with the slot
          contents as the new "<var>input</var>" argument and <var>memory</var>
          as the new "<var>memory</var>" argument.</li>

          <li>Let the [[<a href="#RTCCertificate-handle">handle</a>]] internal
          slot of <var>output</var> refer to the same private keying material
          represented by the [[<a href="#RTCCertificate-handle">handle</a>]]
          internal slot of <var>input</var>.</li>
        </ol>
      </section>

    </section>
  </section>

  <section>
      <h2>RTP Media API</h2>

      <p>The RTP media API lets a web application send and receive <code>MediaStreamTrack</code>s
      over a peer-to-peer connection. Tracks, when added to a <code>RTCPeerConnection</code>, result in
      signaling; when this signaling is forwarded to a remote peer, it causes
      corresponding tracks to be created on the remote side.</p>

      <p>The actual encoding and transmission of <code>MediaStreamTrack</code>s is managed through
      objects called <code>RTCRtpSender</code>s. Similarly, the reception and decoding of
      <code>MediaStreamTrack</code>s is managed through objects called <code>RTCRtpReceiver</code>s.
      Each track to be sent is associated with exactly one <code>RTCRtpSender</code>, and
      each track to be received is associated with exactly one <code>RTCRtpReceiver</code>.</p>

      <p><code>RTCRtpSender</code>s are created when the application attaches a
      <code>MediaStreamTrack</code> to a <code>RTCPeerConnection</code>, via the
      <code>addTrack</code> method. <code>RTCRtpReceiver</code>s, on the other
      hand, are created when remote signaling indicates new tracks are available,
      and each new <code>MediaStreamTrack</code> and its associated <code>RTCRtpReceiver</code>
      are surfaced to the application via the <code>ontrack</code> event.</p>

      <p>A <code><a>RTCPeerConnection</a></code> object contains a
      <dfn id="senders-set">set of <code>RTCRtpSender</code>s</dfn>, representing tracks to
      be sent, and a <dfn id="receivers-set">set of <code>RTCRtpReceiver</code>s</dfn>,
      representing tracks that are to be received on this
      <code><a>RTCPeerConnection</a></code> object, and
      a <dfn id="transceivers-set">set
      of <code>RTCRtpTransceiver</code>s</dfn>, representing the
      paired senders and receiver with some shared state. All of
      these sets are initialized to empty sets when the
      <code><a>RTCPeerConnection</a></code> object is created.</p>

      <section>
        <h3>RTCPeerConnection Interface Extensions</h3>

        <p>The RTP media API extends the
        <code><a>RTCPeerConnection</a></code> interface as described below.</p>

        <dl class="idl" title="partial interface RTCPeerConnection">
          <dt>sequence&lt;RTCRtpSender&gt; getSenders()</dt>

          <dd>
            <p>Returns a sequence of <code><a>RTCRtpSender</a></code> objects
            representing the RTP senders that are currently attached to this
            <code><a>RTCPeerConnection</a></code> object.</p>

            <p>The <dfn id=
            "dom-peerconnection-getsenders"><code>getSenders()</code></dfn>
            method MUST return a new sequence that represents a snapshot of all
            the <code><a>RTCRtpSenders</a></code> objects in this
            <code><a>RTCPeerConnection</a></code> object's <a href=
            "#senders-set">set of senders</a>. The conversion from the
            senders set to the sequence, to be returned, is user agent defined
            and the order does not have to be stable between calls.</p>
          </dd>

          <dt>sequence&lt;RTCRtpReceiver&gt; getReceivers()</dt>

          <dd>
            <p>Returns a sequence of <code><a>RTCRtpReceiver</a></code> objects
            representing the RTP receivers that are currently attached to this
            <code><a>RTCPeerConnection</a></code> object.</p>

            <p>The <dfn id=
            "dom-peerconnection-getreceivers"><code>getReceivers()</code></dfn>
            method MUST return a new sequence that represents a snapshot of all
            the <code><a>RTCRtpReceiver</a></code> objects in this
            <code><a>RTCPeerConnection</a></code> object's <a href=
            "#receivers-set">set of receivers</a>. The conversion from
            the receivers set to the sequence, to be returned, is user agent
            defined and the order does not have to be stable between calls.</p>
          </dd>

          <dt>sequence&lt;RTCRtpTransceivers&gt; getTransceivers()</dt>

          <dd>
            <p>Returns a sequence
            of <code><a>RTCRtpTransceiver</a></code> objects
            representing the RTP transeceivers that are currently
            attached to this
            <code><a>RTCPeerConnection</a></code> object.</p>

            <p>The <dfn id=
            "dom-peerconnection-gettranseceivers"><code>getTransceivers()</code></dfn>
            method MUST return a new sequence that represents a snapshot of all
            the <code><a>RTCRtpTransceiver</a></code> objects in this
            <code><a>RTCPeerConnection</a></code> object's <a href=
            "#transceivers-set">set of transeceivers</a>. The
            conversion from the transeceiver set to the sequence, to
            be returned, is user agent defined and the order does not
            have to be stable between calls.</p>
          </dd>

          <dt>RTCRtpSender addTrack (MediaStreamTrack track, MediaStream... streams)</dt>

          <dd>
            <p>Adds a new track to the <code>RTCPeerConnection</code>, and indicates that it
              is contained in the specified <code>MediaStream</code>s.</p>

            <p>When the <dfn id="dom-peerconnection-addtrack"><code title=
            "">addTrack()</code></dfn> method is invoked, the user agent MUST
            run the following steps:</p>

            <ol>
              <li>
                <p>Let <var>connection</var> be the
                <code><a>RTCPeerConnection</a></code> object on which the
                <code><a>MediaStreamTrack</a></code> <var>track</var>, is to be
                added.</p>
              </li>

              <li>
                <p>If <code><var>connection</var>.<a href=
                "#dom-peerconnection-signaling-state">signalingState</a></code>
                is <code>closed</code>, throw an
                <code>InvalidStateError</code> exception and abort these
                steps.</p>
              </li>

              <li>
                <p>If an <code>RTCRtpSender</code> for <var>track</var> already exists in
                <var>connection</var>'s <a href="#senders-set">set of senders</a>,
                throw an <code>InvalidParameter</code> exception and abort these
                steps.</p>
	      </li>

              <li>
                <p>If an <code>RTCRtpSender</code> exists in <var>connection</var>'s set of
                senders that has never been used to send (the corresponding <a>media description</a> has
                always had a direction of <code>recvonly</code> or <code>inactive</code>),
                then set that sender's <code>.track</code> to <var>track</var> and return
                the sender.</p>

                <p>Doing so will cause future calls to <code>createOffer</code>
                  and <code>createAnswer</code> to mark the corresponding <a>media description</a>
                  as <code>sendrecv</code> or <code>sendonly</code>, as defined in
                  [[!JSEP]].
                </p>.
              </li>

              <li>
                <p>If no such sender exists, create a new <code>RTCRtpTransceiver</code>
                with <code>.sender.track</code> set to <var>track</var>, add it to
                 <var>connection</var>'s set of transceivers, and
                 return <code>.sender</code> to the caller.</p>
              </li>

              <li>
                <p>A track could have contents that are inaccessible to the
                application. This can be due to being marked with a
                <code>peerIdentity</code> option or anything that would make a
                track <a href=
                "http://www.w3.org/html/wg/drafts/html/master/infrastructure.html#cors-cross-origin">
                CORS cross-origin</a>. These tracks can be supplied to the
                <code>addTrack</code> method, and have an <code>RTCRtpSender</code> created for them, but content
                MUST NOT be transmitted, unless they are also marked with
                <code>peerIdentity</code> and they meet the
                requirements for sending (see <a href="#isolated-pc">
                isolated streams and <code>RTCPeerConnection</code></a>).</p>

                <p>All other tracks that are not accessible to the application
                MUST NOT be sent to the peer, with silence (audio), black
                frames (video) or equivalently absent content being sent in
                place of track content.</p>

                <p>Note that this property can change over time.</p>
              </li>

              <li>
                <p>Mark <var>connection</var> as needing negotiation.</p>
              </li>
            </ol>
          </dd>

          <dt>void removeTrack (RTCRtpSender sender)</dt>

          <dd>
            <p>Stops sending media from <var>sender</var>.  The <code><a>RTCRtpSender</a></code> will still
            appear in <code>getSenders</code>. Doing so will cause future calls
            to <code>createOffer</code> to mark the <a>media description</a> for the corresponding
            transceiver as <code>recvonly</code> or <code>inactive</code>, as defined in
            [[!JSEP]].

            <!-- onended -->
            <p>When the other peer stops sending a track in this manner, an
            <code title="event-MediaStreamTrack-ended">ended</code> event is
            fired at the <code><a>MediaStreamTrack</a></code> object.</p>

            <p>When the <dfn id="dom-peerconnection-removetrack"><code title=
            "">removeTrack()</code></dfn> method is invoked, the user agent
            MUST run the following steps:</p>

            <ol>
              <li>
                <p>Let <var>connection</var> be the
                <code><a>RTCPeerConnection</a></code> object on which the
                <code><a>RTCRtpSender</a></code>, <var>sender</var>, is to be
                stopped.</p>
              </li>

              <li>
                <p>If <code><var>connection</var>.<a href=
                "#dom-peerconnection-signaling-state">signalingState</a></code>
                is <code>closed</code>, throw an
                <code>InvalidStateError</code> exception.</p>
              </li>

              <li>
                <p>If <var>sender</var> is not in <var>connection</var>'s
                <a href="#senders-set">set of senders</a>, then abort
                these steps.</p>
              </li>

              <li>
                <p>Stop sending media from <var>sender</var>.</p>
              </li>

              <li>
                <p>Mark <var>connection</var> as needing negotiation.</p>
              </li>
            </ol>
          </dd>

          <dt>RTCRtpTransceiver addTransceiver((MediaStreamTrack or
          DOMString) trackOrKind, RTCRtpTransceiverInit init)</dt>

          <dd>
            <p>Create a new <code><a>RTCRtpTransceiver</a></code> and add it to the
            collection of transceivers that will be returned
            by <code><a href="#dom-peerconnection-getreceivers">getReceivers()</a></code>.</p>

            <p>Adding a transceiver will cause future calls to <code>createOffer</code> to
              add a <a>media description</a> for the corresponding transceiver, as defined in
              [[!JSEP]].
            </p>.

            <p>If a track is passed in, the value of the <code>.sender.track</code> will
            be set to that track and the MSID and media type generated
            by <code>createOffer</code> will be that of the track.</p>

            <p>If a kind is passed in, the value of the <code>.sender.track</code> will be
            null and and media type generated by <code>createOffer</code> will be that of
            the kind.  The MSID generated by <code>createOffer</code> (if necessary, such
            as when <code>init.send == true</code>) will be selected by the user agent and
            will not be related to any track.  Future calls
            to <code>.sender.replaceTrack</code> with a track of a different kind will fail. Future calls
            will not change the MSID associated with the transceiver.</p>

            <p>If <code>init.sendEncodings</code> is set, then subsequent calls
               to <code>createOffer</code> will be configured to send with multiple RTP encodings as
               defined in [[!JSEP]].  When <code>setRemoteDescription</code> is called with a
               corresponding remote description that is able to receive multiple RTP encodings as
               defined in [[!JSEP]], the <code>RTCRtpSender</code> may send multiple RTP
               encodings and the parameters in <code>RTCRtpTransceiver.sender.getParameters()</code>
               will reflect the encodings negotiated.
            </p>

            <p>
              RID values passed into <code>init.sendEncodings</code> must be composed only of
              case-sensitive alphanumeric characters (a-z, A-Z, 0-9) up to a maximum of 16
              characters.
            </p>

          </dd>

          <dt>attribute EventHandler ontrack</dt>

          <dd>
            <p>The event type of this event handler is <code><a href=
            "#event-track">track</a></code>.</p>
          </dd>

        </dl>
        <dl class="idl" title="dictionary RTCRtpTransceiverInit">
          <dt>boolean send = true</dt>

          <dd>
            <p>If true, indicates that
            the <a><code>RTCRtpTransceiver</code></a>'s <a><code>RTCRtpSender</code></a>
            will offer to send RTP and send RTP if the remote peer accepts.  If false,
            indicates that the <a><code>RTCRtpSender</code></a> will not offer to send RTP
            and will not send RTP (the direction of the <a>media description</a> generated by createOffer
            will be <code>recvonly</code> or <code>inactive</code>).</p>
          </dd>

          <dt>boolean receive = true</dt>

          <dd>
            <p>If true, indicates that
            the <a><code>RTCRtpTransceiver</code>'</a>s <a><code>RTCRtpReceiver</code></a>
            will offer to receive RTP and receive RTP if the remote peer accepts.  If
            false, indicates that the <a><code>RTCRtpReceiver</code></a> will not offer to
            receive RTP and will not receive RTP (the direction of the <a>media description</a> generated by
            createOffer will be <code>sendonly</code> or <code>inactive</code>).</p>
          </dd>

	  <dt>sequence&lt;MediaStream&gt; streams</dt>
	  <dd>
	    <p>When the remote PeerConnection's ontrack event fires
	    corresponding to the <a><code>RTCRtpReceiver</code></a>
	    being added, these are the streams that will be put in the
	    event.
	    </p>
	  </dd>
        </dl>

        <section>
          <h4>Processing Remote MediaStreamTracks</h4>

          <p>Rejection of incoming <code><a>MediaStreamTrack</a></code> objects
          can be done by the application, after receiving the track, by stopping
          it.</p>

          <p>To <dfn id="dispatch-receiver">dispatch a receiver</dfn> for an
          incoming media description [[!JSEP]], the user agent MUST run
          the following steps:

          <ol>
            <li>
              <p>Let <var>connection</var> be the
              <code><a>RTCPeerConnection</a></code> expecting this media.</p>
            </li>

            <li>
              <p>If <code><var>connection</var>.<a href=
              "#dom-peerconnection-signaling-state">signalingState</a></code>
              is <code>closed</code>, abort these
              steps.</p>
            </li>

            <li>
              <p>Let <var>streams</var> be a list of <code>
              <a>MediaStream</a></code> objects that the sender indicated the
              sent <code><a>MediaStreamTrack</a></code> being a part of. The
              information needed to collect these objects is part of the media
              description.</p>
            </li>

            <li>
              <p>Run the following steps to create a track
              representing the incoming media description:</p>

              <ol>
                <li>
                  <p>Create a <code><a>MediaStreamTrack</a></code> object
                  <var>track</var> to represent the media description.</p>
                </li>

                <li>
                  <p>Initialize <code><var>track</var>.kind</code>
                  attribute to <code>audio</code> or <code>video</code>
                  depending on the media type of the media description.</p>
                </li>

                <li>
                  <p>Initialize <code><var>track</var>.id</code>
                  attribute to the media description track id.</p>
                </li>

                <li>
                  <p>Initialize <code><var>track</var>.label</code>
                  attribute to <code>remote audio</code> or <code>remote
                  video</code> depending on the media type of the media
                  description.</p>
                </li>

                <li>
                  <p>Initialize <code><var>track</var>.readyState</code>
                  attribute to <code>live</code>.</p>
                </li>

                <li>
                  <p>Initialize <code><var>track</var>.muted</code>
                  attribute to <code>true</code>. See the <a href=
                  "#mediastreamtrack"><code>MediaStreamTrack</code></a> section about how
                  the <code>muted</code> attribute reflects if a
                  <code><a>MediaStreamTrack</a></code> is receiving media data
                  or not.</p>
                </li>

              </ol>
            </li>

            <li>
              <p>If <var>streams</var> is an empty list, create a new <code>
              <a>MediaStream</a></code> object and add it to <var>streams</var>.
              </p>
            </li>

            <li>
              <p>Add <var>track</var> to all <code><a>MediaStream</a></code>
              objects in <var>streams</var>.</p>

              <p class="note">This will, unless track was added to a newly
              created MediaStream, result in an addtrack event being fired on
              the MediaStream as described in [[!GETUSERMEDIA]].</p>
            </li>

            <li>
              <p>Create a new <code><a>RTCRtpReceiver</a></code> object
              <var>receiver</var> for <var>track</var>, and add it
                to <var>connection</var>'s <a href=
              "#receivers-set">set of receivers</a>.</p>
            </li>

            <li>
              <p>Fire an event named
              <code title="event-track"><a href=
              "#event-track">track</a></code> with
              <var>transceiver</var>, <var>track</var>, and <var>streams</var>
              at the <var title="">connection</var> object.</p>
            </li>
          </ol>

          <p>When an <code><a>RTCPeerConnection</a></code> finds that a track
          from the remote peer has been removed, the user agent MUST follow these
          steps:</p>

          <ol>
            <li>
              <p>Let <var>connection</var> be the
              <code><a>RTCPeerConnection</a></code> associated with the track
              being removed.</p>
            </li>

            <li>
              <p>Let <var>track</var> be the <code><a>MediaStreamTrack</a></code>
              object that represents the track being removed, if any. If
              there isn't one, then abort these steps.</p>
            </li>

            <li>
              <p>By definition, <var>track</var> is now ended.</p>

              <p class="note">A <span title="concept-task">task</span> is thus
              <span title="queue a task">queued</span> to update
              <var>track</var> and fire an event.</p>
            </li>

            <li>
              <p>Queue a task to run the following substeps:</p>

              <ol>
                <li>
                  <p>If <code><var>connection</var>.<a href=
                  "#dom-peerconnection-signaling-state">signalingState</a></code>
                  is <code>closed</code>, abort these
                  steps.</p>
                </li><!-- close() was probably called just before this
           task ran -->

                <li>
                  <p>Remove the <code>RTCRtpReceiver</code> associated with <var>track</var> from
                  <var>connection</var>'s <a href="#receivers-set">set of receivers</a>.</p>
                </li>
              </ol>
            </li>
          </ol>

          <div class="issue">
            <p>Since the beginning of this specification, remote MediaStreamTracks have been
            created by the setRemoteDescription call, one track for each non-rejected
            <a>media description</a> in the remote description. This meant that at the caller,
            MediaStreamTracks were not created until the answer was received, and any media
            received prior to a remote description (AKA "early media") would be discarded.
            If any form of remote description is provided (either an answer or a pranswer),
            this issue does not occur.</p>

            <p>If we want to allow early media to be played out, minor changes are necessary.
            Fundamentally, we would need to change when tracks are created
            for the offerer; this would have to happen either as a result of setLocalDescription,
            or when media packets are received. This ensures that these objects can be created and
            connected to media elements for playout.</p>

            <p>However, there are three consequences to this potential change:</p>
              <ol>
                <li>Media may arrive before the remote DTLS fingerprint has been received.
                This means that media could be played out before the validity of the
                DTLS fingerprint has been established, which may be hard to explain to users.
                As such, it is recommended that media not be played out unless some
                TBD RTCConfiguration property (e.g. AllowUnverifiedMedia) has been set.
                </li>
                <li>The information needed to correlate MediaStreamTracks with their
                enclosing MediaStreams will not yet be present when the tracks are
                initially generated. Therefore, the implementation will need to
                create dummy MediaStream objects for each MediaStreamTrack, and then
                possibly change the associated MediaStream for each track when the
                remote description is received (e.g. if it indicates that an audio
                and video MediaStreamTrack should be combined into a single MediaStream).
                Since media elements act on MediaStreams, some complex reshuffling may
                need to occur when the remote description is received.
                </li>
                <li>The track events fired and their timing will change.
                For the offerer, ontrack will now fire during setLocalDescription,
                once for each track being offered, and track.onended will fire during
                setRemoteDescription for any offered tracks that were rejected.
                For the answerer, ontrack will continue to fire during setRemoteDescription,
                as it does today (this is necessary to allow the answerer to reject
                offered tracks by stopping them).
                </li>
              </ol>

            <p>For now, we simply make note of this issue, until it can be
            considered fully by the WG.</p>
          </div>

        </section>
      </section>

      <section>
        <h3>RTCRtpSender Interface</h3>

        <p>The <code>RTCRtpSender</code> interface allows an application to control how a given
        <code>MediaStreamTrack</code> is encoded and transmitted to a remote peer.
        When <code>setParameters</code> is called is on an <code>RTCRtpSender</code> object,
        the encoding is changed appropriately.</p>

        <dl class="idl" title=
          "interface RTCRtpSender">
          <dt>readonly attribute MediaStreamTrack track</dt>

          <dd>
            <p>The <code id=
            "dom-rtpsender-track">track</code>
            attribute is the track that is associated with this
            <code>RTCRtpSender</code> object.</p>
          </dd>

          <dt>readonly attribute RTCDtlsTransport transport</dt>

          <dd>
            <p>The <code id="dom-rtpsender-transport">transport</code>
            attribute is the transport over which media from
            <code>track</code> is sent in the form of RTP
            packets.  When BUNDLE is used,
            many <code>RTCRtpSender</code> objects will share
            one <code>transport</code> and will all send
            RTP over the same transport.  When RTCP mux is
            used, <code>rtcpTransport</code> will be
            null, and both RTP and RTCP traffic will flow
            over the transport described by <code>transport</code>.
          </dd>

          <dt>readonly attribute RTCDtlsTransport? rtcpTransport</dt>

          <dd>
            <p>The <code id="dom-rtpsender-rtcptransport">rtcpTransport</code>
            attribute is the transport over which RTCP is sent and
            received.  When BUNDLE is used,
            many <code>RTCRtpSender</code> objects will share
            one <code>rtcpTransport</code> and will all
            send and receive RTCP over the same transport.  When RTCP
            mux is used, <code>rtcpTransport</code> will
            be null, and both RTP and RTCP traffic will flow
            over the transport described by <code>transport</code>.
          </dd>

          <dt>static RTCRtpCapabilities getCapabilities(DOMString kind)</dt>
          <dd>
            <p>The <dfn id="dom-rtpsender-getcapabilities"><code>RTCRtpSender.getCapabilities</code></dfn>
            method returns the most optimist view on the capabilities
            of the system for sending media of the given kind. It does
            not reserve any resources, ports, or other state but is
            meant to provide a way to discover the types of
            capabilities of the browser including which codecs may be
            supported.
            </p>
          </dd>

          <dt>void setParameters (RTCRtpParameters parameters)</dt>
          <dd>
            <p>The <code id="dom-rtpsender-setparameters">setParameters</code>
            method updates how <code>track</code> is encoded and transmitted to a remote peer.

            <p>If any parameter in the <var>parameters</var> argument, marked
            as a <dfn>Read-only parameter</dfn>, has a value that is different
            from the corresponding parameter value returned from <code><a href=
            "#dom-rtpsender-getparameters">getParameters()</a></code>, the user
            agent MUST throw a <code>ReadOnlyError</code> exception and abort
            this operation without updating the current parameters.</p>

            <p>If codecs are reordered, the new order indicates the
            preference for sending, with the first codec being the
            codec with highest preference.  If a codec is removed,
            that codec will not be used to send.  The effect of
            reordering or removing codecs lasts until the codecs are
            renegotiated.  After the codecs are renegotiated, they are
            set to the value negotiated, and <code>setParameters</code> needs to be
            called again to re-apply codec preferences.</p>
          </dd>

          <dt>RTCRtpParameters getParameters()</dt>

          <dd>
            <p>The <dfn id="dom-rtpsender-getparameters"><code>getParameters</code></dfn>
            method returns the <code>RTCRtpSender</code> object's current parameters for how <code>track</code>
            is encoded and transmitted to a remote <code>RTCRtpReceiver</code>.
            It may used with <code>setParameters</code> to change the parameters in the follwing way:</p>

            <pre class="example highlight">
var params = sender.getParameters();
// ... make changes to RTCRtpParameters
params.encodings[0].active = false;
sender.setParameters(params)
            </pre>
          </dd>

          <dt>Promise&lt;void&gt; replaceTrack (MediaStreamTrack withTrack)</dt>
          <dd>
            <p>Attempts to replace the track being sent with another track
            provided, without renegotiation.</p>

            <p>When the <dfn id="dom-rtpsender-replacetrack">
            <code>replaceTrack()</code></dfn> method is invoked, the user agent
            MUST run the following steps:</p>

            <ol>
              <li>Let <var>sender</var> be the <code>RTCRtpSender</code> object on which <code>replaceTrack</code> is invoked.</li>

              <li>
                <p>Let <var>p</var> be a new promise.</p>
              </li>

              <li>
                <p>Let <var>withTrack</var> be the argument to this method.</p>
              </li>

              <li>
                <p>If <code><var>withTrack</var>.kind</code> differs
                from the <code><var>sender</var>.<a href="#dom-rtpsender-track">track</a>.kind</code>,
                then reject <var>p</var> with <code>TypeError</code>,
                return <var>p</var> and abort these steps.</p>
              </li>

              <li>
                <p>Run the following steps in parallel:</p>

                <ol>
                  <li>
                    <p>Determine if negotiation is needed to transmit
                    <var>withTrack</var> in place of the sender's existing track.
                    Ignore which <code>MediaStream</code> the track resides in and
                    the <code>id</code> attribute of the track in this
                    determination. If negotiation is needed, then reject
                    <var>p</var> with <code>InvalidModificationError</code>, return
                    <var>p</var> and abort these steps.</p>
                  </li>
                  <li>
                    <p>Have the sender switch seamlessly to transmitting
                    <var>withTrack</var> in place of what it is sending, without
                    negotiating. To avoid track identifiers changing on the remote
                    receiving end, the sender MUST retain the original track
                    identifier and stream associations and use these in subsequent
                    negotiations.</p>
                  </li>
                  <li>
                    Set <code><var>sender</var>.<a href="#dom-rtpsender-track">track</a></code>
                    attribute to <var>withTrack</var>, and resolve <var>p</var>
                    with <code>undefined</code>.
                  </li>
                </ol>
              </li>
              <li>
                <p>Return <var>p</var>.</p>
              </li>
            </ol>

            <div class="note">
              <p>Changing dimensions and/or frame rates might not require
              negotiation. Cases that may require negotiation include:</p>
              <ol>
                <li>Changing a frame rate to a value outside of the negotiated
                imageattr bounds, as described in [[!RFC6236]].
                </li>
                <li>Changing a frame rate to a value that causes the block rate
                for the codec to be exceeded.
                </li>
                <li>A video track differing in raw vs. pre-encoded format.</li>
                <li>An audio track having a different number of channels.</li>
                <li>Sources that also encode (typically hardware encoders) might
                be unable to produce the negotiated codec; similarly, software
                sources might not implement the codec that was negotiated for an
                encoding source.</li>
              </ol>
            </div>
          </dd>
        </dl>

        <dl class="idl" title="dictionary RTCRtpParameters">
          <dt>sequence&lt;RTCRtpEncodingParameters&gt; encodings</dt>

          <dd>
            <p>A sequence containing parameters for RTP encodings of media.</p>
          </dd>

          <dt>sequence&lt;RTCRtpHeaderExtensionParameters&gt; headerExtensions</dt>
          <dd>
            <p>A sequence containing parameters for RTP header extensions.</p>
          </dd>

          <dt>RTCRtcpParameters rtcp</dt>

          <dd>
            <p>Parameters used for RTCP.</p>
          </dd>

          <dt>sequence&lt;RTCRtpCodecParameters&gt; codecs</dt>

          <dd>
            <p>A sequence containing the codecs that
              an <a><code>RTCRtpSender</code></a> will choose from in
              order to send media.</p>
          </dd>
        </dl>

        <dl class="idl" title="dictionary RTCRtpEncodingParameters">
          <dt>unsigned long ssrc</dt>
          <dd>
            <p>
              The SSRC of the RTP source stream of this encoding
              (non-RTX, non-FEC RTP stream). <a>Read-only parameter</a>.
            </p>
          </dd>

          <dt>RTCRtxParameters rtx</dt>
          <dd>
            <p>The parameters used for RTX, or unset if RTX is not being used.</p>
          </dd>

          <dt>RTCFecParameters fec</dt>
          <dd>
            <p>The parameters used for FEC, or unset if FEC is not being used.</p>
          </dd>

          <dt>boolean active</dt>

          <dd>
            <p>
              Indicates that this encoding is actively being sent.
              Setting it to false causes this encoding to no longer be sent.
              Setting it to true causes this encoding to be sent.
            </p>
          </dd>

          <dt>RTCPriorityType priority</dt>
          <dd>
            <p>
             Indicates the priority of this encoding.  It is specified
             in [[!RTCWEB-TRANSPORT]], Section 4.
            </p>
          </dd>

          <dt>unsigned long maxBitrate</dt>
          <dd>
            <p>
              Indicates the maximum bitrate that can be used to send
              this encoding.  The encoding may also be further
              constrained by other bandwidth limits (such as
              per-transport or per-session limits) below the maximum
              specified here.  maxBitrate is the Transport Independent Application Specific Maximum (TIAS)  
              bandwidth defined in [[RFC3890]] Section 6.2.2, which is the maximum bandwidth needed without 
              counting IP or other transport layers like TCP or UDP.
           </p>
          </dd>

          <dt>RTCDegradationPreference degradationPreference = "balanced"</dt>
          <dd>
            <p>When bandwidth is constrained and
              the <code><a>RtpSender</a></code> needs to choose between
              degrading resolution or degrading
              framerate, <code>degradationPreference</code> indicates which is prefered.
            </p>
          </dd>

          <dt>DOMString rid</dt>
          <dd>
            <p> If set, this RTP encoding will be sent with the RID header extension as defined by
              [[!JSEP]].
            </p>
          </dd>

          <dt>float scaleResolutionDownBy = 1.0</dt>
          <dd>
            <p>If the sender's <code>kind</code> is "video", the video's resolution will
            be scaled down in each dimension by the given value before sending.  For
            example, if the value is 2.0, the video will be scaled down by a factor of 2
            in each dimension, resulting in sending a video of one quarter the size.  If
            the value is 1.0, the video will not be affected.  The value must be greater
            than 0.</p>
          </dd>
        </dl>

        <dl class="idl" title="enum RTCDegradationPreference">
          <dt>maintain-framerate</dt>

          <dd>
            <p>Degrade resolution in order to maintain framerate.</p>
          </dd>

          <dt>maintain-resolution</dt>

          <dd>
            <p>Degrade framerate in order to maintain resolution.</p>
          </dd>

          <dt>balanced</dt>

          <dd>
            <p>Degrade a balance of framerate and resolution.</p>
          </dd>
        </dl>

        <dl class="idl" title="dictionary RTCRtxParameters">
          <dt>unsigned long ssrc</dt>
          <dd>
            <p>
              The SSRC of the RTP stream for RTX. <a>Read-only parameter</a>.
            </p>
          </dd>
        </dl>

        <dl class="idl" title="dictionary RTCFecParameters">
          <dt>unsigned long ssrc</dt>
          <dd>
            <p>
              The SSRC of the RTP stream for FEC. <a>Read-only parameter</a>.
            </p>
          </dd>
        </dl>

        <dl class="idl" title="dictionary RTCRtcpParameters">
          <dt>DOMString cname</dt>
          <dd>
            <p>The Canonical Name (CNAME) used by RTCP (e.g. in SDES
              messages). <a>Read-only parameter</a>.
          </dd>

          <dt>boolean reducedSize</dt>
          <dd>
            <p>Whether reduced size RTCP [[RFC5506]] is configured (if
            true) or compound RTCP as specified in [[RFC3550]] (if
            false). <a>Read-only parameter</a>.
          </dd>
        </dl>

        <dl class="idl" title="dictionary RTCRtpHeaderExtensionParameters">
          <dt>DOMString uri</dt>
          <dd>
            <p>
              The URI of the RTP header extension, as defined in
              [[RFC5285]]. <a>Read-only parameter</a>.
            </p>
          </dd>

          <dt>unsigned short id</dt>
          <dd>
            <p>
              The value put in the RTP packet to identify the header
              extension. <a>Read-only parameter</a>.
            </p>
          </dd>

          <dt>boolean encrypted</dt>
          <dd>
            <p>
              Whether the header extension is encryted or not.
              <a>Read-only parameter</a>.
            </p>
          </dd>
        </dl>

        <dl class="idl" title="dictionary RTCRtpCodecParameters">
          <dt>unsigned short payloadType</dt>

          <dd>
            <p>The RTP payload type.  This value can be set in the
            RTCRtpParameters.encodings[0].payloadType to control which
            codec should be used to send a given encoding.
            </p>
          </dd>

          <dt>DOMString mimeType</dt>

          <dd>
            <p>The codec MIME type. Valid types are listed in [[IANA-RTP-2]].</p>
          </dd>

          <dt>unsigned long clockRate</dt>

          <dd>
            <p>The codec clock rate expressed in Hertz.</p>
          </dd>

          <dt>unsigned short channels = 1</dt>
          <dd>
            <p>The number of channels (mono=1, stereo=2).</p>
          </dd>

          <dt>DOMString sdpFmtpLine</dt>

          <dd>
            <p>The a=fmtp line in the SDP corresponding to the codec,
            as defined by <span data-jsep="parsing-a-desc">[[!JSEP]]</span>.</p>
          </dd>
        </dl>

        <dl class="idl" title="dictionary RTCRtpCapabilities">
          <dt>sequence&lt;RTCRtpCodecCapability&gt; codecs</dt>

          <dd>
            <p>
              Supported codecs.
            </p>
          </dd>

          <dt>sequence&lt;RTCRtpHeaderExtensionCapability&gt; headerExtensions</dt>
          <dd>
            <p>
              Supported RTP header extensions.
            </p>
          </dd>
        </dl>

        <dl class="idl" title="dictionary RTCRtpCodecCapability">
          <dt>DOMString mimeType</dt>
          <dd>
            <p>The codec MIME type. Valid types are listed in [[IANA-RTP-2]].
            </p>
          </dd>
        </dl>

        <dl class="idl" title="dictionary RTCRtpHeaderExtensionCapability">
          <dt>DOMString uri</dt>
          <dd>
            <p>The URI of the RTP header extension, as defined in [[RFC5285]].
            </p>
          </dd>
        </dl>

      </section>

      <section>
        <h3>RTCRtpReceiver Interface</h3>

        <p>The <code>RTCRtpReceiver</code> interface allows an
        application to control the receipt of a
        <code>MediaStreamTrack</code>. When attributes on an
        <code>RTCRtpReceiver</code> are modified, a negotiation is
        triggered to signal the changes regarding what the application
        wants to receive to the other side.</p>

        <dl class="idl" title=
          "interface RTCRtpReceiver">
          <dt>readonly attribute MediaStreamTrack track</dt>

          <dd>
            <p>The <dfn id=
            "dom-rtpreceiver-track"><code>RTCRtpReceiver.track</code></dfn>
            attribute is the track that is immutably associated with this
            <code><a>RTCRtpReceiver</a></code> object.</p>
          </dd>

         <dt>readonly attribute RTCDtlsTransport transport</dt>

         <dd> <p>The <dfn
            id="dom-rtpreceiver-transport"><code>RTCRtpReceiver.transport</code></dfn>
            attribute is the transport over which media for
            <code>RTCRtpReceiver.track</code> is received in the form
            of RTP packets.  When BUNDLE is used, many
            <code><a>RTCRtpReceiver</a></code> objects will share one
            <code>RTCRtpReceiver.transport</code> and will all receive
            RTP over the same transport.  When RTCP mux is used,
            <code>RTCRtpReceiver.rtcpTransport</code> will be null,
            and both RTP and RTCP traffic will flow over
            <code>RTCRtpReceiver.transport</code>.  </dd>

          <dt>readonly attribute RTCDtlsTransport? rtcpTransport</dt>

          <dd> <p>The <dfn
            id="dom-rtpreceiver-rtcptransport"><code>RTCRtpReceiver.rtcpTransport</code></dfn>
            attribute is the transport over which RTCP is sent and
            received.  When BUNDLE is used, many
            <code><a>RTCRtpReceiver</a></code> objects will share one
            <code>RTCRtpReceiver.rtcpTransport</code> and will all
            send and receive RTCP over the same transport.  When RTCP
            mux is used, <code>RTCRtpReceiver.rtcpTransport</code>
            will be null, and both RTP and RTCP traffic will flow over
            <code>RTCRtpReceiver.transport</code>.  </dd>

          <dt>static RTCRtpCapabilities getCapabilities(DOMString
          kind)</dt> <dd> <p>The <dfn
          id="dom-rtpreceiver-getcapabilities"><code>RTCRtpReceiver.getCapabilities</code></dfn>
          method returns the most optimistic view of the capabilities of
          the system for receiving media of the given kind. It does
          not reserve any resources, ports, or other state but is
          meant to provide a way to discover the types of capabilities
          of the browser including which codecs may be supported.
          </p> </dd>

          <dt> sequence&lt;RTCRtpContributingSource&gt;
            getContributingSources () </dt> <dd> <p>Returns an
            <code><a>RTCRtpContributingSource</a></code> for each
            unique CSRC or SSRC received by this RTCRtpReceiver in the
            last 10 seconds.</p> </dd>
              
	</dl>

    <p> The <dfn>RTCRtpContributingSource</dfn> objects contain
    information about a given contributing source, including the time
    the most recent time a packet was received from the source. The
    browser MUST keep information from RTP packets received in the
    previous 10 seconds.  Each time an RTP packet is received, the
    <code><a>RTCRtpContributingSource</a></code> objects are updated.
    If the RTP packet contains CSRCs, then the
    <code><a>RTCRtpContributingSource</a></code> objects corresponding
    to those CSRCs are updated.  If the RTP packet contains no CSRCs,
    then the <code><a>RTCRtpContributingSource</a></code> object
    corresponding to the SSRC is updated.</p>

	 <dl class="idl" title="interface RTCRtpContributingSource">

	   <dt> readonly attribute DOMHighResTimeStamp timestamp</dt>
	   <dd> <p>The timestamp of type DOMHighResTimeStamp
	   [[!HIGHRES-TIME]], indicating the time of reception of the
	   most recent RTP packet containing the source.  The
	   timestamp is defined in [[!HIGHRES-TIME]] and corresponds to
	   a local clock.</p> </dd>

	   <dt> readonly attribute unsigned long source</dt> <dd> <p>
	   The CSRC or SSRC value of the contributing source. </p>
	   </dd>

	   <dt> readonly attribute byte? audioLevel</dt> <dd> <p> The
       audio level contained in the last RTP packet received from
       this source.  If the source was set from an SSRC, this will be
       the level value defined in [[!RFC6464]].  If an RFC 6464
       extension header is not present, the browser will compute the
       value as if it had come from RFC 6464 and use that.  If the
       source was set from a CSRC, this will be the level value
       defined in [[!RFC6465]].  RFC 6464 and 6465 define the level as
       a integral value from 0 to 127 representing the audio level in
       negative decibels relative to the loudest signal that they system could
       possibly encode. Thus, 0 represents the loudest signal the system could 
       possibly encode, and 127 represents silence.</dd>
	   
	 </dl>
	
      </section>

      <section>
        <h3>RTCRtpTransceiver Interface</h3>

        <p>The <a><code>RTCRtpTransceiver</code></a> interface
        represents a combination of an <a><code>RTCRtpSender</code></a> and
        an <a><code>RTCRtpReceiver</code></a> that share a
        common <code>mid</code>.

        <dl class="idl" title=
          "interface RTCRtpTransceiver">
          <dt>readonly attribute DOMString? mid</dt>

          <dd>
            <p>The <dfn id=
            "dom-rtptransceiver-mid"><code>mid</code></dfn>
            attribute is the <code>mid</code> negotatiated and present
            in the local and remote descriptions as defined in
            <span data-jsep="initial-offers initial-answers">[[!JSEP]]</span>.  Before negotiation is complete,
            the <code>mid</code> value may be null.  After rollbacks,
            the value may change from a non-null value to null.</p>
          </dd>

          <dt>[SameObject] readonly attribute RTCRtpSender sender</dt>

          <dd>
            <p>The <code id="dom-rtptransceiver-sender">sender</code>
            attribute is the <a><code>RTCRtpSender</code></a>
            corresponding to the RTP media that may be sent with mid
            = <a><code>mid</code></a>.</p>
          </dd>

          <dt>[SameObject] readonly attribute RTCRtpReceiver receiver</dt>

          <dd>
            <p>The <code id="dom-rtptransceiver-receiver">receiver</code>
            attribute is the <a><code>RTCRtpReceiver</code></a>
            corresponding to the RTP media that may be received with
            mid = <a><code>mid</code></a>.</p>
          </dd>

          <dt>readonly attribute boolean stopped</dt>

          <dd>
            <p>The <code>stopped</code>
            attribute indicates that the sender of this transceiver
            will no longer send, and that the receiver will no longer
            receive. It is true if
            either <code>stop</code> has been called or
            if setting the local or remote description has caused
            the <a><code>RTCRtpReceiver</code></a> to be stopped.</p>
          </dd>

          <dt>void stop()</dt>

          <dd>
            <p>The <dfn id="dom-rtptransceiver-stop"><code>stop</code></dfn>
            method stops the <a><code>RTCRtpTransceiver</code></a>.
            The sender of this transceiver will no longer send, and
            the receiver will no longer receive.</p>
          </dd>

          <dt>void setCodecPreferences(sequence&lt;RTCRtpCodecCapability&gt; codecs)</dt>
          <dd>
            <p>The <code>setCodecPreferences</code> method overrides the default codec
            preferences used by the <a>user agent</a>.  When generating a session
            description using either <code>createOffer</code> or <code>createAnswer</code>,
            the <a>user agent</a> MUST use the indicated codecs, in the order
            specified in the <var>codecs</var> argument, for the media section
            corresponding to this <code>RTCRtpTransceiver</code>.  Note that calls to
            <code>createAnswer</code> will use only the common subset of these codecs
            and the codecs that appear in the offer.
            </p>
            <p>This method allows applications to disable the negotiation of specific
            codecs.  It also allows an application to cause a remote peer to prefer the
            codec that appears first in the list for sending.
            </p>
            <p>Codec preferences remain in effect for all calls to
            <code>createOffer</code> and <code>createAnswer</code> that include this
            <code>RTCRtpTransceiver</code> until this method is called again.
            Setting <var>codecs</var> to an empty sequence resets codec preferences
            to any default value.
            </p>
          </dd>
        </dl>


      </section>

      <section>
        <h3>RTCDtlsTransport Interface</h3>

        <p>The <code><a>RTCDtlsTransport</a></code> interface allows an
        application access to information about the Datagram Transport
        Layer Security (DTLS) transport over which RTP and RTCP
        packets are sent and received by <code><a>RTCRtpSender</a></code>
        and <code><a>RTCRtpReceiver</a></code> objects, as well other data
        such as SCTP packets sent and received by data channels.  In
        particular, DTLS adds security to an underlying transport, and
        the <code>RTCDtlsTransport</code> interface allows access to
        information about the underlying transport and the security
        added.

        <dl class="idl" title=
          "interface RTCDtlsTransport">
          <dt>readonly attribute RTCIceTransport transport</dt>

          <dd>
            <p>The <code>transport</code>
            attribute is the underlying transport that is used to send
            and receive packets.  The underlying transport may not be
            shared between multiple active <code><a>RTCDtlsTransport</a></code>
            objects.
          </dd>

          <dt>readonly attribute RTCDtlsTransportState state</dt>

          <dd>
            <p>The <code id="dom-dtlstransport-state">state</code>
            attribute MUST return the state of the transport.
          </dd>

          <dt>sequence&lt;ArrayBuffer&gt; getRemoteCertificates()</dt>

          <dd>
            <p>Returns a sequence of <code>ArrayBuffer</code> containing the remote certificates in use by
            the remote side.</p>
          </dd>

          <dt>attribute EventHandler onstatechange</dt>

          <dd>
            This event handler, of event handler event
            type <code><a href=
            "#event-dtlstransport-statechange">statechange</a></code>,
            MUST be fired any time the <a href=
            "#dom-dtlstransport-state"><code>RTCDtlsTransport</code>
            state</a> changes.
          </dd>
        </dl>

        <h3>RTCDtlsTransportState Enum</h3>

        <dl class="idl" title="enum RTCDtlsTransportState">
          <dt>new</dt>

          <dd>DTLS has not started negotiating yet.</dd>

          <dt>connecting</dt>

          <dd>DTLS is in the process of negotiating a secure connection.</dd>

          <dt>connected</dt>

          <dd>DTLS has completed negotiation of a secure connection.</dd>

          <dt>closed</dt>

          <dd>The transport has been closed.</dd>

          <dt>failed</dt>

          <dd>The transport has failed as the result of an error (such
          as a failure to validate the remote fingerprint).</dd>
        </dl>
      </section>

      <section>
        <h3>RTCIceTransport Interface</h3>

        <p>The <code><a>RTCIceTransport</a></code> interface allows an
        application access to information about the ICE transport over
        which packets are sent and received.  In particular, ICE manages
        peer-to-peer connections which involve state which the
        application may want to access.</p>

        <dl class="idl" title=
          "interface RTCIceTransport">
          <dt>readonly attribute RTCIceRole role</dt>

          <dd>
            <p>The <dfn id=
            "dom-icetransport-role"><code>role</code></dfn> attribute
            MUST return the ICE role of the transport.
          </dd>

          <dt>readonly attribute RTCIceComponent component</dt>

          <dd>
            <p>The <dfn id=
            "dom-icetransport-component"><code>component</code></dfn>
            attribute MUST return the ICE component of the transport.
          </dd>

          <dt>readonly attribute RTCIceConnectionState state</dt>

          <dd>
            <p>The <dfn id=
            "dom-icetransport-state"><code>state</code></dfn>
            attribute MUST return the state of the transport.
          </dd>

          <dt>readonly attribute RTCIceGatheringState gatheringState</dt>

          <dd>
            <p>The <dfn id=
            "dom-icetransport-gatheringstate"><code>gathering
            state</code></dfn> attribute MUST return the gathering
            state of the transport.
          </dd>

          <dt>sequence&lt;RTCIceCandidate&gt; getLocalCandidates()</dt>

          <dd>
            <p>Returns a sequence describing the local ICE candidates gathered
            for this <code><a>RTCIceTransport</a></code> and sent in
            <code><a href=
            "#widl-RTCPeerConnection-onicecandidate">onicecandidate</a></code></p>
          </dd>

          <dt>sequence&lt;RTCIceCandidate&gt; getRemoteCandidates()</dt>

          <dd>
            <p>Returns a sequence describing the remote ICE candidates received by
            this <code><a>RTCIceTransport</a></code>
            via <code><a href=
            "#dom-peerconnection-addicecandidate">addIceCandidate()</a></code></p>
          </dd>

          <dt>RTCIceCandidatePair? getSelectedCandidatePair()</dt>
          <dd><p>Returns the selected candidate pair on which packets
          are sent, or <code>null</code> if there is no such pair.</p></dd>

          <dt>RTCIceParameters? getLocalParameters()</dt>

          <dd><p>Returns the local ICE parameters received by
            this <code><a>RTCIceTransport</a></code>
            via <code><a href=
            "#dom-peerconnection-setlocaldescription">setLocalDescription()</a></code>,
            or <code>null</code> if the parameters have not yet been
            received.</p>
          </dd>

          <dt>RTCIceParameters? getRemoteParameters()</dt>

          <dd><p>Returns the remote ICE parameters received by
            this <code><a>RTCIceTransport</a></code>
            via <code><a href=
            "#dom-peerconnection-setremotedescription">setRemoteDescription()</a></code>
            or <code>null</code> if the parameters have not yet been
            received.</p>
          </dd>

          <dt>attribute EventHandler onstatechange</dt>

          <dd>
            This event handler, of event handler event type <code><a href=
            "#event-icetransport-statechange">statechange</a></code>,
            MUST be fired any time the <a href=
            "#dom-icetransport-state"><code>RTCIceTransport</code> state</a> changes.
          </dd>

          <dt>attribute EventHandler ongatheringstatechange</dt>

          <dd>
            This event handler, of event handler event
            type <code><a href=
            "#event-icetransport-gatheringstatechange">gatheringstatechange</a></code>,
            MUST be fired any time the <a href=
            "#dom-icetransport-gatheringstate"><code>RTCIceTransport</code>gathering
            state</a> changes.
          </dd>

          <dt>attribute EventHandler onselectedcandidatepairchange</dt>

          <dd>
            This event handler, of event handler event
            type <code><a href=
            "#event-icetransport-selectedcandidatepairchange">selectedcandidatepairchange</a></code>,
            MUST be fired any time
            the <code><a>RTCIceTransport</a></code>'s selected
            candidate pair changes.
          </dd>
        </dl>

        <dl class="idl" title="dictionary RTCIceParameters">
          <dt>DOMString usernameFragment</dt>
          <dd><p>The ICE username fragment as defined in [[!ICE]], Section 7.1.2.3.</p></dd>
          <dt>DOMString password</dt>
          <dd><p>The ICE password as defined in [[!ICE]], Section 7.1.2.3.</p></dd>
        </dl>

        <dl class="idl" title="dictionary RTCIceCandidatePair">
          <dt>RTCIceCandidate local</dt>
          <dd><p>The local ICE candidate.</p></dd>
          <dt>RTCIceCandidate remote</dt>
          <dd><p>The remote ICE candidate.</p></dd>
        </dl>

        <h3>RTCIceRole Enum</h3>

        <dl class="idl" title="enum RTCIceRole">
          <dt>controlling</dt>

          <dd>A controlling agent as defined by [[!ICE]], Section 3.</dd>

          <dt>controlled</dt>

          <dd>A controlled agent as defined by [[!ICE]], Section 3.</dd>
        </dl>

        <h3>RTCIceComponent Enum</h3>

        <dl class="idl" title="enum RTCIceComponent">
          <dt>RTP</dt>

          <dd>The ICE Transport is used for RTP (or RTP/RTCP-multiplexing), as defined in [[!ICE]], Section 4.1.1.1.
          Protocols multiplexed with RTP (e.g. data channel) share its component ID.</dd>

          <dt>RTCP</dt>

          <dd>The ICE Transport is used for RTCP as defined by [[!ICE]], Section 4.1.1.1.</dd>
        </dl>
      </section>

        <section>
      <h3>RTCTrackEvent</h3>

      <p>The <code><a href="#event-track">track</a></code>
      event uses the
      <code><a>RTCTrackEvent</a></code> interface.</p>

      <p><dfn id="fire-track-event" data-lt="fire track event">Firing an
      RTCTrackEvent event named <var>e</var></dfn> with an <code>
      <a>RTCRtpReceiver</a></code> <var>receiver</var>, a
      <code><a>MediaStreamTrack</a></code> <var>track</var> and a
      <code>MediaStream</code>[] <var>streams</var>, means that an event
      with the name <var>e</var>, which does not bubble (except where otherwise
      stated) and is not cancelable (except where otherwise stated), and which
      uses the <code><a>RTCTrackEvent</a></code> interface with the
      <code><a href="#dom-trackevent-receiver">receiver</a></code> attribute
      set to <var>receiver</var>,
      <code><a href="#dom-trackevent-track">track</a></code> attribute
      set to <var>track</var>,
      <code><a href="#dom-trackevent-streams">streams</a></code> attribute
      set to <var>streams</var>, MUST be created and dispatched at the
      given target.</p>

      <dl class="idl" data-merge="RTCTrackEventInit" title=
      "interface RTCTrackEvent : Event">
        <dt>Constructor(DOMString type, RTCTrackEventInit
        eventInitDict)</dt>

        <dt>readonly attribute RTCRtpReceiver receiver</dt>

        <dd>
          <p>The <dfn id=
          "dom-trackevent-receiver"><code>receiver</code></dfn> attribute
          represents the <code><a>RTCRtpReceiver</a></code> object associated with
          the event.</p>
        </dd>

        <dt>readonly attribute MediaStreamTrack track</dt>

        <dd>
          <p>The <code id="dom-trackevent-track">track</code> attribute
          represents the <code><a>MediaStreamTrack</a></code> object that is
          associated with the <code><a>RTCRtpReceiver</a></code> identified by
          <code>receiver</code>.</p>
        </dd>

         <dt>readonly attribute FrozenArray&lt;MediaStream&gt; streams</dt>

         <dd>
           <p>The <dfn id="dom-trackevent-streams"><code>streams</code></dfn>
           attribute returns an array of <code><a>MediaStream</a></code> objects
           representing the <code><a>MediaStream</a></code>s that this event's
          <code>track</code> is a part of.</p>
        </dd>

      </dl>

      <dl class="idl" title="dictionary RTCTrackEventInit : EventInit">

        <dt>RTCRtpReceiver receiver</dt>
        <dd>
          <p>The <code>receiver</code> attribute
          represents the <code><a>RTCRtpReceiver</a></code> object associated with
          the event.</p>
        </dd>
        <dt>MediaStreamTrack track</dt>
        <dd>
          <p>The <code>track</code> attribute
          represents the <code><a>MediaStreamTrack</a></code> object that is
          associated with the <code><a>RTCRtpReceiver</a></code> identified by
          <code>receiver</code>.</p>
        </dd>
        <dt>sequence&lt;MediaStream&gt; streams</dt>
        <dd>
          <p>The <code>streams</code>
           attribute returns an array of <code><a>MediaStream</a></code> objects
           representing the <code><a>MediaStream</a></code>s that this event's
          <code>track</code> is a part of.</p>
        </dd>
      </dl>
    </section>

  </section>

  <section>
    <h2>Peer-to-peer Data API</h2>

    <p>The Peer-to-peer Data API lets a web application send and receive
    generic application data peer-to-peer. The API for sending and receiving
    data models the behavior of WebSockets [[WEBSOCKETS-API]].</p>

    <section>
      <h3>RTCPeerConnection Interface Extensions</h3>

      <p>The Peer-to-peer data API extends the
      <code><a>RTCPeerConnection</a></code> interface as described below.</p>

      <dl class="idl" title="partial interface RTCPeerConnection">
          <dt>readonly attribute RTCSctpTransport? sctp</dt>

          <dd>
            <p>The SCTP transport over which SCTP data is sent and
            received. If SCTP has not been negotiated, the value
            is null.</p>
          </dd>

        <dt>RTCDataChannel createDataChannel([TreatNullAs=EmptyString]
        DOMString label, optional RTCDataChannelInit dataChannelDict)</dt>

        <dd>
          <p>Creates a new <code><a>RTCDataChannel</a></code> object with the
          given label. The <code><a>RTCDataChannelInit</a></code> dictionary
          can be used to configure properties of the underlying channel such as
          <!--priority and--> data reliability.</p>

          <p>When the <dfn id=
          "dom-peerconnection-createdatachannel"><code>createDataChannel()</code></dfn>
          method is invoked, the user agent MUST run the following steps.</p>

          <ol>
            <li>
              <p>If the <code><a>RTCPeerConnection</a></code> object's
              <a href=
              "#dom-peerconnection-signaling-state"><code>RTCPeerConnection</code>
              signalingState</a> is <code>closed</code>, throw an
              <code>InvalidStateError</code> exception and abort these
              steps.</p>
            </li>

            <li>
              <p>Let <var>channel</var> be a newly created
              <code><a>RTCDataChannel</a></code> object.</p>
            </li>

            <li>
              <p>Initialize <var>channel</var>'s <code><a href=
              "#dom-datachannel-label">label</a></code> attribute to the value
              of the first argument.</p>
            </li>

            <li>
              <p>If the second (dictionary) argument is present, set
              <var>channel</var>'s <code><a href=
              "#dom-datachannel-ordered">ordered</a></code>, <code><a href=
              "#dom-datachannel-maxpacketlifetime">maxPacketLifeTime</a></code>,
              <code><a href=
              "#dom-datachannel-maxretransmits">maxRetransmits</a></code>,
              <code><a href="#dom-datachannel-protocol">protocol</a></code>,
              <code><a href="#dom-datachannel-negotiated">negotiated</a></code>
              and <code><a href="#dom-datachannel-id">id</a></code> attributes
              to the values of their corresponding dictionary members (if
              present in the dictionary).</p>
            </li>

            <li>If <code>negotiated</code> is false
            and <code>label</code> is longer than 65535 bytes
            long, <a href="http://heycam.github.io/webidl/#dfn-throw">throw</a>
            a <code>TypeError</code>.</li>

            <li>If <code>negotiated</code> is false
            and <code>protocol</code> is longer than 65535 bytes
            long, <a href="http://heycam.github.io/webidl/#dfn-throw">throw</a>
            a <code>TypeError</code>.</li>

            <li>
              <p>If both the <code><a href=
              "#dom-datachannel-maxpacketlifetime">maxPacketLifeTime</a></code>
              and <code><a href=
              "#dom-datachannel-maxretransmits">maxRetransmits</a></code>
              attributes are set (not null), then throw a
              <code>SyntaxError</code> exception and abort these steps.</p>
            </li>

            <li>
              <p>If an attribute, either <code><a href=
              "#dom-datachannel-maxpacketlifetime">maxPacketLifeTime</a></code>
              or <code><a href=
              "#dom-datachannel-maxretransmits">maxRetransmits</a></code>, has
              been set to indicate unreliable mode, and that value exceeds the
              maximum value supported by the user agent, the value MUST be set
              to the user agents maximum value.</p>
            </li>

            <li>
              <p>If <code><a href="#dom-datachannel-id">id</a></code> attribute
              is uninitialized (not set via the dictionary), initialize it to a
              value generated by the user agent, according to the WebRTC
              DataChannel Protocol specification, and skip to the next step.
              Otherwise, if the value of the <code><a href=
              "#dom-datachannel-id">id</a></code> attribute is taken by an
              existing <code><a>RTCDataChannel</a></code>, throw a
              <code>ResourceInUse</code> exception and abort these steps.</p>
            </li>

            <li>
              <p>Return <var>channel</var> and continue the following steps in
              the background.</p>
            </li>

            <li>
              <p>Create <var>channel</var>'s associated <a>underlying data
              transport</a> and configure it according to the relevant
              properties of <var>channel</var>.</p>
            </li>

            <li>
              <p>If <var>channel</var> was the first RTCDataChannel created on
              this connection, mark the connection as needing negotiation.
              </p>
          </ol>
        </dd>

        <dt>attribute EventHandler ondatachannel</dt>

        <dd>The event type of this event handler is <code><a href=
        "#event-datachannel">datachannel</a></code>.</dd>
      </dl>
      <section>
        <h3>RTCSctpTransport Interface</h3>

        <p>The <code><a>RTCSctpTransport</a></code> interface allows an
        application access to information about the SCTP data channels
        tied to a particular SCTP association.</p>

        <dl class="idl" title="interface RTCSctpTransport">
          <dt>readonly attribute RTCDtlsTransport transport</dt>

          <dd>
            <p>The transport over which all SCTP packets for data
              channels will be sent and received.</p>
          </dd>

          <dt>readonly attribute unsigned long maxMessageSize</dt>
          <dd>
            <p>The maximum size of data that can be passed
            to <code><a>RTCDataChannel</a></code>'s <code><a href=
          "#dom-datachannel-send">send()</a></code> method.</p>
          </dd>
        </dl>
      </section>
    </section>

    <section>
      <h3>RTCDataChannel</h3>

      <p>The <code><a>RTCDataChannel</a></code> interface represents a
      bi-directional data channel between two peers. A
      <code><a>RTCDataChannel</a></code> is created via a factory method on an
      <code><a>RTCPeerConnection</a></code> object. The messages sent between
      the browsers are described in [[!RTCWEB-DATA]] and
      [[!RTCWEB-DATA-PROTOCOL]].</p>

      <p>There are two ways to establish a connection with
      <code><a>RTCDataChannel</a></code>. The first way is to simply create a
      <code><a>RTCDataChannel</a></code> at one of the peers with the
      <code><a href="#widl-RTCDataChannelInit-negotiated">negotiated</a></code>
      <code><a>RTCDataChannelInit</a></code> dictionary member unset or set to
      its default value false. This will announce the new channel in-band and
      trigger a <code><a>RTCDataChannelEvent</a></code> with the corresponding
      <code><a>RTCDataChannel</a></code> object at the other peer. The second
      way is to let the application negotiate the
      <code><a>RTCDataChannel</a></code>. To do this, create a
      <code><a>RTCDataChannel</a></code> object with the <code><a href=
      "#widl-RTCDataChannelInit-negotiated">negotiated</a></code>
      <code><a>RTCDataChannelInit</a></code> dictionary member set to true, and
      signal out-of-band (e.g. via a web server) to the other side that it
      SHOULD create a corresponding <code><a>RTCDataChannel</a></code> with the
      <code><a href="#widl-RTCDataChannelInit-negotiated">negotiated</a></code>
      <code><a>RTCDataChannelInit</a></code> dictionary member set to true and
      the same <code><a href="#dom-datachannel-id">id</a></code>. This will
      connect the two separately created <code><a>RTCDataChannel</a></code>
      objects. The second way makes it possible to create channels with
      asymmetric properties and to create channels in a declarative way by
      specifying matching <code><a href=
      "#widl-RTCDataChannelInit-id">ids</a></code>.</p>

      <p>Each <code><a>RTCDataChannel</a></code> has an associated
      <dfn>underlying data transport</dfn> that is used to transport actual
      data to the other peer. The transport properties of the <a>underlying
      data transport</a>, such as in order delivery settings and reliability
      mode, are configured by the peer as the channel is created. The
      properties of a channel cannot change after the channel has been created.
      The actual wire protocol between the peers is specified by the WebRTC
      DataChannel Protocol specification [[RTCWEB-DATA]].</p>

      <p>A <code><a>RTCDataChannel</a></code> can be configured to operate in
      different reliability modes. A reliable channel ensures that the data is
      delivered at the other peer through retransmissions. An unreliable
      channel is configured to either limit the number of retransmissions (
      <code><a href=
      "#widl-RTCDataChannelInit-maxRetransmits">maxRetransmits</a></code> ) or
      set a time during which transmissions (including retransmissions) are
      allowed ( <code><a href=
      "#widl-RTCDataChannelInit-maxPacketLifeTime">maxPacketLifeTime</a></code>
      ). These properties can not be used simultaneously and an attempt to do
      so will result in an error. Not setting any of these properties results
      in a reliable channel.</p>

      <p>A <code><a>RTCDataChannel</a></code>, created with <code><a href=
      "#dom-peerconnection-createdatachannel">createDataChannel()</a></code> or
      dispatched via a <code><a>RTCDataChannelEvent</a></code>, MUST initially
      be in the <code>connecting</code> state. When the
      <code><a>RTCDataChannel</a></code> object's <a>underlying data
      transport</a> is ready, the user agent MUST <a href=
      "#announce-datachannel-open">announce the <code>RTCDataChannel</code> as
      open</a>.</p>

      <p>When the user agent is to <dfn id="announce-datachannel-open">announce
      a <code>RTCDataChannel</code> as open</dfn>, the user agent MUST queue a
      task to run the following steps:</p>

      <ol>
        <li>
          <p>If the associated <code><a>RTCPeerConnection</a></code> object's
          <a href=
          "#dom-peerconnection-signaling-state"><code>RTCPeerConnection</code>
          signalingState</a> is <code>closed</code>, abort these steps.</p>
        </li>

        <li>
          <p>Let <var>channel</var> be the <code><a>RTCDataChannel</a></code>
          object to be announced.</p>
        </li>

        <li>
          <p>Set <var>channel</var>'s <code><a href=
          "#dom-datachannel-readystate">readyState</a></code> attribute to
          <code>open</code>.</p>
        </li>

        <li>
          <p>Fire a simple event named <code><a href=
          "#event-datachannel-open">open</a></code> at <var>channel</var>.</p>
        </li>
      </ol>

      <p>When an <a>underlying data transport</a> is to be announced (the other
      peer created a channel with <code><a href=
      "#widl-RTCDataChannelInit-negotiated">negotiated</a></code> unset or set
      to false), the user agent of the peer that did not initiate the creation
      process MUST queue a task to run the following steps:</p>

      <ol>
        <li>
          <p>If the associated <code><a>RTCPeerConnection</a></code> object's
          <a href=
          "#dom-peerconnection-signaling-state"><code>RTCPeerConnection</code>
          signalingState</a> is <code>closed</code>, abort these steps.</p>
        </li>

        <li>
          <p>Let <var>channel</var> be a newly created
          <code><a>RTCDataChannel</a></code> object.</p>
        </li>

        <li>
          <p>Let <var>configuration</var> be an information bundle received
          from the other peer as a part of the process to establish the
          <a>underlying data transport</a> described by the WebRTC DataChannel
          Protocol specification [[!RTCWEB-DATA-PROTOCOL]].</p>
        </li>

        <li>
          <p>Initialize <var>channel</var>'s <code><a href=
          "#dom-datachannel-label">label</a></code>, <code><a href=
          "#dom-datachannel-ordered">ordered</a></code>, <code><a href=
          "#dom-datachannel-maxpacketlifetime">maxPacketLifeTime</a></code>,
          <code><a href=
          "#dom-datachannel-maxretransmits">maxRetransmits</a></code>,
          <code><a href="#dom-datachannel-protocol">protocol</a></code>,
          <code><a href="#dom-datachannel-negotiated">negotiated</a></code> and
          <code><a href="#dom-datachannel-id">id</a></code> attributes to their
          corresponding values in <var>configuration</var>.</p>
        </li>

        <li>
          <p>Set <var>channel</var>'s <code><a href=
          "#dom-datachannel-readystate">readyState</a></code> attribute to
          <code>connecting</code>.</p>
        </li>

        <li>
          <p><a>Fire a datachannel event</a> named <code><a href=
          "#event-datachannel">datachannel</a></code> with <var>channel</var>
          at the <code><a>RTCPeerConnection</a></code> object.</p>
        </li>
      </ol>

      <p>An <code><a>RTCDataChannel</a></code> object's <a>underlying data
      transport</a> may be torn down in a non-abrupt manner by running the
      <dfn id="data-transport-closing-procedure">closing procedure</dfn>. When
      that happens the user agent MUST, unless the procedure was initiated by
      the <code><a href="#dom-datachannel-close">close()</a></code> method,
      queue a task that sets the object's <code><a href=
      "#dom-datachannel-readystate">readyState</a></code> attribute to
      <code>closing</code>. This will eventually render the <a href=
      "#dfn-underlying-data-transport">data transport</a> <a href=
      "#data-transport-closed">closed</a>.</p>

      <p>When a <code><a>RTCDataChannel</a></code> object's <a>underlying data
      transport</a> has been <dfn id="data-transport-closed">closed</dfn>, the
      user agent MUST queue a task to run the following steps:</p>

      <ol>
        <li>
          <p>Let <var>channel</var> be the <code><a>RTCDataChannel</a></code>
          object whose <a href="#dfn-underlying-data-transport">transport</a>
          was closed.</p>

          <div class="issue">
            The data transport protocol will specify what happens to, e.g.
            buffered data, when the data transport is closed.
          </div>
        </li>

        <li>
          <p>Set <var>channel</var>'s <code><a href=
          "#dom-datachannel-readystate">readyState</a></code> attribute to
          <code>closed</code>.</p>
        </li>

        <li>
          <p>If the <a href="#dfn-underlying-data-transport">transport</a> was
          closed <dfn id="data-transport-closed-error">with an error</dfn>,
          fire an NetworkError event at <var>channel</var>.</p>
        </li>

        <li>
          <p>Fire a simple event named <code title=
          "event-RTCDataChannel-close"><a href=
          "#event-datachannel-close">close</a></code> at
          <var>channel</var>.</p>
        </li>
      </ol>

      <dl class="idl" data-merge="RTCDataChannelInit" title=
      "interface RTCDataChannel : EventTarget">
        <dt>readonly attribute DOMString label</dt>

        <dd>
          <p>The <dfn id=
          "dom-datachannel-label"><code>RTCDataChannel.label</code></dfn>
          attribute represents a label that can be used to distinguish this
          <code><a>RTCDataChannel</a></code> object from other
          <code><a>RTCDataChannel</a></code> objects. Scripts are allowed to
          create multiple <code><a>RTCDataChannel</a></code> objects with the
          same label. The attribute MUST return the value to which it was set
          when the <code><a>RTCDataChannel</a></code> object was created.</p>
        </dd>

        <dt>readonly attribute boolean ordered</dt>

        <dd>
          <p>The <dfn id=
          "dom-datachannel-ordered"><code>RTCDataChannel.ordered</code></dfn>
          attribute returns true if the <code><a>RTCDataChannel</a></code> is
          ordered, and false if other of order delivery is allowed. The
          attribute MUST be initialized to true by default and MUST return the
          value to which it was set when the <code><a>RTCDataChannel</a></code>
          was created.</p>
        </dd>

        <dt>readonly attribute unsigned short? maxPacketLifeTime</dt>

        <dd>
          <p>The <dfn id=
          "dom-datachannel-maxpacketlifetime"><code>RTCDataChannel.maxPacketLifeTime</code></dfn>
          attribute returns the length of the time window (in milliseconds)
          during which transmissions and retransmissions may occur in
          unreliable mode, or null if unset. The attribute MUST be initialized
          to null by default and MUST return the value to which it was set when
          the <code><a>RTCDataChannel</a></code> was created.</p>
        </dd>

        <dt>readonly attribute unsigned short? maxRetransmits</dt>

        <dd>
          <p>The <dfn id=
          "dom-datachannel-maxretransmits"><code>RTCDataChannel.maxRetransmits</code></dfn>
          attribute returns the maximum number of retransmissions that are
          attempted in unreliable mode, or null if unset. The attribute MUST be
          initialized to null by default and MUST return the value to which it
          was set when the <code><a>RTCDataChannel</a></code> was created.</p>
        </dd>

        <dt>readonly attribute DOMString protocol</dt>

        <dd>
          <p>The <dfn id=
          "dom-datachannel-protocol"><code>RTCDataChannel.protocol</code></dfn>
          attribute returns the name of the sub-protocol used with this
          <code><a>RTCDataChannel</a></code> if any, or the empty string
          otherwise. The attribute MUST be initialized to the empty string by
          default and MUST return the value to which it was set when the
          <code><a>RTCDataChannel</a></code> was created.</p>
        </dd>

        <dt>readonly attribute boolean negotiated</dt>

        <dd>
          <p>The <dfn id=
          "dom-datachannel-negotiated"><code>RTCDataChannel.negotiated</code></dfn>
          attribute returns true if this <code><a>RTCDataChannel</a></code> was
          negotiated by the application, or false otherwise. The attribute MUST
          be initialized to false by default and MUST return the value to which
          it was set when the <code><a>RTCDataChannel</a></code> was
          created.</p>
        </dd>

        <dt>readonly attribute unsigned short id</dt>

        <dd>
          <p>The <dfn id=
          "dom-datachannel-id"><code>RTCDataChannel.id</code></dfn> attribute
          returns the id for this <code><a>RTCDataChannel</a></code>. The id
          was either assigned by the user agent at channel creation time or
          selected by the script. The attribute MUST return the value to which
          it was set when the <code><a>RTCDataChannel</a></code> was
          created.</p>
        </dd><!--
          <dt>readonly attribute long priority</dt>

    <dd>
      <p>The <dfn id='dom-datachannel-priority'><code>RTCDataChannel.priority</code></dfn>
      attribute returns the priority of the <code><a>RTCDataChannel</a></code>; a channel
      with a higher value is prioritized over a channel with a lower value. The attribute
      MUST return the value to which it was set when the the <code><a>RTCDataChannel</a></code>
      was created.</p>

      <p>The value might not be the value given in the <code><a>RTCDataChannelInit</a></code>
      dictionary since it may have been clamped to fit in the range of valid values.</p>
    </dd>
-->
        <!-- AbstractMessenger -->

        <dt>readonly attribute RTCDataChannelState readyState</dt>

        <dd>
          <p>The <dfn id=
          "dom-datachannel-readystate"><code>RTCDataChannel.readyState</code></dfn>
          attribute represents the state of the <code>RTCDataChannel</code>
          object. It MUST return the value to which the user agent last set it
          (as defined by the processing model algorithms).</p>
        </dd>

        <dt>readonly attribute unsigned long bufferedAmount</dt>

        <dd>
          <p>The <dfn id=
          "dom-datachannel-bufferedamount"><code>bufferedAmount</code></dfn>
          attribute MUST return the number of bytes of application data (UTF-8
          text and binary data) that have been queued using <code><a href=
          "#dom-datachannel-send">send()</a></code> but that, as of the last
          time the event loop started executing a task, had not yet been
          transmitted to the network. (This thus includes any text sent during
          the execution of the current task, regardless of whether the user
          agent is able to transmit text asynchronously with script execution.)
          This does not include framing overhead incurred by the protocol, or
          buffering done by the operating system or network hardware. If the
          channel is closed, this attribute's value will only increase with
          each call to the <code><a href=
          "#dom-datachannel-send">send()</a></code> method (the attribute does
          not reset to zero once the channel closes).</p>
        </dd>

        <dt>attribute unsigned long bufferedAmountLowThreshold</dt>

        <dd>
          <p>The <dfn id="dom-datachannel-bufferedamountlowthreshold">
          <code>bufferedAmountLowThreshold</code></dfn> attribute sets the
          threshold at which the <code><a href=
          "#dom-datachannel-bufferedamount">bufferedAmount</a></code> is
          considered to be low.  When the <code><a href=
          "#dom-datachannel-bufferedamount">bufferedAmount</a></code>
          decreases from above this threshold to equal or below it, the
          <code title="event-RTCDataChannel-bufferedamountlow"><a href=
          "#event-datachannel-bufferedamountlow">bufferedamountlow</a></code>
          event fires. The
          <code><a href="#dom-datachannel-bufferedamountlowthreshold">
          bufferedAmountLowThreshold</a></code> is
          initially zero on each new <code><a>RTCDataChannel</a></code>, but
          the application may change its value at any time.</p>
        </dd>

        <dt>attribute EventHandler onopen</dt>

        <dd>The event type of this event handler is <code><a href=
        "#event-datachannel-open">open</a></code>.</dd>

        <dt>attribute EventHandler onbufferedamountlow</dt>

        <dd>The event type of this event handler is <code><a href=
        "#event-datachannel-bufferedamountlow">bufferedamountlow</a></code>.</dd>

        <dt>attribute EventHandler onerror</dt>

        <dd>The event type of this event handler is <code><a href=
        "#event-datachannel-error">error</a></code>.</dd>

        <dt>attribute EventHandler onclose</dt>

        <dd>The event type of this event handler is <code><a href=
        "#event-datachannel-close">close</a></code>.</dd><!--
        <dt>void close([Clamp] optional unsigned short code, optional DOMString reason)</dt>

    <dd>
      <p>Add text...</p>
    </dd>
-->

        <dt>void close()</dt>

        <dd>
          <p>Closes the <code><a>RTCDataChannel</a></code>. It may be called
          regardless of whether the <code><a>RTCDataChannel</a></code> object
          was created by this peer or the remote peer.</p>

          <p>When the <dfn id="dom-datachannel-close"><code>RTCDataChannel
          close()</code></dfn> method is called, the user agent MUST run the
          following steps:</p>

          <ol>
            <li>
              <p>Let <var>channel</var> be the
              <code><a>RTCDataChannel</a></code> object which is about to be
              closed.</p>
            </li>

            <li>
              <p>If <var>channel</var>'s <code><a href=
              "#dom-datachannel-readystate">readyState</a></code> is
              <code>closing</code> or <code>closed</code>, then abort these
              steps.</p>
            </li>

            <li>
              <p>Set <var>channel</var>'s <code><a href=
              "#dom-datachannel-readystate">readyState</a></code> attribute to
              <code>closing</code>.</p>
            </li>

            <li>
              <p>If the <code><a href=
              "#data-transport-closing-procedure">closing procedure</a></code>
              has not started yet, start it.</p>
            </li>
          </ol>
        </dd>

        <dt>attribute EventHandler onmessage</dt>

        <dd>The event type of this event handler is <code><a href=
        "#event-datachannel-message">message</a></code>.</dd>

        <dt>attribute DOMString binaryType</dt>

        <dd>
          <p>The <dfn id=
          "dom-datachannel-binarytype"><code>binaryType</code></dfn> attribute
          MUST, on getting, return the value to which it was last set. On
          setting, the user agent MUST set the IDL attribute to the new value.
          When a <code><a>RTCDataChannel</a></code> object is created, the
          <code><a href="#dom-datachannel-binarytype">binaryType</a></code>
          attribute MUST be initialized to the string "<code>blob</code>".</p>

          <p>This attribute controls how binary data is exposed to scripts. See
          the [[WEBSOCKETS-API]] for more information.</p>
        </dd>

        <dt>void send(USVString data)</dt>

        <dd>
          <p>Run the steps described by the <code><a href=
          "#dom-datachannel-send">send()</a></code> algorithm with argument
          type <code>string</code> object.</p>
        </dd>

        <dt>void send(Blob data)</dt>

        <dd>
          <p>Run the steps described by the <code><a href=
          "#dom-datachannel-send">send()</a></code> algorithm with argument
          type <code>Blob</code> object.</p>
        </dd>

        <dt>void send(ArrayBuffer data)</dt>

        <dd>
          <p>Run the steps described by the <code><a href=
          "#dom-datachannel-send">send()</a></code> algorithm with argument
          type <code>ArrayBuffer</code> object.</p>
        </dd>

        <dt>void send(ArrayBufferView data)</dt>

        <dd>
          <p>Run the steps described by the <code><a href=
          "#dom-datachannel-send">send()</a></code> algorithm with argument
          type <code>ArrayBufferView</code> object.</p>
        </dd>
      </dl>

      <dl class="idl" title="dictionary RTCDataChannelInit">
        <dt>boolean ordered = true</dt>

        <dd>
          <p>If set to false, data is allowed to be delivered out of order. The
          default value of true, guarantees that data will be delivered in
          order.</p>
        </dd>

        <dt>unsigned short maxPacketLifeTime</dt>

        <dd>
          <p>Limits the time during which the channel will transmit or
          retransmit data if not acknowledged. This value may be clamped if it
          exceeds the maximum value supported by the user agent.</p>
        </dd>

        <dt>unsigned short maxRetransmits</dt>

        <dd>
          <p>Limits the number of times a channel will retransmit data if not
          successfully delivered. This value may be clamped if it exceeds the
          maximum value supported by the user agent..</p>
        </dd>

        <dt>DOMString protocol = ""</dt>

        <dd>
          <p>Subprotocol name used for this channel.</p>
        </dd>

        <dt>boolean negotiated = false</dt>

        <dd>
          <p>The default value of false tells the user agent to announce the
          channel in-band and instruct the other peer to dispatch a
          corresponding <code><a>RTCDataChannel</a></code> object. If set to
          true, it is up to the application to negotiate the channel and create
          a <code><a>RTCDataChannel</a></code> object with the same
          <code><a href="#dom-datachannel-id">id</a></code> at the other
          peer.</p>
        </dd>

        <dt>unsigned short id</dt>

        <dd>
          <p>Overrides the default selection of id for this channel.</p>
        </dd><!-- <dt>boolean reliable</dt> -->
        <!--
        <dt>[Clamp] long priority</dt>
-->
      </dl>

      <p>The <dfn id="dom-datachannel-send"><code>send()</code></dfn> method is
      overloaded to handle different data argument types. When any version of
      the method is called, the user agent MUST run the following steps:</p>

      <ol>
        <li>
          <p>Let <var>channel</var> be the <code><a>RTCDataChannel</a></code>
          object on which data is to be sent.</p>
        </li>

        <li>
          <p>If <var>channel</var>'s <a href=
          "#dom-datachannel-readystate"><code>readyState</code></a> attribute
          is <code>connecting</code>, throw an <code>InvalidStateError</code>
          exception and abort these steps.</p>
        </li>

        <li>
          <p>Execute the sub step that corresponds to the type of the methods
          argument:</p>

          <ul>
            <li>
              <p><code>string</code> object:</p>

              <p>Let <var>data</var> be the object and increase the
              <code><a href=
              "#dom-datachannel-bufferedamount">bufferedAmount</a></code>
              attribute by the number of bytes needed to express
              <var>data</var> as UTF-8.</p>
            </li>

            <li>
              <p><code>Blob</code> object:</p>

              <p>Let <var>data</var> be the raw data represented by the
              <code>Blob</code> object and increase the <code><a href=
              "#dom-datachannel-bufferedamount">bufferedAmount</a></code>
              attribute by the size of data, in bytes.</p>
            </li>

            <li>
              <p><code>ArrayBuffer</code> object:</p>

              <p>Let <var>data</var> be the data stored in the buffer described
              by the <code>ArrayBuffer</code> object and increase the
              <code><a href=
              "#dom-datachannel-bufferedamount">bufferedAmount</a></code>
              attribute by the length of the <code>ArrayBuffer</code> in
              bytes.</p>
            </li>

            <li>
              <p><code>ArrayBufferView</code> object:</p>

              <p>Let <var>data</var> be the data stored in the section of the
              buffer described by the <code>ArrayBuffer</code> object that the
              <code>ArrayBufferView</code> object references and increase the
              <code><a href=
              "#dom-datachannel-bufferedamount">bufferedAmount</a></code>
              attribute by the length of the <code>ArrayBufferView</code> in
              bytes.</p>
            </li>
          </ul>
        </li>

        <li>
          <p>If <var>channel</var>'s <a>underlying data transport</a> is
          not established yet, or if the <code><a href=
          "#data-transport-closing-procedure">closing procedure</a></code> has
          started, then abort these steps.</p>
        </li>

        <li>
          <p>Attempt to send <var>data</var> on <var>channel</var>'s
          <a>underlying data transport</a>; if the data cannot be sent, e.g.
          because it would need to be buffered but the buffer is full, the user
          agent MUST abruptly <a href="#data-transport-closed">close</a>
          <var>channel</var>'s <a>underlying data transport</a> <a href=
          "#data-transport-closed-error">with an error</a>.</p>
        </li>
      </ol>

      <dl class="idl" title="enum RTCDataChannelState">
        <dt>connecting</dt>

        <dd>
          <p>The user agent is attempting to establish the <a>underlying data
          transport</a>. This is the initial state of a
          <code><a>RTCDataChannel</a></code> object created with <code><a href=
          "#dom-peerconnection-createdatachannel">createDataChannel()</a></code>.</p>
        </dd>

        <dt>open</dt>

        <dd>
          <p>The <a>underlying data transport</a> is established and
          communication is possible. This is the initial state of a
          <code><a>RTCDataChannel</a></code> object dispatched as a part of a
          <code><a>RTCDataChannelEvent</a></code>.</p>
        </dd>

        <dt>closing</dt>

        <dd>
          <p>The <code><a href=
          "#data-transport-closing-procedure">procedure</a></code> to close
          down the <a>underlying data transport</a> has started.</p>
        </dd>

        <dt>closed</dt>

        <dd>
          <p>The <a>underlying data transport</a> has been <code><a href=
          "#data-transport-closed">closed</a></code> or could not be
          established.</p>
        </dd>
      </dl>
    </section>

    <section>
      <h3>RTCDataChannelEvent</h3>

      <p>The <code><a href="#event-datachannel">datachannel</a></code> event
      uses the <code><a>RTCDataChannelEvent</a></code> interface.</p>

      <p><dfn id="fire-a-datachannel-event" data-lt=
      "fire a datachannel event">Firing a datachannel event named
      <var>e</var></dfn> with a <code><a>RTCDataChannel</a></code>
      <var>channel</var> means that an event with the name <var>e</var>, which
      does not bubble (except where otherwise stated) and is not cancelable
      (except where otherwise stated), and which uses the
      <code><a>RTCDataChannelEvent</a></code> interface with the <code><a href=
      "#dom-datachannelevent-channel">channel</a></code> attribute set to
      <var>channel</var>, MUST be created and dispatched at the given
      target.</p>

      <dl class="idl" data-merge="RTCDataChannelEventInit" title=
      "interface RTCDataChannelEvent : Event">
        <dt>Constructor(DOMString type, RTCDataChannelEventInit
        eventInitDict)</dt>

        <dt>readonly attribute RTCDataChannel channel</dt>

        <dd>
          <p>The <dfn id=
          "dom-datachannelevent-channel"><code>channel</code></dfn> attribute
          represents the <code><a>RTCDataChannel</a></code> object associated
          with the event.</p>
        </dd>
      </dl>

      <dl class="idl" title="dictionary RTCDataChannelEventInit : EventInit">
        <dt>RTCDataChannel channel</dt>

        <dd>
          <p class="issue">TODO</p>
        </dd>
      </dl>
    </section>

    <section>
      <h3>Garbage Collection</h3>

      <p>A <code><a>RTCDataChannel</a></code> object MUST not be garbage
      collected if its</p>

      <ul>
        <li>
          <p><code><a href="#dom-datachannel-readystate">readyState</a></code>
          is <code>connecting</code> and at least one event listener is
          registered for <code>open</code> events, <code>message</code> events,
          <code>error</code> events, or <code>close</code> events.</p>
        </li>

        <li>
          <p><code><a href="#dom-datachannel-readystate">readyState</a></code>
          is <code>open</code> and at least one event listener is registered
          for <code>message</code> events, <code>error</code> events, or
          <code>close</code> events.</p>
        </li>

        <li>
          <p><code><a href="#dom-datachannel-readystate">readyState</a></code>
          is <code>closing</code> and at least one event listener is registered
          for <code>error</code> events, or <code>close</code> events.</p>
        </li>

        <li>
          <p><a>underlying data transport</a> is established and data is queued
          to be transmitted.</p>
        </li>
      </ul>
    </section>
  </section>

  <section>
    <h3>Peer-to-peer DTMF</h3>

    <p>This section describes an interface on <code><a>RTCRtpSender</a></code>
    to send DTMF (phone keypad) values across an <code><a>RTCPeerConnection</a></code>.
    Details of how DTMF is sent to the other peer are described in [[!RTCWEB-AUDIO]].</p>

    <section>
      <h3>RTCRtpSender Interface Extensions</h3>

      <p>The Peer-to-peer DTMF API extends the
      <code><a>RTCRtpSender</a></code> interface as described below.</p>

      <dl class="idl" title="partial interface RTCRtpSender">
        <dt>readonly attribute RTCDTMFSender? dtmf</dt>

        <dd>
          <p>The <dfn>dtmf</dfn> attribute returns a RTCDTMFSender
          which can be used to send DTMF.  A null value indicates that
          this RTCRtpSender cannot send DTMF.</p>
        </dd>
      </dl>
    </section>

    <section>
      <h4>RTCDTMFSender</h4>

      <dl class="idl" title="[NoInterfaceObject] interface RTCDTMFSender">
        <dt>void insertDTMF(in DOMString tones, optional unsigned long duration = 100,
        optional unsigned long interToneGap = 70)</dt>

        <dd>
          <p>An <code><a>RTCDTMFSender</a></code> object's <dfn id=
          "dom-RTCDTMFSender-insertDTMF"><code>insertDTMF()</code></dfn> method
          is used to send DTMF tones.</p>

          <p>The tones parameter is treated as a series of characters. The
          characters 0 through 9, A through D, #, and * generate the associated
          DTMF tones. The characters a to d are equivalent to A to D. The
          character ',' indicates a delay of 2 seconds before processing the
          next character in the tones parameter. All other characters MUST be
          considered <dfn id="dtmf-unrecognized">unrecognized</dfn>.
          As noted in [[RTCWEB-AUDIO]] Section 3, support for the characters 0 through 9, #, and *
          are required.</p>

          <p>The duration parameter indicates the duration in ms to use for
          each character passed in the tones parameters. The duration cannot be
          more than 6000 ms or less than 40 ms. The default duration is 100 ms
          for each tone.</p>

          <p>The interToneGap parameter indicates the gap between tones. It
          MUST be at least 30 ms. The default value is 70 ms.</p>

          <p>The browser MAY increase the duration and interToneGap times to
          cause the times that DTMF start and stop to align with the boundaries
          of RTP packets but it MUST not increase either of them by more than
          the duration of a single RTP audio packet.</p>

          <p class="issue">How are invalid values handled? (see also <a href="https://github.com/w3c/webrtc-pc/issues/319">Issue 319</a>)</p>

          <p>When the <code><a>insertDTMF()</a></code> method is invoked, the
          user agent MUST run the following steps:</p>

          <ol>
            <li>Set the object's <code><a href=
            "#dom-RTCDTMFSender-tonebuffer">toneBuffer</a></code> attribute to
            the value of the first argument, the <code><a href=
            "#dom-RTCDTMFSender-duration">duration</a></code> attribute to the
            value of the second argument, and the <code><a href=
            "#dom-RTCDTMFSender-intertonegap">interToneGap</a></code> attribute
            to the value of the third argument.</li>

            <li>If <code><a href=
            "#dom-RTCDTMFSender-tonebuffer">toneBuffer</a></code> contains any
            <a href="#dtmf-unrecognized">unrecognized</a> characters, throw an
            <code>InvalidCharacterError</code> exception and abort these steps.
            </li>

            <li>If <code><a href=
            "#dom-RTCDTMFSender-tonebuffer">toneBuffer</a></code> is an empty
            string, return.</li>

            <li>If the value of the <code><a href=
            "#dom-RTCDTMFSender-duration">duration</a></code> attribute is less
            than 40, set it to 40. If, on the other hand, the value is greater
            than 6000, set it to 6000.</li>

            <li>If the value of the <code><a href=
            "#dom-RTCDTMFSender-intertonegap">interToneGap</a></code> attribute
            is less than 30, set it to 30.</li>

            <li>If a <em>Playout task</em> is scheduled to be run; abort these
            steps; otherwise queue a task that runs the following steps
            (<em>Playout task</em>):

              <ol>
                <li>If <code><a href=
                "#dom-RTCDTMFSender-tonebuffer">toneBuffer</a></code> is an
                empty string, fire an event named <code><a href=
                "#event-RTCDTMFSender-tonechange">tonechange</a></code> with an
                empty string at the <code><a>RTCDTMFSender</a></code> object
                and abort these steps.</li>

                <li>Remove the first character from <code><a href=
                "#dom-RTCDTMFSender-tonebuffer">toneBuffer</a></code> and let
                that character be <var>tone</var>.</li>

                <li>Start playout of <var>tone</var> for <code><a href=
                "#dom-RTCDTMFSender-duration">duration</a></code> ms on the
                associated RTP media stream, using the appropriate codec.</li>

                <li>Queue a task to be executed in <code><a href=
                "#dom-RTCDTMFSender-duration">duration</a></code> +
                <code><a href=
                "#dom-RTCDTMFSender-intertonegap">interToneGap</a></code> ms
                from now that runs the steps labelled <em>Playout
                task</em>.</li>

                <li>Fire an event named <code><a href=
                "#event-RTCDTMFSender-tonechange">tonechange</a></code> with a
                string consisting of <var>tone</var> at the
                <code><a>RTCDTMFSender</a></code> object.</li>
              </ol>
            </li>
          </ol>

          <p>Calling <code><a href=
          "#dom-RTCDTMFSender-insertDTMF">insertDTMF()</a></code> with an empty
          tones parameter can be used to cancel all tones queued to play after
          the currently playing tone.</p>
        </dd>

        <dt>attribute EventHandler ontonechange</dt>

        <dd>
          <p>The event type of this event handler is <code><a>tonechange</a></code>. It returns the
          character for each tone as it is played out. See
          <code><a>RTCDTMFToneChangeEvent</a></code> for details.</p>
        </dd>

        <dt>readonly attribute DOMString toneBuffer</dt>

        <dd>
          <p>The <dfn id=
          "dom-RTCDTMFSender-tonebuffer"><code>toneBuffer</code></dfn>
          attribute MUST return a list of the tones remaining to be played out.
          For the syntax, content, and interpretation of this list, see
          <code><a>insertDTMF</a></code>.</p>
        </dd>

        <dt>readonly attribute long duration</dt>

        <dd>
          <p>The <dfn id=
          "dom-RTCDTMFSender-duration"><code>duration</code></dfn> attribute
          MUST return the current tone duration value. This value will be the
          value last set via the <code><a>insertDTMF()</a></code> method, or
          the default value of 100 ms if <code><a>insertDTMF()</a></code> was
          called without specifying the duration.</p>
        </dd>

        <dt>readonly attribute long interToneGap</dt>

        <dd>
          <p>The <dfn id=
          "dom-RTCDTMFSender-intertonegap"><code>interToneGap</code></dfn>
          attribute MUST return the current value of the between-tone gap. This
          value will be the value last set via the
          <code><a>insertDTMF()</a></code> method, or the default value of 70
          ms if <code><a>insertDTMF()</a></code> was called without specifying
          the interToneGap.</p>
        </dd>
      </dl>
    </section>

    <section>
      <h3>RTCDTMFToneChangeEvent</h3>

      <p>The <code><a href=
      "#event-RTCDTMFSender-tonechange">tonechange</a></code> event uses the
      <code><a>RTCDTMFToneChangeEvent</a></code> interface.</p>

      <p><dfn id="fire-a-tonechange-event" data-lt=
      "fire a tonechange event">Firing a tonechange event named
      <var>e</var></dfn> with a <code>DOMString</code> <var>tone</var> means
      that an event with the name <var>e</var>, which does not bubble (except
      where otherwise stated) and is not cancelable (except where otherwise
      stated), and which uses the <code><a>RTCDTMFToneChangeEvent</a></code>
      interface with the <code><a href=
      "#dom-tonechangeevent-tone">tone</a></code> attribute set to
      <var>tone</var>, MUST be created and dispatched at the given target.</p>

      <dl class="idl" data-merge="RTCDTMFToneChangeEventInit" title=
      "interface RTCDTMFToneChangeEvent : Event">
        <dt>Constructor(DOMString type, RTCDTMFToneChangeEventInit
        eventInitDict)</dt>

        <dt>readonly attribute DOMString tone</dt>

        <dd>
          <p>The <dfn id="dom-tonechangeevent-tone"><code>tone</code></dfn>
          attribute contains the character for the tone that has just begun
          playout (see <code><a>insertDTMF()</a></code> ). If the value is the
          empty string, it indicates that the previous tone has completed
          playback.</p>
        </dd>
      </dl>

      <dl class="idl" title=
      "dictionary RTCDTMFToneChangeEventInit : EventInit">
        <dt>DOMString tone</dt>

        <dd>
          <p class="issue">TODO</p>
        </dd>
      </dl>
    </section>
  </section>

  <section>
    <h2 id="sec.stats-model">Statistics Model</h2>

    <section>
      <h3>Introduction</h3>

      <p>The basic statistics model is that the browser maintains a set of
      statistics referenced by a <dfn id="stats-selector">selector</dfn>. The
      selector may, for example, be a <code>MediaStreamTrack</code>. For a
      track to be a valid selector, it MUST be a
      <code>MediaStreamTrack</code> that is sent or received by the
      <code><a>RTCPeerConnection</a></code> object on which the stats request
      was issued. The calling Web application provides the selector to the
      <code><a href="#widl-RTCPeerConnection-getStats-Promise-RTCStatsReport--MediaStreamTrack-selector">
        getStats()</a></code> method
      and the browser emits (in the JavaScript) a set of statistics that it
      believes is relevant to the selector.</p>

      <div class="issue">
        Evaluate the need for other selectors than MediaStreamTrack.
      </div>

      <p>The statistics returned are designed in such a way that repeated
      queries can be linked by the <code><a>RTCStats</a></code> <a href=
      "#dom-rtcstats-id">id</a> dictionary member. Thus, a Web application can
      make measurements over a given time period by requesting measurements at
      the beginning and end of that period.</p>
    </section>

    <section>
      <h3>RTCPeerConnection Interface Extensions</h3>

      <p>The Statistics API extends the <code><a>RTCPeerConnection</a></code>
      interface as described below.</p>

      <dl class="idl" title="partial interface RTCPeerConnection">
        <dt>Promise&lt;RTCStatsReport&gt; getStats(
          optional MediaStreamTrack? selector = null)</dt>

        <dd>
          <p>Gathers stats for the given <a href="#stats-selector">selector</a>
          and reports the result asynchronously.</p>

          <p>When the <dfn id=
          "#widl-RTCPeerConnection-getStats-Promise-RTCStatsReport--MediaStreamTrack-selector">
            <code>getStats()</code></dfn> method is
          invoked, the user agent MUST run the following steps:</p>

          <ol>
            <li>
              <p>Let <var>selectorArg</var> be the methods first argument.</p>
            </li>

            <li>
              <p>If <var>selectorArg</var> is neither <code>null</code> nor a
              valid <a href="#stats-selector">selector</a>,
              return a promise rejected with a <code>TypeError</code>.</p>
            </li>

            <li>
              <p>Let <var>p</var> be a new promise.</p>
            </li>

            <li>
              <p>Run the following steps in parallel:</p>

              <ol>
                <li>
                  <p>Start gathering the stats indicated by <var>selectorArg</var>.
                  If <var>selectorArg</var> is null, stats MUST be gathered
                  for the whole <code><a>RTCPeerConnection</a></code> object.</p>
                </li>

                <li>
                  <p>When the relevant stats have been gathered, resolve
                  <var>p</var> with a new <code><a>RTCStatsReport</a></code>
                  object, representing the gathered stats.</p>
                </li>
              </ol>
            </li>

            <li>
              <p>Return <var>p</var>.</p>
            </li>
          </ol>
        </dd>
      </dl>
    </section>

    <section>
      <h3>RTCStatsCallback</h3>

      <dl class="idl" title="callback RTCStatsCallback = void">
        <dt>RTCStatsReport report</dt>

        <dd>
          <p>A <code><a>RTCStatsReport</a></code> representing the gathered
          stats.</p>
        </dd>
      </dl>
    </section>

    <section>
      <h3>RTCStatsReport Object</h3>

      <p>The <code><a href="#widl-RTCPeerConnection-getStats-Promise-RTCStatsReport--MediaStreamTrack-selector">
        getStats()</a></code>
      method delivers a successful result in the form of an
      <code><a>RTCStatsReport</a></code> object. An
      <code><a>RTCStatsReport</a></code> object is a map between
      strings that identify the inspected objects (<a href=
      "#dom-rtcstats-id">RTCStats.id</a>), and their corresponding
      <code><a>RTCStats</a></code>-derived dictionaries.</p>

      <p>An <code><a>RTCStatsReport</a></code> may be composed of several
      <code><a>RTCStats</a></code>-derived dictionaries, each reporting stats for one
      underlying object that the implementation thinks is relevant for the
      <a href="#stats-selector">selector</a>. One achieves the total for the
      <a href="#stats-selector">selector</a> by summing over all the stats of a
      certain type; for instance, if a <code>MediaStreamTrack</code> is carried
      by multiple SSRCs over the network, the
      <code><a>RTCStatsReport</a></code> may contain one <code>RTCStats</code>-derived
      dictionary per SSRC (which can be distinguished by the value of the "ssrc"
      stats attribute).</p>

      <dl class="idl" title="interface RTCStatsReport">
        <dt>readonly maplike&lt;DOMString, object&gt;</dt>

        <dd>
          Use these to retrieve the various dictionaries
          descended from <code><a>RTCStats</a></code> that
          this stats report is composed of.
          The set of supported property names [[!WEBIDL]] is defined as the
          ids of all the <code><a>RTCStats</a></code>-derived dictionaries that
          have been generated for this stats report.
        </dd>
      </dl>
    </section>

    <section>
      <h3>RTCStats Dictionary</h3>

      <p>An <code><a>RTCStats</a></code> dictionary represents the stats
      gathered by inspecting a specific object relevant to a <a href=
      "#stats-selector">selector</a>. The <code><a>RTCStats</a></code>
      dictionary is a base type that specifies as set of default attributes,
      such as <a href="#dom-rtcstats-timestamp">timestamp</a> and <a href=
      "#dom-rtcstats-type">type</a>. Specific stats are added by extending the
      <code><a>RTCStats</a></code> dictionary.</p>

      <p>Note that while stats names are standardized, any given implementation
      may be using experimental values or values not yet known to the Web
      application. Thus, applications MUST be prepared to deal with unknown
      stats.</p>

      <div class="issue">
        Need to define an IANA registry for this and populate with
        pointers to existing things such as the RTCP statistics.
      </div>

      <p>Statistics need to be synchronized with each other in order to yield
      reasonable values in computation; for instance, if "bytesSent" and
      "packetsSent" are both reported, they both need to be reported over the
      same interval, so that "average packet size" can be computed as "bytes /
      packets" - if the intervals are different, this will yield errors. Thus
      implementations MUST return synchronized values for all stats in an
      <code><a>RTCStats</a></code>-derived dictionary.</p>

      <dl class="idl" title="dictionary RTCStats">
        <dt>DOMHighResTimeStamp timestamp</dt>

        <dd>
          <p>The <dfn id="dom-rtcstats-timestamp"><code>timestamp</code></dfn>,
          of type <code>DOMHighResTimeStamp</code> [[!HIGHRES-TIME]],
          associated with this object. The time is relative to the UNIX epoch
          (Jan 1, 1970, UTC).</p>
        </dd>

        <dt>RTCStatsType type</dt>

        <dd>
          <p>The type of this object.</p>

          <p>The <dfn id="dom-rtcstats-type"><code>type</code></dfn> attribute
          MUST be initialized to the name of the most specific type this
          <code><a>RTCStats</a></code> dictionary represents.</p>
        </dd>

        <dt>DOMString id</dt>

        <dd>
          <p>A unique <dfn id="dom-rtcstats-id"><code>id</code></dfn> that is
          associated with the object that was inspected to produce this
          <code><a>RTCStats</a></code> object. Two <code><a>RTCStats</a></code>
          objects, extracted from two different
          <code><a>RTCStatsReport</a></code> objects, MUST have the same id if
          they were produced by inspecting the same underlying object. User
          agents are free to pick any format for the id as long as it meets the
          requirements above.</p>

          <div class="issue">
            Consider naming id something that indicates that the id refers to
            the underlying object that was inspected to produce the stats,
            instead of being an id for the JavaScript object. Suggestions:
            statsObjectId, reporterId, srcId.
          </div>
        </dd>
      </dl>

      <dl class="idl" title="enum RTCStatsType">
        <dt>inboundrtp</dt>

        <dd>Inbound RTP.</dd>

        <dt>outboundrtp</dt>

        <dd>Outbound RTP.</dd>
      </dl>
    </section>

    <section>
      <h3>Derived Stats Dictionaries</h3>

      <dl class="idl" title="dictionary RTCRTPStreamStats : RTCStats">
        <dt>DOMString ssrc</dt>

        <dd>
          <p>...</p>
        </dd>

        <dt>DOMString remoteId</dt>

        <dd>
          <p>The <code>remoteId</code> can be used to look up the corresponding
          <code><a>RTCStats</a></code> object that represents stats reported by
          the other peer.</p>
        </dd>
      </dl>

      <dl class="idl" title=
      "dictionary RTCInboundRTPStreamStats : RTCRTPStreamStats">
        <dt>unsigned long packetsReceived</dt>

        <dd>
          <p>...</p>
        </dd>

        <dt>unsigned long bytesReceived</dt>

        <dd>
          <p>...</p>
        </dd>
      </dl>

      <dl class="idl" title=
      "dictionary RTCOutboundRTPStreamStats : RTCRTPStreamStats">
        <dt>unsigned long packetsSent</dt>

        <dd>
          <p>...</p>
        </dd>

        <dt>unsigned long bytesSent</dt>

        <dd>
          <p>...</p>
        </dd>
      </dl>
    </section>

    <section>
      <h3>Example</h3>

      <p>Consider the case where the user is experiencing bad sound and the
      application wants to determine if the cause of it is packet loss. The
      following example code might be used:</p>
      <pre class="example highlight">
var baselineReport, currentReport;
var selector = pc.getSenders()[0].track;

pc.getStats(selector).then(function (report) {
    baselineReport = report;
})
.then(function() {
    return new Promise(function(resolve) {
        setTimeout(resolve, aBit); // ... wait a bit
    });
})
.then(function() {
    return pc.getStats(selector);
})
.then(function (report) {
    currentReport = report;
    processStats();
})
.catch(function (error) {
  log(error.toString());
});

function processStats() {
    // compare the elements from the current report with the baseline
    currentReport.forEach (now => {
        if (now.type != "outboundrtp")
            return;

        // get the corresponding stats from the baseline report
        base = baselineReport.get(now.id);

        if (base) {
            remoteNow = currentReport.get(now.remoteId);
            remoteBase = baselineReport.get(base.remoteId);

            var packetsSent = now.packetsSent - base.packetsSent;
            var packetsReceived = remoteNow.packetsReceived - remoteBase.packetsReceived;

            // if fractionLost is &gt; 0.3, we have probably found the culprit
            var fractionLost = (packetsSent - packetsReceived) / packetsSent;
        }
    }
}
</pre>
    </section>
  </section>

  <section>
    <h2 id="sec.identity-proxy">Identity</h2>

    <section>
      <h3>Identity Provider Interaction</h3>

      <p>WebRTC offers and answers (and hence the channels established by
      <code><a>RTCPeerConnection</a></code> objects) can be authenticated by
      using a web-based Identity Provider (IdP). The idea is that the entity
      sending an offer or answer acts as the Authenticating Party (AP) and
      obtains an identity assertion from the IdP which it attaches to the
      session description. The consumer of the session description (i.e., the
      <code><a>RTCPeerConnection</a></code> on which
      <code>setRemoteDescription()</code> is called) acts as the Relying Party
      (RP) and verifies the assertion.</p>

      <p>The interaction with the IdP is designed to decouple the browser from
      any particular identity provider; the browser need only know how to load
      the IdP's JavaScript, the location of which is determined by the IdP's
      identity, and the generic interface to generating and validating
      assertions. The IdP provides whatever logic is necessary to bridge the
      generic protocol to the IdP's specific requirements. Thus, a single
      browser can support any number of identity protocols, including being
      forward compatible with IdPs which did not exist at the time the browser
      was written.</p>

      <section>
        <h4 id="sec.identity-proxy-communications">Identity Provider
        Selection</h4>

        <p>An IdP is used to generate an identity assertion as
        follows:</p>

        <ol>
          <li>If the <code>setIdentityProvider()</code> method has been called,
          the IdP provided shall be used.</li>

          <li>If the <code>setIdentityProvider()</code> method has not been
          called, then the user agent MAY use an IdP configured into the
          browser.</li>
        </ol>

        <p>In order to verify assertions, the IdP domain name and protocol are
        taken from the <code>domain</code> and <code>protocol</code> fields of
        the identity assertion.</p>
      </section>

      <section>
        <h4 id="sec.create-identity-proxy">Instantiating an IdP Proxy</h4>

        <p>In order to communicate with the IdP, the user agent loads the IdP
        JavaScript from the IdP.   The URI for the IdP script is a
        well-known URI formed from the <q>domain</q> and <q>protocol</q>
        fields, as specified in [[!RTCWEB-SECURITY-ARCH]].</p>

        <p>The IdP MAY generate an HTTP redirect to another "https" origin, the
        browser MUST treat a redirect to any other scheme as a fatal error.</p>

        <p>The user agent instantiates an isolated interpreted context, a
        JavaScript <a
        href="http://people.mozilla.org/~jorendorff/es6-draft.html#sec-code-realms"><dfn>realm</dfn></a>
        that operates in the origin of the loaded JavaScript. Note that a
        redirect will change the origin of the loaded script.</p>

        <p>The <a>realm</a> is populated with a global that implements
        <code>WorkerGlobalScope</code> [[!WEBWORKERS]].</p>

        <p>The user agent provides an instance of
        <code><a>RTCIdentityProviderRegistrar</a></code> named
        <var>rtcIdentityProvider</var> in the global scope of the <a>realm</a>.
        This object is used by the IdP to interact with the user agent.</p>

        <p>A global property can only be set by the <a>user agent</a> or the IdP
        proxy itself.  Therefore, the IdP proxy can be assured that requests it
        receives originate from the <a>user agent</a>.  This ensures that an
        arbitrary origin is unable to instantiate an IdP proxy and impersonate
        this API in order obtain identity assertions.</p>

        <dl class="idl" title="interface RTCIdentityProviderGlobalScope : WorkerGlobalScope">
          <dt>readonly attribute RTCIdentityProviderRegistrar rtcIdentityProvider</dt>
          <dd>
            This object is used by the IdP to register an
            <code><a>RTCIdentityProvider</a></code> instance with the browser.
          </dd>
        </dl>
      </section>
    </section>

    <section>
      <h2 id="sec.register-idp">Registering an IdP Proxy</h2>

      <p>An IdP proxy implements the <code><a>RTCIdentityProvider</a></code>
      callback interface, which is the means by which the user agent is able to
      request that an identity assertion be generated or validated.</p>

      <p>Once instantiated, the IdP script is executed.  The IdP MUST call the
      <code>register()</code> function on the
      <code><a>RTCIdentityProviderRegistrar</a></code> instance during script
      execution.  If an IdP is not registered during this script execution, the
      user agent cannot use the IdP proxy and MUST fail any future attempt to
      interact with the IdP.</p>

      <dl class="idl" title="interface RTCIdentityProviderRegistrar">
        <dt>void register(RTCIdentityProvider idp)</dt>
        <dd>
          <p>This method is invoked by the IdP when its script is first
          executed.  This registers an instance of
          <code><a>RTCIdentityProvider</a></code> with the user agent.</p>
        </dd>
      </dl>

      <section>
        <h2>Interface Exposed by Identity Providers</h2>

        <p>The <code>RTCIdentityProvider</code> interface is exposed by identity
        providers and is called by <code>RTCPeerConnection</code> to acquire or
        validate identity assertions.</p>

        <dl class="idl" title="callback interface RTCIdentityProvider">
          <dt>Promise&lt;RTCIdentityAssertionResult&gt;
          generateAssertion(DOMString contents, DOMString origin,
          optional DOMString usernameHint)</dt>
          <dd>
            <p>A user agent invokes this method on the IdP to request the
            generation of an identity assertion.</p>

            <p>The <var>contents</var> parameter includes the information that the
            user agent wants covered by the identity assertion.  A successful
            validation of the provided assertion MUST produce this string.</p>

            <p>The <var>origin</var> parameter identifies the origin of the
            <code><a>RTCPeerConnection</a></code> that triggered this request.
            An IdP can use this information as input to policy decisions about
            use.  This value is generated by the <a>user agent</a> based on the
            origin of the document that created
            the <code>RTCPeerConnection</code> and therefore can be trusted to
            be correct.</p>

            <p>The IdP selects the identity to assert.  The optional
            <var>usernameHint</var> parameter is the same value that was passed to
            <code>setIdentityProvider</code>.</p>

            <p>The IdP provides a promise that resolves to an
            <code><a>RTCIdentityAssertionResult</a></code> to successfully
            generate an identity assertion. Any other value, or a rejected
            promise, is treated as an error.</p>
          </dd>

          <dt>Promise&lt;RTCIdentityValidationResult&gt;
          validateAssertion(DOMString assertion, DOMString origin)</dt>
          <dd>
            <p>A user agent invokes this method on the IdP to request the
            validation of an identity assertion.</p>

            <p>The <var>assertion</var> parameter includes the assertion that was
            recovered from an <code>a=identity</code> in the session description;
            that is, the value that was part of the
            <code><a>RTCIdentityAssertionResult</a></code> provided by the IdP
            that generated the assertion.</p>

            <p>The <var>origin</var> parameter identifies the origin of the
            <code><a>RTCPeerConnection</a></code> that triggered this request.  An
            IdP can use this information as input to policy decisions about
            use.</p>

            <p>The IdP returns a Promise that resolves to an
            <code><a>RTCIdentityValidationResult</a></code> to successfully
            validate an identity assertion and to provide the actual identity.
            Any other value, or a rejected promise, is treated as an error.</p>
          </dd>
        </dl>
      </section>

      <section>
        <h2>Identity Assertion and Validation Results</h2>

        <dl class="idl" data-merge="RTCIdentityProviderRegistrar"
            title="dictionary RTCIdentityAssertionResult">
          <dt>required RTCIdentityProviderDetails idp</dt>
          <dd>
            <p>An IdP provides these details to identify the IdP that validates
            the identity assertion.  This struct contains the same information
            that is provided to <code>setIdentityProvider</code>.</p>
          </dd>

          <dt>required DOMString assertion</dt>
          <dd>
            <p>An identity assertion.  This is an opaque string that MUST
            contain all information necessary to assert identity.  This value is
            consumed by the validating IdP.</p>
          </dd>
        </dl>

        <dl class="idl" data-merge="RTCIdentityProviderRegistrar"
            title="dictionary RTCIdentityProviderDetails">
          <dt>required DOMString domain</dt>
          <dd>
            <p>The domain name of the IdP that validated the associated identity
            assertion.</p>
          </dd>

          <dt>DOMString protocol = "default"</dt>
          <dd>
            <p>The protocol parameter used for the IdP.</p>
          </dd>
        </dl>

        <dl class="idl" data-merge="RTCIdentityProviderRegistrar"
            title="dictionary RTCIdentityValidationResult">
          <dt>required DOMString identity</dt>
          <dd>
            <p>The validated identity of the peer.</p>
          </dd>

          <dt>required DOMString contents</dt>
          <dd>
            <p>The payload of the identity assertion.  An IdP that validates an
            identity assertion MUST return the same string that was provided to
            the original IdP that generated the assertion.</p>

            <p>The user agent uses the <var>contents</var> string to determine if
            the identity assertion matches the session description.
          </dd>
        </dl>
      </section>
    </section>

    <section>
      <h3 id="sec.identity-proxy-assertion-request">Requesting Identity
      Assertions</h3>

      <p>The identity assertion request process is triggered by a call to
      <code>createOffer</code>, <code>createAnswer</code>, or
      <code>getIdentityAssertion</code>.  When these calls are invoked and an
      identity provider has been set, the following steps are executed:</p>

      <ol>
        <li>
          <p>The <code>RTCPeerConnection</code> instantiates an IdP as described
          in <a href="#sec.identity-proxy-communications">Identity Provider Selection</a> and <a
          href="#sec.register-idp">Registering an IdP Proxy</a>.  If the IdP cannot be loaded,
          instantiated, or the IdP proxy is not registered, this process
          fails.</p>
        </li>

        <li>
          <p>The <code>RTCPeerConnection</code> invokes the <code><a
          href="#widl-RTCIdentityProvider-generateAssertion-Promise-RTCIdentityAssertionResult--DOMString-contents-DOMString-origin-DOMString-usernameHint">generateAssertion</a></code>
          method on the <code><a>RTCIdentityProvider</a></code> instance
          registered by the IdP.</p>

          <p>The <code>RTCPeerConnection</code> generates the
          <var>contents</var> parameter to this method as described in
          [[!RTCWEB-SECURITY-ARCH]].  The value of <var>contents</var> includes
          the fingerprint of the certificate that was selected or generated
          during the construction of the <code>RTCPeerConnection</code>.
          The <var>origin</var> parameter contains the origin of the script that
          calls the <code>RTCPeerConnection</code> method that triggers this
          behavior.  The <var>usernameHint</var> value is the same value that is
          provided to
          <code>setIdentityProvider</code>, if any such value was provided.</p>
        </li>

        <li>
          <p>The IdP returns a Promise to the <code>RTCPeerConnection</code>.
          If the user has been authenticated by the IdP, and the IdP is willing
          to generate an identity assertion, the IdP resolves the promise with
          an identity assertion in the form of an
          <code><a>RTCIdentityAssertionResult</a></code>.</p>

          <p>This step depends entirely on the IdP. The methods by which an IdP
          authenticates users or generates assertions is not specified, though
          they could involve interacting with the IdP server or other
          servers.</p>
        </li>

        <li>
          <p>The <code>RTCPeerConnection</code> MAY store the identity assertion
          for use with future offers or answers.  If a fresh identity assertion
          is needed for any reason, applications can create a
          new <code>RTCPeerConnection</code>.</p>
        </li>

        <li>
          <p>If the identity request was triggered by a
          <code>createOffer()</code> or <code>createAnswer()</code>, then the
          assertion is converted to a JSON string, base64-encoded and inserted
          into an <code>a=identity</code> attribute in the session
          description.</p>
        </li>
      </ol>

      <p>This process can fail.  The IdP proxy MAY reject the promise, or the
      process of loading and registering the IdP could fail.  If assertion
      generation fails, then the promise for the corresponding function call is
      rejected.</p>

      <p>The browser SHOULD limit the time that it will allow for this process.
      This includes both the loading of the <a href=
      "#sec.identity-proxy-communications">IdP proxy</a> and the identity
      assertion generation. Failure to do so potentially causes the
      corresponding operation to take an indefinite amount of time. This timer
      can be cancelled when the IdP produces a response. The timer running to
      completion can be treated as equivalent to an error from the IdP.</p>

      <section>
        <h4 id="sec.idp-loginneeded">User Login Procedure</h4>

        <p>An IdP MAY reject an attempt to generate an identity assertion if it
        is unable to verify that a user is authenticated. This might be due to
        the IdP not having the necessary authentication information available to
        it (such as cookies).</p>

        <p>Rejecting the promise returned by <code><a
        href="#widl-RTCIdentityProvider-generateAssertion-Promise-RTCIdentityAssertionResult--DOMString-contents-DOMString-origin-DOMString-usernameHint">generateAssertion</a></code>
        will cause the error to propagate to the application.  Login errors are
        indicated by rejecting the promise with an object that has a
        <code>name</code> attribute set to "IdpLoginError".</p>

        <p>If the rejection object also contains a <code>loginUrl</code>
        attribute, this value will be passed to the application in
        the <code>idpLoginUrl</code> attribute. This URL might link to page
        where a user can enter their (IdP) username and password, or otherwise
        provide any information the IdP needs to authorize a assertion
        request.</p>

        <p>An application can load the login URL in an IFRAME or popup window;
        the resulting page then SHOULD provide the user with an opportunity to
        enter any information necessary to complete the authorization process.</p>

        <p>Once the authorization process is complete, the page loaded in the
        IFRAME or popup sends a message using <var>postMessage</var>
        [[!webmessaging]] to the page that loaded it (through the <var><a href=
        "http://www.w3.org/html/wg/drafts/html/master/browsers.html#dom-opener">
        window.opener</a></var> attribute for popups, or through <var><a href=
        "http://www.w3.org/html/wg/drafts/html/master/browsers.html#dom-parent">
        window.parent</a></var> for pages loaded in an IFRAME). The message MUST
        consist of the <var>DOMString</var> "LOGINDONE". This message informs
        the application that another attempt at generating an identity assertion
        is likely to be successful.</p>
      </section>
    </section>

    <section>
      <h3 id="sec.identity-verify-assertion">Verifying Identity Assertions</h3>

      <p>Identity assertion validation happens when <code><a href=
      "#dom-peerconnection-setremotedescription">setRemoteDescription</a></code>
      is invoked on <code><a>RTCPeerConnection</a></code>. The process runs
      asynchronously, meaning that validation of an identity assertion might not
      block the completion of <code>setRemoteDescription</code>.</p>

      <p>The identity assertion request process involves the following
      asynchronous steps:</p>

      <ol>
        <li>
          <p>The <code>RTCPeerConnection</code> awaits any prior identity
          validation.  Only one identity validation can run at a time for an
          <code>RTCPeerConnection</code>.  This can happen because the
          resolution of <code>setRemoteDescription</code> is not blocked by
          identity validation unless there is
          a <a href="#target-peer-identity">target peer identity</a>.
        </li>
        <li>
          <p>The <code>RTCPeerConnection</code> loads the identity assertion
          from the session description and decodes the base64 value, then parses
          the resulting JSON.  The <var>idp</var> parameter of the resulting
          dictionary contains a <var>domain</var> and an optional
          <var>protocol</var> value that identifies the IdP, as described in
          [[!RTCWEB-SECURITY-ARCH]].</p>
        </li>
        <li>
          <p>The <code>RTCPeerConnection</code> instantiates the identified IdP
          as described in <a href="#sec.identity-proxy-communications"></a> and
          <a href="#sec.register-idp"></a>.  If the IdP cannot be loaded,
          instantiated or the IdP proxy is not registered, this process
          fails.</p>
        </li>

        <li>
          <p>The <code>RTCPeerConnection</code> invokes the <code><a
          href="#widl-RTCIdentityProvider-validateAssertion-Promise-RTCIdentityValidationResult--DOMString-assertion-DOMString-origin">validateAssertion</a></code>
          method on the <code><a>RTCIdentityProvider</a></code> instance
          registered by the IdP.</p>

          <p>The <var>assertion</var> parameter is taken from the decoded
          identity assertion.  The <var>origin</var> parameter contains the
          origin of the script that calls the <code>RTCPeerConnection</code>
          method that triggers this behavior.
        </li>

        <li>
          <p>The IdP proxy returns a promise and performs the validation process
          asynchronously.</p>
          <p>The IdP proxy verifies the identity assertion using whatever means
          necessary.  Depending on the authentication protocol this could
          involve interacting with the IDP server.</p>
        </li>

        <li>
          <p>Once the assertion is successfully verified, the IdP proxy resolves
          the promise with an <code><a>RTCIdentityValidationResult</a></code>
          containing the validated identity and the original contents that are
          the payload of the assertion.</p>
        </li>

        <li>
          <p>The <code>RTCPeerConnection</code> decodes the contents and
          validates that it contains a fingerprint value for every
          <code>a=fingerprint</code> attribute in the session description.  This
          ensures that the certificate used by the remote peer for
          communications is covered by the identity assertion.</p>

          <p>If a peer offers a certificate that doesn't match
          an <code>a=fingerprint</code> line in the negotiated session
          description, the <a>user agent</a> MUST NOT permit communication with
          that peer.</p>
        </li>

        <li>
          <p>The <code>RTCPeerConnection</code> validates that the domain
          portion of the identity matches the domain of the IdP as described in
          [[!RTCWEB-SECURITY-ARCH]].</p>
        </li>

        <li>
          <p>The <code>RTCPeerConnection</code> resolves the <code><a href=
          "#widl-RTCPeerConnection-peerIdentity">peerIdentity</a></code>
          attribute with a new instance of <code>RTCIdentityAssertion</code>
          that includes the IdP domain and peer identity.</p>
        </li>

        <li>
          <p>The browser MAY display identity information to a user in browser
          UI. Any user identity information that is displayed in this fashion
          MUST use a mechanism that cannot be spoofed by content.</p>
        </li>
      </ol>

      <p>This process can fail at any step above.  If identity validation fails,
      the <code><a href=
      "#widl-RTCPeerConnection-peerIdentity">peerIdentity</a></code> promise is
      rejected with a <code>DOMError</code> that has a name of
      <code>IdpError</code>.</p>

      <p>If identity validation fails and there is
      a <a href="#target-peer-identity">target peer identity</a> for the
      <code>RTCPeerConnection</code>, the promise returned by
      <code>setRemoteDescription</code> MUST be rejected.</p>

      <p>If identity validation fails and there is no a <a
      href="#target-peer-identity">target peer identity</a>, the value of the
      <code><a href=
      "#widl-RTCPeerConnection-peerIdentity">peerIdentity</a></code> MUST be set
      to a new, unresolved promise instance.  This permits the use of
      renegotiation (or a subsequent answer, if the session description was a
      provisional answer) to resolve or reject the identity.</p>

      <p>The browser SHOULD limit the time that it will allow for identity
      validation.  This includes both the loading of the <a href=
      "#sec.identity-proxy-communications">IdP proxy</a> and the identity
      assertion validation. Failure to do so potentially causes the operation to
      take an indefinite amount of time. This timer can be cancelled when the
      IdP produces a response. The timer running to completion is treated as
      equivalent to an error from the IdP.</p>
    </section>

    <section>
      <h3>RTCPeerConnection Interface Extensions</h3>

      <p>The Identity API extends the <code><a>RTCPeerConnection</a></code>
      interface as described below.</p>

      <dl class="idl" title="partial interface RTCPeerConnection">
        <dt>void setIdentityProvider(DOMString provider, optional DOMString
        protocol, optional DOMString usernameHint)</dt>

        <dd>
          <p>Sets the identity provider to be used for a given
          <code>RTCPeerConnection</code> object. Applications need not make this
          call; if the browser is already configured for an IdP, then that
          configured IdP might be used to get an assertion.</p>

          <p>When the <dfn
          id="dom-peerconnection-setidentityprovider"><code>setIdentityProvider()</code></dfn>
          method is invoked, the user agent MUST run the following steps:</p>

          <ol>
            <li>
              <p>If the <var>connection</var>'s <a href=
              "#dom-peerconnection-signaling-state"><code>RTCPeerConnection</code>
              signalingState</a> is <code>closed</code>, throw an
              <code>InvalidStateError</code> exception and abort these
              steps.</p>
            </li>

            <li>
              <p>Set the current identity provider values to the triplet
              (<code>provider</code>, <code>protocol</code>,
              <code>usernameHint</code>).</p>
            </li>

            <li>
              <p>If any identity provider value has changed, discard any stored
              identity assertion.</p>
            </li>
          </ol>

          <p>Identity provider information is not used until an identity
          assertion is required, either in response to a call to
          <code>getIdentityAssertion</code>, or a session description is
          requested with a call to either <code>createOffer</code> or
          <code>createAnswer</code>.</p>
        </dd>

        <dt>Promise&lt;DOMString&gt; getIdentityAssertion()</dt>

        <dd>
          <p>Initiates the process of obtaining an identity assertion.
          Applications need not make this call. It is merely intended to allow
          them to start the process of obtaining identity assertions before a
          call is initiated. If an identity is needed, either because the
          browser has been configured with a default identity provider or
          because the <code>setIdentityProvider()</code> method was called,
          then an identity will be automatically requested when an offer or
          answer is created.</p>

          <p>When <code>getIdentityAssertion</code> is invoked, queue a task to
          run the following steps:</p>

          <ol>
            <li>
              <p>If the <var>connection</var>'s <a href=
              "#dom-peerconnection-signaling-state"><code>RTCPeerConnection</code>
              signalingState</a> is <code>closed</code>, abort these steps.</p>
            </li>

            <li>
              <p><a href="#sec.identity-proxy-assertion-request">Request an
              identity assertion</a> from the IdP.</p>
            </li>
            <li>
              <p>Resolve the promise with the base64 and JSON encoded
              assertion.</p>
            </li>
          </ol>
        </dd>

        <dt>readonly attribute Promise&lt;RTCIdentityAssertion&gt; peerIdentity</dt>

        <dd>
          <p>A promise that resolves with the identity of the peer if the
          identity is successfully validated.</p>

          <p>This promise is rejected if an identity assertion is present in a
          remote session description and validation of that assertion fails for
          any reason.  If the promise is rejected, a new unresolved value is
          created, unless there a <a href="#target-peer-identity">target peer
          identity</a> has been established.  If this promise successfully
          resolves, the value will not change.</p>
        </dd>

        <dt>readonly attribute DOMString? idpLoginUrl</dt>

        <dd>
          <p>The URL that an application can navigate to so that the user can
          login to the IdP, as described
          in <a href="#sec.idp-loginneeded"></a>.</p>
        </dd>
      </dl>

      <dl class="idl"
          title="[Constructor(DOMString idp, DOMString name)] interface RTCIdentityAssertion">
        <dt>attribute DOMString idp</dt>

        <dd>
          <p>The domain name of the identity provider that validated this identity.</p>
        </dd>

        <dt>attribute DOMString name</dt>

        <dd>
          <p>An RFC5322-conformant [[RFC5322]] representation of the verified
          peer identity. This identity will have been verified via the
          procedures described in [[!RTCWEB-SECURITY-ARCH]].</p>
        </dd>
      </dl>
    </section>

    <section>
      <h3>Examples</h3>

      <p>The identity system is designed so that applications need not take any
      special action in order for users to generate and verify identity
      assertions; if a user has configured an IdP into their browser, then the
      browser will automatically request/generate assertions and the other side
      will automatically verify them and display the results. However,
      applications may wish to exercise tighter control over the identity
      system as shown by the following examples.</p>

      <div>
        <p>This example shows how to configure the identity provider and
        protocol.</p>
        <pre class="example highlight">
  pc.setIdentityProvider("example.com", "default", "alice@example.com");
</pre>
      </div>

      <div>
        <p>This example shows how to consume identity assertions inside a Web
        application.</p>
        <pre class="example highlight">
  pc.peerIdentity.then(identity =>
    console.log("IdP= " + identity.idp + " identity=" + identity.name));
</pre>
      </div>
    </section>
  </section>

  <section>
    <h2>Media Stream API Extensions for Network Use</h2>

    <section>
      <h3>Introduction</h3>

      <p>The <code>MediaStreamTrack</code> interface, as defined in the
      [[!GETUSERMEDIA]] specification, typically represents a stream of data of
      audio or video. One or more <code>MediaStreamTrack</code>s can be
      collected in a <code>MediaStream</code> (strictly speaking, a <code>
      MediaStream</code> as defined in [[!GETUSERMEDIA]] may contain
      zero or more <code>MediaStreamTrack</code> objects).</p>

      <p>A <code>MediaStreamTrack</code> may be extended to
      represent a media flow that either comes from or is sent to a remote peer
      (and not just the local camera, for instance). The extensions required to
      enable this capability on the <code>MediaStreamTrack</code> object will be
      described in this section. How the media is transmitted to the peer is
      described in [[!RTCWEB-RTP]], [[!RTCWEB-AUDIO]], and
      [[!RTCWEB-TRANSPORT]].</p>

      <p>A <code>MediaStreamTrack</code> sent to another peer will appear as one and
      only one <code>MediaStreamTrack</code> to the recipient. A peer is
      defined as a user agent that supports this specification.
      In addition, the sending side application can indicate what <code>
      MediaStream</code> object(s) the <code>MediaStreamTrack</code> is member
      of. The corresponding <code>MediaStream</code> object(s) on the receiver
      side will be created (if not already present) and populated accordingly.</p>

      <p>As also described earlier in this document, the objects <code>
      RTCRtpSender</code> and <code>RTCRtpReceiver</code> can be used by the
      application to get more fine grained control over the transmission and
      reception of <code>MediaStreamTrack</code>s.</p>

      <p>Channels are the smallest unit considered in the
      <code>MediaStream</code> specification. Channels are intended to be
      encoded together for transmission as, for instance, an RTP payload type.
      All of the channels that a codec needs to encode jointly MUST be in the
      same <code>MediaStreamTrack</code> and the codecs SHOULD be able to
      encode, or discard, all the channels in the track.</p>

      <p>The concepts of an input and output to a given
      <code>MediaStreamTrack</code> apply in the case of <code>MediaStreamTrack</code>
      objects transmitted over the network as well. A
      <code><a>MediaStreamTrack</a></code> created by an
      <code><a>RTCPeerConnection</a></code> object (as described previously in this
      document) will take as input the data received from a remote peer.
      Similarly, a <code>MediaStreamTrack</code> from a local source, for instance a
      camera via [[!GETUSERMEDIA]], will have an output that represents what is
      transmitted to a remote peer if the object is used with an
      <code><a>RTCPeerConnection</a></code> object.</p>

      <p>The concept of duplicating <code>MediaStream</code> and
      <code>MediaStreamTrack</code> objects as described in [[!GETUSERMEDIA]] is
      also applicable here. This feature can be used, for instance, in a
      video-conferencing scenario to display the
      local video from the user's camera and microphone in a local
      monitor, while only transmitting the audio to the remote peer (e.g. in
      response to the user using a "video mute" feature). Combining
      different <code>MediaStreamTrack</code> objects into new <code>MediaStream</code>
      objects is useful in certain situations.</p>

      <p class="note">In this document, we only specify aspects of the
      following objects that are relevant when used along with an
      <code><a>RTCPeerConnection</a></code>. Please refer to the original
      definitions of the objects in the [[!GETUSERMEDIA]] document for general
      information on using <code>MediaStream</code> and
      <code>MediaStreamTrack</code>.</p>
    </section>

    <section>
      <h3>MediaStream</h3>

      <section>
        <h4>id</h4>

        <p>The <code><a href=
        "https://w3c.github.io/mediacapture-main/#dom-mediastream-id">id</a></code> attribute
        specified in <code>MediaStream</code> returns an id that is unique to
        this stream, so that streams can be recognized at the
        remote end of the <code><a href=
        "#rtcpeerconnection-interface">RTCPeerConnection</a></code> API.</p>

        <p>When a <code><a href="#mediastream">MediaStream</a></code> is
        created to represent a stream obtained from a remote peer, the
        <code><a href="https://w3c.github.io/mediacapture-main/#dom-mediastream-id">id</a></code>
        attribute is initialized from information provided by the remote
        source.</p>

        <p class="note">The id of a <code><a>MediaStream</a></code> object is
        unique to the source of the stream, but that does not mean it is not
        possible to end up with duplicates. For example, the tracks of a locally generated
        stream could be sent from one user agent to a remote peer using
        <code><a>RTCPeerConnection</a></code> and then sent back to the
        original user agent in the same manner, in which case the original user
        agent will have multiple streams with the same id (the
        locally-generated one and the one received from the remote peer).</p>
      </section>
    </section>

    <section>
      <h3>MediaStreamTrack</h3>

      <p>A <code>MediaStreamTrack</code> object's reference to its
      <code>MediaStream</code> in the non-local media source case (an RTP
      source, as is the case for <code>MediaStreamTrack</code>s received over an
      <code><a>RTCPeerConnection</a></code> ) is always strong.</p>

      <p>When an <code><a>RTCPeerConnection</a></code> receives data on an RTP
      source for the first time, it MUST <a href="#update-track-muted">update
      the muted state</a> of the corresponding <code><a>MediaStreamTrack</a>
      </code> with the value <code>false</code>.</p>

      <p>When an <code><a>RTCPeerConnection</a></code>'s RTP source is
      temporarily unable to receive media due to a loss of connection or if a
      mute signal has been received, it MUST <a href=
      "#update-track-muted">update the muted state</a> of the corresponding
      <code><a>MediaStreamTrack</a></code> with the value <code>true</code>.
      When media data is available again, the <a href=
      "#update-track-muted">muted state MUST be updated</a> with the value
      <code>false</code>.</p>

      <p class="issue">The mute signal mentioned in the previous paragraph
      is yet to be defined.</p>

      <p>The procedure <dfn id="update-track-muted">update a track's muted
      state</dfn> is specified in [[!GETUSERMEDIA]].</p>

      <p>When a track comes
      from a remote peer and the remote peer has permanently stopped sending
      data the <code>ended</code> event MUST be fired on the track, as
      specified in [[!GETUSERMEDIA]].</p>

      <p class="issue">How do you know when it has stopped? This seems
      like an SDP question, not a media-level question. (Suggestion: when the
      track is ended, either through port 0, or removing the a=msid attrib)</p>
    </section>

    <section>
      <h3>Isolated Media Streams</h3>

      <p>A MediaStream acquired using <code>getUserMedia()</code> is, by
      default, accessible to an application. This means that the application is
      able to access the contents of tracks, modify their content, and send
      that media to any peer it chooses.</p>

      <p>WebRTC supports calling scenarios where media is sent to a
      specifically identified peer, without the contents of media streams being
      accessible to applications. This is enabled by use of the
      <code>peerIdentity</code> parameter to
      <code>getUserMedia()</code>.</p>

      <p>An application willingly relinquishes access to media by including a
      <code>peerIdentity</code> parameter in the
      <code>MediaStreamConstraints</code>. This attribute is set to a
      <code>DOMString</code> containing the identity of a specific peer.</p>

      <p>The <code>MediaStreamConstraints</code> dictionary is
      expanded to include the <code>peerIdentity</code> parameter.</p>

      <dl class="idl" title="partial dictionary MediaStreamConstraints">
        <dt>DOMString peerIdentity</dt>

        <dd>
          <p>If set, <code>peerIdentity</code> isolates media from the
          application. Media can only be sent to the identified peer.</p>
        </dd>
      </dl>

      <p>A user that is prompted to provide consent for access to a camera or
      microphone can be shown the value of the <code>peerIdentity</code>
      parameter, so that they can be informed that the consent is more narrowly
      restricted.</p>

      <p>When the <code><dfn>peerIdentity</dfn></code> option is supplied to
      <code>getUserMedia()</code>, all of the <code>MediaStreamTrack</code>s in
      the resulting <code>MediaStream</code> are isolated so that content is
      not accessible to any application. Isolated
      <code>MediaStreamTrack</code>s can be used for two purposes:</p>

      <ul>
        <li>
          <p>Displayed in an appropriate media tag (e.g., a video or audio
          element). The browser MUST ensure that content is inaccessible to the
          application by ensuring that the resulting content is given the same
          protections as content that is <a href=
          "http://www.w3.org/html/wg/drafts/html/master/infrastructure.html#cors-cross-origin">
          CORS cross-origin</a>, as described in the relevant <a href=
          "http://www.w3.org/html/wg/drafts/html/master/semantics.html#security-and-privacy-considerations">
          Security and privacy considerations section</a> of [[HTML5]].</p>
        </li>

        <li>
          <p>Used as the argument to <a href=
          "#widl-RTCPeerConnection-addTrack-RTCRtpSender-MediaStreamTrack-track-MediaStream-streams">addTrack()</a>
          on an <code><a>RTCPeerConnection</a></code> instance, subject to the
          restrictions in <a href="#isolated-pc">isolated streams and RTCPeerConnection</a>.</p>
        </li>
      </ul>

      <p>A <code>MediaStreamTrack</code> that is added to another
      <code>MediaStream</code> remains isolated. When an isolated
      <code>MediaStreamTrack</code> is added to a <code>MediaStream</code> with
      a different peerIdentity, the <code>MediaStream</code> gets a combination
      of isolation restrictions. A <code>MediaStream</code> containing
      <code>MediaStreamTrack</code> instances with mixed isolation properties
      can be displayed, but cannot be sent using
      <code><a>RTCPeerConnection</a></code>.</p>

      <p>Any <code>peerIdentity</code> property MUST be retained on cloned
      copies of <code>MediaStreamTrack</code>s.</p>
      <!-- Any stream or track that might be derived from an isolated stream,
           such as
           through <a href="https://www.w3.org/TR/streamproc/#media-element-extensions">captureStreamUntilEnded
           or captureStream</a>, MUST also retain any isolation protections.
        -->

      <section id="isolated-track">
        <h4>Extended MediaStreamTrack Properties</h4>

        <p><code>MediaStreamTrack</code> is expanded to include an
        <var>isolated</var> attribute and a corresponding event. This allows an
        application to quickly and easily determine whether a track is
        accessible.</p>

        <dl class="idl" title="partial interface MediaStreamTrack">
          <dt>readonly attribute boolean isolated</dt>

          <dd>
            <p>A <code>MediaStreamTrack</code> is isolated (and the
            corresponding <var>isolated</var> attribute set to <var>true</var>)
            when content is inaccessible to the owning document. This occurs as
            a result of setting the <var>peerIdentity</var> option. A track is
            also isolated if it comes from a cross origin source.</p>
          </dd>

          <dt>attribute EventHandler onisolationchange</dt>

          <dd>
            <p>This event handler, of type <a href=
            "#event-isolationchange">isolationchange</a>, is fired when the
            value of the <var>isolated</var> attribute changes.</p>
          </dd>
        </dl>
      </section>

      <section id="isolated-pc">
        <h4>Isolated Streams and RTCPeerConnection</h4>

        <p>A <code>MediaStreamTrack</code> with a <var>peerIdentity</var>
        option set can be added to any <code><a>RTCPeerConnection</a></code>.
        However, the content of an isolated track MUST NOT be transmitted
        unless all of the following constraints are met:</p>

        <ul>
          <li>
            <p>A <code>MediaStreamTrack</code> from a stream acquired using the
            <var>peerIdentity</var> option can be transmitted if the
            <code><a>RTCPeerConnection</a></code> has successfully <a href=
            "#sec.identity-verify-assertion">validated the identity</a> of the
            peer AND that identity is the same identity that was used in the
            <var>peerIdentity</var> option associated with the track. That is,
            the <code>name</code> attribute of the <code>peerIdentity</code>
            attribute of the <code><a>RTCPeerConnection</a></code> instance
            MUST match the value of the <code>peerIdentity</code> option passed
            to <code>getUserMedia()</code>.</p>

            <p>Rules for matching identity are described in
            [[!RTCWEB-SECURITY-ARCH]].</p>
          </li>

          <li>
            <p>The peer has indicated that it will respect the isolation
            properties of streams. That is, a DTLS connection with a promise to
            respect stream confidentiality, as defined in [[!RTCWEB-ALPN]] has
            been established.</p>
          </li>
        </ul>

        <p>Failing to meet these conditions means that no media can be sent for
        the affected <code>MediaStreamTrack</code>. Video MUST be replaced by
        black frames, audio MUST be replaced by silence, and equivalently
        information-free content MUST be provided for other media types.</p>

        <p>Remotely sourced <code>MediaStreamTrack</code>s MUST be isolated if
        they are received over a DTLS connection that has been negotiated with
        track isolation. This protects isolated media from the application in
        the receiving browser. These tracks MUST only be displayed to a user
        using the appropriate media element (e.g., &lt;video&gt; or
        &lt;audio&gt;).</p>

        <p>Any <code>MediaStreamTrack</code> that has the
        <var>peerIdentity</var> option set causes all tracks sent using the
        same <code><a>RTCPeerConnection</a></code> to be isolated at the
        receiving peer. All DTLS connections created for a
        <code><a>RTCPeerConnection</a></code> with isolated local streams MUST
        be negotiated so that media remains isolated at the remote peer. This
        causes non-isolated media to become isolated at the receiving peer if
        any isolated tracks are added to the same
        <code><a>RTCPeerConnection</a></code>.</p>

        <p class="note">Tracks that are not bound to a particular
        <var>peerIdentity</var> do not cause other streams to be isolated,
        these tracks simply do not have their content transmitted.</p>

        <p>If a stream becomes isolated after initially being accessible, or an
        isolated stream is added to an active session, then media for that
        stream is replaced by information-free content (e.g., black frames or
        silence).</p>
      </section>

      <section id="isolation-protection">
        <h4>Protection Afforded by Media Isolation</h4>

        <p>Media isolation ensures that the content of a
        <code>MediaStreamTrack</code> is not accessible to web applications.
        However, to ensure that media with a <var>peerIdentity</var> option set
        can be sent to peers, some meta-information about the media will be
        exposed to applications.</p>

        <p>Applications will be able to observe the parameters of the media
        that affect session negotiation and conversion into RTP. This includes
        the codecs that might be supported by the track, the bitrate, the
        number of packets, and the current settings that are set on the
        <code>MediaStreamTrack</code>.</p>

        <p>In particular, the <a href="#sec.stats-model">statistics</a> that
        <code><a>RTCPeerConnection</a></code> records are not reduced in
        capability. New statistics that might compromise isolation MUST be
        avoided, or explicitly suppressed for isolated streams.</p>

        <p>Most of these data are exposed to the network when the media is
        transmitted. Only the settings for the <code>MediaStreamTrack</code>
        present a new source of information. This can includes the frame rate
        and resolution of video tracks, the bandwidth of audio tracks, and
        other information about the source, which would not otherwise be
        revealed to a network observer. Since settings don't change at a high
        frequency or in response to changes in media content, settings only
        reveal limited reveal information about the content of a track.
        However, any setting that might change dynamically in response to the
        content of an isolated <code>MediaStreamTrack</code> MUST have changes
        suppressed.</p>
      </section>
    </section>
  </section>

  <section class="informative">
    <h2>Examples and Call Flows</h2>

    <section>
      <h3>Simple Peer-to-peer Example</h3>

      <div>
        <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 class="example highlight">

var signalingChannel = new SignalingChannel();
var configuration = { "iceServers": [{ "urls": "stuns:stun.example.org" }] };
var pc;

// call start() to initiate
function start() {
    pc = new RTCPeerConnection(configuration);

    // send any ice candidates to the other peer
    pc.onicecandidate = function (evt) {
        if (evt.candidate)
            signalingChannel.send(JSON.stringify({ "candidate": evt.candidate }));
    };

    // let the "negotiationneeded" event trigger offer generation
    pc.onnegotiationneeded = function () {
        pc.createOffer().then(function (offer) {
            return pc.setLocalDescription(offer);
        })
        .then(function () {
            // send the offer to the other peer
            signalingChannel.send(JSON.stringify({ "desc": pc.localDescription }));
        })
        .catch(logError);
    };

    // once remote video track arrives, show it in the remote video element
    pc.ontrack = function (evt) {
        if (evt.track.kind === "video")
          remoteView.srcObject = evt.streams[0];
    };

    // get a local stream, show it in a self-view and add it to be sent
    navigator.mediaDevices.getUserMedia({ "audio": true, "video": true }, function (stream) {
        selfView.srcObject = stream;
        if (stream.getAudioTracks().length > 0)
            pc.addTrack(stream.getAudioTracks()[0], stream);
        if (stream.getVideoTracks().length > 0)
            pc.addTrack(stream.getVideoTracks()[0], stream);
    }, logError);
}

signalingChannel.onmessage = function (evt) {
    if (!pc)
        start();

    var message = JSON.parse(evt.data);
    if (message.desc) {
        var desc = message.desc;

        // if we get an offer, we need to reply with an answer
        if (desc.type == "offer") {
            pc.setRemoteDescription(desc).then(function () {
                return pc.createAnswer();
            })
            .then(function (answer) {
                return pc.setLocalDescription(answer);
            })
            .then(function () {
                signalingChannel.send(JSON.stringify({ "desc": pc.localDescription }));
            })
            .catch(logError);
        } else
            pc.setRemoteDescription(desc).catch(logError);
    } else
        pc.addIceCandidate(message.candidate).catch(logError);
};

function logError(error) {
    log(error.name + ": " + error.message);
}

</pre>
      </div>
    </section>

    <section>
      <h3>Simple Peer-to-peer Example with Warm-up</h3>

      <div>
        <p>When two peers decide they are going to set up a connection
        to each other and want to have the ICE, DTLS, and media
        connections "warmed up" such that they are ready to send and
        receive media immediately, they both go through these
        steps. </p>
        <pre class="example highlight">

var signalingChannel = new SignalingChannel();
var configuration = { "iceServers": [{ "urls": "stuns:stun.example.org" }] };
var pc;
var audio = null;
var audioSendTrack = null;
var video = null;
var videoSendTrack = null;
var started = false;

// Call warmp() to warm-up ICE, DTLS, and media, but not send media yet.
function warmup(answerer) {
    pc = new RTCPeerConnection(configuration);
    if (!answerer) {
      audio = pc.addTransceiver("audio");
      video = pc.addTransceiver("video");
    }

    // send any ice candidates to the other peer
    pc.onicecandidate = function (evt) {
        if (evt.candidate)
            signalingChannel.send(JSON.stringify({ "candidate": evt.candidate }));
    };

    // let the "negotiationneeded" event trigger offer generation
    pc.onnegotiationneeded = function () {
        pc.createOffer().then(function (offer) {
            return pc.setLocalDescription(offer);
        })
        .then(function () {
            // send the offer to the other peer
            signalingChannel.send(JSON.stringify({ "desc": pc.localDescription }));
        })
        .catch(logError);
    };

    // once remote video track arrives, show it in the remote video element
    pc.ontrack = function (evt) {
        if (evt.track.kind === "audio") {
          if (answerer) {
            // TODO: Figure out how to reuse an existing m-line with something like:
            // audio = evt.transceiver;
            // audio.sender.activate();
            // This avoids the need for an extra re-offer.
            // Similarly for video.
            audio = pc.addTransceiver(evt.track.kind);
            if (started && audioSendTrack) {
              audio.sender.replaceTrack(audioSendTrack);
            }
          }
        } else if (evt.track.kind === "video") {
          if (answerer) {
            audio = pc.addTransceiver(evt.track.kind);
            if (started && videoSendTrack) {
              video.sender.replaceTrack(audioSendTrack);
            }
          }
          remoteView.srcObject = evt.streams[0];
        }
    };

    // get a local stream, show it in a self-view and add it to be sent
    navigator.mediaDevices.getUserMedia({ "audio": true, "video": true }, function (stream) {
        selfView.srcObject = stream;
        if (stream.getAudioTracks().length > 0) {
          sendAudioTrack = stream.getVideoTracks()[0];
          if (started) {
            audio.sender.replaceTrack(sendAudioTrack);
          }
        }
        if (stream.getVideoTracks().length > 0) {
          sendVideoTrack = stream.getVideoTracks()[0];
          if (started) {
            video.sender.replaceTrack(sendVideoTrack);
          }
        }
    }, logError);
}

// Call start() to start sending media.
function start() {
  started = true;
  signalingChannel.send(JSON.stringify({ "start": true }));
}

signalingChannel.onmessage = function (evt) {
    if (!pc)
        warmup(true);

    var message = JSON.parse(evt.data);
    if (message.desc) {
        var desc = message.desc;

        // if we get an offer, we need to reply with an answer
        if (desc.type == "offer") {
            pc.setRemoteDescription(desc).then(function () {
                return pc.createAnswer();
            })
            .then(function (answer) {
                return pc.setLocalDescription(answer);
            })
            .then(function () {
                signalingChannel.send(JSON.stringify({ "desc": pc.localDescription }));
            })
            .catch(logError);
        } else
            pc.setRemoteDescription(desc).catch(logError);
    } else if (message.start) {
      started = true;
      if (audio && sendAudioTrack) {
        audio.sender.replaceTrack(sendVideoTrack);
      }
      if (video && sendVideoTrack) {
        video.sender.replaceTrack(sendVideoTrack);
      }
    } else
        pc.addIceCandidate(message.candidate).catch(logError);
};

function logError(error) {
    log(error.name + ": " + error.message);
}

</pre>
      </div>
    </section>

    <section>
      <h3>Simple Peer-to-peer Example with media before signaling</h3>

      <div>
        <p>The answerer may wish to send media in parallel with sending the answer, and
        the offerer may wish to render the media before the answer arrives.</p>
        <pre class="example highlight">

var signalingChannel = new SignalingChannel();
var configuration = { "iceServers": [{ "urls": "stuns:stun.example.org" }] };
var pc;

function findReceiver(mid) {
    for (var i = 0; i < receivers.length; i++) {
        var receiver = receiver[i];
        if (receiver.mid == videoSender.mid) {
             return receiver;
        }
    }
    return null;
}

// call start() to initiate
function start() {
    pc = new RTCPeerConnection(configuration);

    // send any ice candidates to the other peer
    pc.onicecandidate = function (evt) {
        if (evt.candidate)
            signalingChannel.send(JSON.stringify({ "candidate": evt.candidate }));
    };

    // let the "negotiationneeded" event trigger offer generation
    pc.onnegotiationneeded = function () {
        pc.createOffer().then(function (offer) {
            return pc.setLocalDescription(offer);
        })
        .then(function () {
            // send the offer to the other peer
            signalingChannel.send(JSON.stringify({ "desc": pc.localDescription }));
        })
        .catch(logError);
    };

    // get a local stream, show it in a self-view and add it to be sent
    navigator.mediaDevices.getUserMedia({ "audio": true, "video": true }, function (stream) {
        selfView.srcObject = stream;
        var remoteStream = new MediaStream();
        if (stream.getAudioTracks().length > 0) {
            var audioSender = pc.addTrack(stream.getAudioTracks()[0], stream);
            remoteStream.addTrack(findReceiver(audioSender.mid).track);
        }
        if (stream.getVideoTracks().length > 0) {
            var videoSender = pc.addTrack(stream.getVideoTracks()[0], stream);
            remoteStream.addTrack(findReceiver(videoSender.mid).track);
        }
        // Render the media even before ontrack fires.
        removeView.srcObject = remoteStream;
    }, logError);
}

signalingChannel.onmessage = function (evt) {
    if (!pc)
        start();

    var message = JSON.parse(evt.data);
    if (message.desc) {
        var desc = message.desc;

        // if we get an offer, we need to reply with an answer
        if (desc.type == "offer") {
            pc.setRemoteDescription(desc).then(function () {
                return pc.createAnswer();
            })
            .then(function (answer) {
                return pc.setLocalDescription(answer);
            })
            .then(function () {
                signalingChannel.send(JSON.stringify({ "desc": pc.localDescription }));
            })
            .catch(logError);
        } else
            pc.setRemoteDescription(desc).catch(logError);
    } else
        pc.addIceCandidate(message.candidate).catch(logError);
};

function logError(error) {
    log(error.name + ": " + error.message);
}

</pre>
      </div>
    </section>

    <section>
      <h3>Simple Simulcast Example</h3>

      <div>
        <p>A client wants to send multiple RTP encodings (simulcast) to a server.</p>
        <pre class="example highlight">

var signalingChannel = new SignalingChannel();
var pc;

// call start() to initiate
function start() {
    pc = new RTCPeerConnection({});

    // let the "negotiationneeded" event trigger offer generation
    pc.onnegotiationneeded = function () {
        pc.createOffer().then(function (offer) {
            return pc.setLocalDescription(offer);
        })
        .then(function () {
            // send the offer to the other peer
            signalingChannel.send(JSON.stringify({ "desc": pc.localDescription }));
        })
        .catch(logError);
    };

    // get a local stream, show it in a self-view and add it to be sent
    navigator.mediaDevices.getUserMedia({ "audio": true, "video": true }, function (stream) {
        selfView.srcObject = stream;
        if (stream.getAudioTracks().length > 0)
            pc.addTransceiver(stream.getAudioTracks()[0], {send: true, receive: false});
        if (stream.getVideoTracks().length > 0) {
            pc.addTransceiver(stream.getVideoTracks()[0], {
                send: true,
                receive: false,
                sendEncodings: [
                    {
                      rid: "f",
                    },
                    {
                      rid: "h",
                      scaleDownResolutionBy: 2.0
                    },
                    {
                      rid: "q",
                      scaleDownResolutionBy: 4.0
                    }
                ]
            });
        }
    }, logError);
}

signalingChannel.onmessage = function (evt) {
    var message = JSON.parse(evt.data);
    if (message.desc) {
        var desc = message.desc;
        pc.setRemoteDescription(message.desc).catch(logError);
    } else
        pc.addIceCandidate(message.candidate).catch(logError);
};

function logError(error) {
    log(error.name + ": " + error.message);
}

</pre>
      </div>
    </section>

    <section>
      <h3>Advanced Peer-to-peer Example</h3>

      <div>
        <p>This example shows the more complete functionality.</p>
        <p class="issue">TODO</p>
        <pre class="example highlight">

</pre>
      </div>
    </section>

    <section>
      <h3>Peer-to-peer Data Example</h3>

      <div>
        <p>This example shows how to create a
        <code><a>RTCDataChannel</a></code> object and perform the offer/answer
        exchange required to connect the channel to the other peer. The
        <code><a>RTCDataChannel</a></code> is used in the context of a simple
        chat application and listeners are attached to monitor when the channel
        is ready, messages are received and when the channel is closed.</p>

        <pre class="example highlight">
var signalingChannel = new SignalingChannel();
var configuration = { "iceServers": [{ "urls": "stuns:stun.example.org" }] };
var pc;
var channel;

// call start(true) to initiate
function start(isInitiator) {
    pc = new RTCPeerConnection(configuration);

    // send any ice candidates to the other peer
    pc.onicecandidate = function (evt) {
        if (evt.candidate)
            signalingChannel.send(JSON.stringify({ "candidate": evt.candidate }));
    };

    // let the "negotiationneeded" event trigger offer generation
    pc.onnegotiationneeded = function () {
        pc.createOffer().then(function (offer) {
            return pc.setLocalDescription(offer);
        })
        .then(function () {
            // send the offer to the other peer
            signalingChannel.send(JSON.stringify({ "desc": pc.localDescription }));
        })
        .catch(logError);
    };

    if (isInitiator) {
        // create data channel and setup chat
        channel = pc.createDataChannel("chat");
        setupChat();
    } else {
        // setup chat on incoming data channel
        pc.ondatachannel = function (evt) {
            channel = evt.channel;
            setupChat();
        };
    }
}

signalingChannel.onmessage = function (evt) {
    if (!pc)
        start(false);

    var message = JSON.parse(evt.data);
    if (message.desc) {
        var desc = message.desc;

        // if we get an offer, we need to reply with an answer
        if (desc.type == "offer") {
            pc.setRemoteDescription(desc).then(function () {
                return pc.createAnswer();
            })
            .then(function (answer) {
                return pc.setLocalDescription(answer);
            })
            .then(function () {
                signalingChannel.send(JSON.stringify({ "desc": pc.localDescription }));
            })
            .catch(logError);
        } else
            pc.setRemoteDescription(desc).catch(logError);
    } else
        pc.addIceCandidate(message.candidate).catch(logError);
};

function setupChat() {
    channel.onopen = function () {
        // e.g. enable send button
        enableChat(channel);
    };

    channel.onmessage = function (evt) {
        showChatMessage(evt.data);
    };
}

function sendChatMessage(msg) {
    channel.send(msg);
}

function logError(error) {
    log(error.name + ": " + error.message);
}

</pre>
      </div><!--div>
    <p>This simple example shows how configure two RTCDataChannel objects for different purposes.</p>
<p><pre   class='example highlight'>
// the chat channel is reliable and not as prioritized as game data
var chatChan = peerConn.createDataChannel("chat", { "priority": 1 });

// the game data channel is prioritized and unreliable low latency channel for high performance
var gameDataChan = peerConn.createDataChannel("data", { "reliable": false, "priority": 10 });
    </pre></p>
  </div-->
    </section>

    <section>
      <h3>Call Flow Browser to Browser</h3>

      <p class="issue">Editors' Note: This example flow needs to be discussed on
      the list and is likely wrong in many ways.</p>

      <p>This shows an example of one possible call flow between two browsers.
      This does not show the procedure to get access to local media or every
      callback that gets fired but instead tries to reduce it down to only show
      the key events and messages.</p>

      <p><img alt=
      "A message sequence chart detailing a call flow between two browsers"
      src="images/ladder-2party-simple.svg" style="width:100%"></p><!--
      <p>The following flow shows a more complete set of the callbacks and
      events that happen.</p>

      <p><img alt=
      "A more complete message sequence chart detailing a call flow between two browsers"
      src="images/ladder-2party-full.svg" style="width:100%"></p>
      -->
    </section>

    <section>
      <h3>DTMF Example</h3>

      <p>Examples assume that <var>sender</var> is an RTCRtpSender.

      <p>Sending the DTMF signal "1234" with 500 ms duration per tone:</p>
      <pre class="example highlight">
if (sender.dtmf) {
    var duration = 500;
    sender.dtmf.insertDTMF("1234", duration);
} else
    log("DTMF function not available");

</pre>

      <p>Send the DTMF signal "1234", and light up the active key using
      <code>lightKey(key)</code> while the tone is playing (assuming that
      <code>lightKey("")</code> will darken all the keys):</p>
      <pre class="example highlight">
if (sender.dtmf) {
  sender.dtmf.ontonechange = function (e) {
      if (!e.tone)
          return;
      // light up the key when playout starts
      lightKey(e.tone);
      // turn off the light after tone duration
      setTimeout(lightKey, sender.duration, "");
  };
  sender.dtmf.insertDTMF("1234");
} else
    log("DTMF function not available");

</pre>

      <p>Send a 1-second "1" tone followed by a 2-second "2" tone:</p>
      <pre class="example highlight">
if (sender.dtmf) {
  sender.dtmf.ontonechange = function (e) {
      if (e.tone == "1")
          sender.dtmf.insertDTMF("2", 2000);
  };
  sender.dtmf.isertDTMF("1", 1000);
} else
    log("DTMF function not available");

</pre>

      <p>It is always safe to append to the tone buffer. This example appends
      before any tone playout has started as well as during playout.</p>
      <pre class="example highlight">

if (sender.dtmf) {
  sender.dtmf.insertDTMF("123");
  // append more tones to the tone buffer before playout has begun
  sender.dtmf.insertDTMF(sender.toneBuffer + "456");

  sender.dtmf.ontonechange = function (e) {
      if (e.tone == "1")
          // append more tones when playout has begun
          sender.dtmf.insertDTMF(sender.toneBuffer + "789");
  };
} else
    log("DTMF function not available");

</pre>

      <p>Send the DTMF signal "123" and abort after sending "2".</p>
      <pre class="example highlight">
if (sender.dtmf) {
  sender.dtmf.ontonechange = function (e) {
      if (e.tone == "2")
          // empty the buffer to not play any tone after "2"
          sender.dtmf.insertDTMF("");
  };
  sender.dtmf.insertDTMF("123");
} else
    log("DTMF function not available");
</pre>
    </section><!--
    <section>
      <h3>Call Flow Browser to MCU</h3>

      <p class="note">Editors' Note: This example flow needs to be discussed on
      the list and is likely wrong in many ways.</p>

      <p>This shows an example of one possible call flow between a centralized
      conferencing server and a browser. This does not show every callback that
      gets fired but instead tries to reduce it down to only show the key
      events and messages.</p>

      <p><img alt=
      "A message sequence chart detailing a call flow between a browser and a centralized conferencing server"
      src="images/ladder-mcu-simple.svg" style="width:100%"></p>
    </section>
-->
  </section>

  <section class="informative">
    <h2>Event summary</h2>

    <p>The following events fire on <code><a>RTCDataChannel</a></code>
    objects:</p>

    <table>
      <tr>
        <th>Event name</th>

        <th>Interface</th>

        <th>Fired when...</th>
      </tr>

      <tbody>
        <tr>
          <td><dfn id="event-datachannel-open"><code>open</code></dfn></td>

          <td><code><a>Event</a></code></td>

          <td>
            The <code><a>RTCDataChannel</a></code> object's <a>underlying data
            transport</a> has been established (or re-established).
          </td>
        </tr>

        <tr>
          <td><dfn id=
          "event-datachannel-message"><code>message</code></dfn></td>

          <td><code><a href="http://www.w3.org/TR/webmessaging/#the-messageevent-interfaces">MessageEvent</a></code> [[!webmessaging]]</td>

          <td>A message was successfully received.</td>
        </tr>

        <tr>
          <td><dfn id="event-datachannel-bufferedamountlow">
            <code>bufferedamountlow</code></dfn></td>

          <td><code><a>Event</a></code></td>

          <td>
            The <code><a>RTCDataChannel</a></code> object's <code><a href=
            "#dom-datachannel-bufferedamount">bufferedAmount</a></code>
            decreases from above its <code><a href=
            "#dom-datachannel-bufferedamountlowthreshold">
            bufferedAmountLowThreshold</a></code> to less
            than or equal to its <code><a href=
            "#dom-datachannel-bufferedamountlowthreshold">
            bufferedAmountLowThreshold</a></code>.
          </td>
        </tr>

        <tr>
          <td><dfn id="event-datachannel-error"><code>error</code></dfn></td>

          <td><code><a>Event</a></code></td>

          <td><p class="issue">TODO</p>.</td>
        </tr>

        <tr>
          <td><dfn id="event-datachannel-close"><code>close</code></dfn></td>

          <td><code><a>Event</a></code></td>

          <td>
            The <code><a>RTCDataChannel</a></code> object's <a>underlying data
            transport</a> has bee closed.
          </td>
        </tr>
      </tbody>
    </table>

    <p>The following events fire on <code><a>RTCPeerConnection</a></code>
    objects:</p>

    <table>
      <tr>
        <th>Event name</th>

        <th>Interface</th>

        <th>Fired when...</th>
      </tr>

      <tbody>
        <tr>
          <td><dfn id=
          "event-mediastream-connecting"><code>connecting</code></dfn></td>

          <td><code>Event</code></td>

          <td><p class="issue">TODO</p></td>
        </tr><!--
        <tr>
          <td><dfn title="event-MediaStream-error"><code>error</code></dfn></td>
          <td><code>Event</code></td>
          <td></td>
        </tr>
        <tr>
          <td><dfn title="event-MediaStream-close"><code>close</code></dfn></td>
          <td><code>Event</code></td>
          <td>The <code title="dom-RTCPeerConnection-close">close()</code> method was
            called. </td>
        </tr>
        <tr>
          <td>
            <dfn id="event-mediastream-message">
              <code>message</code>
            </dfn>
          </td>

          <td>
            <code>MessageEvent</code>
          </td>

          <td>A <a href="#data-udp-media-stream">data UDP media
          stream</a> message was received.</td>
        </tr>
        -->

        <tr>
          <td><dfn id=
          "event-track"><code>track</code></dfn></td>

          <td><code><a>RTCTrackEvent</a></code></td>

          <td>
            A new incoming <code>MediaStreamTrack</code> has been created, and an associated
            <code>RTCRtpReceiver</code> has been added to the <a href=
            "#receivers-set">set of receivers</a>.
          </td>
        </tr>

        <tr>
          <td><dfn id=
          "event-negotiation"><code>negotiationneeded</code></dfn></td>

          <td><code><a>Event</a></code></td>

          <td>The browser wishes to inform the application that session
          negotiation needs to be done (i.e. a createOffer call followed by
          setLocalDescription).</td>
        </tr>

        <tr>
          <td><dfn id=
          "event-signalingstatechange"><code>signalingstatechange</code></dfn></td>

          <td><code><a>Event</a></code></td>

          <td>
            The <a href=
            "#dom-peerconnection-signaling-state"><code>RTCPeerConnection</code>
            signalingState</a> has changed. This state change is the result of
            either <code><a href=
            "#dom-peerconnection-setlocaldescription">setLocalDescription()</a></code>
            or <code><a href=
            "#dom-peerconnection-setremotedescription">setRemoteDescription()</a></code>
            being invoked.
          </td>
        </tr>

        <tr>
          <td><dfn id=
          "event-iceconnectionstatechange"><code>iceconnectionstatechange</code></dfn></td>

          <td><code><a>Event</a></code></td>

          <td>
            The <a href=
            "#dom-peerconnection-ice-connection-state"><code>RTCPeerConnection</code>
            ice connection state</a> has changed.
          </td>
        </tr>

        <tr>
          <td><dfn id="event-icegatheringstatechange"><code>icegatheringstatechange</code></dfn></td>

          <td><code><a>Event</a></code></td>

          <td>
            The <a href="#dom-peerconnection-ice-gathering-state"><code>RTCPeerConnection</code>
            ice gathering state</a> has changed.
          </td>
        </tr>

        <tr>
          <td><dfn id="event-icecandidate"><code>icecandidate</code></dfn></td>

          <td><code><a>RTCPeerConnectionIceEvent</a></code></td>

          <td>A new <code><a>RTCIceCandidate</a></code> is made available to
          the script.</td>
        </tr>

        <tr>
          <td><dfn id=
          "event-connectionstatechange"><code>connectionstatechange</code></dfn></td>

          <td><code><a>Event</a></code></td>

          <td>
            The <a href=
            "#dom-peerconnection-connection-state"><code>RTCPeerConnection</code>
            .connectionstate</a> has changed.
          </td>
        </tr>

        <tr>
          <td><dfn id="event-icecandidateerror"><code>icecandidateerror</code></dfn></td>

          <td><code><a>RTCPeerConnectionIceErrorEvent</a></code></td>

          <td>A failure occured when gathering ICE candidates.</td>
        </tr>

        <tr>
          <td><dfn id="event-datachannel"><code>datachannel</code></dfn></td>

          <td><code><a>RTCDataChannelEvent</a></code></td>

          <td>A new <code><a>RTCDataChannel</a></code> is dispatched to the
          script in response to the other peer creating a channel.</td>
        </tr>

        <tr>
          <td><dfn id=
          "event-isolationchange"><code>isolationchange</code></dfn></td>

          <td><code><a>Event</a></code></td>

          <td>A new <code><a>Event</a></code> is dispatched to the script when
          the <var>isolated</var> attribute on a <code>MediaStreamTrack</code>
          changes.</td>
        </tr>
      </tbody>
    </table>

    <p>The following events fire on <code><a>RTCDTMFSender</a></code>
    objects:</p>

    <table>
      <tr>
        <th>Event name</th>

        <th>Interface</th>

        <th>Fired when...</th>
      </tr>

      <tbody>
        <tr>
          <td><dfn id=
          "event-RTCDTMFSender-tonechange"><code>tonechange</code></dfn></td>

          <td><code><a>Event</a></code></td>

          <td>The <code><a>RTCDTMFSender</a></code> object has either just
          begun playout of a tone (returned as the <code><a>tone</a></code>
          attribute) or just ended playout of a tone (returned as an empty
          value in the <code><a>tone</a></code> attribute).</td>
        </tr>
      </tbody>
    </table>

    <p>The following events fire on <code><a>RTCIceTransport</a></code>
    objects:</p>

    <table>
      <tr>
        <th>Event name</th>

        <th>Interface</th>

        <th>Fired when...</th>
      </tr>

      <tbody>
        <tr>
          <td><dfn id="event-icetransport-statechange"
                   data-lt="RTCIceTransport state change">
              <code>statechange</code></dfn></td>

          <td><code><a>Event</a></code></td>

          <td>The <code><a>RTCIceTransport</a></code> state changes.</td>
        </tr>

        <tr>
          <td><dfn id=
          "event-icetransport-gatheringstatechange"><code>gatheringstatechange</code></dfn></td>

          <td><code><a>Event</a></code></td>

          <td>The <code><a>RTCIceTransport</a></code> gathering state
          changes.</td>
        </tr>

        <tr>
          <td><dfn id=
          "event-icetransport-selectedcandidatepairchange"><code>selectedcandidatepairchange</code></dfn></td>

          <td><code><a>Event</a></code></td>

          <td>The <code><a>RTCIceTransport</a></code>'s selected
            candidate pair changes. </td>
        </tr>
      </tbody>
    </table>

    <p>The following events fire on <code><a>RTCDtlsTransport</a></code>
    objects:</p>

    <table>
      <tr>
        <th>Event name</th>

        <th>Interface</th>

        <th>Fired when...</th>
      </tr>

      <tbody>
        <tr>
          <td><dfn id="event-dtlstransport-statechange"
                   data-lt="RTCDtlsTransport state change" data-lt-noDefault>
              <code>statechange</code></dfn></td>

          <td><code><a>Event</a></code></td>

          <td>The <code><a>RTCDtlsTransport</a></code> state changes.</td>
        </tr>
      </tbody>
    </table>

  </section>

  <section class="informative">
    <h2>Security Considerations</h2>
    <p>This section is non-normative; it specifies no new behaviour,
    but instead summarizes information already present in other parts
    of the specification.</p>

    <p>This document extends the Web platform with the ability to set
    up real time, direct communication between browsers and other
    devices, including other browsers.</p>

    <p>This means that data and media can be shared between
    applications running in different browsers, or between an
    application running in the same browser and something that is not a
    browser, something that is an extension to the usual barriers in
    the Web model against sending data between entities with different
    origins.</p>

    <p>The WebRTC specification provides no user prompts or chrome
    indicators for communication; it assumes that once the Web page
    has been allowed to access media, it is free to share that media
    with other entities as it chooses.</p>

    <p>A mechanism, <code><a>peerIdentity</a></code>, is provided that gives
    Javascript the option of requesting media that the same javascript
    cannot access, but can only be sent to certain other entities.</p>

    <p>Even without WebRTC, the Web server providing a Web application
    will know the public IP
    address to which the application is delivered. Setting up
    communications exposes additional information about the browser’s
    network context to the web application, and may include the set of
    (possibly private) IP addresses available to the browser for WebRTC
    use. Some of this information has to be passed to the
    corresponding party to enable the establishment of a communication
    session.</p>

    <p>Revealing IP addresses can leak location and means of
    connection; this can be sensitive.</p>

    <p>A connection will always reveal the IP addresses proposed for
    communication to the corresponding party. The application can limit
    this exposure by choosing not to use certain addresses using the
    <a>RTCIceTransportPolicy</a>, and by
    using relays (for instance TURN servers) rather than direct
    connections between participants. One will normally assume that
    the IP address of TURN servers is not sensitive information.</p>

    <p>Mitigating the exposure of IP addresses to the application requires
    limiting the IP addresses that can be used, which will impact the
    ability to communicate on the most direct path between endpoints.
    Browsers are encouraged to provide appropriate controls for deciding
    which IP addresses are made available to applications, based on the
    security posture desired by the user.</p>

    <div class="issue" data-number="179">
      <p>The working group is actively discussing what additional text
      regarding exposure of IP addresses is appropriate for this section.
      </p>
    </div>

    <p>Since the browser is an active platform executing in a trusted
    network environment (inside the firewall), it is important to
    limit the damage that the browser can do to other elements on the
    local network, and it is important to protect data from
    interception, manipulation and modification by untrusted
    participants.</p>

    <p>Mitigations include:</p>
    <ul>
      <li>An UA will always request permission from the correspondent
      UA to communicate using ICE. This
      ensures that the UA can only send to partners who you have
      shared credentials with.</li>
      <li>An UA will always request ongoing permission to continue sending
      using ICE continued
      consent. This enables a receiver to withdraw consent to
      receive.</li>
      <li>An UA will always encrypt data, with strong per-session keying
      (DTLS-SRTP).</li>
      <li>An UA wil always use congestion control. This ensures that
      WebRTC cannot be used to flood the network.</li>
    </ul>
    <p>These measures are specified in the relevant IETF documents.</p>


    <p>The fact that communication is taking place cannot be hidden from
    adversaries that can observe the network, so this has to be
    regarded as public information.</p>

  </section><!--section>
    <h2 id="sec-iana">IANA Registrations</h2>



    <p>IANA is requested to register the constraints defined in <a href=
    "#sec-constraints">Constraints Section</a> as specified in
    [[!RTCWEB-CONSTRAINTS]].</p>


    <section>
      <h3 id="sec-constraints">Constraints</h3>


      <p>TOOD: Need to change the naming and declaration of these constraints
      to match the constraints draft once that is a bit further along. The
      names here now are likely not quite right but they serve as a place
      holder.</p>


      <p class="issue">ISSUE: there are multiple ways to add constraints. How
      are multiple values reconciled?</p>


      <p>The following new constraints are defined that can be used with an
      <code>RTCPeerConnection</code> object:</p>


      <p>TODO items - need to register with IANA.</p>
    </section>
  </section-->

  <section>
    <h2>Change Log</h2>

    <p>This section will be removed before publication.</p>
    <!-- Why do the first two headings automatically convert to <h2>? -->
    <!-- Because you haven't added a <section> element around them
         and respec rewrites h? elements based on the section depth -->

    <h3>Changes since October 6, 2015</h3>

    <ol>
      <li>[#325] Adding additional members to RTCIceCandidate dictionary</li>

      <li>[#327] Adding sha-256 to the certificate management options for RSA</li>

      <li>[#342] Using DOMTimestamp for RTCCertificate::expires</li>

      <li>[#293] Add RTCRtpTransceiver and PeerConnection.addMedia</li>

      <li>[#366, #343] Use RTCDegradationPreference</li>

      <li>[#374] Throw on too long label/protocol in createDataChannel()</li>

      <li>[#266] Tidy up setLocal/RemoteDescription processing model</li>

      <li>[#361] Adding setCodecPreferences to RTCRtpTransceiver</li>

      <li>[#371] Add RtcpMuxPolicy</li>

      <li>[#385, #312] Don't invoke public API in legacy function section</li>

      <li>[#394, #393] don't throw on empty iceServers list</li>
    </ol>

    <h3>Changes since September 22, 2015</h3>

    <ol>
      <li>[#289, #153] Add way to set size of ICE candidate pool</li>

      <li>[#256] Fix prose on getStats() wo/selector + move type check to sync
      section</li>

      <li>[#242] Remove SyntaxError on malformed ICE candidate</li>

      <li>[#284] Add icecandidateerror event for indicating ICE gathering
      errors</li>

      <li>[#298] Add support for codec reordering and removal in
      RtpParameters</li>

      <li>[#311] Fixing syntax for required RTCCertificate arguments</li>

      <li>[#280] Add extra IceTransport read-only attributes and methods</li>

      <li>[#291] Add PeerConnection.connectionState</li>

      <li>[#300, #4, #6, #276] Add API to get SSRC and audio levels</li>

      <li>[#301] Fix RTCStatsReport with object and maplike instead of
      getter</li>

      <li>[#302] (Partly) removing interface use for RTCSessionDescription and
      RTCIceCandidate</li>

      <li>[#314, #299] Update the operations queue to handle promises and closed
      signalling</li>

      <li>[#273] Add a bunch of fields to RtpParameters and
      RtpEncodingParameters</li>
    </ol>

    <h3>Changes since June 11, 2015</h3>

    <ol>
      <li>[#234] Add RTCRtpParameters, RTCRtpSender.getParameters, and
      RTCRtpSender.setParameters</li>

      <li>[#225] Support for pending and current SDP</li>

      <li>[#229] Removing the weird optionality from RTCSessionDescription and
      its constructor.</li>

      <li>[#235] Modernize getStats() with promises</li>

      <li>[#243] Mark candidate property of RTCIceCandidateInit required</li>

      <li>[#248] Fix error handling for certificate management</li>

      <li>[#259] Change type of RtpEncodingParameters.priority to an enum</li>

      <li>[#21, #262] Sort out 2119 MUSTs and SHOULDs</li>

      <li>[#268] Add RtpEncodingParameters.maxBitrate</li>

      <li>[#241] Add RtpSender.transport, RtpReceiver.transport,
      RTCDtlsTransport, RTCIceTransport, etc</li>

      <li>[#224, #261] Sort out when responding PeerConnection reaches
      iceConnetionState completed</li>

      <li>[#303] Replace track without renegotiation</li>

      <li>[#269] Add RTCRtpSender.getCapabilities and
      RTCRtpReceiver.getCapabilities</li>
    </ol>

    <h3>Changes since March 6, 2015</h3>

    <ol>
      <li>[PR #167] Removed RTCPeerConnection.createDTMFSender and added
      RTCRtpSender.dtmf, along with corresponding examples.</li>

      <li>[PR #184] RTCPeerConnection will NOT connect unless identity is
      verified.</li>

      <li>[PR #27] Documenting practice with candidate events</li>

      <li>[PR #203] Rewrote mitigations text for security considerations
      section</li>

      <li>[PR #192] Added support for auth tokens. Fixes #190</li>

      <li>[PR #207] Update ice config examples to use multiple urls and *s
      schemes</li>

      <li>[PR #210] Optional RTCConfiguration in RTCPC constructor</li>

      <li>[PR #171] Add RTCAnswerOptions (with common RTCOfferAnswerOptions
      dictionary)</li>

      <li>[PR #178] Identity provider interface redesign</li>

      <li>[PR #193] Add .mid property to sender/receiver. Fixes #191</li>

      <li>[PR #218] Enqueue addIceCandidate</li>

      <li>[PR #213 (1)] Rename updateIce() to setConfiguration()</li>

      <li>[PR #213 (2)] Make RTCPeerConnection.setConfiguration() replace the
      existing configuration</li>

      <li>[PR #214] Certificate management API (Bug 21880)</li>

      <li>[PR #220] Clarify muted state (proposed fix for issue #139)</li>

      <li>[PR #221] Define when RTCRtpReceivers are created and dispatced
      (issue #198)</li>

      <li>[PR #215] Adding expires attribute to certificate management</li>

      <li>[PR #233] Add a "bufferedamountlow" event</li>
    </ol>

    <h3>Changes since December 5, 2014</h3>

    <ol>
      <li>Properly define the negotiationneeded event, and its interactions with
      other API calls.</li>
      <li>Add support for RTCRtpSender and RTCRtpReceiver.</li>
      <li>Update misleading local/RemoteDescription attribute text.</li>

      <li>Add RTCBundlePolicy.</li>

      <li>All callback-based methods have been moved to a legacy section, and
      replaced by same-named overloads using Promises instead.</li>

      <li>[PR #194] Added first version of Security Considerations (more work
        needed)</li>

      <li>Updated identity provider structure.</li>
    </ol>

    <h3>Changes since June 4, 2014</h3>

    <ol>
      <li>Bug 25724: Allow garbage collection of closed PeerConnections</li>

      <li>Bug 27214: Add onicegatheringstatechange event</li>
      <li>Bug 26644: Fixing end of candidates event</li>
    </ol>

    <h3>Changes since April 10, 2014</h3>

    <ol>
      <li>Bug 25774: Mixed isolation</li>
    </ol>

    <h3>Changes since April 10, 2014</h3>

    <ol>
      <li>Bug 25855: Clarification about conformance requirements phrased as
      algorithms</li>

      <li>Bug 25892: SignalingStateChange event should be fired only if there
      is a change in signaling state.</li>

      <li>Bug 25152: createObjectURL used in examples is no longer supported by
      Media Capture and Streams.</li>

      <li>Bug 25976: DTMFSender.insertDTMF steps should validate the values of
      duration and interToneGap.</li>

      <li>Bug 25189: Mandatory errorCallback is missing in examples for
      getStats.</li>

      <li>Bug 25840: Creating DataChannel with same label.</li>

      <li>Updated comment above example ice state transitions (discussed in Bug
      25257).</li>

      <li>Updated insertDTMF() algorithm to ignore unrecognized characters (as
      discussed in bug 25977).</li>

      <li>Made formatting of references to ice connection state
      consistent.</li>

      <li>Made insertDTMF() throw on unrecognized characters (used to
      ignore).</li>

      <li>Removed requestIdentity from RTCConfiguration and
      RTCOfferAnswerOptions. Removed RTCOfferAnswerOptions as a result.</li>

      <li>Adding isolated property and associated event to
      MediaStreamTrack.</li>
    </ol>

    <h3>Changes since March 21, 2014</h3>

    <ol>
      <li>Changes to identity-related text:

        <ul>
          <li>Removed noaccess constraint</li>

          <li>Add the ability to peerIdentity constrain RTCPeerConnection,
          which limits communication to a single peer</li>

          <li>Change the way that the browser communicates with IdP to a
          message channel
          (http://www.w3.org/TR/webmessaging/#message-channels)</li>

          <li>Improved error feedback from IdP interactions (added new events
          with more detailed context)</li>

          <li>Changed the way that an IdP is able to request user login
          (LOGINNEEDED message)</li>
        </ul>
      </li>

      <li>Bug 25155: maxRetransmitTime is not the name of the SCTP concept it
      points to.</li>
    </ol>

    <h3>Changes since January 27, 2014</h3>

    <ol>
      <li>Refined identity assertion generation and validation.</li>

      <li>Default DTMF gap changed from 50 to 70 ms.</li>

      <li>Bug 24875: Examples in the WebRTC spec are not updated As per the
      modified API.</li>
    </ol>

    <h3>Changes since August 30, 2013</h3>

    <ol>
      <li>Make RTCPeerConnection close method be idempotent.</li>

      <li>Clarified ICE server configuration could contain URI types other than
      STUN and TURN.</li>

      <li>Changed the DTMF timing values.</li>

      <li>Allow offerToReceiveAudio/video indicate number of streams to
      offer.</li>

      <li>ACTION-98: Added text about clamping of maxRetransmitTime and
      maxRetransmits.</li>

      <li>ACTION-88: Removed nullable types from dictionaries (added attribute
      default values for attributes that would be left uninitialized without
      the init dictionary present.</li>

      <li>InvalidMediaStreamTrackError changed to InvalidParameter.</li>

      <li>Fire NetworkError when the data transport is closed with an
      error.</li>

      <li>Add an exception for data channel with trying to use existing
      code.</li>

      <li>Change maxRetransmits to be an unsigned type.</li>

      <li>Clarify state changes when ICE restarts.</li>

      <li>Added InvalidStateError exception for operations on a
      RTCPeerConnection that is closed.</li>

      <li>Major changes to Identity Proxy section.</li>

      <li>(ACTION: 95) Moved IceTransports (constraint) to RTCConfiguration
      dictionary.</li>

      <li>(ACTION: 95) Introduced RTCOfferAnswerOptions and RTCOfferOptions
      dictionaries.</li>

      <li>(ACTION: 95) Removed constraints argument from addStream() (and
      removed IANA Constraints section).</li>

      <li>Added validation of the RTCConfiguration dictionary argument(s).</li>

      <li>Added getConfiguration() on RTCPeerConnection.</li>
    </ol>

    <h3>Changes since June 3, 2013</h3>

    <ol>
      <li>Removed synchronous section left-overs.</li>

      <li>RTCIceServer now accepts multiple URLs.</li>

      <li>Redefined the meaning of negotiated for DataChannel.</li>

      <li>Made iceServers a sequence (instead of an Array).</li>

      <li>Updated error reporting (to use DOMError and camel cased names).</li>

      <li>Added success and failure callbacks to addIceCandidate().</li>

      <li>Made local/remoteDescription attributes nullable.</li>

      <li>Added username member to RTCIceServer dictionary.</li>
    </ol>

    <h3>Changes since March 22, 2013</h3>

    <ol>
      <li>Added IceRestart constraint.</li>

      <li>Big updates on DataChannel API to use new channel setup
      procedures.</li>
    </ol>

    <h3>Changes since Feb 22, 2013</h3>

    <ol>
      <li>Example review: Updated DTMF and Stats examples. Added text about
      when to fire "negotiationneeded" event to align with examples.</li>

      <li>Updated RTCPeerConnection state machine. Added a shared processing
      model for setLocalDescription()/setRemoteDescription().</li>

      <li>Updated simple callflow to match the current API.</li>
    </ol>

    <h3>Changes since Jan 16, 2013</h3>

    <ol>
      <li>Initial import of Statistics API to version 2.</li>

      <li>Integration of Statistics API version 2.5 started.</li>

      <li>Updated Statistics API to match Boston/list discussions.</li>

      <li>Extracted API extensions introduced by features, such as the P2P Data
      API, from the RTCPeerConnection API.</li>

      <li>Updated DTMF algorithm to dispatch an event when insertDTMF() is
      called with an empty string to cancel future tones.</li>

      <li>Updated DTMF algorithm to not cancel and reschedule if a playout task
      is running (only update toneBuffer and other values).</li>
    </ol>

    <h3>Changes since Dec 12, 2012</h3>

    <ol>
      <li>Changed AudioMediaStreamTrack to RTCDTMFSender and gave it its own
      section. Updated text to reflect most recent agreements. Also added
      examples section.</li>

      <li>Replaced the localStreams and remoteStreams attributes with functions
      returning sequences of MediaStream objects.</li>

      <li>Added spec text for attributes and methods adopted from the WebSocket
      interface.</li>

      <li>Changed the state ENUMs and transition diagrams.</li>

      <li>Aligned the data channel processing model a bit more with WebSockets
      (mainly closing the underlying transport).</li>
    </ol>

    <h3>Changes since Nov 13, 2012</h3>

    <ol>
      <li>Made some clarifications as to how operation queuing works, and fixed
      a few errors with the error handling description.</li>

      <li>Introduced new representation of tracks in a stream (removed
      MediaStreamTrackList). Added algorithm for creating a track to represent
      an incoming network media component.</li>

      <li>Renamed MediaStream.label to MediaStream.id (the definition needs
      some more work).</li>
    </ol>

    <h3>Changes since Nov 03, 2012</h3>

    <ol>
      <li>Added text describing the queuing mechanism for
      RTCPeerConnection.</li>

      <li>Updated simple P2P example to include all mandatory (error)
      callbacks.</li>

      <li>Updated P2P data example to include all mandatory (error) callbacks.
      Also added some missing RTC prefixes.</li>
    </ol>

    <h3>Changes since Oct 19, 2012</h3>

    <ol>
      <li>Clarified how createOffer() and createAnswer() use their
      callbacks.</li>

      <li>Made all failure callbacks mandatory.</li>

      <li>Added error object types, general error handling principles, and
      rules for when errors should be thrown.</li>
    </ol>

    <h3>Changes since Sept 23, 2012</h3>

    <ol>
      <li>Restructured the document layout and created separate sections for
      features like Peer-to-peer Data API, Statistics and Identity.</li>
    </ol>

    <h3>Changes since Aug 16, 2012</h3>

    <ol>
      <li>Replaced stringifier with serializer on RTCSessionDescription and
      RTCIceCandidate (used when JSON.stringify() is called).</li>

      <li>Removed offer and createProvisionalAnswer arguments from the
      createAnswer() method.</li>

      <li>Removed restart argument from the updateIce() method.</li>

      <li>Made RTCDataChannel an EventTarget</li>

      <li>Updated simple RTCPeerConnection example to match spec changes.</li>

      <li>Added section about RTCDataChannel garbage collection.</li>

      <li>Added stuff for identity proxy.</li>

      <li>Added stuff for stats.</li>

      <li>Added stuff peer and ice state reporting.</li>

      <li>Minor changes to sequence diagrams.</li>

      <li>Added a more complete RTCDataChannel example</li>

      <li>Various fixes from Dan's Idp API review.</li>

      <li>Patched the Stats API.</li>
    </ol>

    <h3>Changes since Aug 13, 2012</h3>

    <ol>
      <li>Made the RTCSessionDescription and RTCIceCandidate constructors take
      dictionaries instead of a strings. Also added detailed stringifier
      algorithm.</li>

      <li>Went through the list of issues (issue numbers are only valid with
      HEAD at fcda53c460). Closed (fixed/wontfix): 1, 8, 10, 13, 14, 16, 18,
      19, 22, 23, 24. Converted to notes: 4, 12. Updated: 9.</li>

      <li>Incorporate <a href=
      "http://lists.w3.org/Archives/Public/www-archive/2012Aug/0015.html">changes
      proposed</a> by Li Li.
      </li>

      <li>Use an enum for DataChannelState and fix IDLs where using an optional
      argument also requires all previous optional arguments to have a default
      value.</li>
    </ol>

    <h3>Changes since Jul 20, 2012</h3>

    <ol>
      <li>Added RTC Prefix to names (including the notes below).</li>

      <li>Moved to new definition of configuration and ice servers object.</li>

      <li>Added correlating lines to candidate structure.</li>

      <li>Converted setLocalDescription and setRemoteDescription to be
      asynchronous.</li>

      <li>Added call flows.</li>
    </ol>

    <h3>Changes since Jul 13, 2012</h3>

    <ol>
      <li>Removed peer attribute from RTCPeerConnectionIceEvent (duplicates
      functionality of Event.target attribute).</li>

      <li>Removed RTCIceCandidateCallback (no longer used).</li>

      <li>Removed RTCPeerConnectionEvent (we use a simple event instead).</li>

      <li>Removed RTCSdpType argument from setLocalDescription() and
      setRemoteDescription(). Updated simple example to match.</li>
    </ol>

    <h3>Changes since May 28, 2012</h3>

    <ol>
      <li>Changed names to use RTC Prefix.</li>

      <li>Changed the data structure used to pass in STUN and TURN servers in
      configuration.</li>

      <li>Updated simple RTCPeerConnection example (RTCPeerConnection
      constructor arguments; use icecandidate event).</li>

      <li>Initial import of new Data API.</li>

      <li>Removed some left-overs from the old Data Stream API.</li>

      <li>Renamed "underlying data channel" to "underlying data transport".
      Fixed closing procedures. Fixed some typos.</li>
    </ol>

    <h3>Changes since April 27, 2012</h3>

    <ol>
      <li>Major rewrite of RTCPeerConnection section to line up with IETF JSEP
      draft.</li>

      <li>Added simple RTCPeerConnection example. Initial update of
      RTCSessionDescription and RTCIceCandidate to support serialization and
      construction.</li>
    </ol>

    <h3>Changes since 21 April 2012</h3>

    <ol>
      <li>Moved MediaStream and related definitions to getUserMedia.</li>

      <li>Removed section "Obtaining local multimedia content".</li>

      <li>Updated getUserMedia() calls in examples (changes in Media Capture TF
      spec).</li>

      <li>Introduced MediaStreamTrackList interface with support for adding and
      removing tracks.</li>

      <li>Updated the algorithm that is run when RTCPeerConnection receives a
      stream (create new stream when negotiated instead of when data
      arrives).</li>
    </ol>

    <h3>Changes since 12 January 2012</h3>

    <ol>
      <li>Clarified the relation of Stream, Track, and Channel.</li>
    </ol>

    <h3>Changes since 17 October 2011</h3>

    <ol>
      <li>Tweak the introduction text and add a reference to the IETF RTCWEB
      group.</li>

      <li>Changed the first argument to getUserMedia to be an object.</li>

      <li>Added a MediaStreamHints object as a second argument to
      RTCPeerConnection.addStream.</li>

      <li>Added AudioMediaStreamTrack class and DTMF interface.</li>
    </ol>

    <h3>Changes since 23 August 2011</h3>

    <ol>
      <li>Separated the SDP and ICE Agent into separate agents and added
      explicit state attributes for each.</li>

      <li>Removed the send method from PeerConenction and associated callback
      function.</li>

      <li>Modified MediaStream() constructor to take a list of MediaStreamTrack
      objects instead of a MediaStream. Removed text about MediaStream parent
      and child relationship.</li>

      <li>Added abstract.</li>

      <li>Moved a few paragraphs from the MediaStreamTrack.label section to the
      MediaStream.label section (where they belong).</li>

      <li>Split MediaStream.tracks into MediaStream.audioTracks and
      MediaStream.videoTracks.</li>

      <li>Removed a sentence that implied that track access is limited to
      LocalMediaStream.</li>

      <li>Updated a few getUserMedia()-examples to use MediaStreamOptions.</li>

      <li>Replaced calls to URL.getObjectURL() with URL.createObjectURL() in
      example code.</li>

      <li>Fixed some broken getUserMedia() links.</li>

      <li>Introduced state handling on MediaStreamTrack (removed state handling
      from MediaStream).</li>

      <li>Reintroduced onended on MediaStream to simplify checking if all
      tracks are ended.</li>

      <li>Aligned the MediaStreamTrack ended event dispatching behavior with
      that of MediaStream.</li>

      <li>Updated the LocalMediaStream.stop() algorithm to implicitly use the
      end track algorithm.</li>

      <li>Replaced an occurrence the term finished track with ended track (to
      align with rest of spec).</li>

      <li>Moved (and extended) the explanation about track references and media
      sources from LocalMediaStream to MediaStreamTrack.</li>
    </ol>
  </section>

  <section class="appendix">
    <h2>Acknowledgements</h2>

    <p>The editors wish to thank the Working Group chairs and Team Contact,
    Harald Alvestrand, Stefan H&aring;kansson and Dominique
    Haza&euml;l-Massieux, for their support. Substantial text in this
    specification was provided by many people including Martin Thomson, Harald
    Alvestrand, Justin Uberti, Eric Rescorla, Peter Thatcher, Jan-Ivar Bruaroey
    and Peter Saint-Andre.</p>

    <p>The RTCRtpSender and RTCRtpReceiver objects were initially described in the
      <a href="https://www.w3.org/community/ortc/">W3C ORTC CG</a>, and have been
      adapted for use in this specification.</p>
  </section>
</body>
</html>