The last round of testing ruled out the pipeline construction itself:
even with the sink bin rebuilt from explicit, individually-checked
link() calls (no thrown errors, playbin reaches PLAYING), the
'new-sample' signal still never fired inside gnome-shell — while an
equivalent pipeline worked fine standalone via gst-launch-1.0.
The remaining, gnome-shell-specific difference: appsink emits
'new-sample' from GStreamer's own streaming thread, not the main
thread. GJS's JS engine isn't safe to call into from an arbitrary
background thread, and a cross-thread signal emission can be silently
dropped rather than invoked or crashed on — which looks exactly like
"the signal never fires" from here, even though the pipeline is
actually running.
Replaces the signal entirely with polling: a ~30fps GLib.timeout_add()
on the main thread calls appsink.try_pull_sample(0), which is
explicitly documented as safe to call from any thread since we are now
the ones calling into GStreamer rather than the reverse. Also updates
the no-frames watchdog to report the poll count instead of a signal
fire count.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019RDqbdjsiisSU7CbQke4g8