fix(scene-source): stop stranding stale browser_source on re-point (#110)#111
Merged
Merged
Conversation
on_set_capture_source created the new browser_source under the canonical
name PulsarSceneSource before removing the old one. While the old source
still owned that name, libobs de-duped the fresh instance to
"PulsarSceneSource 2"; remove_managed_items matched by exact strcmp and so
missed every numbered variant, which accreted on the program scene forever.
A name-based consumer (Prism's findBrowserSourceName) could then lock onto a
stale instance from the 3rd re-point on — the atlas-scene REC symptom.
Remove managed items before adding the fresh source, reclaim the canonical
name once it is free, and match managed items by libobs de-dup variant
("base <n>") so any pre-existing drift is swept too. Guarded by
scripts/probe-scene-name-drift.py in the offline probe suite (asserts exactly
one canonically-named browser_source across N SetCaptureSource calls).
Closes #110
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
84d9df2 to
54bd9e3
Compare
…ically The previous fix reclaimed the canonical name by removing the old scene item then set_name — assuming removal frees the name synchronously. CI proved that false: obs_sceneitem_remove only schedules deferred source destruction, so the old source could still own "PulsarSceneSource" at set_name time, leaving the fresh source stuck as "PulsarSceneSource 2" (intermittent, one CI run failed, a retry passed — a real race, not a flake). remove_managed_items now renames each outgoing managed source to a unique throwaway name before dropping its item. obs_source_set_name updates libobs's global name table synchronously, so the canonical name is guaranteed free the instant it returns — independent of when destruction actually runs. The reclaim then verifies the name was applied (reads it back, warns on drift) instead of assuming success. Probe hardened to 24 rapid re-points. Closes #110 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Closes #110
Problem
on_set_capture_sourcecreated the newbrowser_sourceunder the canonical namePulsarSceneSourcebefore removing the old one. While the old source still held that name, libobs de-duped the fresh instance toPulsarSceneSource 2;remove_managed_itemsmatched by exactstrcmpand thus missed every numbered variant, which accreted on the program scene indefinitely. From the 3rd re-point on, a name-based consumer (Prism'sfindBrowserSourceName, firstbrowser_sourceitem) could lock onto a stale instance — the real-world symptom: REC on an atlas scene showing only the native camera, never the Solar overlay.Fix
plugins/pulsar-scene-source/src/plugin-main.cpp:obs_source_set_name) — the surviving instance is alwaysPulsarSceneSource, never a numbered variant. No-op on the first call.remove_managed_itemsnow matches libobs de-dup variants (baseorbase <digits>, precisely — not a loose prefix), sweeping any pre-existing drift without over-matching an unrelatedPulsarSceneSourceCustom.browser_source_unavailablewithout touching the scene.Test
scripts/probe-scene-name-drift.py(connect-only, wired into the offline probe suite / CTest viarun-probes.ps1): drivespulsar-scene:SetCaptureSourceN=6 times against the sharedpulsar.exeand asserts, after every call, that the program scene holds exactly one managedbrowser_sourceand that it carries the canonical name. This is the websocket-boundary equivalent of the investigation'sprobe_name_drift.py(pure libobs state, no CEF paint / GPU). Light build → typed exit-3 skip, same pattern asprobe-browser-m3.py.Not validated here
Real CEF pixel compositing after re-point (needs an interactive desktop + Solar) is out of CI scope by doctrine — the antenna/live path covers it.
🤖 Generated with Claude Code