<!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<RTCIceServer> 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<RTCCertificate> 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<DOMString>) 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<RTCSessionDescription> 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<RTCSessionDescription> 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<void> 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<void> 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<void> 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<RTCIceServer> 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­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<RTCCertificate> 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<RTCRtpSender> 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<RTCRtpReceiver> 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<RTCRtpTransceivers> 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<MediaStream> 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<void> 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<RTCRtpEncodingParameters> encodings</dt> <dd> <p>A sequence containing parameters for RTP encodings of media.</p> </dd> <dt>sequence<RTCRtpHeaderExtensionParameters> 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<RTCRtpCodecParameters> 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<RTCRtpCodecCapability> codecs</dt> <dd> <p> Supported codecs. </p> </dd> <dt>sequence<RTCRtpHeaderExtensionCapability> 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<RTCRtpContributingSource> 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<RTCRtpCodecCapability> 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<ArrayBuffer> 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<RTCIceCandidate> 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<RTCIceCandidate> 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<MediaStream> 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<MediaStream> 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<RTCStatsReport> 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<DOMString, object></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 > 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<RTCIdentityAssertionResult> 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<RTCIdentityValidationResult> 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<DOMString> 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<RTCIdentityAssertion> 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., <video> or <audio>).</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åkansson and Dominique Hazaë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>