docs: the macOS bundle was fine all along, and record the GUI verification #6

Merged
jknapp merged 1 commits from docs/macos-packaging-and-gui-status into main 2026-09-10 12:31:33 +00:00
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