RtcTransport

Unofficial Proposal Draft,

More details about this document
This version:
https://w3c.github.io/webrtc-rtptransport/
Latest published version:
https://www.w3.org/TR/webrtc-rtptransport/
Feedback:
public-webrtc@w3.org with subject line “[rtc-transport] … message topic …” (archives)
GitHub
Inline In Spec
Editors:
(Microsoft Corporation)
(Microsoft Corporation)
(Google)
(Google)
Participate:
Git Repository.
File an issue.
Version History:
https://github.com/w3c/webrtc-rtptransport/commits

Abstract

This document defines the RtcTransport API, a low-level API used for sending and receiving datagrams over a secure peer-to-peer transport.

Status of this document

1. Introduction

The RtcTransport API is a low-level API used for sending and receiving datagrams over a secure peer-to-peer transport.

The transport is consent-based, meaning that the connection must be accepted by the remote peer before any application data can be sent.

It provides application-level packet scheduling, giving applications full control over packet pacing and bandwidth estimation. Additionally, transport feedback is sent back to the sender and fed into a circuit-breaker, which protects the network by disallowing packets to be sent if abusive behavior is detected.

The API has been designed in a modular fashion to allow wire formats, transport establishment mechanics, and feedback formats to evolve over time.

2. Conformance

As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" are to be interpreted as described in [RFC2119] and [RFC8174] when, and only when, they appear in all capitals, as shown here.

This specification defines conformance criteria that apply to a single product: the user agent that implements the interfaces that it contains.

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.)

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.

3. Concepts

Circuit Breaker

A mechanism used to protect the network by detecting and stoping abusive behavior.

Network Route

A specific route between a local and a remote peer.

Transport Format

A combination of a wire format and a Transport Header.

Transport Header

A transport level header included in packets that carries feedback information from the remote peer, used in conjuction with the Circuit Breaker to detect and prevent abusive network behavior.

Writable

A Network Route is considered writable when it has been verified that the remote peer can successfully receive packets over that specific Network Route.

4. The RtcTransport Interface

[Exposed=(Window,Worker)]
interface RtcTransport {
  constructor(RtcTransportConfig config);
  undefined setFormat(RtcTransportFormat format);
  undefined sendPackets(sequence<RtcPacketToSend> packets, RtcNetworkRoute networkRoute);
  undefined setRemoteFingerprints(sequence<ArrayBuffer> fingerprint);
  Promise<boolean> establishEncryption(RtcNetworkRoute networkRoute);
  sequence<RtcPacketSentInfo> getPacketSentInfo();
  sequence<RtcPacketReceived> getReceivedPacket();
  static readonly attribute FrozenArray<RtcTransportFormat> supportedFormats;
  readonly attribute RtcNetworkRouteController networkRouteController;
  attribute EventHandler ontransportstatus;
  attribute EventHandler onpendingpacketssentinfo;
  attribute EventHandler onpendingpacketsreceived;
  attribute EventHandler onerror;
  attribute EventHandler onfeedbacksent;
};

4.1. Internal slots

An RtcTransport object has the following internal slots.

Internal Slot Description (non-normative)
[[Format]] The configured RtcTransportFormat.
[[RouteController]] The route controller. Instantiated according to the provided transportControllerType.
[[PendingSendPackets]] A queue for packets that are scheduled to be sent.
[[PendingSentInfo]] A queue for information about sent packets.
[[PendingReceivedPackets]] A queue for received packets.
[[EncryptionContext]] The established encryption context.
[[RemoteFingerprints]] A list of fingerprints of the remote peer’s certificates.
[[LastScheduledPacketInfo]] The ID and send time of the last successfully scheduled packet.

4.2. Constructor

constructor(config)

When the RtcTransport() constructor is invoked, the user agent MUST run the following steps:

  1. Let transport be a new RtcTransport object.

  2. Set transport’s [[Format]] internal slot to undefined.

  3. Set transport’s [[PendingSendPackets]] internal slot to a new empty queue.

  4. Set transport’s [[PendingSentInfo]] internal slot to a new empty queue.

  5. Set transport’s [[PendingReceivedPackets]] internal slot to a new empty queue.

  6. Set transport’s [[EncryptionContext]] internal slot to undefined.

  7. Set transport’s [[RemoteFingerprints]] internal slot to undefined.

  8. Set transport’s [[LastScheduledPacketInfo]] internal slot to undefined.

  9. If config’s transportControllerType member is "automaticIceController", set transport’s [[RouteController]] internal slot to a new RtcAutomaticIceController object.

  10. If config’s transportControllerType member is "manualIceController", set transport’s [[RouteController]] internal slot to a new RtcManualIceController object.

  11. Return transport.

4.3. Methods

setFormat(format)

When the setFormat(format) method is invoked, the user agent MUST run the following steps:

  1. Let transport be the RtcTransport object on which the method was invoked.

  2. If transport’s [[Format]] internal slot is not undefined, throw an InvalidStateError.

  3. If format is the RtcTransportFormat value "ICE-DTLS/V0" and transport’s [[RouteController]] internal slot is neither an RtcAutomaticIceController nor an RtcManualIceController object, throw a NotSupportedError.

    In this version of the specification, the only supported RtcTransportFormat is "ICE-DTLS/V0", which is compatible with all available route controllers (RtcAutomaticIceController and RtcManualIceController).

  4. Set transport’s [[Format]] internal slot to format.

sendPackets(packets, networkRoute)

When the sendPackets(packets, networkRoute) method is invoked, the user agent MUST run the following steps:

  1. Let transport be the RtcTransport object on which the method was invoked.

  2. Let controller be transport’s [[RouteController]] internal slot.

  3. If networkRoute’s [[AssociatedController]] internal slot is not controller, throw an InvalidAccessError.

  4. If transport’s [[EncryptionContext]] internal slot is undefined, throw an InvalidStateError.

  5. If networkRoute is not Writable, throw an exception.

  6. If packets is empty, return.

  7. Let lastInfo be transport’s [[LastScheduledPacketInfo]] internal slot.

  8. For each packet in packets:

    1. If packet is the first item in packets:

      1. If lastInfo is not undefined:

        1. If packet’s id is less than or equal to lastInfo’s ID, throw a RangeError.

        2. If packet’s sendTime is less than lastInfo’s send time, throw a RangeError.

    2. Otherwise:

      1. Let previousPacket be the item in packets immediately preceding packet.

      2. If packet’s id is less than or equal to previousPacket’s id, throw a RangeError.

      3. If packet’s sendTime is less than previousPacket’s sendTime, throw a RangeError.

    3. Let now be the current high resolution time.

    4. If packet’s sendTime is greater than now + 100ms, throw a RangeError.

  9. Enqueue all items in packets into transport’s [[PendingSendPackets]] queue.

  10. Let lastPacket be the last item in packets.

  11. Set transport’s [[LastScheduledPacketInfo]] to a new record containing lastPacket’s id as ID and lastPacket’s sendTime as send time.

What type of exceptions should be thrown when the various checks fail?

What should the acceptable range for the send time be? What if the send time is in the past?

Decide what to do if the networkRoute becomes non-writable before packets were scheduled for sending.

Describe how sendPackets interacts with the circuit breaker.

There should be some text describing how sending is done and what the expected behavior should be.

setRemoteFingerprints(fingerprint)

When the setRemoteFingerprints(fingerprint) method is invoked, the user agent MUST run the following steps:

  1. Let transport be the RtcTransport object on which the method was invoked.

  2. If transport’s [[RemoteFingerprints]] internal slot is not undefined, throw an InvalidStateError.

  3. Set transport’s [[RemoteFingerprints]] internal slot to fingerprint.

Should there be any validation of the fingerprints? Is there a particular standard we expect them to adhere to?

establishEncryption(networkRoute)

When the establishEncryption(networkRoute) method is invoked, the user agent MUST run the following steps:

  1. Let transport be the RtcTransport object on which the method was invoked.

  2. Let p be a new promise.

  3. Let controller be transport’s [[RouteController]] internal slot.

  4. If networkRoute’s [[AssociatedController]] internal slot is not controller, reject p with an InvalidAccessError and return p.

  5. If transport’s [[EncryptionContext]] internal slot is not undefined, resolve p with true and return p.

  6. If transport’s [[RemoteFingerprints]] internal slot is undefined, reject p with an InvalidStateError and return p.

  7. If networkRoute is not writable, resolve p with false and return p.

  8. Run the following steps in parallel:

    1. Start or continue the encryption establishment process over networkRoute to establish a secure transport connection.

    2. As part of the encryption establishment process, the user agent MUST verify that the certificate presented by the remote peer matches one of the fingerprints stored in transport’s [[RemoteFingerprints]] internal slot. If the verification fails, the encryption establishment process fails.

      The specific encryption mechanism depends on the configured RtcTransportFormat. For example, for the RtcTransportFormat value "ICE-DTLS/V0", this corresponds to performing a DTLS handshake and verifying the remote certificate against the fingerprints.

    3. If the encryption establishment process completes successfully:

      1. Set transport’s [[EncryptionContext]] internal slot to the established encryption context.

      2. Resolve p with true.

    4. If the encryption establishment process fails or times out:

      1. Resolve p with false.

  9. Return p.

getPacketSentInfo()

When the getPacketSentInfo() method is invoked, the user agent MUST run the following steps:

  1. Let transport be the RtcTransport object on which the method was invoked.

  2. Let result be a new empty list.

  3. While transport’s [[PendingSentInfo]] queue is not empty:

    1. Append the result of dequeueing from transport’s [[PendingSentInfo]] queue to result.

  4. Return result.

getReceivedPacket()

When the getReceivedPacket() method is invoked, the user agent MUST run the following steps:

  1. Let transport be the RtcTransport object on which the method was invoked.

  2. Let result be a new empty list.

  3. While transport’s [[PendingReceivedPackets]] queue is not empty:

    1. Append the result of dequeueing from transport’s [[PendingReceivedPackets]] queue to result.

  4. Return result.

4.4. Attributes

supportedFormats, of type FrozenArray<RtcTransportFormat>, readonly

Returns a list of supported RtcTransportFormats.

networkRouteController, of type RtcNetworkRouteController, readonly

Returns the controller associated with this transport.

ontransportstatus, of type EventHandler

Fired when the circuit-breaker disables or re-enables the transport.

onpendingpacketssentinfo, of type EventHandler

Fired when there is new packet sent info to retrieve.

onpendingpacketsreceived, of type EventHandler

Fired when there are new received packets to retrieve.

onerror, of type EventHandler

Fired on buffer overflows (sent info, feedback, or receive buffers).

onfeedbacksent, of type EventHandler

Fired when the transport automatically generates and sends protocol-level feedback.

5. ICE Controllers

5.1. RtcManualIceController

[Exposed=(Window,Worker)]
interface RtcManualIceController {
  undefined gatherHostCandidates();
  Promise<undefined> gatherSrflxCandidates(IceServerInit iceServer);
  Promise<boolean> refreshSrflxCandidate(LocalIceCandidate localCandidate);
  Promise<undefined> gatherRelayCandidates(IceServerInit server, unsigned long requestedLifetimeInSeconds);
  Promise<unsigned long> refreshRelayCandidate(LocalIceCandidate relayCandidate, unsigned long requestedLifetimeInSeconds);
  IceCandidatePair createCandidatePair(LocalIceCandidate local, RemoteIceCandidateInit remote);
  Promise<IceProbeResult> probeCandidatePair(IceCandidatePair candidatePair);
  attribute EventHandler oncandidategathered;
  attribute EventHandler oncandidateremoved;
  attribute EventHandler onmaxpayloadsizeupdate;
  attribute EventHandler onerror;
};

5.1.1. Internal slots

An RtcManualIceController object has the following internal slots.

Internal Slot Description (non-normative)
[[HostCandidateGatheringStarted]] A boolean indicating whether host candidate gathering has been started.
[[IceUfrag]] A randomly assigned username fragment for local ICE authentication.
[[IcePassword]] A randomly assigned password for local ICE authentication.
[[LocalCandidatesToProcess]] A queue of LocalIceCandidate objects gathered by this controller that are scheduled to be processed.

5.1.2. Instantiation

When a new RtcManualIceController object is created, the user agent MUST run the following steps:

  1. Let controller be a new RtcManualIceController object.

  2. Set controller’s [[HostCandidateGatheringStarted]] internal slot to false.

  3. Set controller’s [[IceUfrag]] internal slot to a newly generated random username fragment.

  4. Set controller’s [[IcePassword]] internal slot to a newly generated random password.

  5. Set controller’s [[LocalCandidatesToProcess]] internal slot to a new empty queue.

  6. Return controller.

5.1.3. Methods

gatherHostCandidates()

When the gatherHostCandidates() method is invoked, the user agent MUST run the following steps:

  1. Let controller be the RtcManualIceController object on which the method was invoked.

  2. If controller’s [[HostCandidateGatheringStarted]] internal slot is true, return.

  3. Set controller’s [[HostCandidateGatheringStarted]] internal slot to true.

  4. Gather host candidates in parallel for controller.

gatherSrflxCandidates(iceServer)

When the gatherSrflxCandidates(iceServer) method is invoked, the user agent MUST run the following steps:

  1. Let controller be the RtcManualIceController object on which the method was invoked.

  2. Validate the IceServer iceServer with expected scheme "stun".

  3. Let p be a new promise.

  4. Run the following steps in parallel:

    1. Let completedCount be 0.

    2. Let availableInterfaces be the system’s available network interfaces.

    3. If availableInterfaces is empty, Queue a task to resolve p with undefined.

    4. Let numInterfaces be the size of availableInterfaces.

    5. For each interface in availableInterfaces:

      1. Run the following steps in parallel:

        1. Send a STUN Binding request to the STUN server defined by iceServer, utilizing a local port allocated for host candidates on interface.

        2. Wait for a successful STUN Binding response, for the request to time out after 30 seconds, or for interface to become unavailable.

        3. If a successful STUN Binding response is received:

          1. Let reflectedAddress and reflectedPort be the mapped IP address and port discovered in the STUN response.

          2. Let candidate be a new LocalIceCandidate object.

          3. Initialize a local candidate candidate for controller on interface, with type "srflx", address reflectedAddress, port reflectedPort, and source server iceServer.

          4. Enqueue candidate into controller’s [[LocalCandidatesToProcess]] queue.

        4. Set completedCount to completedCount + 1.

        5. If completedCount is equal to numInterfaces:

          1. Queue a task to resolve p with undefined.

  5. Return p.

refreshSrflxCandidate(localCandidate)

When the refreshSrflxCandidate(localCandidate) method is invoked, the user agent MUST run the following steps:

  1. Let controller be the RtcManualIceController object on which the method was invoked.

  2. If localCandidate’s [[AssociatedController]] internal slot is not controller, throw an InvalidAccessError.

  3. If localCandidate’s type attribute is not the IceCandidateType value "srflx", throw a TypeError.

  4. Let server be localCandidate’s [[SourceServer]] internal slot.

  5. Let interface be localCandidate’s [[NetworkInterface]] internal slot.

  6. Let p be a new promise.

  7. Run the following steps in parallel:

    1. If interface is unavailable, Queue a task to resolve p with false and return.

    2. Send a STUN Binding request to the STUN server defined by server, utilizing the local port allocated for localCandidate on interface.

    3. Wait for a successful STUN Binding response, for the request to time out after 30 seconds, or for interface to become unavailable.

    4. If a successful STUN Binding response is received:

      1. Queue a task to resolve p with true.

    5. Otherwise:

      1. Queue a task to resolve p with false.

  8. Return p.

gatherRelayCandidates(server, requestedLifetimeInSeconds)

When the gatherRelayCandidates(server, requestedLifetimeInSeconds) method is invoked, the user agent MUST run the following steps:

  1. Let controller be the RtcManualIceController object on which the method was invoked.

  2. Validate the IceServer server with expected scheme "turn".

  3. Let p be a new promise.

  4. Run the following steps in parallel:

    1. Let completedCount be 0.

    2. Let availableInterfaces be the system’s available network interfaces.

    3. If availableInterfaces is empty, Queue a task to resolve p with undefined.

    4. Let numInterfaces be the size of availableInterfaces.

    5. For each interface in availableInterfaces:

      1. Run the following steps in parallel:

        1. Send a TURN Allocate request to the TURN server defined by server, utilizing a local port allocated for host candidates on interface. The Allocate request MUST include a LIFETIME attribute containing requestedLifetimeInSeconds, and utilize the authentication credentials defined by server.

        2. Wait for a successful TURN Allocate response, for the allocation to fail, for the request to time out after 30 seconds, or for interface to become unavailable.

        3. If a successful TURN Allocate response is received:

          1. Let relayedAddress and relayedPort be the relayed IP address and port discovered in the XOR-RELAYED-ADDRESS attribute of the Allocate response.

          2. Let grantedLifetime be the lifetime (in seconds) returned in the LIFETIME attribute of the Allocate response.

          3. Let candidate be a new LocalIceCandidate object.

          4. Initialize a local candidate candidate for controller on interface, with type "relay", address relayedAddress, port relayedPort, source server server, and relay allocation lifetime grantedLifetime.

          5. Enqueue candidate into controller’s [[LocalCandidatesToProcess]] queue.

        4. Set completedCount to completedCount + 1.

        5. If completedCount is equal to numInterfaces:

          1. Queue a task to resolve p with undefined.

  5. Return p.

refreshRelayCandidate(relayCandidate, requestedLifetimeInSeconds)

When the refreshRelayCandidate(relayCandidate, requestedLifetimeInSeconds) method is invoked, the user agent MUST run the following steps:

  1. Let controller be the RtcManualIceController object on which the method was invoked.

  2. If relayCandidate’s [[AssociatedController]] internal slot is not controller, throw an InvalidAccessError.

  3. If relayCandidate’s type attribute is not the IceCandidateType value "relay", throw a TypeError.

  4. Let server be relayCandidate’s [[SourceServer]] internal slot.

  5. Let interface be relayCandidate’s [[NetworkInterface]] internal slot.

  6. Let p be a new promise.

  7. If interface is unavailable, resolve p with 0 and return p.

  8. Run the following steps in parallel:

    1. Send a TURN Refresh request to the TURN server defined by server, utilizing the local port allocated for relayCandidate on interface. The Refresh request MUST include a LIFETIME attribute containing requestedLifetimeInSeconds, and utilize the authentication credentials defined by server.

    2. Wait for a successful TURN Refresh response, for the request to fail, for the request to time out after 30 seconds, or for interface to become unavailable.

    3. If a successful TURN Refresh response is received:

      1. Let grantedLifetime be the lifetime (in seconds) returned in the LIFETIME attribute of the Refresh response.

      2. Set relayCandidate’s [[RelayAllocationLifetime]] internal slot to grantedLifetime.

      3. Queue a task to resolve p with grantedLifetime.

    4. Otherwise:

      1. Queue a task to resolve p with 0.

  9. Return p.

createCandidatePair(local, remote)

When the createCandidatePair(local, remote) method is invoked, the user agent MUST run the following steps:

  1. Let controller be the RtcManualIceController object on which the method was invoked.

  2. If local’s [[AssociatedController]] internal slot is not controller, throw an InvalidAccessError.

  3. Validate the remote candidate remote.

  4. Let pair be a new IceCandidatePair object.

  5. Set pair’s [[LocalCandidate]] internal slot to local.

  6. Set pair’s [[RemoteCandidate]] internal slot to remote.

  7. Set pair’s [[AssociatedController]] internal slot to controller.

  8. Return pair.

probeCandidatePair(candidatePair)

When the probeCandidatePair(candidatePair) method is invoked, the user agent MUST run the following steps:

  1. Let controller be the RtcManualIceController object on which the method was invoked.

  2. If candidatePair’s [[AssociatedController]] internal slot is not controller, throw an InvalidAccessError.

  3. Let local be candidatePair’s localCandidate attribute.

  4. Let remote be candidatePair’s remoteCandidate attribute.

  5. Let interface be local’s [[NetworkInterface]] internal slot.

  6. Let p be a new promise.

  7. Run the following steps in parallel:

    1. If interface is unavailable, run the following steps:

      1. Let result be a new IceProbeResult dictionary, initialized as follows:

      2. Queue a task to resolve p with result and return.

    2. Send a STUN Binding request (probe) to the remote destination defined by remote’s IP address and port, utilizing the local port allocated for local on interface. The probe request MUST utilize standard ICE connectivity check attributes authenticated using the remote candidate’s password fragment.

    3. Let sendTime be the high-resolution timestamp when the STUN Binding request was sent.

    4. Wait for a successful STUN Binding response, for the request to fail, or for the request to time out after 30 seconds, or for interface to become unavailable.

    5. If interface is unavailable, run the following steps:

      1. Let result be a new IceProbeResult dictionary, initialized as follows:

      2. Queue a task to resolve p with result and return.

    6. If a successful STUN Binding response is received:

      1. Let receiveTime be the high-resolution timestamp when the Binding response was received on the local socket.

      2. Let rtt be the measured duration in milliseconds: receiveTime - sendTime.

      3. Let result be a new IceProbeResult dictionary, initialized as follows:

      4. Queue a task to resolve p with result.

    7. Otherwise:

      1. Let result be a new IceProbeResult dictionary, initialized as follows:

      2. Queue a task to resolve p with result.

  8. Return p.

5.1.4. Attributes

oncandidategathered, of type EventHandler

Fired when a local candidate has been found.

oncandidateremoved, of type EventHandler

Fired when a local candidate has been removed.

onmaxpayloadsizeupdate, of type EventHandler

Fired when the max payload size of some IceCandidatePair is updated.

onerror, of type EventHandler

Fired on candidate gathering errors.

5.1.5. Local Candidate Processing

When the [[LocalCandidatesToProcess]] queue of an RtcManualIceController controller is updated:

  1. While controller’s [[LocalCandidatesToProcess]] queue is not empty:

    1. Let candidate be the result of dequeueing from controller’s [[LocalCandidatesToProcess]] queue.

    2. Let source be undefined.

    3. Let lifetime be null.

    4. If candidate’s type attribute is the IceCandidateType value "srflx":

      1. Set source to candidate’s [[SourceServer]] internal slot.

    5. If candidate’s type attribute is the IceCandidateType value "relay":

      1. Set source to candidate’s [[SourceServer]] internal slot.

      2. Set lifetime to candidate’s [[RelayAllocationLifetime]] internal slot.

    6. If candidate’s type attribute is the IceCandidateType value "host":

      1. Set source to "host".

    7. Dispatch a gathered candidate event at controller with candidate, source source, and allocation lifetime lifetime.

The network cost per network type needs to be defined.

What policies should be considered in relation to candidate discovery?

What are reasonable timeout limits? Implementation defined?

Do we need to specify in more detail what it means for an interface to be unavailable?

5.2. RtcAutomaticIceController

[Exposed=(Window,Worker)]
interface RtcAutomaticIceController {
  undefined setIceServers(sequence<IceServer> servers);
  undefined setRemoteCandidates(sequence<RemoteIceCandidate> remoteCandidates);
  attribute EventHandler oncandidategathered;
  attribute EventHandler oncandidateremoved;
  attribute EventHandler onmaxpayloadsizeupdate;
  attribute EventHandler oncandidatepairupdated;
  attribute EventHandler onerror;
};

5.2.1. Internal slots

An RtcAutomaticIceController object has the following internal slots.

Internal Slot Description (non-normative)
[[IceServers]] A list of IceServer dictionaries configured for this controller.
[[IceUfrag]] A username fragment used for remote authentication.
[[IcePassword]] A password used for remote authentication.
[[RemoteCandidates]] A list of RemoteIceCandidate dictionaries representing remote candidates added to the controller.
[[LocalCandidates]] A list of LocalIceCandidate objects representing local candidates active for pair forming.
[[LocalCandidatesToProcess]] A queue of LocalIceCandidate objects gathered by this controller that are scheduled to be processed.

5.2.2. Instantiation

When a new RtcAutomaticIceController object is created, the user agent MUST run the following steps:

  1. Let controller be a new RtcAutomaticIceController object.

  2. Set controller’s [[IceServers]] internal slot to a new empty list.

  3. Set controller’s [[RemoteCandidates]] internal slot to a new empty list.

  4. Set controller’s [[LocalCandidates]] internal slot to a new empty list.

  5. Set controller’s [[LocalCandidatesToProcess]] internal slot to a new empty queue.

  6. Set controller’s [[IceUfrag]] internal slot to a newly generated random username fragment.

  7. Set controller’s [[IcePassword]] internal slot to a newly generated random password.

  8. Start the candidate gathering process for controller.

  9. Return controller.

5.2.3. Methods

setIceServers(servers)

When the setIceServers(servers) method is invoked, the user agent MUST run the following steps:

  1. Let controller be the RtcAutomaticIceController object on which the method was invoked.

  2. For each server in servers:

    1. Validate the IceServer server.

  3. Set controller’s [[IceServers]] internal slot to servers.

setRemoteCandidates(remoteCandidates)

When the setRemoteCandidates(remoteCandidates) method is invoked, the user agent MUST run the following steps:

  1. Let controller be the RtcAutomaticIceController object on which the method was invoked.

  2. For each candidate in remoteCandidates:

    1. Validate the remote candidate candidate.

  3. Set controller’s [[RemoteCandidates]] internal slot to remoteCandidates.

5.2.4. Attributes

oncandidategathered, of type EventHandler

Fired when a local candidate has been found.

oncandidateremoved, of type EventHandler

Fired when a local candidate has been removed.

onmaxpayloadsizeupdate, of type EventHandler

Fired when the max payload size is updated.

oncandidatepairupdated, of type EventHandler

Fired whenever a new IceCandidatePair has been selected.

onerror, of type EventHandler

Fired on candidate gathering errors.

5.2.5. Candidate Gathering

To start the candidate gathering process for a controller controller, the user agent MUST run the following steps in parallel:

  1. Gather host candidates for controller.

  2. Continuously monitor network interfaces.

  3. When a network interface becomes available, for each server in controller’s [[IceServers]] internal slot:

    1. Gather reflexive and relay candidates for controller using server over the network interface.

  4. When controller’s [[IceServers]] internal slot is updated:

    1. Let newServers be the list of IceServers in the new value of [[IceServers]] that were not present in its previous value.

    2. For each server in newServers:

      1. Run the following steps in parallel over each available network interface:

        1. Gather reflexive and relay candidates for controller using server over the network interface.

5.2.6. Gather Reflexive and Relay Candidates

To gather reflexive and relay candidates for a controller controller using an IceServer server over a network interface interface, the user agent MUST run the following steps:

  1. Let url be the result of parsing server’s url attribute as a URL.

  2. If url’s scheme is "stun" or "stuns":

    1. Perform STUN candidate gathering utilizing server on interface.

    2. If a STUN Binding response is successfully received:

      1. Let reflectedAddress and reflectedPort be the mapped IP address and port discovered in the STUN response.

      2. Let candidate be a new LocalIceCandidate object.

      3. Initialize a local candidate candidate for controller on interface, with type "srflx", address reflectedAddress, port reflectedPort, and source server server.

      4. Enqueue candidate into controller’s [[LocalCandidatesToProcess]] queue.

  3. If url’s scheme is "turn" or "turns":

    1. Perform TURN candidate allocation utilizing server on interface.

    2. If a TURN Allocate response is successfully received:

      1. Let relayedAddress and relayedPort be the relayed IP address and port discovered in the XOR-RELAYED-ADDRESS attribute of the Allocate response.

      2. Let grantedLifetime be the lifetime (in seconds) returned in the LIFETIME attribute of the Allocate response.

      3. Let candidate be a new LocalIceCandidate object.

      4. Initialize a local candidate candidate for controller on interface, with type "relay", address relayedAddress, port relayedPort, source server server, and relay allocation lifetime grantedLifetime.

      5. Enqueue candidate into controller’s [[LocalCandidatesToProcess]] queue.

Does STUN/TURN gathering need to be specified in more detail? Is there some other doc we can point to?

5.2.7. Local Candidate Processing

When the [[LocalCandidatesToProcess]] queue of an RtcAutomaticIceController controller is updated:

  1. While controller’s [[LocalCandidatesToProcess]] queue is not empty:

    1. Let localCandidate be the result of dequeueing from controller’s [[LocalCandidatesToProcess]] queue.

    2. Let source be undefined.

    3. Let lifetime be null.

    4. If localCandidate’s type attribute is the IceCandidateType value "srflx":

      1. Set source to localCandidate’s [[SourceServer]] internal slot.

    5. If localCandidate’s type attribute is the IceCandidateType value "relay":

      1. Set source to localCandidate’s [[SourceServer]] internal slot.

      2. Set lifetime to localCandidate’s [[RelayAllocationLifetime]] internal slot.

    6. If localCandidate’s type attribute is the IceCandidateType value "host":

      1. Set source to "host".

    7. Append localCandidate to controller’s [[LocalCandidates]] internal slot.

    8. Dispatch a gathered candidate event at controller with localCandidate, source source, and allocation lifetime lifetime.

5.2.8. Candidate Pair Forming

An RtcAutomaticIceController controller continuously monitors and reacts to updates in its local candidates and remote candidates to form and evaluate candidate pairs:

  1. When controller’s [[LocalCandidates]] internal slot is updated (e.g., when a new local candidate localCandidate is appended):

    1. For each remoteCandidate in controller’s [[RemoteCandidates]] internal slot:

      1. Evaluate whether trying to form a candidate pair with localCandidate and remoteCandidate is worth it or not (e.g., based on candidate types, network type, and routing policies).

      2. If so:

        1. Let pair be an IceCandidatePair created by setting its [[LocalCandidate]] slot to localCandidate, [[RemoteCandidate]] slot to remoteCandidate, and [[AssociatedController]] slot to controller.

        2. Perform an ICE connectivity check (ping) on pair by sending an authenticated STUN Binding request using the remote candidate’s credentials.

  2. When controller’s [[RemoteCandidates]] internal slot is updated:

    1. Let newCandidates be the list of RemoteIceCandidates in the new value of [[RemoteCandidates]] that were not present in its previous value.

    2. For each remoteCandidate in newCandidates:

      1. For each localCandidate in controller’s [[LocalCandidates]] internal slot:

        1. Evaluate whether trying to form a candidate pair with localCandidate and remoteCandidate is worth it or not (e.g., based on candidate types, network type, and routing policies).

        2. If so:

          1. Let pair be an IceCandidatePair created by setting its [[LocalCandidate]] slot to localCandidate, [[RemoteCandidate]] slot to remoteCandidate, and [[AssociatedController]] slot to controller.

          2. Perform an ICE connectivity check (ping) on pair by sending an authenticated STUN Binding request using the remote candidate’s credentials.

  3. Continuously perform ICE connectivity checks by forming candidate pairs with the remote candidates in controller’s [[RemoteCandidates]] internal slot and the local candidates in controller’s [[LocalCandidates]] internal slot, in order to select and maintain network routes.

5.3. Procedures

5.3.1. Validate IceServer

To validate the IceServer server with an optional DOMString expectedScheme:

  1. Let url be the result of parsing server’s url attribute as a URL.

  2. If url is failure, throw a TypeError.

  3. Let scheme be url’s scheme.

  4. If expectedScheme is provided:

    1. If expectedScheme is "stun" and scheme is neither "stun" nor "stuns", throw a TypeError.

    2. If expectedScheme is "turn" and scheme is neither "turn" nor "turns", throw a TypeError.

  5. Otherwise, if scheme is neither "stun", "stuns", "turn", nor "turns", throw a TypeError.

  6. If scheme is "turn" or "turns":

    1. If server’s username member is not present, or if server’s credentials member is not present, throw a TypeError.

5.3.2. Validate Remote Candidate

To validate the remote candidate candidate:

  1. If candidate’s ufrag member is the empty string, throw a TypeError.

  2. If candidate’s pwd member is the empty string, throw a TypeError.

  3. If candidate’s address member is the empty string, throw a TypeError.

  4. If candidate’s port member is equal to 0, throw a TypeError.

  5. If candidate’s type member is not a valid IceCandidateType value, throw a TypeError.

5.3.3. Initialize a Local Candidate

To initialize a local candidate candidate for a controller controller on a network interface interface, with a type type, address address, port port, optional source server server, and optional relay allocation lifetime lifetime, the user agent MUST run the following steps:

  1. Set candidate’s address attribute to address.

  2. Set candidate’s port attribute to port.

  3. Set candidate’s type attribute to type.

  4. Set candidate’s ufrag attribute to controller’s [[IceUfrag]] internal slot.

  5. Set candidate’s pwd attribute to controller’s [[IcePassword]] internal slot.

  6. Set candidate’s networkCost attribute to a value representing the network cost of interface.

  7. Set candidate’s [[NetworkInterface]] internal slot to interface.

  8. If server is provided, set candidate’s [[SourceServer]] internal slot to server.

  9. If lifetime is provided, set candidate’s [[RelayAllocationLifetime]] internal slot to lifetime.

  10. Set candidate’s [[AssociatedController]] internal slot to controller.

5.3.4. Gather Host Candidates

To gather host candidates for an RtcNetworkRouteController controller, the user agent MUST run the following steps in parallel:

  1. Continuously monitor network interfaces.

  2. When a network interface is available:

    1. Let candidate be a new LocalIceCandidate object.

    2. Let port be a port allocated for host candidates on the network interface.

    3. Initialize a local candidate candidate for controller on the network interface, with type "host", address as the IP address of the network interface, and port port.

    4. Enqueue candidate into controller’s [[LocalCandidatesToProcess]] queue.

5.3.5. Dispatch a Gathered Candidate Event

To dispatch a gathered candidate event at a controller controller with a candidate candidate, a source source, and an optional allocation lifetime lifetime, the user agent MUST run the following steps:

  1. Let event be a new IceCandidateGatheredEvent object, initialized as follows:

  2. Queue a task to dispatch event at controller.

6. Helper Types

6.1. RtcTransportConfig

dictionary RtcTransportConfig {
  required DOMString name;
  required RtcNetworkRouteControllerType transportControllerType;
  required sequence<RTCCertificate> certificates;
};
name, of type DOMString

A name useful for debugging/devtools.

transportControllerType, of type RtcNetworkRouteControllerType

Determines the ICE controller type.

certificates, of type sequence<RTCCertificate>

The certificates to use for DTLS.

6.2. RtcPacketToSend

dictionary RtcPacketToSend {
  long long id;
  ArrayBuffer data;
  DOMHighResTimeStamp sendTime;
};
id, of type long long

Monotonically increasing packet ID.

data, of type ArrayBuffer

The byte buffer to be sent.

sendTime, of type DOMHighResTimeStamp

The timestamp describing when the packet should be put on the wire.

6.3. RtcPacketSentInfo

dictionary RtcPacketSentInfo {
  long long id;
  long long packetSizeBytes;
  DOMHighResTimeStamp sendTime;
};
id, of type long long

The ID of the packet.

packetSizeBytes, of type long long

The size of the packet in bytes.

sendTime, of type DOMHighResTimeStamp

The actual timestamp that the packet was put on the wire.

6.4. RtcPacketReceived

dictionary RtcPacketReceived {
  ArrayBuffer data;
  DOMHighResTimeStamp receiveTime;
  RtcNetworkRoute networkRoute;
};
data, of type ArrayBuffer

The byte buffer received.

receiveTime, of type DOMHighResTimeStamp

The timestamp of packet receipt.

networkRoute, of type RtcNetworkRoute

The route the packet arrived on.

6.5. IceServer

dictionary IceServerInit {
  required DOMString url;
  DOMString username;
  DOMString credentials;
};
url, of type DOMString

The URL of the ICE server.

username, of type DOMString

The username used for credential verification.

credentials, of type DOMString

The credentials for authentication.

[Exposed=(Window,Worker)]
interface IceServer {
  readonly attribute DOMString url;
  readonly attribute DOMString username;
  readonly attribute DOMString credentials;
};
url, of type DOMString, readonly

The URL of the ICE server.

username, of type DOMString, readonly

The username used for credential verification.

credentials, of type DOMString, readonly

The credentials for authentication.

6.6. IceCandidateType

enum IceCandidateType {
  "host",
  "srflx",
  "prflx",
  "relay"
};
"host"

Host candidate.

"srflx"

Server reflexive candidate.

"prflx"

Peer reflexive candidate.

"relay"

Relay candidate.

6.7. LocalIceCandidate

[Exposed=(Window,Worker)]
interface LocalIceCandidate {
  readonly attribute DOMString ufrag;
  readonly attribute DOMString pwd;
  readonly attribute DOMString address;
  readonly attribute unsigned short port;
  readonly attribute IceCandidateType type;
  readonly attribute unsigned short networkCost;
};

6.7.1. Internal slots

A LocalIceCandidate object has the following internal slots.

Internal Slot Description (non-normative)
[[SourceServer]] The IceServer dictionary used to discover this candidate, if it is a server reflexive candidate, and undefined otherwise.
[[NetworkInterface]] The dynamic system network interface this candidate is bound to.
[[RelayAllocationLifetime]] An unsigned long representing the TURN allocation lifetime in seconds if this is a relay candidate, and undefined otherwise.
[[AssociatedController]] The ICE controller instance (either RtcManualIceController or RtcAutomaticIceController) that created this candidate.

6.7.2. Instantiation

When a new LocalIceCandidate object is created, the user agent MUST run the following steps:

  1. Let candidate be a new LocalIceCandidate object.

  2. Set candidate’s [[SourceServer]] internal slot to undefined.

  3. Set candidate’s [[NetworkInterface]] internal slot to undefined.

  4. Set candidate’s [[RelayAllocationLifetime]] internal slot to undefined.

  5. Set candidate’s [[AssociatedController]] internal slot to undefined.

  6. Return candidate.

ufrag, of type DOMString, readonly

ICE user fragment.

pwd, of type DOMString, readonly

ICE password.

address, of type DOMString, readonly

IP Address of the candidate.

port, of type unsigned short, readonly

Port of the candidate.

type, of type IceCandidateType, readonly

The candidate type.

networkCost, of type unsigned short, readonly

The costs associated with network route utilization.

6.8. RemoteIceCandidate

[Exposed=(Window,Worker)]
interface RemoteIceCandidate {
  readonly attribute DOMString ufrag;
  readonly attribute DOMString pwd;
  readonly attribute DOMString address;
  readonly attribute unsigned short port;
  readonly attribute IceCandidateType type;
  readonly attribute unsigned short networkCost;
};
ufrag, of type DOMString, readonly

Remote ICE user fragment.

pwd, of type DOMString, readonly

Remote ICE password.

address, of type DOMString, readonly

Remote IP Address of the candidate.

port, of type unsigned short, readonly

Remote Port of the candidate.

type, of type IceCandidateType, readonly

The remote candidate type.

networkCost, of type unsigned short, readonly

The remote costs associated with network route utilization.

[Exposed=(Window,Worker)]
dictionary RemoteIceCandidateInit {
  required DOMString ufrag;
  required DOMString pwd;
  required DOMString address;
  required unsigned short port;
  required IceCandidateType type;
  unsigned short networkCost;
};
ufrag, of type DOMString

Remote ICE user fragment.

pwd, of type DOMString

Remote ICE password.

address, of type DOMString

Remote IP Address of the candidate.

port, of type unsigned short

Remote Port of the candidate.

type, of type IceCandidateType

The remote candidate type.

networkCost, of type unsigned short

The remote costs associated with network route utilization.

6.9. IceCandidatePair

[Exposed=(Window,Worker)]
interface IceCandidatePair {
  readonly attribute LocalIceCandidate localCandidate;
  readonly attribute RemoteIceCandidate remoteCandidate;
};

6.9.1. Internal slots

An IceCandidatePair object has the following internal slots.

Internal Slot Description (non-normative)
[[LocalCandidate]] The local candidate associated with this pair.
[[RemoteCandidate]] The remote candidate associated with this pair.
[[AssociatedController]] The ICE controller instance (either RtcManualIceController or RtcAutomaticIceController) that created this pair.

6.9.2. Instantiation

When a new IceCandidatePair object is created, the user agent MUST run the following steps:

  1. Let pair be a new IceCandidatePair object.

  2. Set pair’s [[LocalCandidate]] internal slot to undefined.

  3. Set pair’s [[RemoteCandidate]] internal slot to undefined.

  4. Set pair’s [[AssociatedController]] internal slot to undefined.

  5. Return pair.

6.9.3. Attributes

localCandidate, of type LocalIceCandidate, readonly

Returns the value of this IceCandidatePair’s [[LocalCandidate]] internal slot.

remoteCandidate, of type RemoteIceCandidate, readonly

Returns the value of this IceCandidatePair’s [[RemoteCandidate]] internal slot.

6.10. IceCandidateGatheredEvent

[Exposed=(Window,Worker)]
interface IceCandidateGatheredEvent : Event {
  readonly attribute (DOMString or IceServer or RemoteIceCandidate) source;
  readonly attribute LocalIceCandidate candidate;
  readonly attribute unsigned long networkCost;
  readonly attribute unsigned long? allocationLifetime;
};
source, of type (DOMString or IceServer or RemoteIceCandidate), readonly

Gathering source descriptor.

candidate, of type LocalIceCandidate, readonly

The gathered candidate.

networkCost, of type unsigned long, readonly

Costs of the network utilized.

allocationLifetime, of type unsigned long, readonly, nullable

Lifetime of allocation granted by allocation servers.

6.11. IceProbeResult

dictionary IceProbeResult {
  required boolean success;
  DOMHighResTimeStamp rtt;
};
success, of type boolean

A boolean indicating whether the route probe check succeeded (received a STUN response).

rtt, of type DOMHighResTimeStamp

Round-trip time discovered by the probe in milliseconds. Only present if success is true.

6.12. Type Definitions and Rest Enums

typedef (RtcManualIceController or RtcAutomaticIceController) RtcNetworkRouteController;
typedef IceCandidatePair RtcNetworkRoute;

enum RtcTransportFormat {
  "ICE-DTLS/V0"
};

enum RtcNetworkRouteControllerType {
  "automaticIceController",
  "manualIceController"
};
RtcNetworkRouteController

Union type describing the underlying ICE route controller.

RtcNetworkRoute

Underlying network route identifier.

"ICE-DTLS/V0"

Wire format utilizing ICE for connection establishment and DTLS as a wire format with Transport Header iteration version 0.

"automaticIceController"

Automatically managed ICE candidates route controller.

"manualIceController"

Manually managed ICE candidates route controller.

7. Security and Privacy Considerations

7.1. Network Route Exposure

Exposing local IP addresses (including private ones) via ICE candidates poses a severe privacy risk. Mitigations should include permission prompts or limiting access to mDNS addresses unless permissions are explicitly granted by the user.

7.2. Circuit Breaker

The ontransportstatus event signals that a circuit-breaker mechanism is present. Implementations MUST shut down the transport if they detect excessive congestion or abusive behavior to protect the integrity of network paths.

7.3. Encryption

The transport MUST be encrypted. Chosen formats like "ICE-DTLS/V0" mandate explicit full-time encryption in flight. The specification requires full secure transport.

7.4. Buffer Overflows

The onerror event mitigates buffer overflows across implementation tiers. Limits must be defined to guarantee bounds on memory allocations, preventing standard memory-exhaustion vectors.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[HR-TIME-3]
Yoav Weiss. High Resolution Time. URL: https://w3c.github.io/hr-time/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[RFC8174]
B. Leiba. Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words. May 2017. Best Current Practice. URL: https://www.rfc-editor.org/info/rfc8174/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/
[WEBRTC]
Cullen Jennings; et al. WebRTC: Real-Time Communication in Browsers. URL: https://w3c.github.io/webrtc-pc/

IDL Index

[Exposed=(Window,Worker)]
interface RtcTransport {
  constructor(RtcTransportConfig config);
  undefined setFormat(RtcTransportFormat format);
  undefined sendPackets(sequence<RtcPacketToSend> packets, RtcNetworkRoute networkRoute);
  undefined setRemoteFingerprints(sequence<ArrayBuffer> fingerprint);
  Promise<boolean> establishEncryption(RtcNetworkRoute networkRoute);
  sequence<RtcPacketSentInfo> getPacketSentInfo();
  sequence<RtcPacketReceived> getReceivedPacket();
  static readonly attribute FrozenArray<RtcTransportFormat> supportedFormats;
  readonly attribute RtcNetworkRouteController networkRouteController;
  attribute EventHandler ontransportstatus;
  attribute EventHandler onpendingpacketssentinfo;
  attribute EventHandler onpendingpacketsreceived;
  attribute EventHandler onerror;
  attribute EventHandler onfeedbacksent;
};

[Exposed=(Window,Worker)]
interface RtcManualIceController {
  undefined gatherHostCandidates();
  Promise<undefined> gatherSrflxCandidates(IceServerInit iceServer);
  Promise<boolean> refreshSrflxCandidate(LocalIceCandidate localCandidate);
  Promise<undefined> gatherRelayCandidates(IceServerInit server, unsigned long requestedLifetimeInSeconds);
  Promise<unsigned long> refreshRelayCandidate(LocalIceCandidate relayCandidate, unsigned long requestedLifetimeInSeconds);
  IceCandidatePair createCandidatePair(LocalIceCandidate local, RemoteIceCandidateInit remote);
  Promise<IceProbeResult> probeCandidatePair(IceCandidatePair candidatePair);
  attribute EventHandler oncandidategathered;
  attribute EventHandler oncandidateremoved;
  attribute EventHandler onmaxpayloadsizeupdate;
  attribute EventHandler onerror;
};

[Exposed=(Window,Worker)]
interface RtcAutomaticIceController {
  undefined setIceServers(sequence<IceServer> servers);
  undefined setRemoteCandidates(sequence<RemoteIceCandidate> remoteCandidates);
  attribute EventHandler oncandidategathered;
  attribute EventHandler oncandidateremoved;
  attribute EventHandler onmaxpayloadsizeupdate;
  attribute EventHandler oncandidatepairupdated;
  attribute EventHandler onerror;
};

dictionary RtcTransportConfig {
  required DOMString name;
  required RtcNetworkRouteControllerType transportControllerType;
  required sequence<RTCCertificate> certificates;
};

dictionary RtcPacketToSend {
  long long id;
  ArrayBuffer data;
  DOMHighResTimeStamp sendTime;
};

dictionary RtcPacketSentInfo {
  long long id;
  long long packetSizeBytes;
  DOMHighResTimeStamp sendTime;
};

dictionary RtcPacketReceived {
  ArrayBuffer data;
  DOMHighResTimeStamp receiveTime;
  RtcNetworkRoute networkRoute;
};

dictionary IceServerInit {
  required DOMString url;
  DOMString username;
  DOMString credentials;
};

[Exposed=(Window,Worker)]
interface IceServer {
  readonly attribute DOMString url;
  readonly attribute DOMString username;
  readonly attribute DOMString credentials;
};

enum IceCandidateType {
  "host",
  "srflx",
  "prflx",
  "relay"
};

[Exposed=(Window,Worker)]
interface LocalIceCandidate {
  readonly attribute DOMString ufrag;
  readonly attribute DOMString pwd;
  readonly attribute DOMString address;
  readonly attribute unsigned short port;
  readonly attribute IceCandidateType type;
  readonly attribute unsigned short networkCost;
};

[Exposed=(Window,Worker)]
interface RemoteIceCandidate {
  readonly attribute DOMString ufrag;
  readonly attribute DOMString pwd;
  readonly attribute DOMString address;
  readonly attribute unsigned short port;
  readonly attribute IceCandidateType type;
  readonly attribute unsigned short networkCost;
};

[Exposed=(Window,Worker)]
dictionary RemoteIceCandidateInit {
  required DOMString ufrag;
  required DOMString pwd;
  required DOMString address;
  required unsigned short port;
  required IceCandidateType type;
  unsigned short networkCost;
};

[Exposed=(Window,Worker)]
interface IceCandidatePair {
  readonly attribute LocalIceCandidate localCandidate;
  readonly attribute RemoteIceCandidate remoteCandidate;
};

[Exposed=(Window,Worker)]
interface IceCandidateGatheredEvent : Event {
  readonly attribute (DOMString or IceServer or RemoteIceCandidate) source;
  readonly attribute LocalIceCandidate candidate;
  readonly attribute unsigned long networkCost;
  readonly attribute unsigned long? allocationLifetime;
};

dictionary IceProbeResult {
  required boolean success;
  DOMHighResTimeStamp rtt;
};

typedef (RtcManualIceController or RtcAutomaticIceController) RtcNetworkRouteController;
typedef IceCandidatePair RtcNetworkRoute;

enum RtcTransportFormat {
  "ICE-DTLS/V0"
};

enum RtcNetworkRouteControllerType {
  "automaticIceController",
  "manualIceController"
};

Issues Index

What type of exceptions should be thrown when the various checks fail?
What should the acceptable range for the send time be? What if the send time is in the past?
Decide what to do if the networkRoute becomes non-writable before packets were scheduled for sending.
Describe how sendPackets interacts with the circuit breaker.
There should be some text describing how sending is done and what the expected behavior should be.
Should there be any validation of the fingerprints? Is there a particular standard we expect them to adhere to?
The network cost per network type needs to be defined.
What policies should be considered in relation to candidate discovery?
What are reasonable timeout limits? Implementation defined?
Do we need to specify in more detail what it means for an interface to be unavailable?
Does STUN/TURN gathering need to be specified in more detail? Is there some other doc we can point to?