In mediasoup, when restartIce is called on a Consumer Transport that uses TCP, the transport frequently transitions into the failed state and cannot recover.
The same restartIce call on a Producer Transport over TCP works as expected. Additionally, if the transport uses UDP (either for Producer or Consumer), restartIce succeeds without entering the failed state.
This phenomenon is specific to the combination of Consumer role + TCP transport.
This is an unfortunate side effect of how ICE TCP works and the fact that mediasoup-client uses separate transport for sending and receiving. When performing ICE restart in a TCP receive transport, we cannot call pc.createOffer(iceRestart: true) because we need that the SDP offer is always generated by the remote (mediasoup server) and hence we need to initiate ICE restart in server side so the browser reacts to it by closing the current TCP connection, and when that happens the ICE state machine in mediasoup server moves to DISCONNECTED status. You can solve it by NOT calling transport.close() in mediasoup server when transport “icestatechange” event happens if the new state is “disconnected”, but only do this if there is an ongoing ICE restart in progress.