Commit 19017c8
Build each output once instead of rebuilding on every notify::caps (#466)
* Build each output once instead of rebuilding on every notify::caps
notify::caps is a GObject property notification, so it can fire more than
once per pad. The decoder negotiates at pad-added, when the output does not
exist yet and its peer caps query is unconstrained, and again once the output
is linked and activation triggers a reconfigure upstream. On macOS with
GStreamer 1.28 those two answers differ, so the video track-setup path runs a
second time and fails: the new bin carries the same hardcoded name as the
first, and GStreamer requires element names to be unique within a bin.
Record the output built for each stream kind and consult it on later
notifications instead of rebuilding. Caps the established output cannot take
are surfaced as ENDPOINT_ERROR; anything else, including a mid-stream
resolution change, is logged and tolerated so a live session is not dropped.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Log both sets of caps on renegotiation and release the test bin
Review feedback on #466:
- The rejection and renegotiation log lines now carry "established caps"
alongside "new caps", so the two can be compared without cross-referencing
an earlier line.
- newTestVideoSinkPad registers a t.Cleanup that sets the bin to NULL, so its
elements are released instead of leaking for the duration of the run.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Drop the accept-caps guard and log every renegotiation
QueryAcceptCaps is an advisory query, answered by a different vfunc than
the one that applies caps, and basetransform's default implementation
checks only the head element's own pad templates. It is therefore more
permissive than real negotiation, so a false answer only covered caps the
bus would reject anyway -- while setting ENDPOINT_ERROR, which stamps
EndedAt, without stopping the pipeline.
Caps the pipeline genuinely cannot take now fail negotiation downstream
and surface on the bus, where messageWatch both reports the error and
quits the loop. The output is still built once per stream kind; a later
notification only logs both sets of caps and returns.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Cover the renegotiation guard with unit tests
onParamsReady returns from the guard before it touches p.sink or p.Params,
so a zero-value Pipeline is a valid fixture: if the guard holds nothing
dereferences them, and if it regresses the test panics. No mock or
injected interface is needed.
A ghost pad's caps come from its own sticky events, so the pad has to
negotiate in the data path for the "caps" property to be set. The helper
builds videotestsrc ! capsfilter ! bin(fakesink) with the ghost pad on the
bin, which is the shape Input surfaces in production.
Verified in the CI image (livekit/gstreamer:1.26.7-dev): golangci-lint
reports no issues and go test ./pkg/... passes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Store the caps event directly and use camelCase log keys
Per review. A pad's caps property is its sticky CAPS event, so it can be
stored with gst_pad_store_sticky_event rather than produced as a
by-product of real negotiation. That drops the videotestsrc pipeline, the
state changes and the cleanup, and the pad is now a src pad, matching what
Input surfaces. An inactive pad is flushing and rejects the store, hence
SetActive.
Log keys in the renegotiation warning are camelCase, consistent with
resourceID, ingressID and streamKey elsewhere.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>1 parent bc0e3bf commit 19017c8
2 files changed
Lines changed: 108 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| 20 | + | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
| |||
56 | 57 | | |
57 | 58 | | |
58 | 59 | | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
59 | 65 | | |
60 | 66 | | |
61 | 67 | | |
| |||
88 | 94 | | |
89 | 95 | | |
90 | 96 | | |
| 97 | + | |
91 | 98 | | |
92 | 99 | | |
93 | 100 | | |
| |||
137 | 144 | | |
138 | 145 | | |
139 | 146 | | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
140 | 165 | | |
141 | 166 | | |
142 | 167 | | |
| |||
149 | 174 | | |
150 | 175 | | |
151 | 176 | | |
152 | | - | |
| 177 | + | |
153 | 178 | | |
154 | 179 | | |
155 | 180 | | |
| |||
159 | 184 | | |
160 | 185 | | |
161 | 186 | | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
162 | 191 | | |
163 | 192 | | |
164 | 193 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
0 commit comments