Skip to content

surface video-context init failures so UI can gate streaming#5941

Closed
summeroff wants to merge 1 commit into
stagingfrom
fix_streaming_crash_no_video
Closed

surface video-context init failures so UI can gate streaming#5941
summeroff wants to merge 1 commit into
stagingfrom
fix_streaming_crash_no_video

Conversation

@summeroff
Copy link
Copy Markdown
Contributor

Summary

Companion to streamlabs/obs-studio-node#1710 (fix_streaming_crash_no_video). With that PR in place, osn::Video::set will throw when SetVideoContext fails. This change catches that throw in establishVideoContext, tears down the partial context, and emits on a new videoContextError Subject so UI consumers can gate Go-Live / Record-Start and show a clear graphics-device error.

Why

Today, when libobs canvas init fails (e.g. DXGI_ERROR_DEVICE_REMOVED during initial texture creation), the JS-side Video setters silently succeed, this.contexts[display] looks valid, and the first time the user clicks "Go Live" the server crashes inside UpdateEncoders — the Sentry crash this is targeted at.

Changes

app/services/settings-v2/video.ts:

  • Add videoContextError = new Subject<{ display: TDisplayType; error: string }>() as a sibling to establishedContext.
  • Wrap the setter block in establishVideoContext (which will throw once osn-node#1710 ships) in try/catch.
  • On catch: destroy() the half-initialized context, run DESTROY_VIDEO_CONTEXT mutation, emit on videoContextError, return false.

Pairs with

Not in scope (follow-up)

  • UI wiring — subscribing the streaming/recording start buttons (and any first-run setup wizard) to videoContextError and surfacing a modal. Once this lands and the new subject is available, a UI-only PR can subscribe to it without further service-layer work.

Test plan

  • yarn eslint app/services/settings-v2/video.ts — clean.
  • tsc --noEmit -p tsconfig.json — clean.
  • Once osn-node update is consumed: force a SetVideoContext failure (mock GPU-loss or repro on an affected machine) and confirm videoContextError emits, this.contexts[display] ends up null, app continues to load.
  • Healthy path: confirm establishVideoContext still produces working contexts and establishedContext still fires.

🤖 Generated with Claude Code

osn::Video::set previously swallowed SetVideoContext errors, so a
failed GPU init at startup left this.contexts[display] looking valid
to JS even though libobs canvas->mix was NULL -- silently producing
the streaming-start crash filed in Sentry.

With osn-node now throwing on IPC failure, wrap the throwing setters
in try/catch, tear down the partial context, and emit a new
videoContextError subject so UI consumers can gate streaming /
recording start on it and show a clear graphics-device error.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bundlemon
Copy link
Copy Markdown

bundlemon Bot commented May 26, 2026

BundleMon

Files added (4)
Status Path Size Limits
renderer.(hash).js
+7.77MB -
vendors~renderer.(hash).js
+4.67MB -
updater.js
+115.29KB -
guest-api.js
+40.23KB -

Total files change +12.59MB

Final result: ✅

View report in BundleMon website ➡️


Current branch size history

@summeroff summeroff closed this May 30, 2026
gettinToasty pushed a commit that referenced this pull request May 30, 2026
* surface video-context init failures from establishVideoContext

osn::Video::set previously swallowed SetVideoContext errors, so a
failed GPU init at startup left this.contexts[display] looking valid
to JS even though libobs canvas->mix was NULL -- silently producing
the streaming-start crash filed in Sentry.

With osn-node now throwing on IPC failure, wrap the throwing setters
in try/catch, tear down the partial context, and emit a new
videoContextError subject so UI consumers can gate streaming /
recording start on it and show a clear graphics-device error.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Reset native mediasoup transceiver on Collab Cam teardown

cleanUpSocketConnection now calls func_reset_device after disconnecting the
socket, so the singleton MediaSoupTransceiver in mediasoup-connector is fully
torn down and rebuilt between Collab Cam sessions instead of accumulating stale
device/factory/transport state across reconnects.

Pairs with the C++ change in streamlabs/mediasoup-connector#37, which adds the
func_reset_device proc and makes LoadDevice idempotent. Two SLD 1.20.9 support
tickets ("Guests on Collab Cam are disconnecting after a few minutes") traced
back to that drift; resetting on full feature teardown (not on every transient
socket reconnect) is the conservative trigger that avoids churn during normal
network blips.

The new proc is a no-op against pre-fix DLLs (unknown proc names are ignored by
the OBS proc handler), so this change is safe to ship ahead of the
obs-studio-node bump.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Update osn: Update obs-studio-node to v0.26.28

* Seed horizontal video context with defaults when canvas reads back 0x0

VideoSettingsService.migrateSettings first-time branch reads `.legacySettings`
off a freshly created IVideo. On a clean profile (no basic.ini, no autoconfig
yet) both `.legacySettings` and `.video` come back zero-initialized. Pushing
those zeros back via `.video = .legacySettings` calls osn-server's
SetVideoContext with base/output dimensions of 0; obs_set_video_info rejects
that and returns OBS_VIDEO_INVALID_PARAM. osn 0.26.28 now propagates the
resulting ErrorCode::Error to JS where it was previously dropped, so the
first-boot path that used to be silently fixed by a later autoconfig step
now throws and tears the whole video context init down.

Add a horizontalDisplayData default next to the existing verticalDisplayData
and use it as the seed when legacy reads back zero dims. Real settings still
land on the context via the regular autoconfig / scene-collection load path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Use 1280x720 (not 1920x1080) for horizontal seed defaults

1080p as the placeholder biased two things: it briefly persisted "1920x1080
base, 1280x720 output" into the dual-output profile before autoconfig got a
chance to detect the real monitor, and the non-1:1 ratio is an opinionated
downscale choice for what should be a neutral filler.

1280x720 base + 1280x720 output (1:1) is the OBS-conventional fresh-profile
starting point, matches what osn-server already initializes its first canvas
to (see osn log line ~24), and gets overwritten by autoconfig within seconds
on a real user's first launch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Fix prettier formatting in seed-defaults block

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants