webrtc: drop stale mux candidates after network change#5782
Conversation
When webrtcLocalUDPAddress is set, mediamtx creates a single UDPMuxDefault at startup. Pion populates its localAddrsForUnspecified once at construction time. After a network change (e.g. WiFi switch), the mux still advertises startup-time IPs as host candidates in SDP answers, while the new network IP is never generated. Fix by querying net.Interfaces() fresh in removeUnwantedCandidates for each new session when ICEUDPMux is set and no explicit AdditionalHosts or IPsFromInterfaces filter is configured, dropping any host UDP candidate whose IP no longer appears on a live interface. Fixes bluenviron#5097
|
Hello, this PR only solves half of the issue: it removes ICE candidates associated with IPs that are not valid anymore, but it doesn't add new IPs in case a certain interface returns online. Furthermore, the entity that is in charge of caching and updating IPs is pion/ice, not MediaMTX - wouldn't it be better to send a patch to pion/ice instead and fix the problem at the root? |
Thank you for the feedback. You're right on both counts. For point 1, the missing piece is that the new IP needs to be surfaced For point 2, I agree the root fix belongs in pion/ice — specifically in Before I do: would you prefer the pion/ice fix (re-query on each |
Fixes #5097
Problem
When
webrtcLocalUDPAddressis set (the default), a singleUDPMuxDefaultis created at server startup. Pion collects local interface addresses once at
that point and caches them inside the mux. When the server's network changes
(e.g. the host switches WiFi networks), the mux keeps advertising the
startup-time IP as a host candidate in every new SDP answer. The new network
IP is never added, so ICE negotiation on the new network fails and the stream
cannot recover without a full server restart.
Fix
removeUnwantedCandidatesalready has the right place to intercept this.When
ICEUDPMuxis set and the caller has not configuredIPsFromInterfacesor
AdditionalHosts(both of which have their own filtering logic), callnet.Interfaces()fresh for each new session and drop any host UDP candidatewhose IP is no longer present on a live interface.
The call is cheap — one syscall per session at SDP answer time — and
completely non-fatal: if the query fails, a warning is logged and the filter
is skipped rather than rejecting the session.
Tested
Reproduced the bug by switching WiFi networks while mediamtx was running and
observing the stale IP in the SDP answer. After the fix the stale candidate
is dropped and the new session negotiates successfully on the new network.
Before (stale
192.168.0.9advertised to client on new network):After (stale candidate dropped, connection succeeds via
172.18.0.1):A unit test covering this code path is included in
peer_connection_test.go.