Repository navigation
fix(video): retry an rtsp source over tcp after a udp address-family failure - #485
Merged
Merged
Conversation
…failure rtspsrc opens a stream's UDP ports for the address type of the server's session description (IPv4 when it names none), not for the family the control connection reached the server on. When a dual-stack name's IPv4 address is refused or unreachable, the connection falls back to IPv6 after the transport was chosen, the RTCP udpsink refuses the server's IPv6 address with "Invalid address family", and every reconnect repeats it. The up-front rule (a name whose first answer is IPv6 gets TCP) cannot see this, and the error reached the operator as the element's raw settings text. The receiver now hands every failed attempt's bus error to the input (VideoInputBase.on_bus_error) before the next attempt is built. The RTSP input reads "Invalid address family" in the debug string and keeps that host on TCP interleaved for the input's lifetime; a changed host or a rebuilt input tries every transport again. classify_failure reads the mismatch by the phase like an open failure, so it is NO_DATA after the stream was described rather than UNKNOWN. Verified against GStreamer 1.28.7 on loopback with a stub RTSP server on ::1: an SDP with c=IN IP4 or no c= line fails this way for a name and an IPv6 literal alike, c=IN IP6 does not, and TCP interleaved avoids it. The video guide said the UDP family followed the URL literal; it now states the session description. Fixes #373 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
Review roundsEach round re-read the whole diff against Round 1 (source, docs, tests)
Round 2 (whole diff again)Nothing beyond cosmetic:
Round 3 (whole diff again)Nothing beyond cosmetic or rare:
Results
|
michelhonold
marked this pull request as ready for review
October 25, 2026 07:42
This was referenced Oct 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Plan
Invalid address family; the receiver hands a failed attempt's error to the plugin before the next build; the error is classified, not shown rawVideoInputBase.on_bus_errorhook, called by the receiver for every failed attempt that carries an errorclassify_failure: an address-family mismatch reads by how far the feed gotrtspsrcpicks its UDP familySummary
Fixes #373.
When a dual-stack camera name's IPv4 address is refused or unreachable, the RTSP connection falls back to IPv6 after the transport was already chosen.
rtspsrcthen fails withInvalid address family, and every reconnect fails the same way. The operator saw the element's raw "Could not get/set settings from/on resource" text.Now:
VideoInputBase.on_bus_error, before the next attempt is built. A hook that raises is logged and the retry still runs.Invalid address family. Every later attempt and heal of the input then uses TCP. A different URL host, or an input rebuilt by a saved change to the source's settings or type, tries every transport again.classify_failurenames the failure. An address-family mismatch is classified by how far the feed got, like an open failure:NO_DATAonce the stream was described. It no longer comes out asUNKNOWNwith the element's raw text, and no new failure type or wording is added.How rtspsrc picks its UDP family (corrects the video guide)
The guide said
rtspsrcopens its UDP ports for the address family of the literal in the URL. That is not what it does. It uses the address type in the server's session description (c=IN IP4/IP6, or IPv4 when there is noc=line), whatever family the control connection reached the server on.Checked locally against GStreamer 1.28.7, with a real
rtspsrcand a stub RTSP server on::1(loopback only):c=IN IP4udpsink0postsgst-resource-error-quark:13,Invalid address family (got N)afteron-sdpIN IP4IN IP6protocols=TCPIN IP4The GStreamer 1.26 source picks the family the same way (
gst_rtspsrc_do_stream_connection). As a result, this fix also recovers an IPv6-literal URL whose server describes IPv4: it now moves to TCP after one failed attempt. Before, it failed on every attempt.Test plan
tests/test_video_input_rtsp.py: after an address-family failure the next builds of that host request TCP only. Covered for a dual-stack name and an IPv6 literal. Other failures (refused, empty SDP, rejected login, no error identity), another host, a URL that names no host and a newly built input all keep every transporttests/test_video_receiver.py: the receiver passes the error to the input, a timeout passes nothing, and a hook that raises still gets its retry. With the realRtspInputbehind the receiver (fake GStreamer): the retry after the failure runs over TCP, the failure readsNO_DATA, and a TCP retry that also fails stays on TCPtests/test_video_failure_classification.py: the mismatch reads by phase, case-insensitively, and only underRESOURCE_SETTINGSNoneguard and exception isolation, classification rule, code check, case folding), all killedrtsp.py,failure.pyandreceiver.py;ruff,ruff format,mypycleanmake ci-remote/etcon the station)/etc/hosts, for example192.0.2.99 cam6.exampleand2001:db8::10 cam6.example, and putrtsp://cam6.example:554/<path>in Video Source. Make sure the station's address selection puts the IPv4 entry first, so the up-front rule still offers UDP. The log should show one attempt failing withInvalid address family, thentcp interleaved: an earlier attempt's UDP ports were of the other IP family, then video. Live Statistics should show the "answered, but … did not receive video" sentence during the retry, not the raw settings textRTSP UDP ports did not match the server's IP family; using TCP interleaved from now on, the retry logged astcp interleaved: an earlier attempt's UDP ports were of the other IP family, video 12 s later; Live Statistics showed the "answered, but this station did not receive video from it" sentence during the retry.c=IN IP4(for example MediaMTX, if its SDP says so on the station's version): one failed attempt, then video over TCPc=IN IP4 0.0.0.0over the IPv6 connection: one failed attempt, then TCP interleaved and video within 2 s.🤖 Generated with Claude Code