From ab455a9cfe03707f47f3bdb03293c2f77c845e93 Mon Sep 17 00:00:00 2001 From: Josh Knapp Date: Thu, 10 Sep 2026 05:31:09 -0700 Subject: [PATCH] docs: the macOS bundle was fine all along, and record the GUI verification Two corrections and one promotion, all from evidence rather than inference. 1. The "macOS packaging gap (known, unfixed)" section was WRONG, and it contradicted the release notes for the same build. It claimed the artifact is "a bare streamer-tools-camera.so" with a relative libobs install name that "will not load in OBS.app as it stands". Downloading and inspecting the shipped streamer-tools-camera-v0.1.0-macos.zip shows otherwise: - a proper streamer-tools-camera.plugin bundle -- Contents/MacOS/ is Mach-O MH_BUNDLE (what OBS loads), with Info.plist (BNDL, correct CFBundleExecutable), Contents/Resources/locale/en-US.ini, and both LiveKit dylibs in Contents/Frameworks/ - install names are right: the module loads @rpath/libobs.framework/Versions/A/libobs and carries LC_RPATH @executable_path/../Frameworks, which inside OBS.app resolves to OBS.app/Contents/Frameworks; @rpath/liblivekit.dylib resolves through LC_RPATH @loader_path/../Frameworks to the bundle's own copy, and liblivekit.dylib finds liblivekit_ffi.dylib through LC_RPATH @loader_path. Nothing points into a build tree. - all three binaries carry LC_CODE_SIGNATURE, which is not optional: arm64 macOS refuses to load unsigned code. The real macOS limitation is different and now stated: the bundle is arm64-only (no x86_64 slice), macOS 13+. Nobody has still ever opened it in OBS.app -- well formed and signed is a prior, not a load. 2. Linux and Windows are confirmed working in the OBS GUI: video and audio both arrive and hold up across a session, Linux by the project owner and Windows by two directors independently, and the plugin carried a live show on 2026-09-07. Since listing cameras requires an API call, that also retires "the WinHTTP backend has never run against a real streamer-tools server". Scoped, not inflated: MEASURED A/V sync and latency against the egress path are still unverified (no drift reported is not a measurement), as is mid-show publisher restart. The "Not verified anywhere" list is now deduplicated and says exactly that. 3. The CI table's Windows row still said "Failing, fix pushed and awaiting a completed run". It is green, after the WinHTTP deadline fix. Release notes template updated to match, and v0.1.0's published notes have been regenerated through it so the public page stops repeating the bare-.so claim. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01AzGnvQ6wfD7bw7PZN35ft9 --- .gitea/scripts/publish-release.sh | 24 ++++--- README.md | 110 +++++++++++++++++------------- 2 files changed, 75 insertions(+), 59 deletions(-) diff --git a/.gitea/scripts/publish-release.sh b/.gitea/scripts/publish-release.sh index 0940b66..c476233 100755 --- a/.gitea/scripts/publish-release.sh +++ b/.gitea/scripts/publish-release.sh @@ -25,7 +25,7 @@ set -euo pipefail MACOS_BUNDLE_FOUND="${MACOS_BUNDLE_FOUND:-false}" if [ "${MACOS_BUNDLE_FOUND}" = "true" ]; then - MACOS_NOTE="This archive contains a \`.plugin\` bundle." + MACOS_NOTE="This archive contains a \`.plugin\` bundle (verified on v0.1.0: MH_BUNDLE + Info.plist, libobs via \`@rpath\` + \`@executable_path/../Frameworks\`, LiveKit dylibs bundled, all three binaries code-signed). **arm64 only -- no Intel slice**, macOS 13+. Never yet loaded in OBS.app by a human." else MACOS_NOTE="This archive is packaged as a bare \`streamer-tools-camera.so\` (the layout \`build/package/\` currently produces on macOS), **not** an OBS.app-loadable \`.plugin\` bundle. It will not load in the OBS GUI as-is -- see the \"macOS packaging gap\" section of \`README.md\`." fi @@ -36,18 +36,22 @@ cat > "${NOTES_FILE}" <.plugin` bundles (`Contents/MacOS/`, `Contents/Resources/`, - an `Info.plist`), which is what obs-plugintemplate's - `cmake/macos/helpers.cmake` builds and which this project deliberately did - not vendor. -2. `otool -L` shows the libobs dependency recorded as the relative path - `libobs/libobs.framework/Versions/A/libobs`, inherited from the - from-source libobs's own install name. A real plugin needs - `@rpath/libobs.framework/Versions/A/libobs` plus an `LC_RPATH` pointing at - `OBS.app/Contents/Frameworks`. +- It is a proper bundle: `streamer-tools-camera.plugin/Contents/MacOS/streamer-tools-camera` + (Mach-O **`MH_BUNDLE`**, which is what OBS loads), plus `Info.plist` + (`CFBundlePackageType BNDL`, `CFBundleExecutable streamer-tools-camera`), + `Contents/Resources/locale/en-US.ini`, and both LiveKit dylibs under + `Contents/Frameworks/`. +- The install names are right, which was the specific doubt. The module loads + `@rpath/libobs.framework/Versions/A/libobs` and carries + `LC_RPATH @executable_path/../Frameworks` — inside OBS.app that resolves to + `OBS.app/Contents/Frameworks`, where libobs lives. `@rpath/liblivekit.dylib` + resolves through `LC_RPATH @loader_path/../Frameworks` to the bundle's own + copy, and `liblivekit.dylib` finds `liblivekit_ffi.dylib` through its own + `LC_RPATH @loader_path`. Nothing points into a build tree. +- All three binaries carry an `LC_CODE_SIGNATURE` (superblob `0xfade0cc0`), + which is not optional: arm64 macOS refuses to load unsigned code at all. -Fixing this means either vendoring the template's macOS bundle helpers or -adding an `install_name_tool` pass and a bundle layout — bounded work, but -work that has to be done and checked on an actual Mac. It is deliberately not -attempted here rather than guessed at. +**The real macOS limitation is different: the bundle is arm64-only.** There is +no x86_64 slice, so Intel Macs cannot load it, and `LSMinimumSystemVersion` is +`13.0`. Shipping a universal binary would mean building both slices and +`lipo`-ing them, on a Mac. + +Everything above is static inspection of the artifact. **Nobody has yet opened +it in OBS.app** — well-formed and signed is a strong prior, not a load. ### Where the Windows bootstrap got to