An API is described for sourcing and terminating streams of real-time media in a browser. The API provides a means of describing how media streams are serialized into a stream of RTP packets or deserialized from a stream of packets.
The API is structed in two sections: Real-Time Media Streaming and Real-Time, Peer-to-Peer Transport.
Thanks in no small part to the exponential improvements in Web infrastructure over the last few years, it is now possible to leverage the digital backbone of the Internet to create experiences for which dedicated media and networks (cable TV, telephone) were necessary until not too long ago. Furthermore, these developments have enabled the creation of media experiences heretofore either plainly inaccessible or too impractical for most.
Inexpensive, real time video conferencing is one such experience. It has grown enormously in popularity and it is now a daily component of many people’s lives, bringing together families and friends, and making business easier all over the world.
But there are other applications of the same general technology, which are also experiencing substantial growth. Online gaming requires the real time exchange of data across geographically dispersed computers, and so do certain business critical applications like those that govern the functioning of financial markets.
The Internet Engineering Task Force and the World Wide Web Council have recently created complementary working groups to bring these powerful capabilities to the most familiar and widespread application used to experience the Internet: the web browser. The goal of this initiative is to add a new level of interactivity for web users with real-time communications (Web RTC) in the browser.
While the overarching goal is simple to describe, there are several critical requirements that a successful, widely adoptable Web RTC API will need to meet:
Real-Time communications between browsers depends on the packetization of media. This API provides a way to control how media streams are turned into packets and how those packets are turned into media streams.
Interoperable real-time media between browsers uses RTP [[!I-D.rtcweb-rtp-usage]]. RTP depends on the existence of a signaling channel to establish a common understanding of the meaning of packets. This includes identification of different streams, codecs, and codec parameters.
An RTP session consists of a series of RTP streams. Each stream has a source and one or more sinks. This API provides objects that directly map to RTP streams. The source and sink of each real-time media stream is a MediaStreamTrack
[[!GETUSERMEDIA]]. This allows applications to build more complex arrangements of streams, composing them into aggregate MediaStream
collections.
Exchanging media in real time between browsers requires the use of a real time media transport, such as is described in .
The exchange of real-time media between two browsers follows the process:
Local capture and playback of media (steps 1. and 4.) can be achieved by the media capture API [[!GETUSERMEDIA]]. The real-time media streaming API provides access to functions that allow for the transmission of media stream across a network between these two points.
The basic primitive of this API, the RealtimeMediaStream
is a single, unidirectional stream of media. This basic unit can be used to assemble more complex communications scenarios. For example, an application that wishes to enable two-way audio and video communications between peers can create four such streams: an audio stream in each direction, plus a video stream in each direction.
In order to transmit a track from a local media stream—audio or video—an application takes the track and a RealtimeTransport
and creates a RealtimeMediaStream
. A RealtimeMediaDescription
is used to describe how the track is encoded.
navigator.getUserMedia({ audio: true }, function(media) { var track = media.audioTracks[0]; var description = new RealtimeMediaDescription(track); var localRtStream = new LocalRealtimeMediaStream(track, description, realtimeTransport); signalingChannel.send(description.toDictionary()); });
In order to receive the same stream, the RealtimeMediaDescription
is signaled between the two peers. This description can be used to create a RealtimeMediaStream
that decodes encoded tracks.
function receiveDescriptionFromSignaling(remoteDescription) { var description = new RealtimeMediaDescription(remoteDescription); var remoteRtStream = new RemoteRealtimeMediaStream(description, realtimeTransport); var remoteMedia = new MediaStream(remoteRtStream.track); outputTag.src = URL.createObjectURL(remoteMedia); });
A RealtimeMediaStream
represents a uni-directional flow of media to or from the browser.
Instances of RealtimeMediaStream
are created through type-specific constructors, either LocalRealtimeMediaStream
or RemoteRealtimeMediaStream
. Each MUST be created for a single type of stream; audio and video cannot be mixed in a single stream.
Synchronization of streams is achieved by having audio and video tracks added to the same MediaStream
so that packet timestamps and playback can be properly matched between the streams.
rtcpTransport
parameter is omitted or the same as the transport
, then RTCP multiplexing with RTP [[!RFC5761]] is used.
This value is true
if the stream is playing. A playing stream generates packets on the transport if the transport is open.
This value can be true if the underlying RealtimeTransport
is currently closed.
LocalRealtimeMediaStream
Object
The LocalRealtimeMediaStream
represents a locally-sourced stream of real-time media.
The constructor for LocalRealtimeMediaStream
ignores any information in the RealtimeMediaDescription
that it is passed that is not applicable to the provided track.
RemoteRealtimeMediaStream
Object
A RemoteRealtimeMediaStream
represents a stream of real-time media that originates on the network.
The constructor to RemoteRealtimeMediaStream
constructs a MediaStreamTrack
based on the provided RealtimeMediaDescription
. If the browser is unable to construct this object, then an error is thrown. This error might be thrown if the media description includes information for both audio and video tracks.
Some errors in media descriptions cannot be immediately detected by the browser. Descriptions that contain unsupported or conflicting features can be readily detected. Other errors are not obvious until incompatible media arrives.
One such error arises for an incoming stream when an RTP packet type is not assigned to a codec. In this case, the first instance of an RTP packet arriving with an unknown packet type triggers an UnknownPacketTypeEvent
to be fired. After the first instance of this event, packets marked with the unknown packet type are ignored.
Updating the RealtimeMediaDescription
on a stream resets the event status of any existing unknown packet types. When another packet containing an unknown packet type arrives, the event is fired once more.
RealtimeMediaDescription
Object
A RealtimeMediaDescription
is the basic means of specifying what a packetized stream of media looks like. A RealtimeMediaDescription
is used to specify what an outgoing stream is to look like and to describe what an incoming stream looks like.
RealtimeMediaDescription
provides a basic form of media negotiation through the update()
method.
Error
if the resulting description cannot possibly be used to describe any real-time stream because the constraints are incompatible with the current state of the description.
Error
if the mandatory constraints cannot be met.
RealtimeMediaDescriptionDictionary
. This method allows for easier application access to data for exchange with peers.
RealtimeMediaDescriptionDictionary
Object
Since a media description is likely to be exchanged over a signaling channel, this object represents the value of a RealtimeMediaDescription
without the corresponding methods.
RtpStreamDescription
Object
A RtpStreamDescription
describes a single codec and how it is applied to both encoding or decoding. This includes the packet type for the codec and any codec-specific parameters.
RtpExtension
ObjectRTP Extensions [[!RFC5285]] enables the addition of extension information to the RTP header. This enumeration identifies specific extensions that might be enabled. A set of these values may be used to describe each real-time stream. Omitting the set indicates that header extensions cannot be used on the stream.
enum RtpExtension {
"rapid-sync", "c2m-alevel", "m2c-alevel"
};
rapid-sync
c2m-alevel
m2c-alevel
RtcpFeature
ObjectThe real-time feedback channel provided by RTCP [[!RFC3550]] supports a number of optional features. This enumeration identifies specific features. A set of these values are used to describe each real-time stream.
enum RtcpFeature {
"avpf", "nack", "pli", "sli", "rpsi", "reduced", "rtx", "fir", "tmmbr", "tstr"
};
avpf
nack
pli
sli
rpsi
reduced
rtx
fir
tmmbr
tstr
CodecDescription
Object
A CodecDescription
describes a single codec and how it is applied to both encoding or decoding. This includes the packet type for the codec and any codec-specific parameters.
When generating a RealtimeMediaDescription
, the browser MUST specify values for all fields. Values can be omitted from RealtimeMediaDescriptionDictionary
values, which allows the browser to select values for any unspecified values.
video/H264
or audio/PCMA
.
RealtimeMediaDescriptionConstraints
Object
The constraints structure is defined in [[!GETUSERMEDIA]]. RealtimeMediaDescriptionConstraints
uses this scheme with a different set of possible constraints.
The following constraints are defined:
boolean
value that determines the value for the silenceSuppression
parameter of the CodecDescription
.
unsigned long
value for the overall bandwidth allocated to the stream (or set of streams).
Establishing flows of real-time media to and from browsers requires a transport that is suited to this purpose. This document describes how real-time transport flows can be created in a browser. A real-time transport flow is a construct that allows for bidirectional exchange of UDP packets.
UDP and RTP [[!RFC3550]] provide the means for the delivery of time-sensitive media between peers. This channel is secured using SRTP [[!RFC3711]] with key negotiation in signaling or through DTLS.
Establishing flows of UDP through middleboxes such as Network Address Translators (NAT) or firewalls requires the use of techniques such as Interactive Connectivity Establishment (ICE) [[!RFC5245]]. The provided API describes primitives that enable the implementation of ICE, but do not require it other than requiring the consent mechanisms that it provides, which is critical to the security of the web.
This API only deals with the creation of a secured transport between peers.
RealtimeTransportBuilder
The RealtimeTransportBuilder
provides a simple interface for the creation of peer-to-peer real-time transport.
Operation of the RealtimeTransportBuilder
is straightforward. The constructor accepts the options that include the RealtimeTransportOptions
used to construct a RealtimeTransport
. After calling start()
, the transport builder produces events when ICE candidates (RealtimePort
s) are gathered, and when a transport is successfully created. The following example illustrates its use.
var options = { transport: transportOptions, stun: stunServer }; var builder = new RealtimeTransportBuilder(options); builder.onport = function(e) { signaling.send('port', e.port); }; signaling.onport = function(port) { builder.addRemote(port); }; builder.onconnect = function(e) { e.target.stop(); gotTransport(e.transport); // at which point streams can be added, etc... }; builder.start();
RealtimeTransportBuilder
Advanced uses of the transport API can establishing real-time media transport by interacting with the following two objects:
RealtimePort
is the end point for a real-time transport. This represents a UDP port, opened by the browser. The RealtimePort encapsulates the functions necessary to perform an ICE negotiation [[!RFC5245]]. In ICE terms, a RealtimePort
is a local candidate.
RealtimeTransport
is a peer-to-peer bearer for secured media. It binds a local RealtimePort
to a remote RealtimePort
and enables the bidirectional exchange of media packets.
In order to establish a transport between a local peer and remote peer, the following process is applied:
RealtimeMediaStream
s can then be added to the transport.
In the first step of this scenario one or more RealtimePort
objects are created in different ways. The browser allocates a local UDP port on each of the available network interfaces and returns these to the application.
RealtimePort.openLocalPorts(function(ports) { signalingChannel.send('candidates', ports); localCandidates.push(ports); });
Each real-time port consists of an IP address, a port number, a username fragment, a password and a priority. This information is exchanged with the remote peer using whatever signaling mechanism is chosen by the application.
Other forms of real-time port might be necessary for successful traversal of middleboxes like firewalls and NATs. For instance, a relay port (i.e., relay candidate) uses a relay server to forward packets. Because the relay server is publically reachable, many of the concerns with middlebox traversal do not apply to it, enabling communication in more challenging network conditions.
RealtimePort.allocateRelay(relay, function(error, relayCandidates) { if (!error) { signalingChannel.send('candidate', relayCandidate); } });
Local and remote real-time ports are paired and connectivity checking is used for each pair to determine which ports can be used for exchanging packets.
function receivePeerCandidates(remotePorts) { var candidatePairs = localCandidates.forEach(function(local) { local.addEventListener('checksuccess', checkSuccessCallback); return remotePorts.forEach(function(remote) { local.check(remote); }); }); }
Of the successful connectivity checks, one or more pairs are selected. A RealtimeTransport
is then created from the pair of ports.
function checkSuccessCallback(event) { var local = event.target; var remote = event.remote; RealtimeTransport.createTransport(local, remote, options, function(err, transport) { realtimeTransport = transport; }); }
The resulting transport object can be used to securely exchange media with the peer.
A real-time transport builder provides an application with an ICE implementation that produces a RealtimeTransport
with minimal effort. The RealtimeTransportBuilder
uses the RealtimePort
API, and provides a means for the application to inspect, control or interrupt the ongoing ICE setup.
Additional options for RealtimeTransportBuilder
include optional STUN and TURN servers, plus control over whether this peer is in the ICE controlling or controlled role.
RealtimeTransportBuilder
Object
A RealtimeTransportBuilder
is responsible for constructing a peer-to-peer transport using ICE.
RealtimePort
s in priority order (highest priority first). These ports can be interacted with directly.
RemoteRealtimePort
s provided to the addRemote()
method, sorted in priority order.
null
prior to the successful completion of processing.
Starts or restarts the transport builder. The transport builder will perform the ICE process as though for a single component.
It is possible invoke this method multiple times, where each subsequent invocation triggers a restart of ICE processing. While running, the builder will automatically restart the process if it detects network events that necessitate a restart.
connect
event is fired when a transport is successfully created. This event could fire multiple times during the operation of the transport builder if a transport with a higher priority is selected, or network changes cause the current transport to fail.
port
event is fired when a local port is gathered.
error
is fired by a transport builder when no candidates can be gathered or when transport creation fails.
RealtimeTransportBuilderOptions
Dictionary
A RealtimeTransportBuilderOptions
contains all the information necessary to establish a peer-to-peer transport using RealtimeTransportBuilder
. All values, except transport
are optional.
RealtimeTransport
.
RealtimeTransportConnectEventHandler
Callback FunctionThis callback is invoked when a transport builder successfully creates a transport.
callback RealtimeTransportConnectEventHandler = void (RealtimeTransportConnectEvent event);
RealtimeTransportConnectEvent
Interface
The RealtimeTransportConnectEvent
event object passed to the RealtimeTransportConnectEventHandler
includes the transport that was created.
RealtimeTransport
that was connected by the transport builder.
RealtimePortEventHandler
Callback FunctionThis callback is invoked when a transport builder opens, discovers or allocates a local port.
callback RealtimePortEventHandler = void (RealtimePortEvent event);
RealtimePortEvent
Interface
The RealtimePortEvent
event object passed to the RealtimePortEventHandler
includes the port that was opened.
RealtimePort
that was opened, discovered, or allocated (i.e., gathered) by the transport builder. This could be a relayed or reflexive candidate. Relayed or reflexive candidates that include a specific base port implement the DerivedRealtimePort
interface, which includes the base
attribute. Relayed ports that use transports other than UDP do not include base
attribute.
DerivedRealtimePort
Interface
The DerivedRealtimePort
interface is used by the RealtimeTransportBuilder
to provide information on the base for derived candidates. This includes server reflexive, peer reflexive and UDP relay candidates.
Reflexive candidates that implement this interface do not provide any events relating to connectivity checking. Connectivity checking events are provided on the corresponding base port. Relayed ports provide a complete implementation.
RealtimePort
that this object was derived from. The base
provides information necessary to distinguish unique candidates in some unusual network configurations.
DerivedRealtimePort
implements RealtimePort
:
DerivedRealtimePort implements RealtimePort;
A RealtimeTransport
represents the flow of packets between a local and a remote real-time port.
Upon creation, a RealtimeTransport
beings automatically generating connectivity checks toward the selected remote peer. If a consent check fails, the transport remains open, but no packets can be sent.
RealtimeTransport
Objecttrue
. Note that absence or expiry of consent from the remote peer can cause a transport to be unable to send on an open transport.
close
event is fired when the transport is closed.
false
when consent toward the remote peer has expired.
consent
event is fired when consent checks toward the remote peer succeed after having failed.
consentexpired
event is fired when consent checks toward the remote peer time out and no packets are able to be sent on this transport.
bandwidthchange
event is fired when the browser learns of a change in available bandwidth on the transport. The browser MAY limit the rate of notifications, or suppress notification for small (10% or less) changes in available bandwidth.
oninactive
event is fired.
inactive
event is fired when the transport has been inactive for inactivityInterval
milliseconds. That is, the time since the last packet was received from the peer exceeds the specified time.
The unknownssrc
event is fired when an RTP packet arrives on the transport without a corresponding RealtimeMediaStream
. Applications that do not signal SSRCs can use this event to recognize a new or changed SSRC and trigger the addition or modification of streams.
The browser MUST buffer packets that arrive with the SSRC until all event handlers have returned or until a RealtimeMediaStream
is created to accept the incoming data. This allows an application to ensure that packets are not lost due to SSRC renumbering or absence of SSRC in signaling.
Specifying RealtimeTransportOptions
can be used to alter the characteristics of a transport.
Descriptionfrom the TLS cipher suite registry. The browser cannot negotiate any suite that is not included in this set.
enum RealtimeTransportMode {
"srtp", "dtls-srtp"
};
srtp
RealtimeTransport
using SRTP. When this option is chosen, the RealtimeTransportOptions
MUST also include outboundSdes
and inboundSdes
.
dtls-srtp
RealtimeTransport
using DTLS-SRTP [[!RFC5764]]. When this option is chosen, the RealtimeTransportOptions
MUST also include role
and it SHOULD include validate
.
DTLS Roles are applicable when creating a transport over DTLS. This option determines whether the local browser is in the client or server role.
enum DtlsRole {
"client", "server"
};
client
RealtimeTransport
. The browser acts as a DTLS client and initiates the DTLS handshake.
server
RealtimeTransport
. The browser waits for the remote peer to initiate the DTLS handshake.
This callback method is invoked when a DTLS transport is being created. It allows the application to block the creation of a new transport based on the identity of the peer.
callback CertificateValidationCallback = boolean (RemoteCertificateInformation remoteCertificate);
The callback is passed information about the certificate offered by the remote peer. The application can make a decision based on this and either return true
to indicate that the transport creation should proceed, or false
to indicate that the transport creation should be aborted.
Information about an X.509 certificate, as used with DTLS.
This is another candidate for moving to another working group.
Users are expected to make their own determination about trustworthiness based on the feedback information presented in browser chrome. Certificate information allows application developers a better way of building more trustworthy applications.
ArrayBuffer
containing the value of the fingerprint. Browsers MUST implement SHA-1 (sha-1
) and SHA-2 256 (sha-256
).
Information about a remotely proffered X.509 certificate, which includes all the basic certificate information, plus fields that reveal what knowledge the browser has about trust (for instance, is this a valid domain certificate).
For example, an application might register the following CertificateValidationCallback
to check that it is talking to the expected domain:
function validateCertificate(certInfo) { return certInfo.isValidForDomain('example.com'); }
This dictionary describes the parameters necessary to interoperably configure an SRTP stream. Default values are the defaults defined in [[!RFC3711]].
n_a
.
n_s
.
This callback function is invoked when a transport is created.
callback TransportCallback = void (DOMString error, RealtimeTransport transport);
The callback is called when a RealtimeTransport
is created.
If the transport creation was successful, the error
argument is null
and the transport
argument contains the newly created RealtimeTransport
.
If the creation was unsuccessful, the error
argument contains a string describing the error and the transport
argument is null
.
This event handler is invoked when an SSRC for which there is no corresponding RealtimeMediaStream
is observed.
callback UnknownSsrcEventHandler = void (UnknownSsrcEvent event);
This event indicates that an SSRC arrived for which there was no corresponding RTP stream.
A RealtimePort
object represents an open UDP port. The RealtimePort
also encapsulates all the information necessary to find and use that port.
RemoteRealtimePort
Object
The RemoteRealtimePort
object is used to describe a remote real-time port. It is a simple dictionary of values, sufficient to describe how to connect to a remote peer.
USERNAME
attribute explicitly. If present, this parameter is used in preference to the username fragment. See server reflexive addresses for an explanation of this parameter.
RealtimePort
Object
A local RealtimePort
provides limited access to the browsers STUN [[!RFC5389]] implementation which provides a means to trigger connectivity checking, the gathering of server reflexive addresses and allocation of TURN relays.
The application cannot select or alter the values chosen for local ports. The browser MAY select any UDP port number, and MUST select values for ufrag and pwd that have sufficient random entropy that they cannot be easily guessed. This guarantees that only entities that receive this information are able to successfully make a connectivity check. It also allows peers to identify unique browsers.
RealtimePort
is opened for each network interface on the host. Calls the provided callback when complete, passing the ports that were opened as a result of the function call. Ports are provided to the callback in priority order.
navigator
or even the network information API.
true
when the object is passed to the application and false
after the close method is invoked.
onchecksuccess
event is never triggered for the specified check.
true
iff the remote port was successfully checked recently. The specific time is based on the browser's configured consent expiration timer.
RealtimePortCallback
Callback
The RealtimePortCallback
callback function is passed to openLocalPorts
or allocateRelay
. When the port is either successfully opened, or opening fails, the callback is invoked. Opening local ports cannot fail. Allocating a TURN relay port creates a single port.
callback RealtimePortCallback = void (DOMString? error, sequence<RealtimePort> ports);
The error parameter is set to null
unless the allocation fails, in which case it contains a DOMString
that explains the reasons for the error. (Ed: Need to specify error code values here.)
ConnectivityCheckEventHandler
Callback FunctionThis callback is invoked with an event whenever a connectivity check event occurs. This is tied to the following events:
onremotecheck
—when a valid connectivity check is made by a remote peer
onchecksent
—when a connectivity check is made by the browser
onchecksuccess
—when a connectivity check succeeds
callback ConnectivityCheckEventHandler = void (ConnectivityCheckEvent event);
ConnectivityCheckEvent
Interface
The event object passed to the ConnectivityCheckEventHandler
includes a target of the local port, the remote port and information on the STUN Binding request and Binding response messages that triggered the event.
The onchecksent
event does not include either STUN message because revealing the STUN transaction identifier chosen by the browser could allow a web attacker to spoof a response.
ip
and port
.
onchecksuccess
and onremotecheck
events, this includes the STUN Binding request that was respectively sent or received. For the onchecksent
event, this attribute is null
.
onchecksuccess
and onremotecheck
events, this includes the STUN Binding response that was respectively received or sent. For the onchecksent
event, this attribute is null
.
RealtimePort
Lifecycle
A local RealtimePort is created by the browser in response to a call to openLocalPorts(callback)
or allocateRelay(callback)
. Each RealtimePort is given to the application with the open attribute set to true.
Host-local ports (host candidates in ICE) are UDP ports that are opened on the local host. These ports are opened by the browser in response to a call to RealtimePort.openLocalPorts(callback)
.
The username fragment and password used in ICE is normally global. That is, the same values are shared for all candidates in the same session. Browsers that wish to interoperate with non-browser peers SHOULD provide the same value for ufrag and pwd as a result of each request to open local ports.
A server reflexive address is the addressing information for a given port, as seen by a server. The server reports the address that it sees when the browser sends it a packet. Where there are network address translation (NAT) middleboxes between the browser and the server, this reveals the translated address at the NAT, a value that might be undetectable from the browser.
Server reflexive addresses are gathered by making connectivity checks to STUN servers from a specific local real-time port. The server provides the address that it sees in the XOR-MAPPED-ADDRESS
attribute of the response.
Using a server reflexive address ultimately results in packets arriving at the corresponding host-local port. Therefore, server reflexive addresses do not require the creation of additional RealtimePort
objects in the browser.
The connectivity check interface is used to send queries to STUN servers. When querying a STUN server, the RemoteRealtimePort
can include several variations on the set of included options:
USERNAME
attribute is populated by concatenating the remote username fragment (remotePort.ufrag
), a colon character (':') and the local username fragment. The MESSAGE-INTEGRITY
attribute is created using the remote password (remotePort.pwd
) as described in [[!RFC5389]].
USERNAME
attribute. MESSAGE-INTEGRITY
is filled as normal.
USERNAME
attribute.
MESSAGE-INTEGRITY
attribute.
A port pair is only marked as having active consent if the ICE-compatible connectivity check is used. This ensures that STUN servers cannot be bombarded with media from browsers.
If long-term credentials are in use for the STUN server, as described in [[!RFC5389]], then the application is responsible for calculating the value of the password.
UDP relays are allocated by calling RealtimePort.allocateRelay(turnServerRealtimePort, callback[, attributes])
. The browser performs a TURN [[!RFC5766]] relay allocation with the identified host and provides a relayed RealtimePort
to the provided callback.
A turn attribute can be set on the TURN server RemoteRealtimePort
to select the transport used between the browser and TURN server. The turn attribute takes one of three values: udp
, tcp
, or tls
. The browser uses UDP to communicate with the TURN server unless otherwise specified. The turn attribute only determines the transport used between browser and TURN server; UDP is the only supported transport between the server and remote peers.
Once the allocation has completed, the callback method is invoked. An error parameter is set to an error code if the allocation fails. An array containing a single RealtimePort
parameter is provided if the allocation is successful.
function createRelayCandidate() { var relay = { ip: '192.0.2.75', port: 7754, username: 'user', password: 'password1', turn: 'udp' }; RealtimePort.allocateRelay(relay, function(error, relayCandidates) { if (error) { reportError(error); } else { signalingChannel.send('candidate', relayCandidate); scheduleConnectivityChecks(relayCandidate); } }); }
In order to select a specific local candidate for the allocation of relays, the allocateRelay
method can be called on a candidate instance. This is only possible if the transport to the relay server is UDP.
Application-selected attributes can be added to the allocation request, just as they can be added to connectivity checks.
enum TurnRelayTransport {
"udp", "tcp", "tls"
};
udp
tcp
tls
Real-Time ports can be closed by calling close()
. This sets the open attribute to false and closes any transports that use the port. Any attempt to invoke methods on a closed RealtimePort
triggers an exception, except for status(remotePort)
that can harmlessly return false
.
Closing a real-time port does not prevent packets from arriving, though it stops them from being seen by applications and thus connectivity checks to these ports fail. A well-behaved remote peer will eventually stop sending when connectivity checks fail.
To establish a bidirectional transport flow between peers, both are required to successfully complete one or more connectivity check requests. Connectivity checks are used to open ports on NAT and firewall middleboxes, to validate end-to-end connectivity and to establish that the peer is willing to receive packets.
Applications can request the sending of a STUN Binding request to perform a connectivity check or collect additional addressing information. The browser performs a connectivity check by sending a STUN Binding request using port.check(remotePort, callback[, attributes])
.
The browser invokes the callback function if the connectivity check successfully completes. The STUN request and response messages are passed to the callback.
Binding requests MUST be globally rate limited by the browser. Any requests that cannot be immediately sent are enqueued. A browser MAY limit the number of requests that it will enqueue; lower limits SHOULD be applied to individual origins to prevent origins from monopolizing access to this feature.
ICE specifies a rate limiting function that is based on the expected bandwidth of media. Since this depends on information provided by a potential web attacker, this input cannot be used. The browser MUST rate limit connectivity checks based only on information that cannot be influenced or altered by a web attacker.
The browser is responsible for populating the STUN USERNAME
, MESSAGE-INTEGRITY
and FINGERPRINT
attributes. STUN attributes can be added or overwritten by including values in the optional attributes
parameter. STUN attributes specified in this manner are covered by the integrity check. Attributes that would cause the STUN request to exceed its size limit cause an exception to be thrown.
DOMString values for ufrag
and pwd
are encoded using UTF-8 [[!UTF-8]] in Binding requests.
Prior to the successful completion of a connectivity check, the browser MUST NOT reveal the transaction identifier to the application. Knowing the transaction identifier of a STUN request prior to receiving a successful response would enable the spoofing of responses, potentially tricking the browser into sending media packets to an unwilling recipient.
The browser MUST limit the time that an outstanding connectivity check remains valid. However, the browser is not responsible for providing a callback when this timer expires. The application is responsible for looking after its own timers.
The browser is responsible for tracking valid remote real-time port pairs. Any time that a locally originated connectivity check succeeds, the browser marks the pair of ports (local port + remote port) as valid. The valid marking lasts for a fixed duration. The browser SHOULD keep a port pair valid for 40 seconds.
The browser MUST NOT send anything other than a connectivity check unless the port pair is valid. This ensures that the remote peer has consented to receive packets and that the consent is recent.
The status of a port pair can be queried by using candidate.status(remotePort)
. This method returns true
if a connectivity check between the two ports succeeded recently.
The browser responds to valid connectivity checks on all open ports. Received packets that do not conform with the following rules MUST be ignored:
USERNAME
attribute that starts with the browser-assigned username fragment, plus a colon (ASCII 0x3a).
MESSAGE-INTEGRITY
attribute that is calculated over the USERNAME
attribute.
FINGERPRINT
attribute.
Applications can register a callback listener against a real-time port. This function is called when a valid connectivity check is received. The callback signature is identical to the callback for locally originated conectivity checks. Both the request and response message are passed to the callback.
Browsers respond to connectivity checks on each port that it opens. The browser MUST limit the number of unique peers that it generates connectivity check responses for. This ensures that the number of flows that can be created towards the browser from different browsers is limited. This mitigates an attack where a web attacker shares open port information with multiple browsers.
STUN attributes that are provided to the application MUST NOT include any attributes that are not covered by the MESSAGE-INTEGRITY
attribute.
StunBinding
Object
The StunBinding
object contains information necessary to construct and interpret STUN Binding requests.
MESSAGE-INTEGRITY
are not authenticated.
StunAttribute
of the given type. This method only returns authenticated attributes.
XOR-MAPPED-ADDRESS
attribute. This returns a dictionary containing ip
and port
.
StunAttribute
Object
The StunAttribute
dictionary contains a single STUN attribute.
Address
ObjectWhen referring to addressing information, the following dictionary is used.
Network interfaces are imperfect and impermanent. They can change, appear and disappear with no warning, especially on mobile devices. Reacting to changes in connectivity is a crucial part of providing good real-time transport.
The networkchange
event is registered against a local RealtimePort
.
Ideally, this would be globally registered, but since events can't originate on static objects, this is difficult. Again, ideally this is something for the network information API to solve.
The browser fires a networkchange
event when it detects a potential change in the status of the network. Events that trigger this callback include changes to open network interfaces and the addition or removal of network interfaces.
Applications that establish peer-to-peer transports require that the IP addresses of a peer are signaled to the remote peer. This can pose a privacy exposure even though an IP address can only be loosely correlated with a person. For instance, it is possible to use IP addresses to determine the physical location of a person.
In some applications, establishing a peer-to-peer transport occurs prior to establishing user consent for the session. This can be necessary to remove the delays associated with transport setup that might otherwise occur after session acceptance. Exposing IP address information prior to acceptance provides the initiator of the session a way to collect the IP address of even an unwilling peer.
Applications are encouraged to only signal relay ports prior to gaining explicit consent from users.
Travis Leithead provided guidance on modern web API design that was invaluable. Tim Moore provided input on mapping media to RTP streams.