Commit Graph
15 Commits
Author SHA1 Message Date
shadowdaoandClaude Sonnet 5 104326d05a docs/release: drop the C1 licensing gate, simplify install instructions
Build / macOS (macos-latest) (push) Successful in 29s
Build / Linux (ubuntu-24.04) (push) Successful in 49s
Build / Windows (windows-latest) (push) Successful in 2m50s
Release / macOS (macos-latest) (push) Successful in 33s
Release / Linux (ubuntu-24.04) (push) Successful in 56s
Release / Windows (windows-latest) (push) Successful in 3m20s
Release / Create Gitea Release (draft) (push) Successful in 19s
The WebRTC/OpenH264 attribution question tracked as "C1" throughout
README, third_party/livekit/README.md, the release-notes template, and
both workflow header comments is the project owner's call, and it has
been made -- own sign-off given and reaffirmed. Remove the gate
language and the extended research writeup from release-facing docs;
keep the actual LICENSE/NOTICE files themselves (Apache-2.0 requires
shipping those regardless of any of this).

Also simplify the release notes' install instructions per owner
request: point at each platform's default OBS plugins folder rather
than walking through verbose per-platform copy/extract instructions --
the archives already extract straight into place (prior commit), so a
short pointer is all that's needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
2026-09-07 09:40:49 -07:00
shadowdaoandClaude Sonnet 5 e050b81d6c ci: stop re-downloading CMake/Ninja on every Windows run
Build / macOS (macos-latest) (push) Successful in 32s
Build / Linux (ubuntu-24.04) (push) Successful in 56s
Build / Windows (windows-latest) (push) Successful in 2m52s
Release / macOS (macos-latest) (push) Successful in 43s
Release / Linux (ubuntu-24.04) (push) Successful in 56s
Release / Windows (windows-latest) (push) Successful in 3m23s
Release / Create Gitea Release (draft) (push) Successful in 19s
lukka/get-cmake@latest re-fetched and re-extracted CMake + Ninja on
every single Windows CI run. Its own cache (routed through this
act_runner's built-in cache server) reported "Cloud cache miss" on
every run, even one immediately after a run that logged a successful
save under the exact same key -- an incompatibility between its
bundled cache client and this act_runner's cache-server implementation,
not a config gap. Separately and more importantly: the archive
extraction step alone measured ~7.5 minutes for a 45MB zip on this VM,
consistent with Defender real-time scanning rather than raw disk I/O.
Together this was the dominant cost of every Windows CI run.

CMake 4.4.2 and Ninja 1.12.1 are now installed once, directly on the
winvm-builder VM's system PATH (C:\BuildTools\cmake, C:\BuildTools\
ninja), sidestepping the third-party action's cache entirely rather
than debugging its internals further. Both Windows jobs now just
verify cmake/ninja are present and fail loudly if not, instead of
silently falling back to a slow reinstall. Full detail, including how
to redo this if the VM is ever rebuilt, is in README's new "Windows
runner: persistent build tools" section -- this is VM state, not
something git reproduces.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
2026-09-07 09:07:23 -07:00
shadowdaoandClaude Sonnet 5 14fa00af3f docs: OpenH264/MPEG-LA royalty finding sharpens C1 -- not resolved
Build / macOS (macos-latest) (push) Successful in 28s
Build / Linux (ubuntu-24.04) (push) Successful in 59s
Build / Windows (windows-latest) (push) Successful in 10m45s
Cisco's own OpenH264 FAQ (openh264.org/faq.html) is explicit: they cover
MPEG-LA/AVC patent-pool royalties only for their own prebuilt binary,
downloaded at install time. Anyone who compiles OpenH264 from source
and redistributes it inside their own binary takes on "all applicable
license fees" themselves -- Cisco "will not be liable for any licensing
fees incurred by other parties" in that case.

LiveKit's client-sdk-cpp links Google libwebrtc via the webrtc-sdk
org's fork, whose documented build args (rtc_use_h264=true,
ffmpeg_branding="Chrome") are the standard Chromium/WebRTC recipe --
which links a from-source, statically-compiled copy of OpenH264 (from
Google's mirror, not Cisco's runtime binary) into libwebrtc. That is
exactly the shape of case Cisco's FAQ says voids their coverage. Not
independently confirmed against LiveKit's actual pinned v1.10.1 build
(their release archives ship only compiled output, no build manifest)
-- this is webrtc-sdk/libwebrtc's documented default, not a verified
fact about this specific artifact.

This sharpens C1 into a concrete mechanism instead of a general open
question. It does not resolve C1 -- if anything it strengthens the case
for treating it as unresolved -- and none of this is a substitute for
an actual legal opinion. Recorded in third_party/livekit/README.md (the
full writeup), README.md's Status section, and the release-notes
template in publish-release.sh so it reaches whoever opens a draft
release next, not just this one.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
2026-09-07 07:45:36 -07:00
shadowdaoandClaude Sonnet 5 1f342b1971 docs: Windows CI is green, log-verified; scope the w32-pthreads fallback
Build / macOS (macos-latest) (push) Successful in 32s
Build / Linux (ubuntu-24.04) (push) Successful in 52s
Build / Windows (windows-latest) (push) Successful in 10m36s
Records the outcome of f27b1c0 against the actual job log rather than the
job status: the from-source libobs bootstrap configures/builds/installs,
find_package(libobs) resolves through .deps/cmake/libobs, all 6 CTest suites
pass, and build\package\bin\64bit\streamer-tools-camera.dll (136,192 bytes)
is staged beside livekit.dll and livekit_ffi.dll. First completed green
Windows run on this repository. That also retires three separately-unproven
items at once -- the -A x64 fix, the PowerShell rewrite of the Windows steps,
and the add_subdirectory(deps/w32-pthreads) bootstrap patch.

The log also settles which branch of the new code ran: the "w32-pthreads_DIR
not set" message means OBS's own exported package was at
.deps/cmake/w32-pthreads/ the whole time and the fallback find module was
never loaded. The export was never missing, only unfindable -- worth
recording, because "w32-pthreads has no install rules" was the first
hypothesis and it was wrong.

Also narrows when that fallback is exposed at all. It reads artifacts out of
.deps/ and nowhere else, so it is only appended to CMAKE_MODULE_PATH when
this repo's own bootstrap actually produced an obs-studio tree there. A
developer building against an external OBS SDK (STPLUGIN_BOOTSTRAP_OBS=OFF,
or an explicit -Dlibobs_DIR=...) stays on CMake's normal search, where
whatever w32-pthreads package their SDK provides can still win -- a find
module that could only ever fail would have made their error worse, not
better. Linux reconfigures unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
2026-09-07 05:56:18 -07:00
shadowdaoandClaude Sonnet 5 f27b1c0b45 Fix Windows configure: point find_package at OBS's exported w32-pthreads
Build / macOS (macos-latest) (push) Successful in 28s
Build / Linux (ubuntu-24.04) (push) Successful in 46s
Build / Windows (windows-latest) (push) Successful in 13m44s
The libobs_DIR fix in 79de5e8f worked -- libobsConfig.cmake now loads on the
Windows runner -- and immediately exposed the next link in the same chain.
obs-studio's libobsConfig.cmake.in carries, under if(MSVC), a hard

    find_dependency(w32-pthreads REQUIRED)

because libobs/cmake/os-windows.cmake links PUBLIC OBS::w32-pthreads. That
lookup failed and aborted the whole configure.

The cause is not a missing export, which was the first hypothesis:
deps/w32-pthreads/CMakeLists.txt ends in target_export(w32-pthreads), the
same helper libobs itself uses, so the install(TARGETS ... EXPORT),
install(EXPORT ... NAMESPACE OBS::) and generated w32-pthreadsConfig.cmake
all exist and all run -- CMake would have hard-errored at generate time if
w32-pthreads were in no export set, and our own patch adds it under the
libobs subtree, which installs before the tolerated obs-frontend-api install
error stops the rest.

It is the same search-path mismatch libobs itself had: target_export installs
to <prefix>/${OBS_CMAKE_DESTINATION}/<target>/, which on Windows is
<prefix>/cmake/w32-pthreads/ -- a shape find_package's Config-mode suffixes
never search. So apply the same remedy CMake's own error message suggests,
and apply it before the find_package(libobs) call that transitively triggers
the find_dependency.

Also adds a fallback Findw32-pthreads.cmake, reached only when that export is
genuinely absent, which reconstructs OBS::w32-pthreads from the bootstrap's
artifacts, and a repair for a locationless imported target mirroring the
existing OBS::libobs one. The fallback deliberately lives in
cmake/windows/find-fallback/ rather than cmake/windows/, which osconfig.cmake
already puts on CMAKE_MODULE_PATH: a find module there would shadow OBS's
real exported package on every build, since MODULE mode is tried first.

Verified on Linux (this is a Linux sandbox) by reconstructing the exact
failure -- a stub libobsConfig.cmake with the same find_dependency, reached
through libobs_DIR -- and confirming it fails without this block and passes
with it, and separately that deleting the package routes find_package through
the fallback module instead. A full Linux configure of the repo is unchanged;
both new blocks are inside if(OS_WINDOWS) and the upstream find_dependency is
inside if(MSVC), so macOS and Linux are no-ops.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
2026-09-07 05:40:38 -07:00
shadowdaoandClaude Sonnet 5 2b216d3d75 ci: add tag-triggered release packaging workflow
Build / macOS (macos-latest) (push) Successful in 33s
Build / Linux (ubuntu-24.04) (push) Successful in 54s
Build / Windows (windows-latest) (push) Failing after 7m50s
Adds .gitea/workflows/release.yml, triggered only on a pushed v* tag, which
builds all three platforms (reusing the exact same configure/build/test
commands as build.yml, now factored out into .gitea/scripts/ so the two
workflows can't drift), zips each platform's build/package/ output, and
creates a draft Gitea Release with the archives attached.

This is packaging automation only -- it does not resolve or bypass the C1
WebRTC/OpenH264 release gate documented in README.md's Status section.
Nothing publishes until a human deliberately pushes a version tag (which
should not happen before owner sign-off) and then explicitly publishes the
resulting draft. The generated release notes lead with a restatement of the
open C1 question specifically so that second step can't be taken by
accident.

build.yml is refactored (not rewritten) to call the same shared scripts;
its job/step behavior is otherwise unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
2026-09-07 05:06:25 -07:00
shadowdaoandClaude Sonnet 5 969b8db94a license: relicense first-party code from GPL-2.0-or-later to Apache-2.0
Build / macOS (macos-latest) (push) Successful in 33s
Build / Linux (ubuntu-24.04) (push) Successful in 54s
Build / Windows (windows-latest) (push) Successful in 12m10s
Owner sign-off: replace root LICENSE with Apache License 2.0, add a root
NOTICE file, and swap the GPL-2.0 boilerplate header in every first-party
core/ and obs-adapter/ source file for a short Apache-2.0 notice.

This resolves review finding C2 (GPLv2 top-level LICENSE vs. the vendored
Apache-2.0 LiveKit SDK is a license-compatibility violation): the whole
repo is now Apache-2.0, matching LiveKit, so there's no GPL/Apache clash
left. Updated the README Status gate and the CI workflow comment to reflect
that C2 is resolved, while leaving the C1 WebRTC/OpenH264 patent/royalty
gate untouched -- that question is still open and still blocks release.

third_party/ stays under its own upstream licenses; only this project's own
code changed hands. All 6 CTest suites still pass after the header swap.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
2026-09-07 04:44:16 -07:00
shadowdaoandClaude Sonnet 5 a3579d4fd5 docs: bash-on-Windows is proven broken (WSL as local system), with the log
Build / macOS (macos-latest) (push) Successful in 32s
Build / Linux (ubuntu-24.04) (push) Successful in 54s
Build / Windows (windows-latest) (push) Failing after 11m21s
The 58f4832 Windows run completed and failed, but not on the bootstrap: its
Windows steps still used `shell: bash`, and on winvm-builder bash resolves to
WSL, which refuses to run under the runner's service account:

  Running WSL as local system is not supported.
  Error code: Bash/WSL_E_LOCAL_SYSTEM_NOT_SUPPORTED
  ##[error]Process completed with exit code 1.

The step died on the shell without ever invoking cmake. So the PowerShell
rewrite in 524e78c -- which was written pre-emptively from reading the
workflow back, on the reasoning that bash "cannot be assumed present" -- is
now confirmed necessary by a real log rather than by argument. It is still
unproven in the other direction: no completed run has yet included it.

Equally important for reading the record correctly: this failure says nothing
about the OBS::w32-pthreads blocker. That result stands on edb0c02 alone, and
the README now says so explicitly so a later reader does not count 58f4832 as
corroboration.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
2026-09-06 23:12:57 -07:00
shadowdaoandClaude Sonnet 5 2bbd94775a ci: patch obs-studio's Windows CMake to define OBS::w32-pthreads
Build / macOS (macos-latest) (push) Successful in 32s
Build / Linux (ubuntu-24.04) (push) Successful in 1m2s
Build / Windows (windows-latest) (push) Failing after 11m20s
libobs/cmake/os-windows.cmake unconditionally links OBS::w32-pthreads, but
in the OBS_CMAKE_VERSION>=3.0.0 ("modern") top-level CMakeLists.txt branch
this bootstrap selects, nothing ever adds deps/w32-pthreads (confirmed at
every checked tag, 30.0.2 through 31.1.1) -- only the legacy branch's
add_subdirectory(deps) does, and libobs/CMakeLists.txt itself only adds
deps/libcaption and deps/uthash.

Upstream's own CI never hits this because it leaves ENABLE_UI on, and
UI/cmake/os-windows.cmake happens to add deps/w32-pthreads as a side effect
of building the Qt UI. Building obs-frontend-api instead of libobs (as
upstream's CI does) does not help: UI/obs-frontend-api/CMakeLists.txt only
links OBS::libobs, and UI/CMakeLists.txt returns before reaching the file
that adds w32-pthreads whenever ENABLE_UI is off -- which this bootstrap
deliberately keeps off to avoid a ~100 MB Qt6 download this plugin's plain
obs_properties_* UI does not need.

Add _patch_obs_studio_w32_pthreads() to buildspec_common.cmake: after the
obs-studio archive is extracted and before the OBS sub-configure runs, patch
its libobs/CMakeLists.txt to add deps/w32-pthreads itself, guarded by the
same if(NOT TARGET OBS::w32-pthreads) check UI/cmake/os-windows.cmake already
uses upstream. Idempotent (skips if already patched) and fails loudly if the
expected anchor text is missing, rather than silently no-opping against a
future OBS version with a different libobs/CMakeLists.txt shape.

Verified locally: the CMake string(FIND)/string(REPLACE) patch logic was run
against the real libobs/CMakeLists.txt fetched from the obs-studio 30.0.2
tag, confirmed to produce the intended block, and confirmed idempotent on a
second run. The actual Windows CMake configure/build this unblocks cannot be
verified from this Linux sandbox -- that's what the next CI run is for.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
2026-09-06 23:12:41 -07:00
shadowdaoandClaude Sonnet 5 c5fedd176f docs: the -A x64 fix is confirmed; Windows now blocked on OBS's own CMake
Build / macOS (macos-latest) (push) Successful in 31s
Build / Linux (ubuntu-24.04) (push) Successful in 55s
Build / Windows (windows-latest) (push) Failing after 9m41s
Updates the Windows record written in 551f782, which was accurate when
written but has since been overtaken: the run it described as "in progress"
(edb0c02, the first commit carrying the -A x64 fix) has now completed.

The informative part is that the fix worked and Windows failed further along.
obs-deps and Qt6 downloaded, CEF was skipped, the OBS sub-configure ran for
53s and correctly reported "Plugin Support" and "User Interface" disabled --
then failed at generate time:

  CMake Error at libobs/cmake/os-windows.cmake:46 (target_link_libraries):
    Target "libobs" links to:
      OBS::w32-pthreads
    but the target was not found.

Traced at the 30.0.2 tag, and it does not appear to be anything this repo is
doing wrong:

  - libobs/cmake/os-windows.cmake links OBS::w32-pthreads;
  - that target exists only in deps/w32-pthreads/CMakeLists.txt, reached only
    via deps/CMakeLists.txt;
  - deps/ is added only by the LEGACY branch of the top-level CMakeLists. The
    modern branch that -DOBS_CMAKE_VERSION=3.0.0 selects adds libobs,
    libobs-d3d11, libobs-winrt, libobs-opengl, plugins, test/test-input and
    UI -- never deps;
  - libobs/CMakeLists.txt adds only deps/libcaption and deps/uthash;
  - plugins/CMakeLists.txt returns immediately under ENABLE_PLUGINS=OFF, and
    does not add deps/ even when enabled.

macOS is unaffected because its libobs does not link w32-pthreads, and at
30.0.2 the modern path was the default only on macOS -- consistent with the
Windows side of it being under-exercised upstream.

Deliberately NOT "fixed" here by bumping the pin: 30.0.2, 30.1.2, 30.2.3,
31.0.3 and 31.1.1 all still link OBS::w32-pthreads and none of them add
deps/w32-pthreads from libobs/CMakeLists.txt, so a bump is not obviously the
answer and needs checking rather than assuming. Three options are written up
with the evidence behind each, so whoever picks this up starts from a
diagnosis instead of from the error message.

Everything else 551f782 said stands, including its caution not to treat
either fix as confirmed without a green run -- the PowerShell rewrite is
still queued and still unproven, and is marked as such. The CI table row and
the top-level Status paragraph are updated to match; the licensing/release
gate is untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
2026-09-06 23:08:39 -07:00
shadowdaoandClaude Sonnet 5 551f782d8a docs: correct Windows CI record, add release-gating note (C1/C2, I6)
Build / macOS (macos-latest) (push) Successful in 34s
Build / Linux (ubuntu-24.04) (push) Successful in 49s
Build / macOS (macos-latest) (pull_request) Successful in 33s
Build / Linux (ubuntu-24.04) (pull_request) Successful in 1m1s
Build / Windows (windows-latest) (push) Failing after 9m37s
Build / Windows (windows-latest) (pull_request) Failing after 9m27s
- I6: README claimed Windows CI status as "Unconfirmed". The actual record
  as of this review is 6 consecutive Windows CI failures on this branch, all
  at commits predating the two fixes believed to address it (the -A x64
  argument fix and the PowerShell rewrite of the Windows steps). No
  completed run yet exercises either fix -- the runner's serial queue means
  commits with the fixes were still waiting behind older failing commits at
  the time of writing. Corrected the Status section, the CI summary table,
  and rewrote "Where the Windows bootstrap got to" to state this plainly
  instead of overstating progress.

- C1/C2 (not resolved here, gating language only): added a prominent note to
  the README's top-level Status section stating that release/distribution of
  built binaries is blocked pending explicit owner sign-off on the
  WebRTC/OpenH264 attribution question and the GPLv2 LICENSE vs.
  Apache-2.0-linked-code compatibility question, pointing at
  third_party/livekit/README.md where the details already live. Checked
  .gitea/workflows/build.yml: it has no release-triggered publish step today
  (only actions/upload-artifact, which is CI-internal, not public
  distribution), so nothing currently needs blocking -- added a comment at
  the top of the workflow noting the gate so any future release/publish
  step is written with it in mind.

Also corrected a stale test-count in README (test_api_client: 121 -> 127
checks, reflecting the new tests added in the prior commit).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
2026-09-06 23:00:48 -07:00
shadowdaoandClaude Sonnet 5 6829dd545a Stage the plugin into the directory layout OBS actually searches
Build / macOS (macos-latest) (push) Successful in 32s
Build / Linux (ubuntu-24.04) (push) Successful in 46s
Build / Windows (windows-latest) (push) Failing after 9m35s
The staged package put the module in build/package/bin. OBS does not look
there. From AddExtraModulePaths() in obs-studio's UI/window-basic-main.cpp,
the per-user plugin layout on Linux and Windows is:

  <config>/obs-studio/plugins/<name>/bin/64bit/<name>.{so,dll}
  <config>/obs-studio/plugins/<name>/data/

so build/package/ now uses bin/64bit and is a straight drop-in. Re-verified in
the headless libobs harness from the new path: the module loads, both sources
connect, frames arrive, the camera switch round-trips, and `ldd` on the staged
copy resolves liblivekit and liblivekit_ffi from bin/64bit via $ORIGIN.

macOS deliberately keeps the flat bin/ -- there OBS looks for a
<name>.plugin/Contents/MacOS bundle, which this build does not produce. That
gap is documented in README.md rather than papered over with a directory name
that would only look right.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
2026-09-06 22:36:01 -07:00
shadowdaoandClaude Sonnet 5 9a1a1474a9 docs: record what CI actually proved, and the macOS packaging gap it does not
Build / macOS (macos-latest) (push) Successful in 33s
Build / Linux (ubuntu-24.04) (push) Successful in 56s
Build / Windows (windows-latest) (push) Failing after 7m52s
The macOS bootstrap now works end to end: obs-deps and obs-studio download,
libobs 30.0.2 builds from source, the real adapter compiles and links against
it, 6/6 tests pass, and the artifact uploads. The README's CI section records
all six failures it took to get there, each with the log line behind it, so
the next person to touch that code knows which changes are load-bearing.

It also records the gap CI cannot see. **The macOS artifact will not load in
OBS.app**, for two reasons neither a compile nor a link can catch:

  - it is a bare streamer-tools-camera.so, and OBS on macOS loads plugins as
    <name>.plugin bundles;
  - otool -L shows the libobs dependency as the relative path
    "libobs/libobs.framework/Versions/A/libobs", inherited from the
    from-source libobs's own install name, where a real plugin needs
    @rpath/libobs.framework/Versions/A/libobs plus an LC_RPATH into
    OBS.app/Contents/Frameworks.

Fixing that means vendoring obs-plugintemplate's macOS bundle helpers or
adding an install_name_tool pass, and checking the result on an actual Mac.
Deliberately not attempted here rather than guessed at.

Windows is recorded as unverified. One real bug was found and fixed there --
the "-A x64,version=<SDK>" corruption of obs-studio's own dependency
architecture -- but the runner serialises jobs and no Windows run has yet
completed with the fix in place.

Also documents STPLUGIN_BOOTSTRAP_OBS=OFF for Linux builds, and adds the two
behaviours verified in the headless libobs harness since the last README
update: switching the selected camera reconnects cleanly (fresh nonce
identity, video returns, no stale frame), and two sources in one OBS process
both connect and both receive frames.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
2026-09-06 22:28:52 -07:00
shadowdaoandClaude Sonnet 5 a484abec61 Make the OBS adapter real: properties UI, connect, and frame output
The stub source becomes an actual streamer-tools camera. On create it reads
server URL / room slug / read key / camera identity from obs_data_t, mints a
subscribe-only token through ApiClient, connects LiveKitSession, and pushes
decoded frames into obs_source_output_video / obs_source_output_audio. The
source is now OBS_SOURCE_ASYNC_VIDEO | OBS_SOURCE_AUDIO |
OBS_SOURCE_DO_NOT_DUPLICATE with an OBS_ICON_TYPE_CAMERA icon.

The file is C++ rather than C now: the core library's API is C++ and the C ABI
shim existed only to avoid that. obs-module.h already declares the module
entry points extern "C", so nothing is lost.

Properties UI: server URL, room slug, a masked read-key field (it is a
credential and is masked everywhere else in streamer-tools), a camera dropdown,
a "Refresh camera list" button, and a status line.

- The dropdown is built from a cache the worker keeps warm on every connect,
  so opening properties never blocks on the network. The button is the
  explicit way to force a round trip, with a shortened 5s timeout -- for which
  ApiClient's two calls gained a timeout_ms parameter.
- The currently-selected identity is always in the list, labelled "(not in
  this room)" if absent, so OBS cannot silently clear a working setting just
  because the room happens to be dark.
- The status line is the OBS_TEXT_INFO property's description (which is what
  OBS actually renders) and switches to the warning info type on a real error.

Threading: OBS's UI and graphics threads are never blocked on the network.
Each source owns a worker thread that mints, connects, and reconnects with
exponential backoff (1s -> 30s), waking early on any settings change via a
generation counter. Frames are pushed from LiveKitSession's reader threads
directly; obs_source_output_video/_audio are thread-safe.

Two details that matter operationally:
 - A null frame is pushed whenever the session leaves Connected, so a camera
   that stopped publishing clears instead of leaving its last frame on screen.
   Leaving stale media up is precisely the failure this plugin exists to avoid.
 - The SDK's own logging is routed into OBS's log file via
   livekit::setLogCallback, instead of stderr where a director would never
   see it. The adapter also logs the first frame and every later geometry
   change, so a log answers "did video ever arrive, and at what size".

Packaging: the build now stages a runnable layout into build/package/ --
the module (RPATH $ORIGIN / @loader_path, so it resolves the LiveKit
libraries from beside itself rather than from the build tree), liblivekit +
liblivekit_ffi, the locale data, and the licence files. third_party/livekit/
carries client-sdk-cpp's Apache-2.0 LICENSE and NOTICE from the pinned tag.

Its README records a correction to the design doc: the "bundled LICENSE.md
with ~28 third-party licence blocks" the doc expects DOES NOT EXIST at
v1.10.1 -- not in any of the five release archives (which contain only
include/, lib/, bin/ and build-info.json) and not in the repo at that tag,
which has only LICENSE and NOTICE. The aggregated third-party notice covering
the WebRTC/OpenH264 code inside liblivekit_ffi.so has not been located, and
that is flagged as an open licensing question rather than papered over.

Verified on Ubuntu 24.04 against real libobs 30.0.2, a real
livekit-server 1.13.6, and a stand-in API serving plugin.routes.ts's exact
shapes, using a headless libobs harness (obs_startup + obs_reset_audio +
obs_reset_video + obs_open_module + obs_source_create):

  registered=1  output_flags=0x87
  [streamer-tools-camera] connected to ws://127.0.0.1:7880 as
      obs:main-room:qY85r9D0PaPt, watching cam-test
  [streamer-tools-camera] video frame 640x360 I420
  camera dropdown has 3 items:
    [0] (no camera selected) =
    [1] Test Camera = cam-test
    [2] Dark Camera (offline) = other-cam
  status: connected (info_type=0)

and with a deliberately wrong read key:

  status: unknown room slug, or the read key is wrong or has been rotated
      (info_type=1)

with retry-and-backoff and no crash. ctest: 6/6 passed.

Still unverified, and the README says so plainly: the OBS GUI on any platform,
macOS/Windows beyond compiling, A/V sync, and end-to-end latency.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
2026-09-06 21:54:11 -07:00
shadowdaoandClaude Sonnet 5 105f1041ab Scaffold core/OBS-adapter split, prove CMake toolchain, add 3-platform CI
Build / Windows (windows-latest) (push) Failing after 10s
Build / macOS (macos-latest) (push) Successful in 20s
Build / Linux (ubuntu-latest) (push) Successful in 31s
First pass on the streamer-tools OBS camera plugin: a minimal but real
CMake project matching the design doc's core-library/OBS-adapter split
(docs/superpowers/specs/2026-09-06-obs-camera-plugin-design.md in the
streamer-tools repo). No LiveKit FFI integration yet -- this proves the
toolchain works.

- core/: dependency-free C++17 library (no OBS dependency), unit tested
  via CTest with no external test framework.
- obs-adapter/: adapted from obsproject/obs-plugintemplate (commit
  3e7d7ac, 2025-12-09). Registers a real, stubbed OBS source type;
  builds as a genuine dynamically-linked OBS module against Ubuntu's
  system libobs-dev (confirmed via ldd/nm, not a fake stand-in).
- Simpler hand-written top-level CMakeLists.txt in place of the
  template's full buildspec-driven bootstrap (which downloads full OBS
  source + prebuilt deps) -- find_package(libobs) alone is enough on
  Linux; falls back to core-library-only when libobs isn't found
  (expected on macOS/Windows CI for now).
- .gitea/workflows/build.yml: 3-platform matrix (ubuntu-latest,
  macos-latest, windows-latest) matching the runners confirmed
  available to this repo under the CyberCoveLLC org.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
2026-09-06 20:46:08 -07:00