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/<name> 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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzGnvQ6wfD7bw7PZN35ft9
This commit is contained in:
2026-09-10 05:31:09 -07:00
co-authored by Claude Opus 5
parent e763d61ed3
commit ab455a9cfe
2 changed files with 75 additions and 59 deletions
+14 -10
View File
@@ -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}" <<EOF
Built from commit \`${SHA}\`.
**Read the per-platform notes below before relying on this.** The module has
been loaded in the OBS GUI exactly once -- Windows, OBS 32.2.2 on Windows 11,
2026-09-09 -- and only "it loads and registers its source type" is confirmed
there. Whether video renders correctly, A/V sync, end-to-end latency and
mid-show publisher restart are all still unverified on every platform. See
"What is verified, and how" in \`README.md\` for exactly what is backed by
automated tests versus a human watching OBS.
**Confirmed working on Linux and Windows, including a live show.** The plugin
carried a real broadcast on 2026-09-07. Video and audio both arrive and hold
up across a session: Linux verified by the project owner, Windows by two
directors independently.
Still unverified: **macOS in the OBS GUI** (nobody has opened it -- see the
table), **measured** A/V sync and end-to-end latency against the existing
egress path (no drift reported, but nothing measured), and whether a publisher
restarting mid-show recovers cleanly on screen. See "What is verified, and
how" in \`README.md\` for what is backed by automated tests versus a human
watching OBS.
| Platform | Archive | Notes |
|---|---|---|
| Linux (x64) | \`streamer-tools-camera-${TAG}-linux-x64.zip\` | Functionally complete and verified end to end against a real LiveKit server and a real libobs (see README); OBS GUI itself still unverified |
| Windows (x64) | \`streamer-tools-camera-${TAG}-windows-x64.zip\` | Built and tested by this workflow's Windows job. Confirmed to load in the OBS GUI (32.2.2 / Windows 11, 2026-09-09); nothing past module load is verified. The WinHTTP backend has never been exercised against a real streamer-tools server, only a loopback test server -- see README's Windows CI section |
| Linux (x64) | \`streamer-tools-camera-${TAG}-linux-x64.zip\` | Functionally complete, verified end to end against a real LiveKit server and a real libobs (see README), and confirmed working in the OBS GUI |
| Windows (x64) | \`streamer-tools-camera-${TAG}-windows-x64.zip\` | Built and tested by this workflow's Windows job, and confirmed working in the OBS GUI by two directors independently (first load: OBS 32.2.2 / Windows 11) -- which also exercises the WinHTTP backend against a real streamer-tools server |
| macOS | \`streamer-tools-camera-${TAG}-macos.zip\` | Built and tested by this workflow's macOS job. ${MACOS_NOTE} |
## Installing
+61 -49
View File
@@ -24,15 +24,21 @@ The plugin is **functionally complete on Linux and verified end to end there**
real streamer-tools API shape, and pushes decoded frames into
`obs_source_output_video`/`_audio`).
**First confirmed OBS GUI load: Windows, 2026-09-09** — the v0.1.0 release
artifact loaded into OBS 32.2.2 on Windows 11 (build 26200) on a director's
machine, from
`C:\ProgramData\obs-studio\plugins\streamer-tools-camera\bin\64bit\`.
That retires "the module will not even load in a real OBS" for Windows. It
does **not** yet cover whether video renders correctly, colours, A/V sync or
latency — see "Not verified anywhere" below for what is still open. Linux and
macOS have still never been opened in the GUI; macOS builds the real module in
CI but its artifact is not yet loadable (see the macOS packaging gap under CI).
**Confirmed working in the OBS GUI on Linux and Windows, including a live
show.** The plugin carried a real broadcast on 2026-09-07 and was reported to
work well. Video and audio both arrive and hold up across a session: Linux
verified by the project owner, Windows by two directors independently
(2026-09-09/10; the first Windows load was OBS 32.2.2 on Windows 11 build
26200, from
`C:\ProgramData\obs-studio\plugins\streamer-tools-camera\bin\64bit\`).
Because listing cameras requires an API call, that also retires "the WinHTTP
backend has never run against a real streamer-tools server".
What that does **not** cover: measured A/V sync and end-to-end latency against
the existing egress path (no drift reported over a session, but nothing was
measured), mid-show publisher restart, and **macOS in the GUI — still never
opened by anyone**, though its artifact is now known to be correctly packaged
(see macOS packaging below). See "Not verified anywhere" for the current list.
⚠️ **The install directory is not the same on every platform, and getting it
wrong fails silently.** On Windows it is
@@ -169,15 +175,15 @@ plugins. This bit a director on 2026-09-09: a correctly-shaped install under
`AppData\Roaming` produced a log with zero mention of the module.
The module resolves the LiveKit libraries from `$ORIGIN` (verified: `ldd` on the staged copy resolves both
to `bin/64bit/`), not from the build tree. macOS is not this shape; see the
macOS packaging gap under CI.
to `bin/64bit/`), not from the build tree. macOS is not this shape — it ships
a `.plugin` bundle; see macOS packaging under CI.
## Testing this by hand
**The module has been loaded in the OBS GUI on Windows once (2026-09-09, OBS
32.2.2 / Windows 11 26200) — nothing beyond "it loads and registers its source"
is confirmed there, and Linux and macOS have never been opened in the GUI at
all.** To do it on Linux:
**Linux and Windows are confirmed working in the GUI — video and audio over a
real session, Linux by the project owner and Windows by two directors
independently (2026-09-09/10). macOS has never been opened in the GUI by
anyone.** To repeat the Linux run:
```
mkdir -p ~/.config/obs-studio/plugins/streamer-tools-camera
@@ -233,21 +239,17 @@ livekit-server 1.13.6 in dev mode):
| Two sources in one OBS process | same harness with a second source added: both connect with distinct nonce identities, both receive frames, both tear down cleanly |
**Not verified anywhere:**
- Anything past module load in the OBS GUI. Windows 2026-09-09 confirms the
module loads and its source type appears; whether video actually renders
(right way up, right colours), what the A/V sync and latency look like, and
whether a publisher restarting mid-show recovers on screen are all still
unanswered. Linux and macOS have not been opened in the GUI at all.
- macOS beyond "CI builds and links the real module and the core tests pass".
Its artifact is a bare `.so` with a relative libobs install name and will
not load in OBS.app — see the macOS packaging gap under CI.
- Windows beyond "the core library and the WinHTTP backend compile and their
tests pass", from runs predating the current fixes. The WinHTTP backend has
never run against a real streamer-tools server, only against the loopback
test server in `test_api_client`.
- A/V sync and end-to-end latency against the existing egress path.
- Behaviour against the real production streamer-tools server (only against a
stand-in serving the same shapes).
- **macOS in the OBS GUI.** Nobody has opened it. Its artifact is now known to
be a correctly-formed, correctly-linked, code-signed `.plugin` bundle
(verified by inspecting the shipped v0.1.0 zip — see macOS packaging under
CI), and it is arm64-only, so Intel Macs are out regardless. "The bundle is
well formed" is not "OBS loaded it".
- **Measured** A/V sync and end-to-end latency against the existing egress
path. A live show and several sessions on Linux and Windows produced no
reported drift, which is not the same as a measurement — and the timestamp
caveat above is the reason to want real numbers.
- Whether a publisher restarting mid-show recovers cleanly on screen.
- Token expiry across a session longer than an hour (see below).
- Token expiry after an hour. Expiry is handled *reactively*: a fatal
disconnect makes the worker mint a fresh token and reconnect. The design
doc's "proactively refreshed before expiry" is **not** implemented —
@@ -261,8 +263,8 @@ runners available to this repo under the `CyberCoveLLC` org.
| Job | `runs-on` | Runner | State |
|---|---|---|---|
| `linux` | `ubuntu-24.04` | `localhost.localdomain` | **Green.** Builds the real adapter against Ubuntu's libobs-dev 30.0.2, runs all six test suites, uploads `build/package` as an artifact |
| `macos` | `macos-latest` | `home-mac` (Global) | **Green.** Builds libobs 30.0.2 from source, then the real adapter; 6/6 tests; artifact uploaded. But see the macOS packaging gap below |
| `windows` | `windows-latest` | `winvm-builder` (org-scoped) | **Failing, fix pushed and awaiting a completed run.** Every completed run so far has failed; the latest got as far as building libobs and stopped on an OBS-side `OBS::w32-pthreads` target that its own modern CMake path never defines. A bootstrap patch for that gap has been pushed but not yet confirmed by a green run; see below |
| `macos` | `macos-latest` | `home-mac` (Global) | **Green.** Builds libobs 30.0.2 from source, then the real adapter; 6/6 tests; artifact uploaded as a `.plugin` bundle. Never loaded in OBS.app, and arm64-only — see macOS packaging below |
| `windows` | `windows-latest` | `winvm-builder` (org-scoped) | **Green.** Builds libobs 30.0.2 from source, then the real adapter; 6/6 tests; artifact staged. Was red twice more after the bootstrap was fixed, both times on `test_api_client`'s timeout probe — see "WinHTTP timeouts are not deadlines" below |
The Linux job is pinned to `ubuntu-24.04` rather than `ubuntu-latest`: this
instance's two Linux runners answer `ubuntu-latest` with different releases,
@@ -356,26 +358,36 @@ obs-studio, builds libobs from source, builds and links the real adapter,
passes 6/6 tests, and uploads its artifact. `otool -L` on the result shows it
linked against libobs and `@rpath/liblivekit.dylib`.
### macOS packaging gap (known, unfixed)
### macOS packaging (was described here as broken; it is not)
**The macOS artifact will not load in OBS.app as it stands.** Two reasons,
neither of which CI can catch, because CI only proves it compiles and links:
**This section used to claim the macOS artifact was a bare
`streamer-tools-camera.so` with a relative libobs install name that "will not
load in OBS.app as it stands". That is wrong, and it contradicted the release
notes for the same build.** Corrected 2026-09-10 by inspecting the shipped
`streamer-tools-camera-v0.1.0-macos.zip` itself:
1. It is a bare `streamer-tools-camera.so`. OBS on macOS loads plugins as
`<name>.plugin` bundles (`Contents/MacOS/<name>`, `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