skip to content

When a WebRTC caller's laptop moves from office Wi-Fi to a phone hotspot mid-call, how does ICE detect the dead path, and how does an ICE restart recover the call?

level: seniorimportance: should knowfreq 14%

answer

  1. STUN binding as a heartbeat
  2. 30 seconds without an answer
  3. disconnected is transient, failed is not
  4. new ice-ufrag and ice-pwd
  5. the same DTLS connection continues

basics

~20 s

Consent freshness (RFC 7675) sends authenticated STUN checks on the selected pair; after 30 seconds without a response the endpoint must stop sending. An ICE restart, an offer with new ufrag and password, gathers candidates on the new network and selects a new pair.

solid answer

~50 s

Under RFC 7675 each endpoint sends a STUN Binding request on the selected pair about every 5 seconds (randomised to 4–6 s), authenticated with the ICE short-term credentials; if no valid response arrives for 30 seconds it **MUST** stop sending on that 5-tuple, and it may not reuse those ICE credentials there. The application typically sees the ICE transport go `disconnected` (transient, implementation-defined) and, once every pair has failed or lost consent, `failed`, which is terminal until a restart; the W3C specification recommends restarting on `failed`. `restartIce()` (or `createOffer` with `iceRestart: true`) makes the next offer carry new `ice-ufrag` and `ice-pwd`, which RFC 8445 requires both of. After the offer/answer exchange a new gathering phase finds the hotspot's candidates, checks run, and the controlling agent nominates a pair. Roles are kept, and if the DTLS fingerprint and `tls-id` are unchanged the same DTLS connection continues over the new pair.

code

pseudocode · 12 lines
pseudocode
on iceconnectionstatechange:
    if pc.iceConnectionState == "failed":
        pc.restartIce()                 // next offer gets new ice-ufrag / ice-pwd
    else if pc.iceConnectionState == "disconnected":
        wait 3 seconds
        if pc.iceConnectionState == "disconnected" and bytes_received_since(pc.getStats()) == 0:
            pc.restartIce()

on negotiationneeded:
    offer = pc.createOffer()            // carries the fresh ICE credentials
    pc.setLocalDescription(offer)       // starts a new gathering phase
    signal(pc.localDescription)

go deeper

for a junior

Remember that a network change can kill the selected path and that an ICE restart, with new ICE credentials, recovers it.

for a middle

Explain consent freshness timers, the difference between disconnected and failed, and what a restart offer changes in the SDP.

for a senior

Design the restart policy: when to restart on disconnected, how to avoid restart storms, and why TURN must stay configured for hotspots.

for a principal

Weigh proactive restarts on platform network signals against waiting for consent expiry, trading call continuity against signalling load.

## What breaks when the interface changes An ICE session ends with a **selected candidate pair**: one local and one remote transport address that carry the media. Moving from Wi-Fi to a hotspot invalidates the local half: - the Wi-Fi **host candidate** disappears with the interface; - the NAT binding behind the **server-reflexive candidate** belonged to the office network; - a **TURN allocation** is tied to the 5-tuple the client used to reach the relay, which is gone. Nothing on the new network has candidates yet, and the far peer keeps sending to an address that no longer answers. ## Detecting loss: consent freshness WebRTC uses **consent freshness** (RFC 7675) to keep proving the far end still wants the traffic, and it doubles as a liveness check: | Rule | Value | |---|---| | What is sent | a STUN Binding request on the selected pair, authenticated with the ICE short-term credentials | | Interval | SHOULD default to 5 s, randomised to 0.8–1.2 times, never under 4 s | | Consent expiry | 30 s without a valid, authenticated response | | On expiry | MUST stop sending on that 5-tuple | | Afterwards | the same ICE credentials MUST NOT be used on it again | The last row is why recovery needs a restart: consent lost on a 5-tuple cannot be regained with the old credentials. ## The states the application sees The W3C API reports, per ICE transport and aggregated as `iceConnectionState`: - **`disconnected`** — connectivity currently lost; how this is detected is implementation-defined, and it may resolve itself on a flaky network. - **`failed`** — every pair has failed checks or lost consent and nothing new is expected; this is **terminal until ICE is restarted**. It does not close the DTLS transport, the SCTP association or its data channels, so a restart can resume them. The W3C specification recommends a restart on `failed`, and allows an application to restart on `disconnected` after checking, for example with `getStats`, that no bytes are arriving. ## What an ICE restart does 1. The application calls `restartIce()`, or passes `iceRestart: true` to `createOffer`. 2. The next offer carries new `ice-ufrag` and `ice-pwd`; RFC 8445 says a restart **MUST** change both. 3. The offer and answer cross the signalling channel, which the application provides. 4. Applying the new local description starts a **gathering phase** on the hotspot: host, reflexive and relay candidates. 5. Connectivity checks run on the new pairs, and the controlling agent nominates one. 6. Until then, data may continue on the old pair if it still works, and consent checks continue there. Either agent may restart (RFC 8445). When both try at once, the offers collide, which the negotiation layer resolves. ## What survives the restart - **Roles.** RFC 8445 says an ICE restart does not redetermine the controlling and controlled roles, apart from the exceptions it lists. - **The DTLS connection.** JSEP (RFC 9429) says that if the DTLS fingerprint and `tls-id` are unchanged, the same DTLS connection continues over the new ICE channel, so no new handshake and no new SRTP keys are needed. - **Tracks and data channels.** They were not closed by `failed` and carry on over the new pair. ## Production judgment - Restart on `failed` always; on `disconnected`, wait a few seconds and restart only if traffic has stopped. - An application that learns of a network change from the platform may restart at once instead of waiting for consent to expire. - Keep TURN in the configuration: a hotspot may put the user behind a carrier NAT whose mapping defeats direct paths, leaving only the relay. - Rate-limit restarts so a flapping network does not become a storm of offers. - Measure it: count restarts, how many reach `connected` again, and how long the media gap lasted. A rising failure rate after restarts usually points at relay reachability on the new networks, not at ICE itself. - Expect a gap. Even a fast restart costs a signalling round trip, a gathering phase and a round of checks, so the user hears a short silence; the goal is seconds, not zero.

  • Wi-Fi comes back after 40 seconds; why can the call not simply resume on the old candidate pair?
    After 30 seconds without a valid response, consent on that 5-tuple expired, and RFC 7675 says the same ICE credentials MUST NOT be used on it again; only a new session or an ICE restart can regain it. Within the 30 seconds the `disconnected` state can recover by itself, which is why applications wait briefly before restarting.
  • Does an ICE restart redo the DTLS handshake and change the SRTP keys?
    Not by default. RFC 8842 says an ICE restart does not require a new DTLS association, and JSEP says that when the fingerprint and `tls-id` are unchanged the same DTLS connection continues over the new ICE channel. The SRTP keys derived from it therefore stay in use; a new association happens only if an endpoint changes those attributes.
  • Which side starts the restart, and do the ICE roles change?
    Either agent may restart, and in the browser API it is the side that creates the next offer. RFC 8445 keeps the controlling and controlled roles across a restart, so the same agent nominates the new pair. If both sides restart at once, the colliding offers are resolved by the negotiation layer.

saying these in an interview costs you the question

  • An ICE restart always tears down DTLS and renegotiates the SRTP keys.
  • The disconnected state is terminal, so the call must be rebuilt from scratch.
  • An ICE restart needs only a new ice-pwd; the ice-ufrag can stay.
  • After consent expires the endpoint keeps sending media in case the path recovers.
  • An ICE restart re-elects which agent is controlling.