The right way to performing ICE Restart in a VideoRoom Publisher

Hello,

I have implemented failure handling logic for WebRTC sessions on the publisher side in a videoroom. In my JavaScript client, when the iceconnectionstatechange event triggers with the state “failed”, I create a new offer with iceRestart: true, set the local description with this new offer, and then send a “configure” command to Janus with `“refresh”: true. After receiving the answer, I set the remote description.

From the Janus logs, I can see that the ICE agent restarts:

  • Log entries showing ICE agent creation, warnings about audio mode, and ICE failure messages.
  • Entries about closing video and audio recordings.
  • More log entries about ICE agent creation, warnings, and negotiation updates indicating an ICE restart.

However, I’m confused about how the ICE restart process works with Janus. According to the documentation, I should send "refresh": true (First experiments with ICE restarts by lminiero · Pull Request #753 · meetecho/janus-gateway · GitHub), but in the Janus code, it seems that "restart": true is expected. I tried sending “restart” and observed the same result.

When I send the “configure” command again without “refresh” or “restart”, I get the same result. It appears that Janus recognizes that negotiation has already occurred and performs an ICE restart automatically.

Could you please clarify the correct way to trigger an ICE restart with Janus?

This is Janus logs:
[1954854557672680] Creating ICE agent (ICE Full mode, controlled)
janus-1_1 | [WARN] Audio offered as ‘recvonly’, but we need ‘recvonly’ for us: using ‘inactive’
janus-1_1 | [WARN] [1954854557672680] ICE failed for component 1 in stream 1, but let’s give it some time… (trickle received, answer received, alert not set)
janus-1_1 | [ERR] [ice.c:janus_ice_check_failed:2066] [1954854557672680] ICE failed for component 1 in stream 1…
janus-1_1 | [janus.plugin.videoroom-0x7f6663050680] No WebRTC media anymore; 0x7f6664260500 0x7f6664264180
janus-1_1 | File is 8 bytes: 2024-03-12T18-10-34.356Z-video-0.mjr
janus-1_1 | Closed video recording 2024-03-12T18-10-34.356Z-video-0.mjr
janus-1_1 | File is 8 bytes: 2024-03-12T18-10-34.356Z-audio-1.mjr
janus-1_1 | Closed audio recording 2024-03-12T18-10-34.356Z-audio-1.mjr
janus-1_1 | [1954854557672680] WebRTC resources freed; 0x7f6664260500 0x7f66642640c0
janus-1_1 | [1954854557672680] Creating ICE agent (ICE Full mode, controlled)
janus-1_1 | [WARN] Audio offered as ‘recvonly’, but we need ‘recvonly’ for us: using ‘inactive’
janus-1_1 | [ERR] [ice.c:janus_ice_setup_remote_candidates:3519] [1954854557672680] No remote candidates for component 1 in stream 1: was the remote SDP parsed?
janus-1_1 | [1954854557672680] Negotiation update, checking what changed…
janus-1_1 | [1954854557672680] ICE restart detected
janus-1_1 | [1954854557672680] Restarting ICE…
janus-1_1 | [WARN] Audio offered as ‘recvonly’, but we need ‘recvonly’ for us: using ‘inactive’
janus-1_1 | [1954854557672680] Negotiation update, checking what changed…
janus-1_1 | [1954854557672680] ICE restart detected
janus-1_1 | [1954854557672680] Restarting ICE…
janus-1_1 | [WARN] Audio offered as ‘recvonly’, but we need ‘recvonly’ for us: using ‘inactive’
janus-1_1 | [1954854557672680] Negotiation update, checking what changed…
janus-1_1 | [1954854557672680] ICE restart detected
janus-1_1 | [1954854557672680] Restarting ICE…
janus-1_1 | [WARN] Audio offered as ‘recvonly’, but we need ‘recvonly’ for us: using ‘inactive’
janus-1_1 | [WARN] [1954854557672680] Failed to add some remote candidates (added 0, expected 1)
janus-1_1 | [1954854557672680] The DTLS handshake has been completed
janus-1_1 | [janus.plugin.videoroom-0x7f6663050680] WebRTC media is now available

Depends on the role. For publishers, you need to have the client generate an offer with an ICE restart (which is what the iceRestart: true passed to createOffer will do, if you use janus.js) and send that updated offer to the VideoRoom. The Janus core will recognize the restart from the new ICE credentials; the VideoRoom itself won’t care, so even just a configure will suffice, no need for other stuff. For subscibers, it’s the VideoRoom that must trigger an ICE restart, and so there you do need to pass a custom flag (can’t remember which one, the docs will tell you).