ICE restarts

🎻 April 2022 fiddle

Want to learn more about WebRTC?

Look us up here for the WebRTC Fiddle of the Month, created… once a month.

Or just enroll to one of our excellent WebRTC training courses.



ICE Restart

Tsahi: Hi, and welcome to the WebRTC fiddle of the month, and this time we’re going to talk about ICE Restarts.

Philipp: One of my favorite topics.

Tsahi: Okay, so the thing is this, we’ve got ICE. It’s this algorithm that runs everything to get our call connected in WebRTC. It goes collect STUN and TURN addresses, takes them then runs ICE negotiations or connectivity checks, decides what got us disconnected, then we have a kind of a conversation like the one we’re having now, Philipp.

Philipp: Yes. And this is selecting a candidate pair to use.

Tsahi: Okay, so I’ve got my IP address connected to your IP address.

Philipp: Yes.

Tsahi: We’re done.

Philipp: That may change.

Tsahi: Why?

Philipp: Well, for example, ICE can find a better pass that is not the first one that gets selected. But then it thinks, oh, there is a higher priority pass available to us, so let’s switch to that one. Or you can do an ICE restart after you failed.

Tsahi: Then that’s because I’m on a mobile network. And I’m moving to WiFi and back.

Philipp: Yes.

Tsahi: Okay.

Philipp: And your application needs to happen in some way. 

Tsahi: Okay. And you have a fiddle for us for that. 

Philipp: Yes. So let’s look at the fiddle. So it’s pretty standard, we have two buttons, one for a start and that’s a full restart and the log area. And here we have, of course, the log area to show something. We create two peer connections, wire up the onIceCandidate handlers to the other side’s addIceCandidate, and we also have the ICE connection state change events that we listen to.

Tsahi: Okay.

Philipp: So that’s fairly simple. That tells you where the ICE is connected. And then we have here, the start button handler, which calls getUserMedia with audio, and the track to the peer connection, creates an offer, call setLocalDescription, and then after setLocalDescription, we have an iceTransport object.

Tsahi: Okay.

Philipp: At least in Chrome and Safari. Firefox doesn’t implement that yet, sadly.

Tsahi: Okay.

Philipp: And we can have two events on that. One is the state change on the iceTransport, which is a low level variant of the peer connection’s ICE connection state change event.

Tsahi: Why do we need the lower level one? What’s the difference between the two?

Philipp: Typically, you don’t care much about that one, you want the overall ICE connection state change. Unless you’re doing fancy things like not bundling … then this might be useful. But in general, I wouldn’t care much.

Tsahi: Okay.

Philipp: And then we have this onselectedcandidatepairchange event, which gives you a local and remote candidate, and that happens whenever ICE changes what is selected as the candidate pair. And then we call setRemoteDescription, create an answer, setLocalDescription, setRemoteDescription with the answer, and we’re done.

And then we have the restart, which is we’re doing it a bit old style; we create an offer with ICE restart set to true. And then do the usual setLocalDescription, setRemoteDescription, createAnswer, setLocalDescription, setRemoteDescription stuff.

Tsahi: Okay, but in real life, we won’t be doing that with a button, we’ll simply wait for an event to occur that will ask us to do a restart.

Philipp: Yes, typically, I would do it like, three, four seconds after a ICE connection state changes to disconnected. I wouldn’t even wait for the failed event, this is because that takes 30 seconds, which is a bit of an unacceptable user experience.

Tsahi: So like we start the call, we get to a connected state, we’re happy. If we get disconnected state your suggestion is to wait two to three seconds, and then try to do a restart because it might work.

Philipp: Yes.

Tsahi: Okay.

Philipp: So if we do this, we click the Start button, so we see ICE connection state change goes to checkings, the ICE transport goes to checking as well. And then we have some selected candidate pair change, which in this case shows my IPv6 address and then the ICE connection state change goes to connected to after that, whether it should be in that order, we’ll need some discussion but it works.

Tsahi: This is interesting because we got the state of the candidate pair changed, but we didn’t have a candidate to change from.

Philipp: Yes but it’s a state translation from no pair selected to a pair selected.

Tsahi: Okay.

Philipp: So all is good. And then we do the restart, which is a bit fake because we don’t really get disconnected, but it shows how this stuff works. So, we get another selected candidate pair change, and you will see here that the username fragment changed (ufrag) compared to the first version, and the port changed as well. And now we’re running the traffic of his new connection.

Tsahi: Okay, and we didn’t get another state connected, because we’re still connected.

Philipp: Yes. And that is where the old version of the API was a bit better. Because we can see here, let me see… this is where we do our trade off with ICE restart set to true. And then we have this legacy ICE connection state change to connect it, even though the previous one was already… well, it was completed before and we don’t have that in the new API anymore, so there is no state change anymore. But that set event is no longer available to JavaScript.

Tsahi: Okay.

Philipp: So we need to use a selected candidate page change to determine that things actually worked out.

Tsahi: Okay, when we talked earlier, we said that there is only one or multiple problems with this new great callback, and that being that…

Philipp: Yes. So far, it implements the ICE transport API, but it doesn’t have his event wired up.

Tsahi: Okay, so it’s probably a matter of time, because it’s part of the specification anyway.

Philipp: Yes.

Tsahi: Okay. So just to sum things up: we collect the call, we get ICE to be connected, we might have a restart, either because we want to, or most likely because the network changes on us. And then we can use this new callback to know that that even happened and that we succeeded in that process.

Philipp: Right.

Tsahi: Okay. So thank you, Philipp, and see you all next month in our next fiddle.