Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ICE improvements: prevent candidate pair removal #166

Closed
sam-vi opened this issue May 8, 2023 · 3 comments · Fixed by #168
Closed

ICE improvements: prevent candidate pair removal #166

sam-vi opened this issue May 8, 2023 · 3 comments · Fixed by #168

Comments

@sam-vi
Copy link
Contributor

sam-vi commented May 8, 2023

Background: An incremental approach for improving ICE control capabilities was discussed at the WebRTC WG April 2023 interim meeting. This issue relates to the first in a series of proposed improvements.

Problem: Applications should be able to maintain multiple candidate pairs by preventing the removal of candidate pairs that are not in active use for transport. This is necessary for applications that want to maintain redundant candidate pairs for connection resiliency, or move traffic to an alternate route based on the network cost or other factors.

Proposal: This could be achieved a few different ways.

  1. Cancelable event for candidate pair removal

    When the ICE agent has decided to prune a candidate pair (eg. due to inactivity), the user agent fires a cancelable event to let the application know that a candidate pair is about to be removed. The application can prevent the removal from happening by calling preventDefault() on the event. If not prevented, the ICE agent is free to prune the candidate pair.

    The API looks like

    partial interface RTCIceTransport  {
      attribute EventHandler /* RTCIceCandidatePairEvent */ oncandidatepairadded;      // not strictly necessary for this to work
      attribute EventHandler /* RTCIceCandidatePairEvent */ oncandidatepairremoval;    // before removal
    };
    
    interface RTCIceCandidatePairEvent : Event {    // cancelable
      readonly attribute RTCIceCandidatePair candidatePair;
    };

    This approach to preventing the user agent from taking default action has a precedent in touch event and form submit event.

    This event conveys to the application exactly when the removal is to occur, and allows the decision to permit or prevent removal to be deferred until it actually needs to be made. It sidesteps any race conditions that may have to be averted with the other options.

  2. Change automatic behaviour - removable attribute

    The application can change the ICE agent's automatic behaviour by setting an attribute (or an internal slot, through a method) to prevent a candidate pair from being automatically pruned by the ICE agent.

    partial interface RTCIceTransport  {
      attribute EventHandler /* RTCIceCandidatePairEvent */ oncandidatepairadded;
      attribute EventHandler /* RTCIceCandidatePairEvent */ oncandidatepairremoved;    // after removal
    };
    
    partial interface RTCIceCandidatePair {
      attribute boolean removable;
    };
  3. Change automatic behaviour - idleTimeout attribute

    This attribute leaves it up to the ICE agent to manage the candidate pair lifecycle, but with input from the application. The ICE agent may prune the candidate pair if no data or ICE check activity has occurred on the candidate pair within the timeout duration.

    partial interface RTCIceTransport  {
      attribute EventHandler /* RTCIceCandidatePairEvent */ oncandidatepairadded;
      attribute EventHandler /* RTCIceCandidatePairEvent */ oncandidatepairremoved;    // after removal
    };
    
    partial interface RTCIceCandidatePair {
      attribute unsigned long idleTimeout;    // initialized to the default timeout
    };

    The idleTimeout can achieve the same effect as removable, with max value meaning never remove, and 0 meaning the ICE agent can prune freely.

    This option gives more control than a removable attribute - an application can choose to simply extend the duration for which an inactive candidate pair is retained.

    Another benefit is that there is no need for a new API to let the application prune candidate pairs. The ICE agent will eventually clean up inactive candidate pairs after the timeout. The user agent could also enfore policies on how long of a timeout the application is allowed to set.

@sam-vi
Copy link
Contributor Author

sam-vi commented May 11, 2023

Here's how a basic usage of this API looks.

const pc = new RTCPeerConnection({iceServers: [/* ice servers */]});
const transceiver = pc.addTransceiver("video");
await pc.setLocalDescription();

// Option 1 - cancelable event
transceiver.sender.transport.iceTransport.oncandidatepairremoval = (e) => {
  if (e.candidatePair.local.type === 'relay' || e.candidatePair.local.protocol === 'udp') {
    e.preventDefault();
  }
  // else e.candidatePair gets removed
};


// Option 2 - removable attribute
transceiver.sender.transport.iceTransport.oncandidatepairadded = (e) => {
  if (e.candidatePair.local.type === 'relay' || e.candidatePair.local.protocol === 'udp') {
    e.candidatePair.removable = false;
  }
};


// Option 3 - idleTimeout attribute
transceiver.sender.transport.iceTransport.oncandidatepairadded = (e) => {
  if (e.candidatePair.local.type === 'relay' || e.candidatePair.local.protocol === 'udp') {
    e.candidatePair.idleTimeout = Number.MAX_SAFE_INTEGER;
  }
};

@dontcallmedom-bot
Copy link

This issue had an associated resolution in WebRTC May 2023 meeting – 16 May 2023 (IceController: Prevent removal of candidate pairs w3c/webrtc-extensions#166):

RESOLUTION: Write a PR for a cancelable event approach

@dontcallmedom-bot
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants