Author SHA1 Message Date
shadowdaoandClaude Sonnet 5 eef9f99117 docs: bash-on-Windows is proven broken (WSL as local system), with the log
Build / macOS (macos-latest) (push) Successful in 30s
Build / Linux (ubuntu-24.04) (push) Successful in 54s
Build / Windows (windows-latest) (push) Failing after 9m38s
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:11:46 -07:00
shadowdaoandClaude Sonnet 5 753213ea1b 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 58s
Build / Windows (windows-latest) (push) Failing after 9m33s
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:07:04 -07:00
47 changed files with 778 additions and 1968 deletions
-17
View File
@@ -1,17 +0,0 @@
#!/usr/bin/env bash
# Shared with .gitea/workflows/build.yml and .gitea/workflows/release.yml --
# this is the actual Linux configure/build/test/verify sequence. Edit once,
# here, so both workflows stay in sync instead of drifting copies.
#
# Linux keeps its distribution libobs; the buildspec bootstrap (macOS/Windows)
# is for the two platforms that have no such package.
set -euo pipefail
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DSTPLUGIN_BOOTSTRAP_OBS=OFF
cmake --build build
ctest --test-dir build --output-on-failure
# Show what was built
ls -la build/package/bin/64bit build/package/data/locale build/package/licenses
ldd build/package/bin/64bit/streamer-tools-camera.so | grep -E 'obs|livekit'
nm -D build/package/bin/64bit/streamer-tools-camera.so | grep -E ' T obs_module_(load|unload)'
-7
View File
@@ -1,7 +0,0 @@
#!/usr/bin/env bash
# Shared with .gitea/workflows/build.yml and .gitea/workflows/release.yml --
# both need the exact same Linux build dependencies. Edit once, here.
set -euo pipefail
sudo apt-get update -qq
sudo apt-get install -y -qq cmake ninja-build libobs-dev libcurl4-openssl-dev
-112
View File
@@ -1,112 +0,0 @@
#!/usr/bin/env bash
# Shared with .gitea/workflows/build.yml and .gitea/workflows/release.yml --
# this is the actual macOS configure/build/test/verify sequence. Edit once,
# here, so both workflows stay in sync instead of drifting copies.
#
# The buildspec bootstrap runs here: it fetches obs-deps + the pinned
# obs-studio source and builds libobs before this project configures.
#
# If that fails, fall back to a core-library-only build rather than going
# red: the core library and its tests are what this job mainly guards, and
# the fallback is loud (a workflow warning, plus the check below reporting no
# module) rather than silent. Do not remove the warning -- a green job that
# quietly stopped building the plugin is worse than a red one.
set -euo pipefail
if ! cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release; then
echo "::warning::OBS SDK bootstrap failed on macOS; building the core library only. The plugin module was NOT built."
rm -rf build
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DSTPLUGIN_BOOTSTRAP_OBS=OFF
fi
cmake --build build
ctest --test-dir build --output-on-failure
# Show what was built.
#
# This is not purely informational: the macOS bootstrap has been reliably
# building the real module in CI (6/6 tests, artifact uploaded -- see
# README), so a missing module here is a regression to fail loudly on, not
# the old silent fallback.
#
# This used to only check for a bare streamer-tools-camera.so, which is
# exactly the shape the "macOS packaging gap" in README.md documented as
# broken: OBS.app cannot load a bare .so on macOS, it needs a <name>.plugin
# bundle, and this check was blind to whether one was actually produced --
# another instance of the same false-positive-green class of bug this check
# exists to catch (see the Windows find_package(libobs) incident this
# project just had). Now hard-fails unless:
# 1. a real streamer-tools-camera.plugin bundle exists at the top level of
# build/package (macOS's plugin search wants the whole .plugin dropped
# straight into .../obs-studio/plugins/, not nested under a bin/
# subdirectory the way Linux/Windows are -- see
# obs-studio/UI/window-basic-main.cpp AddExtraModulePaths()), with
# Contents/MacOS/streamer-tools-camera, Contents/Info.plist,
# Contents/Resources/locale/en-US.ini (the module's locale data -- OBS
# passes Contents/Resources as the module's data path on macOS, not a
# sibling data/), and the bundled LiveKit dylibs under
# Contents/Frameworks;
# 2. the libobs dependency in the built binary resolves via
# @rpath/libobs.framework, not the old relative path
# (libobs/libobs.framework/...) that a real OBS.app cannot load;
# 3. the binary carries LC_RPATH entries for both
# @loader_path/../Frameworks (this bundle's own Frameworks) and
# @executable_path/../Frameworks (OBS.app/Contents/Frameworks).
ls -la .deps/Frameworks/libobs.framework/Resources/cmake || true
bundle="build/package/streamer-tools-camera.plugin"
binary="${bundle}/Contents/MacOS/streamer-tools-camera"
plist="${bundle}/Contents/Info.plist"
locale="${bundle}/Contents/Resources/locale/en-US.ini"
if [ ! -f "${binary}" ]; then
echo "::error::no plugin bundle was built -- ${binary} is missing. The macOS from-source libobs bootstrap is expected to succeed and produce a real .plugin bundle (not a bare .so, and not nested under bin/); treat this as a build failure, not a core-library-only fallback or a silently-reverted bundle."
exit 1
fi
if [ ! -f "${plist}" ]; then
echo "::error::${bundle} exists but has no Contents/Info.plist -- this is not a loadable OBS.app bundle."
exit 1
fi
if [ ! -f "${locale}" ]; then
echo "::error::${locale} is missing -- OBS passes Contents/Resources as this module's data path on macOS (see AddExtraModulePaths() in obs-studio's UI/window-basic-main.cpp), so OBS_MODULE_USE_DEFAULT_LOCALE will fail to load the en-US locale at runtime."
exit 1
fi
echo "--- bundle contents ---"
find "${bundle}" -maxdepth 4 -exec ls -ld {} \;
echo "--- Info.plist ---"
cat "${plist}"
echo "--- otool -L ---"
otool -L "${binary}"
if ! ls "${bundle}"/Contents/Frameworks/liblivekit*.dylib >/dev/null 2>&1; then
echo "::error::no LiveKit dylibs found under ${bundle}/Contents/Frameworks -- the plugin will fail to load at runtime."
exit 1
fi
if otool -L "${binary}" | grep -q 'libobs/libobs\.framework'; then
echo "::error::the libobs dependency is still recorded as the old relative path (libobs/libobs.framework/...) instead of @rpath/libobs.framework/... -- this is the exact macOS packaging gap the bundle fixup exists to close, and it did not take effect."
otool -L "${binary}" | grep -E 'obs|livekit'
exit 1
fi
if ! otool -L "${binary}" | grep -q '@rpath/libobs\.framework'; then
echo "::error::expected an @rpath/libobs.framework dependency in ${binary}, found none."
otool -L "${binary}" | grep -E 'obs|livekit'
exit 1
fi
echo "--- LC_RPATH ---"
rpath_dump=$(otool -l "${binary}" | grep -A2 LC_RPATH)
echo "${rpath_dump}"
if ! echo "${rpath_dump}" | grep -q '@loader_path/../Frameworks'; then
echo "::error::${binary} has no @loader_path/../Frameworks LC_RPATH (needed to resolve the bundled LiveKit dylibs)."
exit 1
fi
if ! echo "${rpath_dump}" | grep -q '@executable_path/../Frameworks'; then
echo "::error::${binary} has no @executable_path/../Frameworks LC_RPATH (needed to resolve libobs.framework inside OBS.app)."
exit 1
fi
echo "macOS bundle verification passed: real .plugin bundle, @rpath libobs dependency, both LC_RPATH entries present."
-5
View File
@@ -1,5 +0,0 @@
#!/usr/bin/env bash
# Shared with .gitea/workflows/build.yml and .gitea/workflows/release.yml.
set -euo pipefail
brew install cmake ninja
-109
View File
@@ -1,109 +0,0 @@
#!/usr/bin/env bash
# Creates a (draft) Gitea Release for the tag that triggered
# .gitea/workflows/release.yml, and uploads every archive in $DIST_DIR as a
# release asset. Draft because nobody has run this plugin in the OBS GUI on
# any platform yet -- a human still opens it and clicks Publish once that's
# no longer true (or once they're satisfied regardless).
#
# Required env: GITEA_TOKEN, SERVER, OWNER, REPO, TAG, SHA, DIST_DIR
# Optional env: MACOS_BUNDLE_FOUND ("true"/"false", default "false")
set -euo pipefail
: "${GITEA_TOKEN:?}"
: "${SERVER:?}"
: "${OWNER:?}"
: "${REPO:?}"
: "${TAG:?}"
: "${SHA:?}"
: "${DIST_DIR:?}"
MACOS_BUNDLE_FOUND="${MACOS_BUNDLE_FOUND:-false}"
if [ "${MACOS_BUNDLE_FOUND}" = "true" ]; then
MACOS_NOTE="This archive contains a \`.plugin\` bundle."
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
NOTES_FILE="$(mktemp)"
cat > "${NOTES_FILE}" <<EOF
# streamer-tools Camera Plugin -- ${TAG}
Built from commit \`${SHA}\`.
**Nobody has yet run this plugin in the OBS GUI, on any platform.** See "What
is verified, and how" in \`README.md\` for exactly what has and has not been
checked, including which claims are backed by automated tests versus a human
watching OBS. This is why the release is a draft -- open it and click Publish
once you're satisfied.
| 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; the WinHTTP backend has never been exercised against a real streamer-tools server, only a loopback test server -- see README's Windows CI section |
| macOS | \`streamer-tools-camera-${TAG}-macos.zip\` | Built and tested by this workflow's macOS job. ${MACOS_NOTE} |
## Installing
Extract the archive into your OBS plugins folder for your platform (the
default locations are easy to find online -- typically
\`~/.config/obs-studio/plugins/\` on Linux, \`%APPDATA%\\obs-studio\\plugins\\\`
on Windows, \`~/Library/Application Support/obs-studio/plugins/\` on macOS).
Each archive's top-level folder already matches the shape OBS expects there,
so extracting is the whole install step. Then in OBS: Sources -> \`+\` ->
"streamer-tools Camera" -> fill in the server URL, room slug and read key
from the room's settings page -> "Refresh camera list" -> pick a camera.
## What this is
Native OBS Studio source plugin that pulls streamer-tools camera feeds
directly from LiveKit over WebRTC. See \`README.md\` in the repository for
the full design, what is and is not verified, and current CI status.
EOF
echo "----- release notes -----"
cat "${NOTES_FILE}"
echo "--------------------------"
BODY_JSON="$(python3 - "$TAG" "$NOTES_FILE" <<'PYEOF'
import json, sys
tag, notes_file = sys.argv[1], sys.argv[2]
with open(notes_file) as f:
notes = f.read()
print(json.dumps({
"tag_name": tag,
"name": tag,
"body": notes,
"draft": True,
"prerelease": False,
}))
PYEOF
)"
echo "Creating release for tag ${TAG} ..."
RESP="$(curl -sS -f -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d "${BODY_JSON}" \
"${SERVER}/api/v1/repos/${OWNER}/${REPO}/releases")"
RELEASE_ID="$(python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])' <<<"${RESP}")"
echo "Created release id ${RELEASE_ID} (draft)."
shopt -s nullglob
ASSETS=("${DIST_DIR}"/*)
if [ "${#ASSETS[@]}" -eq 0 ]; then
echo "::error::no archives found in ${DIST_DIR} -- nothing to upload."
exit 1
fi
for f in "${ASSETS[@]}"; do
name="$(basename "${f}")"
echo "Uploading ${name} ..."
curl -sS -f -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-F "attachment=@${f}" \
"${SERVER}/api/v1/repos/${OWNER}/${REPO}/releases/${RELEASE_ID}/assets?name=${name}" \
> /dev/null
done
echo "Done. Draft release: ${SERVER}/${OWNER}/${REPO}/releases/${RELEASE_ID}"
-38
View File
@@ -1,38 +0,0 @@
# Shared with .gitea/workflows/build.yml and .gitea/workflows/release.yml --
# this is the actual Windows configure/build/test/verify sequence. Edit once,
# here, so both workflows stay in sync instead of drifting copies.
#
# The default Visual Studio generator is required, not Ninja:
# cmake/windows/buildspec.cmake keys the dependency slice off
# CMAKE_VS_PLATFORM_NAME, which only a VS generator sets.
#
# Same fallback as macOS, and the same warning: a green job that quietly
# stopped building the plugin is worse than a red one. PowerShell, not bash:
# self-hosted Windows runners here cannot be assumed to have a working bash
# (WSL as local system is refused).
cmake -S . -B build -A x64
if ($LASTEXITCODE -ne 0) {
Write-Host "::warning::OBS SDK bootstrap failed on Windows; building the core library only. The plugin module was NOT built."
Remove-Item -Recurse -Force build -ErrorAction SilentlyContinue
cmake -S . -B build -A x64 -DSTPLUGIN_BOOTSTRAP_OBS=OFF
if ($LASTEXITCODE -ne 0) { exit 1 }
}
cmake --build build --config Release
ctest --test-dir build -C Release --output-on-failure
# Show what was built.
#
# This is not purely informational: the from-source libobs bootstrap is
# expected to work reliably on this runner (that is the whole point of the
# buildspec bootstrap + find_package fix), so a missing module here is a
# regression to fail loudly on, not the old silent fallback.
$module = "build\package\bin\64bit\streamer-tools-camera.dll"
if (Test-Path $module) {
Get-ChildItem build\package\bin\64bit
} else {
Write-Host "::error::no plugin module was built -- $module is missing. The Windows from-source libobs bootstrap is expected to succeed; treat this as a build failure, not a core-library-only fallback."
exit 1
}
+85 -117
View File
@@ -10,27 +10,17 @@ name: Build
# downloads the pinned obs-deps bundle and obs-studio source and builds just # downloads the pinned obs-deps bundle and obs-studio source and builds just
# `libobs`. That step is the slow one: several minutes on a cold runner. # `libobs`. That step is the slow one: several minutes on a cold runner.
# #
# The actual per-platform dependency-install and configure/build/test/verify # RELEASE GATE: this workflow only builds, tests, and uploads CI-internal
# commands live in .gitea/scripts/ and are shared with # workflow artifacts (actions/upload-artifact, below) -- it does not create a
# .gitea/workflows/release.yml, so the two workflows can't drift apart -- # Gitea Release, push a tag-triggered publish, or otherwise distribute
# edit the scripts, not either workflow, to change how a platform builds. # binaries publicly, and it must not start doing so without explicit owner
# # sign-off on the WebRTC/OpenH264 attribution and GPLv2/Apache-2.0
# This workflow only builds, tests, and uploads CI-internal workflow # license-compatibility questions tracked in third_party/livekit/README.md
# artifacts (actions/upload-artifact, below) -- it does not create a Gitea # and the README's top-level Status section. If a real release/publish step
# Release. .gitea/workflows/release.yml is that publish step, gated on a # is ever added here, it must carry that same gate.
# pushed version tag rather than on every push.
on: on:
push: push:
# Excludes tag pushes -- a bare `push:` matches every ref push, tags
# included, which meant tagging a release triggered THIS workflow's full
# 3-platform build (Windows and all) at the same time as
# release.yml's own -- two full Windows builds serialized behind the
# runner's capacity:1, for one tag push. release.yml already covers
# exactly this build (plus packaging) on every `v*` tag; this workflow's
# job is ordinary commits.
branches:
- "**"
pull_request: pull_request:
jobs: jobs:
@@ -47,10 +37,26 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install build dependencies - name: Install build dependencies
run: .gitea/scripts/linux-deps.sh run: |
sudo apt-get update -qq
sudo apt-get install -y -qq cmake ninja-build libobs-dev libcurl4-openssl-dev
- name: Configure, build, test, verify - name: Configure
run: .gitea/scripts/linux-build.sh # Linux keeps its distribution libobs; the buildspec bootstrap is for
# the two platforms that have no such package.
run: cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DSTPLUGIN_BOOTSTRAP_OBS=OFF
- name: Build
run: cmake --build build
- name: Test (core library)
run: ctest --test-dir build --output-on-failure
- name: Show what was built
run: |
ls -la build/package/bin/64bit build/package/data/locale build/package/licenses
ldd build/package/bin/64bit/streamer-tools-camera.so | grep -E 'obs|livekit'
nm -D build/package/bin/64bit/streamer-tools-camera.so | grep -E ' T obs_module_(load|unload)'
- name: Upload plugin - name: Upload plugin
continue-on-error: true continue-on-error: true
@@ -67,42 +73,36 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install build dependencies - name: Install build dependencies
run: .gitea/scripts/macos-deps.sh run: brew install cmake ninja
- name: Cache OBS SDK bootstrap deps - name: Configure
# cmake/macos/buildspec.cmake downloads the pinned obs-deps bundle + # The buildspec bootstrap runs here: it fetches obs-deps + the pinned
# obs-studio source into .deps/ and already skips re-downloading via # obs-studio source and builds libobs before this project configures.
# SHA256 marker files -- but .deps/ lives inside the checkout, so a #
# fresh `actions/checkout` above wipes it every run regardless. This # If that fails, fall back to a core-library-only build rather than
# cache step is what actually makes that existing skip-logic apply # going red: the core library and its tests are what this job mainly
# across runs. The runner's built-in cache server is on by default # guards, and the fallback is loud (a workflow warning, plus the
# (cache.enabled: true), so this needs no runner-side config. # "Show what was built" step below reporting no module) rather than
uses: actions/cache@v4 # silent. Do not remove the warning -- a green job that quietly stopped
with: # building the plugin is worse than a red one.
path: .deps run: |
key: obs-deps-v2-${{ runner.os }}-${{ hashFiles('cmake/macos/buildspec.cmake', 'cmake/common/buildspec_common.cmake', 'buildspec.json') }} if ! cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release; then
echo "::warning::OBS SDK bootstrap failed on macOS; building the core library only. The plugin module was NOT built."
rm -rf build
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DSTPLUGIN_BOOTSTRAP_OBS=OFF
fi
- name: Configure, build, test, verify - name: Build
run: .gitea/scripts/macos-build.sh run: cmake --build build
- name: Drop non-relocatable OBS build tree before caching - name: Test (core library)
# cmake/common/buildspec_common.cmake's obs-studio sub-build writes run: ctest --test-dir build --output-on-failure
# an out-of-source CMakeCache.txt (.deps/obs-studio-*/build_*) that
# bakes in this job's absolute checkout path. The next run's - name: Show what was built
# checkout lands at a *different* absolute path, so restoring that run: |
# directory from the cache above makes CMake refuse to reconfigure ls -la .deps/Frameworks/libobs.framework/Resources/cmake || true
# it ("CMakeCache.txt directory ... is different than the directory ls -la build/package/bin || true
# ... where CMakeCache.txt was created"). Everything that actually otool -L build/package/bin/streamer-tools-camera.so || true
# needs to survive between runs -- the extracted source, and the
# already-installed libobs package under .deps/cmake, .deps/include,
# .deps/lib -- has no such path baked in and is unaffected. Delete
# only the intermediate build tree, after it has already done its
# job (libobs is built and installed by this point), so the cache
# saved at the end of this job contains nothing that requires the
# path it was created under.
if: always()
continue-on-error: true
run: rm -rf .deps/obs-studio-*/build_*
- name: Upload plugin - name: Upload plugin
continue-on-error: true continue-on-error: true
@@ -118,75 +118,43 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Verify build dependencies - name: Install build dependencies
# winvm-builder is a self-hosted act_runner labeled "windows-latest"; # winvm-builder is a self-hosted act_runner labeled "windows-latest";
# it is NOT the GitHub-hosted image, so none of that image's # it is NOT the GitHub-hosted image, so none of that image's
# preinstalled tooling can be assumed present. This used to be # preinstalled tooling (cmake included) can be assumed present.
# `uses: lukka/get-cmake@latest`, which re-downloaded and uses: lukka/get-cmake@latest
# re-extracted CMake + Ninja on every single run -- its own cache
# (routed through this act_runner's cache server) reported a "cloud
# cache miss" on every run even immediately after a successful save,
# and separately the extraction step alone measured ~7.5 minutes on
# this VM (consistent with Defender real-time scanning, not raw I/O)
# -- together the dominant cost of every Windows CI run. CMake and
# Ninja are now installed once, directly on winvm-builder's system
# PATH (C:\BuildTools\cmake\bin, C:\BuildTools\ninja -- see the
# README's "Windows runner: persistent build tools" section for
# exactly what that machine has installed and how to redo it if the
# VM is ever rebuilt). This step just fails loudly if that ever
# stops being true, rather than silently falling back to a slow
# re-download.
shell: powershell
run: |
$ErrorActionPreference = "Stop"
cmake --version
ninja --version
- name: Cache OBS SDK bootstrap deps - name: Configure
# See the matching step in the macOS job above for why this is # The default Visual Studio generator is required, not Ninja:
# needed: cmake/windows/buildspec.cmake's own download logic is # cmake/windows/buildspec.cmake keys the dependency slice off
# already idempotent, it just never gets the chance because .deps/ # CMAKE_VS_PLATFORM_NAME, which only a VS generator sets.
# lives inside the checkout and is wiped by every fresh clone.
# #
# The `v2` in the key: actions/cache never overwrites an existing # Same fallback as macOS, and the same warning: a green job that
# key -- once a key has a saved entry, every later job's save step is # quietly stopped building the plugin is worse than a red one.
# skipped as a no-op, cache hit or not. The very first job ever # PowerShell, not bash: this runner is a plain Windows VM and bash
# to populate this cache did so BEFORE the "Drop non-relocatable OBS # cannot be assumed present.
# build tree" step below existed, so its save included the bad run: |
# build_x86 directory -- and because saves under an existing key are cmake -S . -B build -A x64
# permanently skipped, every run after that kept restoring that same if ($LASTEXITCODE -ne 0) {
# bad entry forever, not "one more transitional run" as it looked at Write-Host "::warning::OBS SDK bootstrap failed on Windows; building the core library only. The plugin module was NOT built."
# the time. Bumping the key is what actually forces a fresh save; Remove-Item -Recurse -Force build -ErrorAction SilentlyContinue
# bump it again (v3, ...) if this cache is ever found to be stale in cmake -S . -B build -A x64 -DSTPLUGIN_BOOTSTRAP_OBS=OFF
# a way a workflow change alone can't fix. if ($LASTEXITCODE -ne 0) { exit 1 }
uses: actions/cache@v4 }
with:
path: .deps
key: obs-deps-v2-${{ runner.os }}-${{ hashFiles('cmake/windows/buildspec.cmake', 'cmake/common/buildspec_common.cmake', 'buildspec.json') }}
- name: Configure, build, test, verify - name: Build
# Windows PowerShell (powershell.exe), not PowerShell Core (pwsh) -- run: cmake --build build --config Release
# this self-hosted runner does not have pwsh installed, only the
# in-box Windows PowerShell 5.1 the original inline steps implicitly
# ran under.
shell: powershell
run: ./.gitea/scripts/windows-build.ps1
- name: Drop non-relocatable OBS build tree before caching - name: Test (core library)
# See the matching step in the macOS job above. Confirmed live on run: ctest --test-dir build -C Release --output-on-failure
# this runner: caching .deps/obs-studio-30.0.2/build_x86 as-is made
# every run's first configure attempt fail with a path mismatch - name: Show what was built
# against the job that populated the cache, falling back to run: |
# -DSTPLUGIN_BOOTSTRAP_OBS=OFF and only succeeding because the if (Test-Path build\package\bin\64bit) {
# already-installed libobs package (path-independent) was still Get-ChildItem build\package\bin\64bit
# found. That fallback masked the problem behind a misleading } else {
# "::warning::OBS SDK bootstrap failed" every run instead of fixing Write-Host "no plugin module was built (core library only)"
# it. Deleting the build tree here, after libobs is already built }
# and installed, is the actual fix.
if: always()
continue-on-error: true
shell: powershell
run: Remove-Item -Recurse -Force .deps\obs-studio-*\build_* -ErrorAction SilentlyContinue
- name: Upload plugin - name: Upload plugin
continue-on-error: true continue-on-error: true
-227
View File
@@ -1,227 +0,0 @@
name: Release
# Packages a build of each platform into a downloadable archive and creates
# a (draft) Gitea Release for it, so the project owner and other directors
# can grab a ready-to-use build instead of compiling from source.
#
# Runs only on a pushed version tag (see `on.push.tags` below) -- never on an
# ordinary push or PR, unlike build.yml. The release it creates is a DRAFT:
# it stays invisible to anyone without write access until a human explicitly
# opens it and clicks Publish, since nobody has run this plugin in the OBS
# GUI on any platform yet.
#
# The actual per-platform build commands live in .gitea/scripts/ and are the
# same scripts .gitea/workflows/build.yml uses, so this workflow can't drift
# from what CI already builds and verifies on every push.
on:
push:
tags:
- "v*"
jobs:
linux:
name: Linux (ubuntu-24.04)
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install build dependencies
run: .gitea/scripts/linux-deps.sh
- name: Configure, build, test, verify
run: .gitea/scripts/linux-build.sh
- name: Package archive
run: |
set -euo pipefail
# zip is not guaranteed present on a minimal self-hosted runner
# image (unlike GitHub-hosted ubuntu-24.04, which build.yml's
# deps script doesn't need to care about).
command -v zip >/dev/null || sudo apt-get install -y -qq zip
out="streamer-tools-camera-${GITEA_REF_NAME}-linux-x64.zip"
root="$(pwd)"
# Wrap build/package/'s bin/+data/ inside a top-level
# streamer-tools-camera/ directory, matching the plugin directory
# name OBS itself expects under <config>/obs-studio/plugins/ (see
# obs-adapter/CMakeLists.txt's staging comment). This makes the
# archive a straight `unzip -d ~/.config/obs-studio/plugins/`
# drop-in -- no manual `cp -r bin data` step required.
stage="$(mktemp -d)"
mkdir -p "${stage}/streamer-tools-camera"
cp -r build/package/. "${stage}/streamer-tools-camera/"
( cd "${stage}" && zip -r "${root}/${out}" streamer-tools-camera )
rm -rf "${stage}"
mkdir -p dist
mv "${out}" "dist/${out}"
ls -la dist
env:
GITEA_REF_NAME: ${{ github.ref_name }}
- name: Upload archive
uses: actions/upload-artifact@v3
with:
name: release-archive-linux-x64
path: dist
macos:
name: macOS (macos-latest)
runs-on: macos-latest
outputs:
bundle_found: ${{ steps.package.outputs.bundle_found }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install build dependencies
run: .gitea/scripts/macos-deps.sh
- name: Configure, build, test, verify
run: .gitea/scripts/macos-build.sh
- name: Package archive
id: package
run: |
set -euo pipefail
out="streamer-tools-camera-${GITEA_REF_NAME}-macos.zip"
root="$(pwd)"
mkdir -p dist
# Look for a *.plugin bundle rather than assuming its exact final
# location, falling back to packaging build/package/ as-is (a
# bare .so, not a loadable bundle) only if the bundle step didn't
# run or produced nothing -- see the macOS packaging gap in
# README.md for when that fallback path is actually live. The
# bundle itself is zipped at the archive's top level (cd into its
# parent, zip just the bundle dir) so the archive is already a
# straight `unzip -d ~/Library/Application\ Support/obs-studio/
# plugins/` drop-in -- no wrapping needed here, unlike
# Linux/Windows above, because OBS wants the whole *.plugin
# bundle directly under plugins/, not nested under a named
# subdirectory.
bundle="$(find build -maxdepth 4 -type d -name '*.plugin' 2>/dev/null | head -n1 || true)"
if [ -n "${bundle}" ]; then
echo "Found macOS .plugin bundle: ${bundle}"
( cd "$(dirname "${bundle}")" && zip -r "${root}/${out}" "$(basename "${bundle}")" )
echo "bundle_found=true" >> "${GITHUB_OUTPUT}"
else
echo "::warning::No .plugin bundle found under build/ -- packaging build/package/ as-is. This is NOT yet a loadable OBS.app plugin; see the macOS packaging gap in README.md."
( cd build/package && zip -r "${root}/${out}" . )
echo "bundle_found=false" >> "${GITHUB_OUTPUT}"
fi
mv "${out}" "dist/${out}"
ls -la dist
env:
GITEA_REF_NAME: ${{ github.ref_name }}
- name: Upload archive
uses: actions/upload-artifact@v3
with:
name: release-archive-macos
path: dist
windows:
name: Windows (windows-latest)
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Verify build dependencies
# See build.yml's Windows job for why this is no longer
# lukka/get-cmake@latest -- CMake and Ninja are installed once,
# directly on winvm-builder's system PATH; this just fails loudly
# if that ever stops being true.
shell: powershell
run: |
$ErrorActionPreference = "Stop"
cmake --version
ninja --version
- name: Configure, build, test, verify
# Windows PowerShell (powershell.exe), not PowerShell Core (pwsh) --
# this self-hosted runner does not have pwsh installed. See the same
# note in build.yml.
shell: powershell
run: ./.gitea/scripts/windows-build.ps1
- name: Package archive
shell: powershell
run: |
$ErrorActionPreference = "Stop"
$out = "streamer-tools-camera-$env:GITEA_REF_NAME-windows-x64.zip"
New-Item -ItemType Directory -Force -Path dist | Out-Null
# Wrap build\package\'s bin\+data\ inside a top-level
# streamer-tools-camera\ directory, matching the plugin directory
# name OBS itself expects under %APPDATA%\obs-studio\plugins\ (see
# obs-adapter/CMakeLists.txt's staging comment). This makes the
# archive a straight `Expand-Archive -DestinationPath
# $env:APPDATA\obs-studio\plugins\` drop-in -- no manual copy step
# required. Compress-Archive includes the source folder's own name
# as the archive root when given a single directory path, so
# staging under a streamer-tools-camera\ dir is enough on its own.
$stage = Join-Path $env:TEMP "stplugin-stage-$([guid]::NewGuid())"
$pluginDir = Join-Path $stage "streamer-tools-camera"
New-Item -ItemType Directory -Force -Path $pluginDir | Out-Null
Copy-Item -Path build\package\* -Destination $pluginDir -Recurse
Compress-Archive -Path $pluginDir -DestinationPath "dist\$out" -Force
Remove-Item -Recurse -Force $stage
Get-ChildItem dist
env:
GITEA_REF_NAME: ${{ github.ref_name }}
- name: Upload archive
uses: actions/upload-artifact@v3
with:
name: release-archive-windows-x64
path: dist
release:
name: Create Gitea Release (draft)
needs: [linux, macos, windows]
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- name: Checkout
# Not strictly needed to build anything here, but publish-release.sh
# lives in the repo and this keeps the release job self-contained /
# easy to reason about rather than reaching into another job's
# checkout.
uses: actions/checkout@v4
- name: Download Linux archive
uses: actions/download-artifact@v3
with:
name: release-archive-linux-x64
path: dist
- name: Download macOS archive
uses: actions/download-artifact@v3
with:
name: release-archive-macos
path: dist
- name: Download Windows archive
uses: actions/download-artifact@v3
with:
name: release-archive-windows-x64
path: dist
- name: Create draft release and upload assets
run: .gitea/scripts/publish-release.sh
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
SERVER: https://repo.anhonesthost.net
OWNER: CyberCoveLLC
REPO: obs-streamer-tools-plugin
TAG: ${{ github.ref_name }}
SHA: ${{ github.sha }}
DIST_DIR: dist
MACOS_BUNDLE_FOUND: ${{ needs.macos.outputs.bundle_found }}
+1 -179
View File
@@ -136,179 +136,8 @@ find_package(LiveKit CONFIG REQUIRED)
add_subdirectory(core) add_subdirectory(core)
# On Windows, OBS's own modern-CMake install layout
# (obs-studio/cmake/windows/defaults.cmake: OBS_CMAKE_DESTINATION=cmake)
# installs libobs's CMake package config to <prefix>/cmake/<target>/ --
# a shape find_package(<pkg> CONFIG) never searches under CMAKE_PREFIX_PATH.
# CMake's documented Config-mode search suffixes include
# "<prefix>/(cmake|CMake)/" (the file directly inside that dir, no <name>
# subdirectory) and "<prefix>/<name>*/(cmake|CMake)/[...]" (a <name>-prefixed
# directory first) -- neither matches "<prefix>/cmake/<name>*/". Verified
# empirically: a find_package(libobs CONFIG) run with CMAKE_PREFIX_PATH
# pointed at a directory laid out exactly like this (cmake/libobs/
# libobsConfig.cmake underneath it) never even tries that path, confirmed
# with --debug-find-pkg=libobs.
#
# macOS does not have this problem -- its OBS_CMAKE_DESTINATION is
# "lib/cmake", so the package lands at <prefix>/lib/cmake/libobs/, which
# matches the standard "<prefix>/lib*/cmake/<name>*/" suffix -- and neither
# does Linux's libobs-dev, which installs to
# /usr/lib/<arch-triplet>/cmake/libobs/, the same standard suffix. Windows is
# the one platform whose own upstream install destination CMake's
# find_package was never going to locate on its own; this is not caused by,
# and is not fixed by, the earlier "file INSTALL cannot find
# obs-frontend-api.dll" error tolerated in
# cmake/common/buildspec_common.cmake's _setup_obs_studio -- libobs is the
# FIRST subdirectory obs-studio's modern top-level CMakeLists.txt adds
# (before libobs-d3d11/-winrt/-opengl, plugins, test/test-input and finally
# UI), so libobs's own install(EXPORT ...) rules, including this Config file,
# already ran to completion by the time cmake --install later aborts inside
# UI/obs-frontend-api's install script.
#
# So: point find_package(libobs) directly at the from-source Windows install
# rather than relying on path-search heuristics that were never going to find
# it. Guarded by "NOT libobs_DIR" so an explicit -Dlibobs_DIR=... from a
# developer with their own OBS SDK is never overridden, and by EXISTS so this
# is a no-op whenever STPLUGIN_BOOTSTRAP_OBS=OFF or the bootstrap didn't
# reach this point.
if(OS_WINDOWS AND NOT libobs_DIR)
set(_stplugin_win_libobs_dir "${CMAKE_CURRENT_SOURCE_DIR}/.deps/cmake/libobs")
if(EXISTS "${_stplugin_win_libobs_dir}/libobsConfig.cmake")
set(libobs_DIR "${_stplugin_win_libobs_dir}" CACHE PATH
"Directory containing libobsConfig.cmake" FORCE)
message(STATUS
"libobs_DIR not set; OBS's Windows OBS_CMAKE_DESTINATION=cmake "
"does not match any of CMake's standard find_package Config-mode "
"search suffixes, so pointing it directly at the from-source "
"install: ${_stplugin_win_libobs_dir}")
endif()
endif()
# ...and the exact same problem, one level down, for w32-pthreads.
#
# libobs/cmake/os-windows.cmake links `PUBLIC OBS::w32-pthreads`, so
# obs-studio's libobsConfig.cmake.in carries, verbatim:
#
# if(MSVC)
# find_dependency(w32-pthreads REQUIRED)
# endif()
#
# That call is REQUIRED, it runs from inside libobsConfig.cmake, and until
# this block existed it aborted the whole configure the moment the libobs_DIR
# fix above finally succeeded in loading that config file:
#
# By not providing "Findw32-pthreads.cmake" in CMAKE_MODULE_PATH this
# project has asked CMake to find a package configuration file provided by
# "w32-pthreads", but CMake did not find one.
# .deps/cmake/libobs/libobsConfig.cmake:30 (find_dependency)
#
# This is NOT a missing export. deps/w32-pthreads/CMakeLists.txt ends with
# `target_export(w32-pthreads)`, which is the same helper libobs itself uses
# (cmake/common/helpers_common.cmake): it emits install(TARGETS ... EXPORT
# w32-pthreadsTargets), install(EXPORT ... NAMESPACE OBS::), a generated
# w32-pthreadsConfig.cmake and its version file, all COMPONENT Development.
# Those rules *must* exist and *must* have run, for two independent reasons:
#
# 1. CMake hard-errors at generate time if a target in one export set links
# to a target that is in no export set at all ("install(EXPORT
# "libobsTargets") includes target "libobs" which requires target
# "w32-pthreads" that is not in any export set"). obs-studio's generate
# step succeeded, so w32-pthreads was exported.
# 2. The install rules land under the libobs *directory* (this repo's
# _patch_obs_studio_w32_pthreads adds deps/w32-pthreads from
# libobs/CMakeLists.txt), and libobs is the first subdirectory the modern
# top-level CMakeLists.txt adds -- so its whole subtree installs before
# the tolerated UI/obs-frontend-api install error aborts the rest.
#
# The failure is purely the search path, identical to libobs's: target_export
# installs the package to "${OBS_CMAKE_DESTINATION}/${target}", which on
# Windows is <prefix>/cmake/w32-pthreads/ -- a shape find_package never
# searches. So apply the same remedy CMake's own error message suggests, and
# do it BEFORE find_package(libobs) below, because that is the call that
# transitively triggers find_dependency(w32-pthreads).
#
# macOS and Linux never reach this: the find_dependency is inside `if(MSVC)`,
# and OS_WINDOWS gates the block regardless -- a pure no-op off Windows.
if(OS_WINDOWS AND NOT w32-pthreads_DIR)
set(_stplugin_win_pthreads_dir "${CMAKE_CURRENT_SOURCE_DIR}/.deps/cmake/w32-pthreads")
if(EXISTS "${_stplugin_win_pthreads_dir}/w32-pthreadsConfig.cmake")
set(w32-pthreads_DIR "${_stplugin_win_pthreads_dir}" CACHE PATH
"Directory containing w32-pthreadsConfig.cmake" FORCE)
message(STATUS
"w32-pthreads_DIR not set; libobsConfig.cmake's "
"find_dependency(w32-pthreads REQUIRED) hits the same "
"OBS_CMAKE_DESTINATION=cmake search-suffix problem as libobs "
"itself, so pointing it directly at the from-source install: "
"${_stplugin_win_pthreads_dir}")
else()
# Fall back to a hand-written find module rather than letting the
# REQUIRED find_dependency kill the configure. cmake/windows is
# already on CMAKE_MODULE_PATH (see cmake/common/osconfig.cmake), so
# the fallback module deliberately lives in a subdirectory that is
# NOT -- a Findw32-pthreads.cmake sitting on the default module path
# would shadow OBS's own exported package on every build, and its
# real export is the better answer whenever it is present.
#
# ...and only when this repo's own bootstrap actually ran, which is
# the only situation the fallback module knows how to serve: it reads
# artifacts out of .deps/ and nowhere else. A developer building
# against their own external OBS SDK (STPLUGIN_BOOTSTRAP_OBS=OFF, or
# an explicit -Dlibobs_DIR=...) must be left on CMake's normal search
# so that whatever w32-pthreads package their SDK does provide still
# wins -- exposing a find module that can only ever fail would turn
# their build's outcome into a worse error, not a better one.
file(GLOB _stplugin_deps_obs_trees "${CMAKE_CURRENT_SOURCE_DIR}/.deps/obs-studio-*")
if(_stplugin_deps_obs_trees)
# Reaching here means the bootstrap ran but its install did not
# produce the export, so say exactly what IS in .deps/cmake/ --
# the next CI log then answers the question directly instead of
# costing another run.
file(GLOB _stplugin_deps_cmake_dirs "${CMAKE_CURRENT_SOURCE_DIR}/.deps/cmake/*")
message(STATUS
"No w32-pthreadsConfig.cmake at ${_stplugin_win_pthreads_dir}; "
"OBS CMake packages actually installed under .deps/cmake: "
"'${_stplugin_deps_cmake_dirs}'. Falling back to this repo's own "
"Findw32-pthreads.cmake, which builds OBS::w32-pthreads straight "
"from the bootstrap's build artifacts.")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/windows/find-fallback")
endif()
endif()
endif()
find_package(libobs QUIET) find_package(libobs QUIET)
# OBS::w32-pthreads can come back locationless for exactly the same reason
# OBS::libobs can (see the block below this one): the package config loads,
# but the per-configuration w32-pthreadsTargets-release.cmake that carries
# IMPORTED_IMPLIB/IMPORTED_LOCATION may not have been installed. libobs links
# it PUBLIC, so it is on this plugin's own link line and an empty location is
# a generate-time error, not a warning. Repair it from the known install
# destinations (obs-studio/cmake/windows/defaults.cmake:
# OBS_EXECUTABLE_DESTINATION=bin/64bit for the DLL, OBS_LIBRARY_DESTINATION=lib
# for the import library) -- the same repair, and the same reasoning, as the
# OBS::libobs one.
if(OS_WINDOWS AND TARGET OBS::w32-pthreads)
get_target_property(_stplugin_pthreads_implib OBS::w32-pthreads IMPORTED_IMPLIB)
get_target_property(_stplugin_pthreads_implib_release OBS::w32-pthreads IMPORTED_IMPLIB_RELEASE)
if(NOT _stplugin_pthreads_implib AND NOT _stplugin_pthreads_implib_release)
find_file(_stplugin_pthreads_implib_found w32-pthreads.lib
PATHS "${CMAKE_CURRENT_SOURCE_DIR}/.deps/lib" NO_DEFAULT_PATH)
find_file(_stplugin_pthreads_dll_found w32-pthreads.dll
PATHS "${CMAKE_CURRENT_SOURCE_DIR}/.deps/bin/64bit" NO_DEFAULT_PATH)
if(_stplugin_pthreads_implib_found)
set_target_properties(OBS::w32-pthreads PROPERTIES
IMPORTED_IMPLIB "${_stplugin_pthreads_implib_found}")
if(_stplugin_pthreads_dll_found)
set_target_properties(OBS::w32-pthreads PROPERTIES
IMPORTED_LOCATION "${_stplugin_pthreads_dll_found}")
endif()
message(STATUS
"OBS::w32-pthreads had no imported location; pointed it at "
"${_stplugin_pthreads_implib_found}")
endif()
endif()
endif()
# The imported OBS::libobs target can come back without a location. OBS 30.0.2 # The imported OBS::libobs target can come back without a location. OBS 30.0.2
# installs libobsTargets.cmake but not the per-configuration # installs libobsTargets.cmake but not the per-configuration
# libobsTargets-<config>.cmake alongside it when libobs is built on its own, # libobsTargets-<config>.cmake alongside it when libobs is built on its own,
@@ -347,15 +176,8 @@ if(libobs_FOUND AND TARGET OBS::libobs)
message(STATUS "OBS::libobs had no imported location; pointed it at ${_stplugin_obs_binary}") message(STATUS "OBS::libobs had no imported location; pointed it at ${_stplugin_obs_binary}")
endif() endif()
elseif(WIN32) elseif(WIN32)
# obs-studio/cmake/windows/defaults.cmake sets
# OBS_EXECUTABLE_DESTINATION=bin/64bit (the RUNTIME destination
# obs.dll installs to as a SHARED_LIBRARY target) and
# OBS_LIBRARY_DESTINATION=lib (the ARCHIVE destination for
# obs.lib) -- not a flat "bin", which is what upstream
# obs-plugintemplate's own equivalent macOS-only repair never had
# to get right.
find_file(_stplugin_obs_implib_found obs.lib PATHS "${_stplugin_deps}/lib" NO_DEFAULT_PATH) find_file(_stplugin_obs_implib_found obs.lib PATHS "${_stplugin_deps}/lib" NO_DEFAULT_PATH)
find_file(_stplugin_obs_dll_found obs.dll PATHS "${_stplugin_deps}/bin/64bit" NO_DEFAULT_PATH) find_file(_stplugin_obs_dll_found obs.dll PATHS "${_stplugin_deps}/bin" NO_DEFAULT_PATH)
if(_stplugin_obs_implib_found) if(_stplugin_obs_implib_found)
set_target_properties(OBS::libobs PROPERTIES IMPORTED_IMPLIB "${_stplugin_obs_implib_found}") set_target_properties(OBS::libobs PROPERTIES IMPORTED_IMPLIB "${_stplugin_obs_implib_found}")
if(_stplugin_obs_dll_found) if(_stplugin_obs_dll_found)
+306 -169
View File
@@ -1,202 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Apache License Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
Version 2.0, January 2004 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
http://www.apache.org/licenses/ Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION Preamble
1. Definitions. The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
"License" shall mean the terms and conditions for use, reproduction, When we speak of free software, we are referring to freedom, not
and distribution as defined by Sections 1 through 9 of this document. price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
"Licensor" shall mean the copyright owner or entity authorized by To protect your rights, we need to make restrictions that forbid
the copyright owner that is granting the License. anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
"Legal Entity" shall mean the union of the acting entity and all For example, if you distribute copies of such a program, whether
other entities that control, are controlled by, or are under common gratis or for a fee, you must give the recipients all the rights that
control with that entity. For the purposes of this definition, you have. You must make sure that they, too, receive or can get the
"control" means (i) the power, direct or indirect, to cause the source code. And you must show them these terms so they know their
direction or management of such entity, whether by contract or rights.
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity We protect your rights with two steps: (1) copyright the software, and
exercising permissions granted by this License. (2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
"Source" form shall mean the preferred form for making modifications, Also, for each author's protection and ours, we want to make certain
including but not limited to software source code, documentation that everyone understands that there is no warranty for this free
source, and configuration files. software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
"Object" form shall mean any form resulting from mechanical Finally, any free program is threatened constantly by software
transformation or translation of a Source form, including but patents. We wish to avoid the danger that redistributors of a free
not limited to compiled object code, generated documentation, program will individually obtain patent licenses, in effect making the
and conversions to other media types. program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
"Work" shall mean the work of authorship, whether in Source or The precise terms and conditions for copying, distribution and
Object form, made available under the License, as indicated by a modification follow.
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object GNU GENERAL PUBLIC LICENSE
form, that is based on (or derived from) the Work and for which the TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including 0. This License applies to any program or other work which contains
the original version of the Work and any modifications or additions a notice placed by the copyright holder saying it may be distributed
to that Work or Derivative Works thereof, that is intentionally under the terms of this General Public License. The "Program", below,
submitted to Licensor for inclusion in the Work by the copyright owner refers to any such program or work, and a "work based on the Program"
or by an individual or Legal Entity authorized to submit on behalf of means either the Program or any derivative work under copyright law:
the copyright owner. For the purposes of this definition, "submitted" that is to say, a work containing the Program or a portion of it,
means any form of electronic, verbal, or written communication sent either verbatim or with modifications and/or translated into another
to the Licensor or its representatives, including but not limited to language. (Hereinafter, translation is included without limitation in
communication on electronic mailing lists, source code control systems, the term "modification".) Each licensee is addressed as "you".
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity Activities other than copying, distribution and modification are not
on behalf of whom a Contribution has been received by Licensor and covered by this License; they are outside its scope. The act of
subsequently incorporated within the Work. running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
2. Grant of Copyright License. Subject to the terms and conditions of 1. You may copy and distribute verbatim copies of the Program's
this License, each Contributor hereby grants to You a perpetual, source code as you receive it, in any medium, provided that you
worldwide, non-exclusive, no-charge, royalty-free, irrevocable conspicuously and appropriately publish on each copy an appropriate
copyright license to reproduce, prepare Derivative Works of, copyright notice and disclaimer of warranty; keep intact all the
publicly display, publicly perform, sublicense, and distribute the notices that refer to this License and to the absence of any warranty;
Work and such Derivative Works in Source or Object form. and give any other recipients of the Program a copy of this License
along with the Program.
3. Grant of Patent License. Subject to the terms and conditions of You may charge a fee for the physical act of transferring a copy, and
this License, each Contributor hereby grants to You a perpetual, you may at your option offer warranty protection in exchange for a fee.
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the 2. You may modify your copy or copies of the Program or any portion
Work or Derivative Works thereof in any medium, with or without of it, thus forming a work based on the Program, and copy and
modifications, and in Source or Object form, provided that You distribute such modifications or work under the terms of Section 1
meet the following conditions: above, provided that you also meet all of these conditions:
(a) You must give any other recipients of the Work or a) You must cause the modified files to carry prominent notices
Derivative Works a copy of this License; and stating that you changed the files and the date of any change.
(b) You must cause any modified files to carry prominent notices b) You must cause any work that you distribute or publish, that in
stating that You changed the files; and whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
(c) You must retain, in the Source form of any Derivative Works c) If the modified program normally reads commands interactively
that You distribute, all copyright, patent, trademark, and when run, you must cause it, when started running for such
attribution notices from the Source form of the Work, interactive use in the most ordinary way, to print or display an
excluding those notices that do not pertain to any part of announcement including an appropriate copyright notice and a
the Derivative Works; and notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
(d) If the Work includes a "NOTICE" text file as part of its These requirements apply to the modified work as a whole. If
distribution, then any Derivative Works that You distribute must identifiable sections of that work are not derived from the Program,
include a readable copy of the attribution notices contained and can be reasonably considered independent and separate works in
within such NOTICE file, excluding those notices that do not themselves, then this License, and its terms, do not apply to those
pertain to any part of the Derivative Works, in at least one sections when you distribute them as separate works. But when you
of the following places: within a NOTICE text file distributed distribute the same sections as part of a whole which is a work based
as part of the Derivative Works; within the Source form or on the Program, the distribution of the whole must be on the terms of
documentation, if provided along with the Derivative Works; or, this License, whose permissions for other licensees extend to the
within a display generated by the Derivative Works, if and entire whole, and thus to each and every part regardless of who wrote it.
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and Thus, it is not the intent of this section to claim rights or contest
may provide additional or different license terms and conditions your rights to work written entirely by you; rather, the intent is to
for use, reproduction, or distribution of Your modifications, or exercise the right to control the distribution of derivative or
for any such Derivative Works as a whole, provided Your use, collective works based on the Program.
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, In addition, mere aggregation of another work not based on the Program
any Contribution intentionally submitted for inclusion in the Work with the Program (or with a work based on the Program) on a volume of
by You to the Licensor shall be under the terms and conditions of a storage or distribution medium does not bring the other work under
this License, without any additional terms or conditions. the scope of this License.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade 3. You may copy and distribute the Program (or a work based on it,
names, trademarks, service marks, or product names of the Licensor, under Section 2) in object code or executable form under the terms of
except as required for reasonable and customary use in describing the Sections 1 and 2 above provided that you also do one of the following:
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or a) Accompany it with the complete corresponding machine-readable
agreed to in writing, Licensor provides the Work (and each source code, which must be distributed under the terms of Sections
Contributor provides its Contributions) on an "AS IS" BASIS, 1 and 2 above on a medium customarily used for software interchange; or,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, b) Accompany it with a written offer, valid for at least three
whether in tort (including negligence), contract, or otherwise, years, to give any third party, for a charge no more than your
unless required by applicable law (such as deliberate and grossly cost of physically performing source distribution, a complete
negligent acts) or agreed to in writing, shall any Contributor be machine-readable copy of the corresponding source code, to be
liable to You for damages, including any direct, indirect, special, distributed under the terms of Sections 1 and 2 above on a medium
incidental, or consequential damages of any character arising as a customarily used for software interchange; or,
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing c) Accompany it with the information you received as to the offer
the Work or Derivative Works thereof, You may choose to offer, to distribute corresponding source code. (This alternative is
and charge a fee for, acceptance of support, warranty, indemnity, allowed only for noncommercial distribution and only if you
or other liability obligations and/or rights consistent with this received the program in object code or executable form with such
License. However, in accepting such obligations, You may act only an offer, in accord with Subsection b above.)
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
APPENDIX: How to apply the Apache License to your work. If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
To apply the Apache License to your work, attach the following 4. You may not copy, modify, sublicense, or distribute the Program
boilerplate notice, with the fields enclosed by brackets "[]" except as expressly provided under this License. Any attempt
replaced with your own identifying information. (Don't include otherwise to copy, modify, sublicense or distribute the Program is
the brackets!) The text should be enclosed in the appropriate void, and will automatically terminate your rights under this License.
comment syntax for the file format. We also recommend that a However, parties who have received copies, or rights, from you under
file or class name and description of purpose be included on the this License will not have their licenses terminated so long as such
same "printed page" as the copyright notice for easier parties remain in full compliance.
identification within third-party archives.
Copyright [yyyy] [name of copyright owner] 5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
Licensed under the Apache License, Version 2.0 (the "License"); 6. Each time you redistribute the Program (or any work based on the
you may not use this file except in compliance with the License. Program), the recipient automatically receives a license from the
You may obtain a copy of the License at original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
http://www.apache.org/licenses/LICENSE-2.0 7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
Unless required by applicable law or agreed to in writing, software If any portion of this section is held invalid or unenforceable under
distributed under the License is distributed on an "AS IS" BASIS, any particular circumstance, the balance of the section is intended to
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. apply and the section as a whole is intended to apply in other
See the License for the specific language governing permissions and circumstances.
limitations under the License.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
-4
View File
@@ -1,4 +0,0 @@
obs-streamer-tools-plugin
Copyright 2026 CyberCoveLLC
Licensed under the Apache License, Version 2.0.
+49 -275
View File
@@ -8,49 +8,35 @@ Media-Source path for directors. Full design:
## Status ## Status
This project's own code is Apache-2.0 (relicensed from GPL-2.0-or-later to **Release/distribution of built binaries is blocked pending owner sign-off.**
match the vendored LiveKit binaries, which are also Apache-2.0 — see This plugin statically/dynamically pulls in Google WebRTC and OpenH264 code
`LICENSE` and `NOTICE`, and `third_party/livekit/` for LiveKit's own). through the LiveKit SDK, and this repository's own top-level `LICENSE` is
GPLv2 while the vendored LiveKit binaries are Apache-2.0 — both a real patent/
`.gitea/workflows/build.yml` builds, tests, and uploads CI-internal build royalty question (OpenH264/WebRTC) and a real license-compatibility question
artifacts on every push. `.gitea/workflows/release.yml` packages a tagged (GPLv2 vs. Apache-2.0-linked code) that only the project owner can decide.
build (`v*`) into a **draft** Gitea Release; a human still needs to open it Nothing in this repo should be built into a package and handed out, posted,
and click Publish. or attached to a public release until that sign-off happens. See
`third_party/livekit/README.md` for the specifics of what is and is not
currently known/shipped on the licensing side. (CI in `.gitea/workflows/build.yml`
currently only builds, tests, and uploads CI-internal build artifacts — it
does not create a Gitea Release or otherwise publish anything publicly; if
that ever changes, the new step must carry this same gate.)
The plugin is **functionally complete on Linux and verified end to end there** The plugin is **functionally complete on Linux and verified end to end there**
(module loads into real libobs, connects to a real LiveKit server through the (module loads into real libobs, connects to a real LiveKit server through the
real streamer-tools API shape, and pushes decoded frames into real streamer-tools API shape, and pushes decoded frames into
`obs_source_output_video`/`_audio`). `obs_source_output_video`/`_audio`).
**First confirmed OBS GUI load: Windows, 2026-09-09** — the v0.1.0 release It has **not been run in the OBS GUI on any platform.** macOS builds the real
artifact loaded into OBS 32.2.2 on Windows 11 (build 26200) on a director's module in CI but its artifact is not yet loadable (see the macOS packaging gap
machine, from under CI). Windows CI has **failed on every completed run so far**. The
`C:\ProgramData\obs-studio\plugins\streamer-tools-camera\bin\64bit\`. `-A x64` argument fix is now confirmed working — the run carrying it got as
That retires "the module will not even load in a real OBS" for Windows. It far as building libobs — but it exposed a deeper blocker: OBS 30.0.2's
does **not** yet cover whether video renders correctly, colours, A/V sync or opt-in modern CMake path never defines the `OBS::w32-pthreads` target its own
latency — see "Not verified anywhere" below for what is still open. Linux and Windows libobs links against. The PowerShell rewrite of the Windows steps is
macOS have still never been opened in the GUI; macOS builds the real module in still queued and unproven. See "Where the Windows bootstrap got to" under CI
CI but its artifact is not yet loadable (see the macOS packaging gap under CI). below for the trace and the options, and check current CI status rather than
trusting this paragraph's age.
⚠️ **The install directory is not the same on every platform, and getting it
wrong fails silently.** On Windows it is
`C:\ProgramData\obs-studio\plugins\` (`GetProgramDataPath`
`CSIDL_COMMON_APPDATA`), **not** `%APPDATA%\obs-studio\` — see the packaging
section. That mistake cost the director above an evening: OBS logs nothing at
all for a plugin it never finds.
**Windows CI is now green.** The run at `f27b1c0` is the first completed
green Windows job on this repository: the from-source libobs bootstrap
configures, builds and installs, `find_package(libobs)` resolves, all 6 CTest
suites pass, and `build\package\bin\64bit\streamer-tools-camera.dll`
(136,192 bytes) is staged next to `livekit.dll` and `livekit_ffi.dll` — read
out of the job's own log body, not inferred from the job status. That also
retires three previously-unproven items in one go: the `-A x64` argument fix,
the PowerShell rewrite of the Windows steps, and the `add_subdirectory`
patch for `OBS::w32-pthreads`. Windows has since been **loaded in the real OBS
GUI** (see above); Linux and macOS have not. See "Where the Windows bootstrap got
to" under CI below for the whole trace, and check current CI status rather
than trusting this paragraph's age.
See "What is verified, and how" below for exactly what has and has not been See "What is verified, and how" below for exactly what has and has not been
checked, and "Testing this by hand" for what a human still needs to do. checked, and "Testing this by hand" for what a human still needs to do.
@@ -76,9 +62,7 @@ obs-adapter/ - thin OBS glue (C++)
data/locale/en-US.ini data/locale/en-US.ini
scripts/livekit-dev-room.py - mints tokens for the integration test scripts/livekit-dev-room.py - mints tokens for the integration test
third_party/livekit/ - redistribution notices for the LiveKit binaries third_party/livekit/ - redistribution notices for the LiveKit binaries
.gitea/scripts/ - the actual per-platform build commands, shared by build.yml and release.yml .gitea/workflows/build.yml - 3-platform CI matrix
.gitea/workflows/build.yml - 3-platform CI matrix (every push/PR; never publishes)
.gitea/workflows/release.yml - packages + creates a draft Gitea Release (only on a `v*` tag push; see Status above)
``` ```
## How it works ## How it works
@@ -154,28 +138,17 @@ build/package/licenses/...
``` ```
That is exactly the layout OBS searches on Linux and Windows — That is exactly the layout OBS searches on Linux and Windows —
`<base>/obs-studio/plugins/<name>/bin/64bit` plus a sibling `data/`, per `<config>/obs-studio/plugins/<name>/bin/64bit` plus a sibling `data/`, per
`AddExtraModulePaths()` in obs-studio (`UI/window-basic-main.cpp` in 30.x, `AddExtraModulePaths()` in obs-studio's `UI/window-basic-main.cpp` — so
`frontend/widgets/OBSBasic.cpp` in 32.x) — so `build/package/` is a straight `build/package/` is a straight drop-in. The module resolves the LiveKit
drop-in. **`<base>` is NOT the same directory on every platform**, and getting libraries from `$ORIGIN` (verified: `ldd` on the staged copy resolves both
this wrong is silent: OBS logs nothing at all for a plugin it never finds.
Linux uses the user config dir (`GetAppConfigPath``~/.config`), but Windows
uses `GetProgramDataPath` (`CSIDL_COMMON_APPDATA`) — i.e.
`C:\ProgramData\obs-studio\plugins\`, **not** `%APPDATA%\obs-studio\`
(`CSIDL_APPDATA`), which on Windows holds OBS's config and is never scanned for
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 to `bin/64bit/`), not from the build tree. macOS is not this shape; see the
macOS packaging gap under CI. macOS packaging gap under CI.
## Testing this by hand ## Testing this by hand
**The module has been loaded in the OBS GUI on Windows once (2026-09-09, OBS **Nobody has yet run this in the OBS GUI. That test is still outstanding on
32.2.2 / Windows 11 26200) — nothing beyond "it loads and registers its source" all three platforms.** To do it on Linux:
is confirmed there, and Linux and macOS have never been opened in the GUI at
all.** To do it on Linux:
``` ```
mkdir -p ~/.config/obs-studio/plugins/streamer-tools-camera mkdir -p ~/.config/obs-studio/plugins/streamer-tools-camera
@@ -231,11 +204,7 @@ 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 | | 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:** **Not verified anywhere:**
- Anything past module load in the OBS GUI. Windows 2026-09-09 confirms the - The OBS GUI, on any platform. No human has looked at this in OBS.
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". - 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 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. not load in OBS.app — see the macOS packaging gap under CI.
@@ -260,7 +229,7 @@ runners available to this repo under the `CyberCoveLLC` org.
|---|---|---|---| |---|---|---|---|
| `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 | | `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 | | `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 | | `windows` | `windows-latest` | `winvm-builder` (org-scoped) | **Failing** — every completed run on this branch has failed. The latest gets as far as building libobs and stops on an OBS-side `OBS::w32-pthreads` target that its own modern CMake path never defines; see below |
The Linux job is pinned to `ubuntu-24.04` rather than `ubuntu-latest`: this 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, instance's two Linux runners answer `ubuntu-latest` with different releases,
@@ -283,51 +252,6 @@ and a permanently red CI teaches people to ignore CI. **Do not remove the
warning:** a green job that quietly stopped building the plugin is worse than warning:** a green job that quietly stopped building the plugin is worse than
a red one. a red one.
### Windows runner: persistent build tools (2026-09-07)
`winvm-builder`'s Windows job used to install its own CMake + Ninja on every
single run via `uses: lukka/get-cmake@latest`. That action has its own
caching (routed through this act_runner's built-in cache server, the same
mechanism `.deps/`'s `actions/cache` step above relies on and that one does
work) but it never hit: every run logged `Cloud cache miss` against the same
cache key, even immediately after a run that logged a successful save under
that exact key -- some incompatibility between `lukka/get-cmake`'s bundled
cache client and this act_runner's cache-server implementation, not
"caching isn't configured." Separately, and the larger cost: the archive
extraction step alone measured **~7.5 minutes** for a 45MB zip on this VM
(13:11:14 to 13:18:48 in one captured run) -- consistent with Windows
Defender real-time-scanning every extracted file, not raw disk I/O, though
that specific cause is not confirmed. Together this was the dominant cost of
every Windows CI run, cold cache or not.
Fix: CMake 4.4.2 and Ninja 1.12.1 are now installed once, directly on the
`winvm-builder` VM (Proxmox VMID 110, host pve4/192.168.1.145), not fetched
per-run:
- `C:\BuildTools\cmake\` (from
`cmake-4.4.2-windows-x86_64.zip`, Kitware's GitHub releases) and
`C:\BuildTools\ninja\` (from `ninja-win.zip`, `ninja-build/ninja` v1.12.1
release) — plain `Expand-Archive` drops, nothing installed via an
installer/MSI.
- Both added to the **Machine**-level `PATH`
(`[Environment]::SetEnvironmentVariable('PATH', ..., 'Machine')`, not
`setx`, which silently truncates a `PATH` this long).
- The `GiteaRunner-winvm-builder` scheduled task (`C:\gitea-runner\
gitea-runner.exe daemon`, runs as SYSTEM) was stopped and restarted after
the `PATH` change — a already-running process does not pick up an updated
Machine environment variable, only processes started after the change do,
and every CI job is a child process of this one long-running daemon.
Both workflows' Windows jobs now just run `cmake --version` / `ninja
--version` as a "Verify build dependencies" step and fail loudly if either
is missing, instead of silently falling back to the slow per-run install.
**This is VM state, not something `git clone` reproduces.** If
`winvm-builder` is ever rebuilt or reimaged, redo the three steps above
(download+extract both zips under `C:\BuildTools\`, extend the Machine
`PATH`, restart the scheduled task) before expecting Windows CI to pass
again — there is nothing in this repo that does it automatically.
### Where the macOS bootstrap actually got to ### Where the macOS bootstrap actually got to
Six CI iterations, each fixing a real failure visible in the logs: Six CI iterations, each fixing a real failure visible in the logs:
@@ -381,12 +305,8 @@ Windows is by far the slowest job — the `lukka/get-cmake` step alone takes
7-15 minutes on `winvm-builder`, and the runner serialises jobs, so a burst of 7-15 minutes on `winvm-builder`, and the runner serialises jobs, so a burst of
pushes leaves a queue that takes an hour to drain. pushes leaves a queue that takes an hour to drain.
**The honest record, as it stood before `f27b1c0`: every completed Windows CI **The honest record: every completed Windows CI run on this branch has
run on this branch had failed.** (`f27b1c0` is the one that finally went failed.** The first 7 failures were all at commits predating the `-A x64` fix
green — see "After the w32-pthreads target" at the end of this section. The
history below is kept because each dead end in it is a real constraint
someone will otherwise rediscover.) The first 7 failures were all at commits
predating the `-A x64` fix
below. The 8th, at `edb0c02` — the first commit that actually carries that fix below. The 8th, at `edb0c02` — the first commit that actually carries that fix
— has since completed, and it is the informative one: **the `-A x64` fix — has since completed, and it is the informative one: **the `-A x64` fix
worked, and Windows failed further along, on something else.** A later run worked, and Windows failed further along, on something else.** A later run
@@ -433,53 +353,16 @@ Deliberately **not** "fixed" by bumping the pin: 30.0.2, 30.1.2, 30.2.3,
`OBS::w32-pthreads` from `libobs/cmake/os-windows.cmake` while none of them `OBS::w32-pthreads` from `libobs/cmake/os-windows.cmake` while none of them
add `deps/w32-pthreads` from `libobs/CMakeLists.txt`. A version bump is add `deps/w32-pthreads` from `libobs/CMakeLists.txt`. A version bump is
therefore not obviously the answer and needs checking rather than assuming. therefore not obviously the answer and needs checking rather than assuming.
Options, roughly in order of preference:
Option 1 (build `obs-frontend-api`, matching obs-plugintemplate's own CI, and 1. Work out how obs-plugintemplate's own Windows CI satisfies this target at
accept the Qt dependency on Windows only) was investigated and **rejected**: its 31.1.1 pin — it builds `obs-frontend-api` rather than `libobs`, which
`UI/obs-frontend-api/CMakeLists.txt` only links `OBS::libobs`, nothing else — may pull in a different subdirectory set. If so, building that target (and
it does not itself pull in `deps/w32-pthreads`. What actually satisfies the accepting the Qt dependency on Windows only) is the smallest change.
target upstream is that `UI/CMakeLists.txt` returns early when 2. Have the bootstrap add `add_subdirectory(deps/w32-pthreads)` to the
`ENABLE_UI=OFF`, *before* reaching `include(cmake/os-windows.cmake)` — the extracted OBS tree before configuring. Effective, but a patch against a
file that (via its own `if(NOT TARGET OBS::w32-pthreads)` guard) adds third-party tree that must be carried across pin bumps.
`deps/w32-pthreads`. Upstream's CI never sets `ENABLE_UI=OFF`, so that 3. Drop the from-source libobs on Windows and find a prebuilt OBS SDK.
add-as-a-side-effect-of-Qt always happens for them. Building
`obs-frontend-api` instead of `libobs` would not change any of that; the only
way to get the same side effect is to stop passing `-DENABLE_UI:BOOL=OFF`,
which is exactly the ~100 MB Qt6 download this bootstrap was trimmed to avoid
(see the Windows `buildspec.cmake` comment) and buys this plugin nothing,
since its properties UI is plain `obs_properties_*`.
Went with Option 2 instead: `cmake/common/buildspec_common.cmake` now carries
`_patch_obs_studio_w32_pthreads()`, called for `OS_WINDOWS` right before
`_setup_obs_studio()`. It patches the freshly-extracted
`libobs/CMakeLists.txt` to add the one missing subdirectory itself, using the
exact same `if(NOT TARGET OBS::w32-pthreads)` guard
`UI/cmake/os-windows.cmake` already relies on upstream:
```cmake
if(OS_WINDOWS)
if(NOT TARGET OBS::w32-pthreads)
add_subdirectory("${CMAKE_SOURCE_DIR}/deps/w32-pthreads" "${CMAKE_BINARY_DIR}/deps/w32-pthreads")
endif()
include(cmake/os-windows.cmake)
...
```
It is idempotent (checks for `deps/w32-pthreads` already present in the file
before patching, so re-running against a previously-patched extraction is a
no-op) and fails loudly with `FATAL_ERROR` if the anchor text it expects to
find is not there, rather than silently doing nothing on a future OBS version
whose `libobs/CMakeLists.txt` has changed shape. Verified locally (this is a
Linux sandbox, so only the CMake string-patching logic itself could be
checked, not a real Windows configure/build): ran the same `string(FIND)`
/`string(REPLACE)` sequence against the real `libobs/CMakeLists.txt` fetched
from the obs-studio 30.0.2 tag, confirmed it produces the intended
`if(OS_WINDOWS) / if(NOT TARGET ...) / add_subdirectory(...) / endif() /
include(...)` block, and confirmed a second run against the already-patched
file is a no-op. Whether this actually gets libobs through CMake generate and
building on a real Windows runner is the thing the next CI run needs to
prove — option 3 (dropping the from-source libobs on Windows for a prebuilt
SDK) remains the fallback if it does not.
Two bugs of its own were found; the first is now proven fixed by `edb0c02` Two bugs of its own were found; the first is now proven fixed by `edb0c02`
getting past it, the second is still unproven: getting past it, the second is still unproven:
@@ -514,118 +397,9 @@ getting past it, the second is still unproven:
`58f4832`'s failure says nothing about the `w32-pthreads` blocker; that `58f4832`'s failure says nothing about the `w32-pthreads` blocker; that
result comes from `edb0c02` alone. result comes from `edb0c02` alone.
(Superseded by the next subsection: the `w32-pthreads` blocker described above Until a Windows run completes green, Windows should be treated as unverified
*was* the next thing solved, and the `add_subdirectory` patch and the beyond "the core library and the WinHTTP backend compile and their tests
PowerShell rewrite are both now proven by a completed green run. What stands pass", which earlier (failing-job) runs did show before failing later in the
from this subsection is its reasoning — why `ENABLE_UI=OFF` exposes the gap, job. The `w32-pthreads` blocker above is the next thing to solve, and it is
and why re-enabling Qt or bumping the OBS pin is not the answer.) upstream's problem to work around rather than a defect in this repo's
bootstrap.
### After the w32-pthreads target: the w32-pthreads *package*
The `add_subdirectory(deps/w32-pthreads)` patch above did its job — the
`edb0c02`-era generate error is gone, obs-studio 30.0.2 configures, builds
`w32-pthreads.dll` and `obs.dll`, and installs. Two further Windows-only
blockers then surfaced behind it, both the same underlying upstream mismatch
and neither one a defect in this repo:
1. **`find_package(libobs)` could not locate the package it had just
installed.** obs-studio's `cmake/windows/defaults.cmake` sets
`OBS_CMAKE_DESTINATION=cmake`, and `target_export()` installs each
package to `<prefix>/${OBS_CMAKE_DESTINATION}/<target>/` — i.e.
`.deps/cmake/libobs/`. That is not one of CMake's Config-mode search
suffixes (`<prefix>/cmake/` is, but only for a config file sitting
*directly* in it; `<prefix>/<name>*/cmake/` is, but the `<name>`
directory has to come first). Fixed in `79de5e8f` by setting
`libobs_DIR` explicitly; the long comment above that block in
`CMakeLists.txt` has the full reasoning.
2. **…and then `libobsConfig.cmake` could not locate `w32-pthreads` for
exactly the same reason.** `libobs/cmake/os-windows.cmake` links
`PUBLIC OBS::w32-pthreads`, so upstream's `libobsConfig.cmake.in` carries
a hard `find_dependency(w32-pthreads REQUIRED)` under `if(MSVC)`. Once
fix 1 finally got that config file loaded, the dependency lookup inside
it failed and killed the configure:
```
By not providing "Findw32-pthreads.cmake" in CMAKE_MODULE_PATH this project
has asked CMake to find a package configuration file provided by
"w32-pthreads", but CMake did not find one.
.deps/cmake/libobs/libobsConfig.cmake:30 (find_dependency)
```
**This is not a missing export**, which was the first hypothesis and is
worth recording as wrong: `deps/w32-pthreads/CMakeLists.txt` ends with
`target_export(w32-pthreads)`, the same helper `libobs` itself uses, so
it does emit `install(TARGETS … EXPORT w32-pthreadsTargets)`,
`install(EXPORT … NAMESPACE OBS::)` and a generated
`w32-pthreadsConfig.cmake`, all `COMPONENT Development`. Two independent
arguments say those rules ran: CMake hard-errors at generate time if an
exported target links a target that is in no export set at all (and OBS's
generate step succeeded), and this repo's patch adds `deps/w32-pthreads`
from `libobs/CMakeLists.txt`, making it part of the `libobs` subtree —
which installs *before* the tolerated `UI/obs-frontend-api` install error
aborts the rest. The package really is at `.deps/cmake/w32-pthreads/`;
`find_package` was simply never going to look there.
So the fix is the same one-liner as for `libobs`, and it is literally
what CMake's own error message suggests: set `w32-pthreads_DIR` before
the `find_package(libobs)` call that transitively triggers the
`find_dependency`. Both `_DIR` blocks now sit next to each other in
`CMakeLists.txt`.
Behind that sits `cmake/windows/find-fallback/Findw32-pthreads.cmake`,
used only if that export is genuinely absent from `.deps/`. It rebuilds
`OBS::w32-pthreads` by hand from the bootstrap's own artifacts. It
deliberately does *not* live in `cmake/windows/`, which
`cmake/common/osconfig.cmake` already puts on `CMAKE_MODULE_PATH` for
every Windows configure — a find module there would shadow OBS's real
exported package on every build, since `find_package` tries MODULE mode
before CONFIG mode. `CMakeLists.txt` appends the `find-fallback/`
directory to `CMAKE_MODULE_PATH` only after it has established the real
export is missing, and logs what *is* under `.deps/cmake/` when it does,
so a future failure of this shape is answered by the CI log rather than
by another run.
Note this package is load-bearing for more than the dependency check:
`libobs/util/threading.h` does `#include <pthread.h>`, and on Windows
that header only exists because `target_export(w32-pthreads)` installs
`pthread.h`/`sched.h` as `PUBLIC_HEADER` into `.deps/include/`.
Verified before pushing, on Linux, since this is a Linux sandbox: a
reconstruction of the exact failure — a stub `libobsConfig.cmake` containing
`find_dependency(w32-pthreads REQUIRED)`, reached through `libobs_DIR`, with
the package installed at `.deps/cmake/w32-pthreads/` — reproduces the CI
error without the `w32-pthreads_DIR` block and passes with it; and the
fallback find module was exercised separately by deleting that package, with
`find_package` resolving through MODULE mode to it instead. A full Linux
configure of this repo is unchanged (both blocks are inside `if(OS_WINDOWS)`,
and the upstream `find_dependency` is inside `if(MSVC)`, so macOS and Linux
are pure no-ops).
**Confirmed on the real runner.** The Windows job for `f27b1c0` completed
green, and its log body — not just its status — shows the whole chain:
```
-- w32-pthreads_DIR not set; libobsConfig.cmake's find_dependency(w32-pthreads
REQUIRED) hits the same OBS_CMAKE_DESTINATION=cmake search-suffix problem as
libobs itself, so pointing it directly at the from-source install:
...\.deps\cmake\w32-pthreads
-- libobs found (...\.deps\cmake\libobs) -- building OBS adapter module
streamer-tools-camera.vcxproj -> ...\build\obs-adapter\Release\streamer-tools-camera.dll
100% tests passed out of 6
Directory: ...\build\package\bin\64bit
-a---- 3078656 livekit.dll
-a---- 25008640 livekit_ffi.dll
-a---- 136192 streamer-tools-camera.dll
```
Note which branch that log took: the `w32-pthreads_DIR` message means the
package config really was sitting at `.deps/cmake/w32-pthreads/` all along and
the fallback find module was never loaded. The export was never missing — only
unfindable. Linux and macOS were green in the same run, confirming the no-op.
The one piece of noise left in that log is the tolerated
`UI/obs-frontend-api/cmake_install.cmake` error, which now repeats once per
CMake re-configure because Visual Studio's `ZERO_CHECK` target re-runs the
bootstrap during the build. It is cosmetic and pre-dates this change, but it
makes the Windows log harder to read than it should be.
-69
View File
@@ -24,7 +24,6 @@
# build tree, so it does not trip over the install rules of targets that # build tree, so it does not trip over the install rules of targets that
# were deliberately never built. # were deliberately never built.
# 7. _resolve_versioned_macos_sdk exists at all -- see its own comment. # 7. _resolve_versioned_macos_sdk exists at all -- see its own comment.
# 8. _patch_obs_studio_w32_pthreads exists at all -- see its own comment.
# #
include_guard(GLOBAL) include_guard(GLOBAL)
@@ -148,70 +147,6 @@ function(_resolve_versioned_macos_sdk out_path)
endif() endif()
endfunction() endfunction()
# _patch_obs_studio_w32_pthreads: Windows-only. Confirmed at every obs-studio
# tag from 30.0.2 through 31.1.1 (checked directly against
# libobs/cmake/os-windows.cmake and the top-level CMakeLists.txt at each tag):
# libobs/cmake/os-windows.cmake unconditionally links `OBS::w32-pthreads`, but
# that target is defined only by deps/w32-pthreads/CMakeLists.txt, and nothing
# in the OBS_CMAKE_VERSION>=3.0.0 ("modern") top-level CMakeLists.txt branch --
# the one -DOBS_CMAKE_VERSION=3.0.0 selects -- ever adds deps/w32-pthreads.
# libobs/CMakeLists.txt itself only adds deps/libcaption and deps/uthash.
#
# Upstream obs-studio's own CI never hits this because it builds with
# ENABLE_UI left ON: UI/cmake/os-windows.cmake happens to add
# deps/w32-pthreads too (guarded by `if(NOT TARGET OBS::w32-pthreads)`), which
# satisfies libobs's link by the time CMake generates -- purely as a side
# effect of Qt still being in the build, not because anything wires
# w32-pthreads to libobs on purpose. This bootstrap deliberately builds with
# ENABLE_UI:BOOL=OFF (see the file header) specifically to avoid pulling in
# Qt6, so that side effect never happens here, and the gap is exposed.
#
# Rather than re-enable ENABLE_UI (and pay for a ~100 MB Qt6 download this
# plugin's plain obs_properties_* UI does not need) or vendor a full copy of
# deps/CMakeLists.txt, patch libobs/CMakeLists.txt to add the one missing
# subdirectory itself, using the exact same existence guard
# UI/cmake/os-windows.cmake already relies on. Idempotent: running this again
# against an already-patched tree is a no-op (the search text no longer
# matches), so it is safe to call on every configure regardless of whether
# .deps/ was freshly extracted or reused from a previous run.
function(_patch_obs_studio_w32_pthreads)
set(_cmakelists "${dependencies_dir}/${_obs_destination}/libobs/CMakeLists.txt")
if(NOT EXISTS "${_cmakelists}")
message(FATAL_ERROR "Cannot apply the w32-pthreads workaround: ${_cmakelists} does not exist.")
endif()
file(READ "${_cmakelists}" _contents)
string(FIND "${_contents}" "deps/w32-pthreads" _already_patched)
if(NOT _already_patched EQUAL -1)
message(STATUS "libobs/CMakeLists.txt already carries the w32-pthreads workaround - skipping")
return()
endif()
set(_needle "if(OS_WINDOWS)\n include(cmake/os-windows.cmake)")
set(_replacement
"if(OS_WINDOWS)\n if(NOT TARGET OBS::w32-pthreads)\n add_subdirectory(\"\${CMAKE_SOURCE_DIR}/deps/w32-pthreads\" \"\${CMAKE_BINARY_DIR}/deps/w32-pthreads\")\n endif()\n include(cmake/os-windows.cmake)"
)
string(FIND "${_contents}" "${_needle}" _pos)
if(_pos EQUAL -1)
message(
FATAL_ERROR
"Could not find the expected 'if(OS_WINDOWS) / include(cmake/os-windows.cmake)' block in "
"${_cmakelists} to apply the w32-pthreads workaround. obs-studio's libobs/CMakeLists.txt "
"layout may have changed since this was written against 30.0.2."
)
endif()
string(REPLACE "${_needle}" "${_replacement}" _patched "${_contents}")
file(WRITE "${_cmakelists}" "${_patched}")
message(
STATUS
"Patched ${_cmakelists}: added deps/w32-pthreads so OBS::w32-pthreads exists "
"(obs-studio's modern Windows CMake path never defines it with ENABLE_UI=OFF)."
)
endfunction()
# _setup_obs_studio: Create obs-studio build project, then build libobs and obs-frontend-api # _setup_obs_studio: Create obs-studio build project, then build libobs and obs-frontend-api
function(_setup_obs_studio) function(_setup_obs_studio)
if(NOT libobs_DIR) if(NOT libobs_DIR)
@@ -431,9 +366,5 @@ function(_check_dependencies)
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} CACHE PATH "CMake prefix search path" FORCE) set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} CACHE PATH "CMake prefix search path" FORCE)
if(OS_WINDOWS)
_patch_obs_studio_w32_pthreads()
endif()
_setup_obs_studio() _setup_obs_studio()
endfunction() endfunction()
-28
View File
@@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>@STPLUGIN_BUNDLE_EXECUTABLE@</string>
<key>CFBundleIdentifier</key>
<string>@STPLUGIN_BUNDLE_ID@</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>@STPLUGIN_BUNDLE_NAME@</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>@STPLUGIN_BUNDLE_VERSION@</string>
<key>CFBundleVersion</key>
<string>@STPLUGIN_BUNDLE_VERSION@</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>LSMinimumSystemVersion</key>
<string>@STPLUGIN_BUNDLE_MIN_OS@</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright (c) @STPLUGIN_BUNDLE_YEAR@ @STPLUGIN_BUNDLE_AUTHOR@</string>
</dict>
</plist>
-46
View File
@@ -1,46 +0,0 @@
#!/bin/sh
# cmake/macos/fixup-libobs-rpath.sh <plugin-binary>
#
# The from-source libobs build this project's macOS bootstrap runs
# (cmake/common/buildspec_common.cmake) records its own install name (its
# LC_ID_DYLIB) as a relative path -- "libobs/libobs.framework/Versions/A/libobs"
# -- rather than an @rpath reference. That is a property of that from-source
# OBS build itself, not something this project's own link step controls: the
# LC_LOAD_DYLIB entry our plugin binary gets for a dependency is copied
# straight from that dependency's own LC_ID_DYLIB by the linker. A relative
# path is not resolvable at runtime from inside an OBS.app plugin bundle --
# see the "macOS packaging gap" this script fixes, documented in README.md.
#
# Rewrite that one dependency entry to @rpath/libobs.framework/Versions/A/libobs.
# stplugin_macos_finalize_bundle() (cmake/macos/helpers.cmake) gives the
# plugin binary an LC_RPATH of @executable_path/../Frameworks, which resolves
# @rpath against the *host* OBS.app's own Contents/Frameworks/libobs.framework
# at runtime (@executable_path is always relative to the process's main
# executable -- OBS.app/Contents/MacOS/obs -- not to this dlopen'd bundle, no
# matter how deeply the .plugin is nested under
# ~/Library/Application Support/obs-studio/plugins/<name>/bin/).
#
# The LiveKit runtime dylibs this same helper copies into the bundle's own
# Contents/Frameworks are NOT touched here: client-sdk-cpp's own release
# build already records their install names as @rpath references (confirmed
# by otool -L on prior CI runs -- see README's "Where the macOS bootstrap
# actually got to"), so the @loader_path/../Frameworks half of the same
# LC_RPATH already resolves them with no rewrite needed.
set -eu
binary="$1"
if [ ! -f "$binary" ]; then
echo "fixup-libobs-rpath: no such file: $binary" >&2
exit 1
fi
old_ref=$(otool -L "$binary" \
| awk '/libobs\.framework\/Versions\/A\/libobs/ && $1 !~ /^@rpath/ {print $1; exit}')
if [ -n "${old_ref:-}" ]; then
echo "fixup-libobs-rpath: rewriting '$old_ref' -> '@rpath/libobs.framework/Versions/A/libobs' in $binary"
install_name_tool -change "$old_ref" "@rpath/libobs.framework/Versions/A/libobs" "$binary"
else
echo "fixup-libobs-rpath: libobs dependency in $binary is already @rpath-relative (or was not found via otool -L); nothing to rewrite"
fi
-181
View File
@@ -1,181 +0,0 @@
# cmake/macos/helpers.cmake
#
# macOS ".plugin" bundle packaging for the OBS adapter module -- closes the
# "macOS packaging gap" documented in README.md.
#
# Adapted from obsproject/obs-plugintemplate's cmake/macos/helpers.cmake
# (fetched 2026-09-07, master branch) -- deliberately NOT vendored as-is.
# Upstream's set_target_properties_plugin() builds the bundle almost
# entirely through XCODE_ATTRIBUTE_* target properties
# (XCODE_ATTRIBUTE_GENERATE_INFOPLIST_FILE for Info.plist, an Xcode "Embed
# Frameworks" build phase for bundling its own dependencies, Xcode-driven
# codesigning), and upstream's own CI drives that with `xcodebuild -project
# <name>.xcodeproj` (.github/scripts/build-macos). None of that is available
# here: XCODE_ATTRIBUTE_* properties are silent no-ops under any generator
# but Xcode, and this project cannot use the Xcode generator on the `home-mac`
# CI runner -- see cmake/common/buildspec_common.cmake's CI-iteration-1
# comment, which already established empirically that this runner has only
# the Command Line Tools installed, not Xcode.app, so there is no xcodebuild
# to drive an .xcodeproj with. This project builds macOS with Ninja
# end-to-end (both the from-source libobs bootstrap and this project's own
# configure -- see the CI workflow), so this reimplements the same
# *outcome* -- a real <name>.plugin bundle with Contents/MacOS,
# Contents/Resources and a working Info.plist -- using CMake's own
# generator-agnostic bundle support (the BUNDLE / BUNDLE_EXTENSION /
# MACOSX_BUNDLE_INFO_PLIST target properties, which the Makefile/Ninja
# generators implement natively, not just Xcode's), and does the two things
# upstream gets "for free" from Xcode's embed/codesign build phases by hand:
#
# 0. copies obs-adapter/data/** into Contents/Resources/**, since OBS's own
# macOS module search (UI/window-basic-main.cpp AddExtraModulePaths())
# passes "<plugin>.plugin/Contents/Resources" as a module's *data path*
# -- not a sibling "data/" directory next to "bin/", which is the
# Linux/Windows shape and does NOT apply on macOS. Concretely: this
# project's OBS_MODULE_USE_DEFAULT_LOCALE(PLUGIN_NAME, "en-US") loads
# "<data_path>/locale/en-US.ini", so on macOS that file must land at
# Contents/Resources/locale/en-US.ini, not a top-level data/locale/.
# Mirrors upstream's own target_install_resources() -- also not
# Xcode-specific, since MACOSX_PACKAGE_LOCATION is another generator-
# agnostic bundle-content source-file property.
# 1. copies the LiveKit runtime dylibs into Contents/Frameworks (the
# conventional location for a plugin bundle's own bundled dependencies)
# 2. rewrites the libobs dependency from the relative path the from-source
# libobs build records as its own install name
# (libobs/libobs.framework/Versions/A/libobs) to
# @rpath/libobs.framework/Versions/A/libobs -- see
# cmake/macos/fixup-libobs-rpath.sh for why that rewrite is needed at
# all and cannot be done by our own link step -- and gives the plugin
# binary the LC_RPATH entries that make @rpath resolve for both
# dependencies: @loader_path/../Frameworks (this bundle's own
# Contents/Frameworks, for LiveKit) and @executable_path/../Frameworks
# (OBS.app/Contents/Frameworks, for libobs.framework itself).
#
# Bundle metadata (name/version/bundle id/author) is sourced from
# buildspec.json, the same file the OBS-SDK bootstrap (buildspec_common.cmake)
# already reads -- see its "platformConfig.macos.bundleId" / "name" /
# "version" / "author" fields.
include_guard(GLOBAL)
# stplugin_macos_finalize_bundle: turn a MODULE library target into a real
# OBS.app-loadable <name>.plugin bundle. No-op on non-Apple hosts so callers
# do not need to guard every call site with if(APPLE).
function(stplugin_macos_finalize_bundle target)
if(NOT APPLE)
return()
endif()
if(NOT DEFINED LIVEKIT_SDK_RUNTIME_LIBS)
message(FATAL_ERROR
"stplugin_macos_finalize_bundle(${target}): LIVEKIT_SDK_RUNTIME_LIBS is "
"not set. include(LiveKitSDK) + livekit_sdk_setup() must run before "
"this is called (see top-level CMakeLists.txt).")
endif()
# --- bundle metadata, from buildspec.json ---------------------------------
file(READ "${CMAKE_SOURCE_DIR}/buildspec.json" _stplugin_buildspec)
string(JSON _stplugin_bundle_name GET "${_stplugin_buildspec}" name)
string(JSON _stplugin_bundle_version GET "${_stplugin_buildspec}" version)
string(JSON _stplugin_bundle_author GET "${_stplugin_buildspec}" author)
string(JSON _stplugin_bundle_id GET "${_stplugin_buildspec}" platformConfig macos bundleId)
string(TIMESTAMP STPLUGIN_BUNDLE_YEAR "%Y" UTC)
set(STPLUGIN_BUNDLE_EXECUTABLE "${target}")
set(STPLUGIN_BUNDLE_NAME "${_stplugin_bundle_name}")
set(STPLUGIN_BUNDLE_VERSION "${_stplugin_bundle_version}")
set(STPLUGIN_BUNDLE_AUTHOR "${_stplugin_bundle_author}")
set(STPLUGIN_BUNDLE_ID "${_stplugin_bundle_id}")
if(CMAKE_OSX_DEPLOYMENT_TARGET)
set(STPLUGIN_BUNDLE_MIN_OS "${CMAKE_OSX_DEPLOYMENT_TARGET}")
else()
set(STPLUGIN_BUNDLE_MIN_OS "13.0")
endif()
set(_stplugin_plist_out "${CMAKE_CURRENT_BINARY_DIR}/${target}-Info.plist")
configure_file(
"${CMAKE_SOURCE_DIR}/cmake/macos/Info.plist.in"
"${_stplugin_plist_out}"
@ONLY
)
# --- Contents/Resources: the module's data path on macOS ----------------
# See the "0." bullet in the file header. CMAKE_CURRENT_SOURCE_DIR here is
# obs-adapter (this function is called from obs-adapter/CMakeLists.txt, and
# include() does not change directory scope), so this globs
# obs-adapter/data/** the same way the flat-layout staging step elsewhere
# in that file does.
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/data")
file(GLOB_RECURSE _stplugin_data_files "${CMAKE_CURRENT_SOURCE_DIR}/data/*")
foreach(_stplugin_data_file IN LISTS _stplugin_data_files)
cmake_path(
RELATIVE_PATH _stplugin_data_file
BASE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/data"
OUTPUT_VARIABLE _stplugin_data_relpath
)
cmake_path(GET _stplugin_data_relpath PARENT_PATH _stplugin_data_reldir)
target_sources(${target} PRIVATE "${_stplugin_data_file}")
if(_stplugin_data_reldir)
set_property(SOURCE "${_stplugin_data_file}" PROPERTY
MACOSX_PACKAGE_LOCATION "Resources/${_stplugin_data_reldir}")
else()
set_property(SOURCE "${_stplugin_data_file}" PROPERTY
MACOSX_PACKAGE_LOCATION "Resources")
endif()
endforeach()
endif()
# --- bundle shape -----------------------------------------------------
# BUNDLE + BUNDLE_EXTENSION is CMake's own generator-agnostic mechanism
# (not Xcode-specific) for turning a MODULE library into a CFBundle;
# MACOSX_BUNDLE_INFO_PLIST tells the same mechanism which Info.plist to
# copy into Contents/. This is the traditional, non-Xcode-only path CMake
# has supported since long before XCODE_ATTRIBUTE_GENERATE_INFOPLIST_FILE
# existed, and is exactly what makes this work under Ninja.
set_target_properties(${target} PROPERTIES
BUNDLE TRUE
BUNDLE_EXTENSION "plugin"
MACOSX_BUNDLE_INFO_PLIST "${_stplugin_plist_out}"
)
# --- rpaths -------------------------------------------------------------
# BUILD_WITH_INSTALL_RPATH ON (matching the non-Apple UNIX branch in
# obs-adapter/CMakeLists.txt) means these two rpaths get embedded as
# LC_RPATH load commands by the linker itself at build time -- the
# artifact that ships is a straight copy of what gets built here, so the
# build-tree RPATH must never leak in.
# @loader_path/../Frameworks -> this bundle's own Contents/Frameworks
# (LiveKit dylibs, staged below)
# @executable_path/../Frameworks -> OBS.app/Contents/Frameworks
# (libobs.framework itself).
# @executable_path is always relative
# to the process's main executable
# (OBS.app/Contents/MacOS/obs), not to
# this dlopen'd bundle, regardless of
# how deeply the .plugin is nested
# under the user's plugin directory.
set_target_properties(${target} PROPERTIES
BUILD_WITH_INSTALL_RPATH ON
INSTALL_RPATH "@loader_path/../Frameworks;@executable_path/../Frameworks"
)
# --- bundled runtime deps + the libobs @rpath fixup --------------------
# $<TARGET_BUNDLE_DIR:target> is .../<target>.plugin for a BUNDLE target
# (available since CMake 3.0, unlike TARGET_BUNDLE_CONTENT_DIR which needs
# CMake >= 3.20 -- this project's cmake_minimum_required(VERSION 3.19)
# floor in the top-level CMakeLists.txt), so appending Contents/Frameworks
# avoids a ".." in the path TARGET_FILE_DIR would otherwise need.
set(_stplugin_frameworks_dir "$<TARGET_BUNDLE_DIR:${target}>/Contents/Frameworks")
add_custom_command(TARGET ${target} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E make_directory "${_stplugin_frameworks_dir}"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different ${LIVEKIT_SDK_RUNTIME_LIBS} "${_stplugin_frameworks_dir}/"
COMMENT "Copying LiveKit runtime dylibs into ${target}.plugin/Contents/Frameworks"
VERBATIM
)
add_custom_command(TARGET ${target} POST_BUILD
COMMAND sh "${CMAKE_SOURCE_DIR}/cmake/macos/fixup-libobs-rpath.sh" "$<TARGET_FILE:${target}>"
COMMENT "Rewriting the libobs dependency of ${target} to @rpath"
VERBATIM
)
endfunction()
@@ -1,118 +0,0 @@
# Findw32-pthreads.cmake -- last-resort fallback, Windows only.
#
# WHY THIS EXISTS
#
# obs-studio's libobs links `PUBLIC OBS::w32-pthreads` on Windows
# (libobs/cmake/os-windows.cmake), so the libobsConfig.cmake it installs
# carries an unconditional, REQUIRED dependency on a findable `w32-pthreads`
# CMake package:
#
# if(MSVC)
# find_dependency(w32-pthreads REQUIRED)
# endif()
#
# obs-studio *does* export that package -- deps/w32-pthreads/CMakeLists.txt
# ends in `target_export(w32-pthreads)` -- but it exports it to
# <prefix>/cmake/w32-pthreads/, the same OBS_CMAKE_DESTINATION shape that
# find_package's Config-mode search suffixes never look at. The top-level
# CMakeLists.txt therefore points `w32-pthreads_DIR` straight at it, exactly
# as it already does for `libobs_DIR`, and that is the path this build is
# expected to take.
#
# This module is only reached when that export is genuinely absent from
# .deps/ -- for instance if a future obs-studio changes where or whether
# deps/w32-pthreads installs its package, or if the tolerated
# UI/obs-frontend-api install error in
# cmake/common/buildspec_common.cmake::_setup_obs_studio ever starts aborting
# the install *before* libobs's own subtree instead of after it. In that case
# the alternative is a hard configure failure inside libobsConfig.cmake with
# no plugin module built at all, so reconstructing the imported target by
# hand from artifacts the bootstrap definitely produced is strictly better.
#
# It deliberately lives in cmake/windows/find-fallback/ and NOT in
# cmake/windows/, which cmake/common/osconfig.cmake puts on CMAKE_MODULE_PATH
# for every Windows configure. A Findw32-pthreads.cmake on the default module
# path would win over OBS's own exported package on every single build
# (find_package tries MODULE mode before CONFIG mode), permanently replacing
# upstream's real export metadata with this approximation. The top-level
# CMakeLists.txt appends this directory to CMAKE_MODULE_PATH only when it has
# already established that the real export is missing.
#
# Nothing outside Windows ever loads this: the find_dependency above is
# inside `if(MSVC)`, and the CMAKE_MODULE_PATH append that exposes this file
# is inside `if(OS_WINDOWS ...)`.
if(TARGET OBS::w32-pthreads)
set(w32-pthreads_FOUND TRUE)
return()
endif()
# Resolve paths from this file's own location rather than
# CMAKE_CURRENT_SOURCE_DIR: a find module runs in whatever scope called
# find_package, and here that call comes from inside libobsConfig.cmake.
# <repo>/cmake/windows/find-fallback/ -> <repo>
get_filename_component(_w32pt_repo_root "${CMAKE_CURRENT_LIST_DIR}/../../.." ABSOLUTE)
set(_w32pt_deps "${_w32pt_repo_root}/.deps")
# Search order, both from obs-studio's own Windows layout:
# 1. the bootstrap's install prefix -- obs-studio/cmake/windows/defaults.cmake
# sets OBS_LIBRARY_DESTINATION=lib (ARCHIVE, i.e. the import library),
# OBS_EXECUTABLE_DESTINATION=bin/64bit (RUNTIME, i.e. the DLL) and
# OBS_INCLUDE_DESTINATION=include (where target_export installs
# w32-pthreads' PUBLIC_HEADER pthread.h/sched.h);
# 2. the obs-studio build tree the bootstrap just built in, in case the
# install step is what failed rather than the export.
file(GLOB _w32pt_build_trees "${_w32pt_deps}/obs-studio-*/build_*/deps/w32-pthreads/Release")
file(GLOB _w32pt_source_trees "${_w32pt_deps}/obs-studio-*/deps/w32-pthreads")
find_library(
w32-pthreads_IMPLIB
NAMES w32-pthreads
PATHS "${_w32pt_deps}/lib" ${_w32pt_build_trees}
NO_DEFAULT_PATH
)
find_file(
w32-pthreads_RUNTIME_LIBRARY
NAMES w32-pthreads.dll
PATHS "${_w32pt_deps}/bin/64bit" ${_w32pt_build_trees}
NO_DEFAULT_PATH
)
find_path(
w32-pthreads_INCLUDE_DIR
NAMES pthread.h
PATHS "${_w32pt_deps}/include" ${_w32pt_source_trees}
NO_DEFAULT_PATH
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
w32-pthreads
REQUIRED_VARS w32-pthreads_IMPLIB w32-pthreads_INCLUDE_DIR
REASON_FAILURE_MESSAGE
"The OBS SDK bootstrap neither exported a w32-pthreads CMake package under ${_w32pt_deps}/cmake/ nor left a w32-pthreads import library anywhere under ${_w32pt_deps}."
)
if(w32-pthreads_FOUND)
# SHARED, matching deps/w32-pthreads/CMakeLists.txt's own
# `add_library(w32-pthreads SHARED ...)`. IMPORTED_LOCATION is the DLL and
# IMPORTED_IMPLIB the .lib, which is what an imported SHARED library means
# on Windows; if only the .lib was found, declare it UNKNOWN instead so
# CMake does not demand a DLL it will never be handed.
if(w32-pthreads_RUNTIME_LIBRARY)
add_library(OBS::w32-pthreads SHARED IMPORTED)
set_target_properties(
OBS::w32-pthreads
PROPERTIES IMPORTED_LOCATION "${w32-pthreads_RUNTIME_LIBRARY}" IMPORTED_IMPLIB "${w32-pthreads_IMPLIB}"
)
else()
add_library(OBS::w32-pthreads UNKNOWN IMPORTED)
set_target_properties(OBS::w32-pthreads PROPERTIES IMPORTED_LOCATION "${w32-pthreads_IMPLIB}")
endif()
set_target_properties(
OBS::w32-pthreads
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${w32-pthreads_INCLUDE_DIR}"
)
message(STATUS "Findw32-pthreads (fallback): OBS::w32-pthreads -> ${w32-pthreads_IMPLIB}")
endif()
mark_as_advanced(w32-pthreads_IMPLIB w32-pthreads_RUNTIME_LIBRARY w32-pthreads_INCLUDE_DIR)
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - streamer-tools API client streamer-tools OBS Camera Plugin - streamer-tools API client
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#pragma once #pragma once
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - core library streamer-tools OBS Camera Plugin - core library
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#pragma once #pragma once
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - core library streamer-tools OBS Camera Plugin - core library
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#pragma once #pragma once
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - HTTP client interface streamer-tools OBS Camera Plugin - HTTP client interface
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#pragma once #pragma once
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - minimal JSON reader streamer-tools OBS Camera Plugin - minimal JSON reader
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#pragma once #pragma once
+11 -11
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - LiveKit session wrapper streamer-tools OBS Camera Plugin - LiveKit session wrapper
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#pragma once #pragma once
@@ -43,13 +50,6 @@ struct SessionConfig {
bool subscribe_audio = true; bool subscribe_audio = true;
/// False for an audio-only source (the soundboard, say): the wanted
/// video track is never attached (no AttachVideo command posted), and
/// its publication is explicitly disabled server-side (RemoteTrack-
/// Publication::setEnabled(false)) so the SFU stops sending it at all --
/// not just "decoded and discarded here", genuinely not delivered.
bool subscribe_video = true;
/// How long connect() waits for the room to come up before giving up. /// How long connect() waits for the room to come up before giving up.
int connect_timeout_ms = 15000; int connect_timeout_ms = 15000;
}; };
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - session types and pure session logic streamer-tools OBS Camera Plugin - session types and pure session logic
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#pragma once #pragma once
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - streamer-tools API client streamer-tools OBS Camera Plugin - streamer-tools API client
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#include "stplugin/api_client.h" #include "stplugin/api_client.h"
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - core library streamer-tools OBS Camera Plugin - core library
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#include "stplugin/core.h" #include "stplugin/core.h"
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - HTTP helpers shared by all backends streamer-tools OBS Camera Plugin - HTTP helpers shared by all backends
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#include "stplugin/http.h" #include "stplugin/http.h"
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - libcurl HTTP backend (Linux/macOS) streamer-tools OBS Camera Plugin - libcurl HTTP backend (Linux/macOS)
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#include "stplugin/http.h" #include "stplugin/http.h"
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - WinHTTP backend (Windows) streamer-tools OBS Camera Plugin - WinHTTP backend (Windows)
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
// WinHTTP rather than libcurl on Windows: it ships with the OS, does TLS // WinHTTP rather than libcurl on Windows: it ships with the OS, does TLS
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - minimal JSON reader streamer-tools OBS Camera Plugin - minimal JSON reader
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#include "stplugin/json.h" #include "stplugin/json.h"
+13 -52
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - LiveKit session wrapper streamer-tools OBS Camera Plugin - LiveKit session wrapper
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#include "stplugin/session.h" #include "stplugin/session.h"
@@ -218,52 +225,6 @@ struct LiveKitSession::Impl : public livekit::RoomDelegate {
queue_cv.notify_one(); queue_cv.notify_one();
} }
// Handles the wanted video track once matched, shared by onTrackSubscribed
// (a fresh subscription) and attachExistingTracks (one already up when
// this session started watching). Two responsibilities that only make
// sense together, both keyed off the SAME publication:
//
// - subscribe_video: an audio-only source (the soundboard) never wants
// this video at all. Rather than attach it and let the OBS adapter
// discard every decoded frame, disable the publication itself
// (RemoteTrackPublication::setEnabled(false)) so the SFU stops
// sending it -- real bandwidth saved, not just wasted decode.
// - Fixed video quality: LiveKit's default subscriber behaviour lets
// the SFU switch simulcast layers per its own adaptive/bandwidth
// logic, which for a source with no rendered-size hint (this is a
// native C++ subscriber, not a sized <video> element) means the
// received resolution can hop between layers -- observed live as OBS
// source geometry visibly changing size mid-show. Pinning to HIGH
// asks the SFU to always send the top layer, which is what a fixed
// OBS source needs regardless of bandwidth (the plugin has no
// picture-in-picture tier to fall back to the way a browser grid
// view would).
void handleWantedVideoTrack(const std::shared_ptr<livekit::Track> &track,
const std::shared_ptr<livekit::RemoteTrackPublication> &publication)
{
if (!config.subscribe_video) {
if (publication) {
try {
publication->setEnabled(false);
} catch (const std::exception &) {
// Best-effort: worst case this track keeps being
// delivered and decoded, wasting bandwidth -- it is
// still never attached to OBS below.
}
}
return;
}
if (publication) {
try {
publication->setVideoQuality(livekit::VideoQuality::HIGH);
} catch (const std::exception &) {
// Best-effort: worst case this track keeps whatever quality
// it already had, which is the pre-existing behaviour.
}
}
post(CommandType::AttachVideo, track);
}
// --- RoomDelegate ------------------------------------------------------ // --- RoomDelegate ------------------------------------------------------
void onTrackSubscribed(livekit::Room &, const livekit::TrackSubscribedEvent &event) override void onTrackSubscribed(livekit::Room &, const livekit::TrackSubscribedEvent &event) override
@@ -276,7 +237,7 @@ struct LiveKitSession::Impl : public livekit::RoomDelegate {
event.publication ? toMediaSource(event.publication->source()) : MediaSource::Unknown; event.publication ? toMediaSource(event.publication->source()) : MediaSource::Unknown;
if (isWantedVideoTrack(config.participant_identity, identity, kind, source)) if (isWantedVideoTrack(config.participant_identity, identity, kind, source))
handleWantedVideoTrack(event.track, event.publication); post(CommandType::AttachVideo, event.track);
else if (config.subscribe_audio && isWantedAudioTrack(config.participant_identity, identity, kind, source)) else if (config.subscribe_audio && isWantedAudioTrack(config.participant_identity, identity, kind, source))
post(CommandType::AttachAudio, event.track); post(CommandType::AttachAudio, event.track);
} }
@@ -597,7 +558,7 @@ struct LiveKitSession::Impl : public livekit::RoomDelegate {
const MediaKind kind = toMediaKind(track->kind()); const MediaKind kind = toMediaKind(track->kind());
const MediaSource source = toMediaSource(publication->source()); const MediaSource source = toMediaSource(publication->source());
if (isWantedVideoTrack(config.participant_identity, identity, kind, source)) if (isWantedVideoTrack(config.participant_identity, identity, kind, source))
handleWantedVideoTrack(track, publication); post(CommandType::AttachVideo, track);
else if (config.subscribe_audio && isWantedAudioTrack(config.participant_identity, identity, kind, source)) else if (config.subscribe_audio && isWantedAudioTrack(config.participant_identity, identity, kind, source))
post(CommandType::AttachAudio, track); post(CommandType::AttachAudio, track);
} }
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - session types and pure session logic streamer-tools OBS Camera Plugin - session types and pure session logic
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#include "stplugin/session_types.h" #include "stplugin/session_types.h"
-22
View File
@@ -7,28 +7,6 @@ function(stplugin_add_test name)
if(WIN32) if(WIN32)
# loopback_server.h needs Winsock for the real-backend tests. # loopback_server.h needs Winsock for the real-backend tests.
target_link_libraries(${name} PRIVATE ws2_32) target_link_libraries(${name} PRIVATE ws2_32)
# stplugin_core links LiveKit::livekit PUBLICly (see
# ../CMakeLists.txt), so every test executable here is linked
# against livekit.dll / livekit_ffi.dll. Unlike the RPATH/$ORIGIN
# handling obs-adapter/CMakeLists.txt sets up for Linux/macOS,
# Windows has no way to find a DLL relative to the .exe -- it must
# physically sit next to it (or be on PATH) at process start, or
# the loader fails before main() with STATUS_DLL_NOT_FOUND
# (0xc0000135), which is exactly what CTest saw for test_session,
# test_integration_livekit and test_livekit_smoke. Copy the same
# LIVEKIT_SDK_RUNTIME_LIBS list (from cmake/LiveKitSDK.cmake) that
# obs-adapter stages next to the plugin module, next to each test
# binary instead. Applied to every test here, not just the three
# known to actually reference LiveKit symbols today -- harmless for
# the others and avoids re-diagnosing this if a future test starts
# touching stplugin_core's LiveKit-dependent code paths.
add_custom_command(TARGET ${name} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${LIVEKIT_SDK_RUNTIME_LIBS} "$<TARGET_FILE_DIR:${name}>"
COMMENT "Copying LiveKit runtime DLLs next to ${name}"
VERBATIM
)
endif() endif()
add_test(NAME ${name} COMMAND ${name}) add_test(NAME ${name} COMMAND ${name})
# Nothing here should ever take a minute; a hang is a failure, not a # Nothing here should ever take a minute; a hang is a failure, not a
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - minimal loopback HTTP server for tests streamer-tools OBS Camera Plugin - minimal loopback HTTP server for tests
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#pragma once #pragma once
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - API client tests streamer-tools OBS Camera Plugin - API client tests
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
// Two layers of coverage: // Two layers of coverage:
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - core library tests streamer-tools OBS Camera Plugin - core library tests
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
// NOTE on why this file uses ST_ASSERT and not assert(): CI builds Release, // NOTE on why this file uses ST_ASSERT and not assert(): CI builds Release,
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - LiveKit end-to-end integration test streamer-tools OBS Camera Plugin - LiveKit end-to-end integration test
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
// The one test that proves the session wrapper actually receives media. // The one test that proves the session wrapper actually receives media.
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - JSON reader tests streamer-tools OBS Camera Plugin - JSON reader tests
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#include <string> #include <string>
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - LiveKit SDK link smoke test streamer-tools OBS Camera Plugin - LiveKit SDK link smoke test
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
// Proves the pinned client-sdk-cpp release is genuinely linked and callable: // Proves the pinned client-sdk-cpp release is genuinely linked and callable:
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - session wrapper tests streamer-tools OBS Camera Plugin - session wrapper tests
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
// What is and is not covered here, stated plainly because it matters: // What is and is not covered here, stated plainly because it matters:
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin - minimal test harness streamer-tools OBS Camera Plugin - minimal test harness
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
#pragma once #pragma once
+22 -61
View File
@@ -42,32 +42,18 @@ set_target_properties(${STPLUGIN_PROJECT_NAME} PROPERTIES
# straight copy of the built module (see the staging step below), so the # straight copy of the built module (see the staging step below), so the
# build-tree RPATH must never be baked in -- it would work on the build # build-tree RPATH must never be baked in -- it would work on the build
# machine and nowhere else. # machine and nowhere else.
# if(APPLE)
# APPLE's rpath (and its whole bundle shape) is handled by set_target_properties(${STPLUGIN_PROJECT_NAME} PROPERTIES
# stplugin_macos_finalize_bundle() below instead -- a bundle needs two BUILD_WITH_INSTALL_RPATH ON
# rpaths (its own Contents/Frameworks *and* the host OBS.app's INSTALL_RPATH "@loader_path"
# Contents/Frameworks for libobs.framework), not the single flat )
# "@loader_path" this used to set back when macOS staged a bare .so. See elseif(UNIX)
# cmake/macos/helpers.cmake.
if(UNIX AND NOT APPLE)
set_target_properties(${STPLUGIN_PROJECT_NAME} PROPERTIES set_target_properties(${STPLUGIN_PROJECT_NAME} PROPERTIES
BUILD_WITH_INSTALL_RPATH ON BUILD_WITH_INSTALL_RPATH ON
INSTALL_RPATH "$ORIGIN" INSTALL_RPATH "$ORIGIN"
) )
endif() endif()
# --- macOS: turn the flat MODULE library into a real OBS.app-loadable
# <name>.plugin bundle (Contents/MacOS, Contents/Resources, Info.plist,
# Contents/Frameworks for the bundled LiveKit dylibs, and the libobs
# @rpath fixup). Closes the "macOS packaging gap" in README.md. Must run
# before the staging step below, which copies the finished bundle directory
# -- add_custom_command(POST_BUILD) commands attached to the same target run
# in the order they were registered.
if(APPLE)
include(helpers)
stplugin_macos_finalize_bundle(${STPLUGIN_PROJECT_NAME})
endif()
# --- staged, runnable layout ------------------------------------------------ # --- staged, runnable layout ------------------------------------------------
# Everything a human needs to copy into an OBS plugin directory ends up under # Everything a human needs to copy into an OBS plugin directory ends up under
# build/package/, with the LiveKit shared libraries and the licence files # build/package/, with the LiveKit shared libraries and the licence files
@@ -82,52 +68,27 @@ set(STPLUGIN_PACKAGE_DIR "${CMAKE_BINARY_DIR}/package")
# <config>/obs-studio/plugins/<name>/data/ # <config>/obs-studio/plugins/<name>/data/
# so staging into bin/64bit makes build/package/ a straight drop-in. # so staging into bin/64bit makes build/package/ a straight drop-in.
# #
# macOS is a COMPLETELY different shape, not just "bin without 64bit": the # macOS is NOT this shape -- there OBS looks for a
# same AddExtraModulePaths() passes GetConfigPath(..., # <name>.plugin/Contents/MacOS bundle -- and this build does not produce one.
# "obs-studio/plugins/%module%.plugin") as the base, then # See the macOS packaging gap in README.md; the flat bin/ here is honest
# obs_add_module_path(base + "/Contents/MacOS", base + "/Contents/Resources") # about being unfinished rather than pretending to be installable.
# -- i.e. OBS wants the ENTIRE <name>.plugin bundle dropped directly into
# .../obs-studio/plugins/, not nested under a bin/ subdirectory the way
# Linux/Windows are. So build/package/ on macOS holds the bundle itself at
# its top level (build/package/<name>.plugin), not build/package/bin/....
# stplugin_macos_finalize_bundle() (cmake/macos/helpers.cmake) makes
# ${STPLUGIN_PROJECT_NAME} an actual BUNDLE target for APPLE and also copies
# obs-adapter/data/** into Contents/Resources/** -- see that file for why
# Contents/Resources (not a sibling data/) is where OBS looks for this
# module's data on macOS.
if(APPLE) if(APPLE)
add_custom_command(TARGET ${STPLUGIN_PROJECT_NAME} POST_BUILD set(STPLUGIN_PACKAGE_BIN_DIR "${STPLUGIN_PACKAGE_DIR}/bin")
COMMAND ${CMAKE_COMMAND} -E make_directory "${STPLUGIN_PACKAGE_DIR}"
COMMAND ${CMAKE_COMMAND} -E rm -rf "${STPLUGIN_PACKAGE_DIR}/${STPLUGIN_PROJECT_NAME}.plugin"
COMMAND ${CMAKE_COMMAND} -E copy_directory
"$<TARGET_BUNDLE_DIR:${STPLUGIN_PROJECT_NAME}>"
"${STPLUGIN_PACKAGE_DIR}/${STPLUGIN_PROJECT_NAME}.plugin"
COMMENT "Staging the ${STPLUGIN_PROJECT_NAME}.plugin bundle into ${STPLUGIN_PACKAGE_DIR}"
VERBATIM
)
else() else()
set(STPLUGIN_PACKAGE_BIN_DIR "${STPLUGIN_PACKAGE_DIR}/bin/64bit") set(STPLUGIN_PACKAGE_BIN_DIR "${STPLUGIN_PACKAGE_DIR}/bin/64bit")
add_custom_command(TARGET ${STPLUGIN_PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory "${STPLUGIN_PACKAGE_BIN_DIR}"
COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE:${STPLUGIN_PROJECT_NAME}>" "${STPLUGIN_PACKAGE_BIN_DIR}/"
COMMAND ${CMAKE_COMMAND} -E copy ${LIVEKIT_SDK_RUNTIME_LIBS} "${STPLUGIN_PACKAGE_BIN_DIR}/"
COMMAND ${CMAKE_COMMAND} -E make_directory "${STPLUGIN_PACKAGE_DIR}/data/locale"
COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_CURRENT_SOURCE_DIR}/data/locale/en-US.ini"
"${STPLUGIN_PACKAGE_DIR}/data/locale/"
COMMENT "Staging plugin + LiveKit runtime libraries + locale data into ${STPLUGIN_PACKAGE_DIR}"
VERBATIM
)
endif() endif()
# Licence files: not something OBS's module loader looks for at all (unlike
# the locale data above), so these always land in the same top-level spot
# regardless of platform -- next to the bundle on macOS, next to bin/ on
# Linux/Windows. Redistributing LiveKit's prebuilt binaries means shipping
# their licence and notice with them; see third_party/livekit/README.md,
# including what upstream does NOT ship, which is an open question, not a
# solved one.
add_custom_command(TARGET ${STPLUGIN_PROJECT_NAME} POST_BUILD add_custom_command(TARGET ${STPLUGIN_PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory "${STPLUGIN_PACKAGE_BIN_DIR}"
COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE:${STPLUGIN_PROJECT_NAME}>" "${STPLUGIN_PACKAGE_BIN_DIR}/"
COMMAND ${CMAKE_COMMAND} -E copy ${LIVEKIT_SDK_RUNTIME_LIBS} "${STPLUGIN_PACKAGE_BIN_DIR}/"
COMMAND ${CMAKE_COMMAND} -E make_directory "${STPLUGIN_PACKAGE_DIR}/data/locale"
COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_CURRENT_SOURCE_DIR}/data/locale/en-US.ini"
"${STPLUGIN_PACKAGE_DIR}/data/locale/"
# Redistributing LiveKit's prebuilt binaries means shipping their licence
# and notice with them. See third_party/livekit/README.md -- including
# what upstream does NOT ship, which is an open question, not a solved one.
COMMAND ${CMAKE_COMMAND} -E make_directory "${STPLUGIN_PACKAGE_DIR}/licenses/livekit" COMMAND ${CMAKE_COMMAND} -E make_directory "${STPLUGIN_PACKAGE_DIR}/licenses/livekit"
COMMAND ${CMAKE_COMMAND} -E copy COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_SOURCE_DIR}/third_party/livekit/LICENSE" "${CMAKE_SOURCE_DIR}/third_party/livekit/LICENSE"
@@ -137,6 +98,6 @@ add_custom_command(TARGET ${STPLUGIN_PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy COMMAND ${CMAKE_COMMAND} -E copy
"${CMAKE_SOURCE_DIR}/LICENSE" "${CMAKE_SOURCE_DIR}/LICENSE"
"${STPLUGIN_PACKAGE_DIR}/licenses/" "${STPLUGIN_PACKAGE_DIR}/licenses/"
COMMENT "Staging licences into ${STPLUGIN_PACKAGE_DIR}" COMMENT "Staging plugin + LiveKit runtime libraries + licences into ${STPLUGIN_PACKAGE_DIR}"
VERBATIM VERBATIM
) )
-1
View File
@@ -4,7 +4,6 @@ RoomSlug="Room"
ReadKey="Read key" ReadKey="Read key"
Camera="Camera" Camera="Camera"
RefreshCameras="Refresh camera list" RefreshCameras="Refresh camera list"
AudioOnly="Audio only (no video)"
Status="Status" Status="Status"
NoCameraSelected="(no camera selected)" NoCameraSelected="(no camera selected)"
OfflineSuffix=" (offline)" OfflineSuffix=" (offline)"
+12 -26
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin streamer-tools OBS Camera Plugin
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
// The thin glue layer, per the design doc: source registration, the // The thin glue layer, per the design doc: source registration, the
@@ -57,7 +64,6 @@ constexpr const char *kSettingServerUrl = "server_url";
constexpr const char *kSettingRoomSlug = "room_slug"; constexpr const char *kSettingRoomSlug = "room_slug";
constexpr const char *kSettingReadKey = "read_key"; constexpr const char *kSettingReadKey = "read_key";
constexpr const char *kSettingCamera = "camera"; constexpr const char *kSettingCamera = "camera";
constexpr const char *kSettingAudioOnly = "audio_only";
constexpr const char *kSettingStatus = "status"; constexpr const char *kSettingStatus = "status";
constexpr const char *kPropRefresh = "refresh"; constexpr const char *kPropRefresh = "refresh";
@@ -97,10 +103,6 @@ struct CameraSource {
std::mutex mutex; std::mutex mutex;
ConnectionConfig config; ConnectionConfig config;
std::string camera_identity; std::string camera_identity;
/// True hides video entirely for this source (the soundboard, typically)
/// -- see SessionConfig::subscribe_video for what that actually does at
/// the LiveKit level.
bool audio_only = false;
/// Bumped every time settings change; the worker compares it to what it /// Bumped every time settings change; the worker compares it to what it
/// last connected with, so a stale in-flight connect is abandoned rather /// last connected with, so a stale in-flight connect is abandoned rather
/// than fought over. /// than fought over.
@@ -224,7 +226,6 @@ void workerLoop(CameraSource *self)
for (;;) { for (;;) {
ConnectionConfig config; ConnectionConfig config;
std::string camera; std::string camera;
bool audio_only = false;
std::uint64_t generation = 0; std::uint64_t generation = 0;
{ {
std::unique_lock<std::mutex> lock(self->mutex); std::unique_lock<std::mutex> lock(self->mutex);
@@ -232,7 +233,6 @@ void workerLoop(CameraSource *self)
break; break;
config = self->config; config = self->config;
camera = self->camera_identity; camera = self->camera_identity;
audio_only = self->audio_only;
generation = self->generation; generation = self->generation;
} }
@@ -289,7 +289,6 @@ void workerLoop(CameraSource *self)
session_config.ws_url = token.ws_url; session_config.ws_url = token.ws_url;
session_config.token = token.lk_token; session_config.token = token.lk_token;
session_config.participant_identity = camera; session_config.participant_identity = camera;
session_config.subscribe_video = !audio_only;
if (self->session->connect(session_config)) { if (self->session->connect(session_config)) {
connected = true; connected = true;
@@ -338,7 +337,6 @@ void sourceGetDefaults(obs_data_t *settings)
obs_data_set_default_string(settings, kSettingRoomSlug, ""); obs_data_set_default_string(settings, kSettingRoomSlug, "");
obs_data_set_default_string(settings, kSettingReadKey, ""); obs_data_set_default_string(settings, kSettingReadKey, "");
obs_data_set_default_string(settings, kSettingCamera, ""); obs_data_set_default_string(settings, kSettingCamera, "");
obs_data_set_default_bool(settings, kSettingAudioOnly, false);
} }
void applySettings(CameraSource *self, obs_data_t *settings) void applySettings(CameraSource *self, obs_data_t *settings)
@@ -348,19 +346,16 @@ void applySettings(CameraSource *self, obs_data_t *settings)
config.room_slug = settingString(settings, kSettingRoomSlug); config.room_slug = settingString(settings, kSettingRoomSlug);
config.read_key = settingString(settings, kSettingReadKey); config.read_key = settingString(settings, kSettingReadKey);
const std::string camera = settingString(settings, kSettingCamera); const std::string camera = settingString(settings, kSettingCamera);
const bool audio_only = obs_data_get_bool(settings, kSettingAudioOnly);
{ {
std::lock_guard<std::mutex> guard(self->mutex); std::lock_guard<std::mutex> guard(self->mutex);
const bool changed = config.server_url != self->config.server_url || const bool changed = config.server_url != self->config.server_url ||
config.room_slug != self->config.room_slug || config.room_slug != self->config.room_slug ||
config.read_key != self->config.read_key || camera != self->camera_identity || config.read_key != self->config.read_key || camera != self->camera_identity;
audio_only != self->audio_only;
if (!changed) if (!changed)
return; return;
self->config = config; self->config = config;
self->camera_identity = camera; self->camera_identity = camera;
self->audio_only = audio_only;
++self->generation; ++self->generation;
} }
self->wake.notify_all(); self->wake.notify_all();
@@ -397,7 +392,6 @@ void *sourceCreate(obs_data_t *settings, obs_source_t *source)
self->config.room_slug = settingString(settings, kSettingRoomSlug); self->config.room_slug = settingString(settings, kSettingRoomSlug);
self->config.read_key = settingString(settings, kSettingReadKey); self->config.read_key = settingString(settings, kSettingReadKey);
self->camera_identity = settingString(settings, kSettingCamera); self->camera_identity = settingString(settings, kSettingCamera);
self->audio_only = obs_data_get_bool(settings, kSettingAudioOnly);
self->generation = 1; self->generation = 1;
} }
@@ -540,14 +534,6 @@ obs_properties_t *sourceGetProperties(void *data)
obs_properties_add_button(props, kPropRefresh, obs_module_text("RefreshCameras"), refreshButtonClicked); obs_properties_add_button(props, kPropRefresh, obs_module_text("RefreshCameras"), refreshButtonClicked);
// For a picked slot with no visual content worth showing (the
// soundboard, which publishes a throwaway black keep-alive frame purely
// because RTMP egress needs a video track -- see Soundboard.tsx in the
// streamer-tools repo). Disables the video track at the LiveKit level
// (RemoteTrackPublication::setEnabled(false), see session.cpp), not just
// locally: the SFU stops sending it.
obs_properties_add_bool(props, kSettingAudioOnly, obs_module_text("AudioOnly"));
// An OBS_TEXT_INFO property renders its *description* as the visible // An OBS_TEXT_INFO property renders its *description* as the visible
// label, so the status line goes there rather than into a tooltip an // label, so the status line goes there rather than into a tooltip an
// operator would never hover over mid-show. // operator would never hover over mid-show.
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin streamer-tools OBS Camera Plugin
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
/* Adapted from obsproject/obs-plugintemplate (commit 3e7d7ac, /* Adapted from obsproject/obs-plugintemplate (commit 3e7d7ac,
+11 -4
View File
@@ -2,11 +2,18 @@
streamer-tools OBS Camera Plugin streamer-tools OBS Camera Plugin
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com> Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); This program is free software; you can redistribute it and/or modify
you may not use this file except in compliance with the License. it under the terms of the GNU General Public License as published by
You may obtain a copy of the License at the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
http://www.apache.org/licenses/LICENSE-2.0 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/ */
/* Adapted from obsproject/obs-plugintemplate (commit 3e7d7ac, /* Adapted from obsproject/obs-plugintemplate (commit 3e7d7ac,
+26 -2
View File
@@ -8,5 +8,29 @@ module — so the SDK's licence and notice files ship with it.
`LICENSE` and `NOTICE` here are copied verbatim from the pinned release tag `LICENSE` and `NOTICE` here are copied verbatim from the pinned release tag
`v1.10.1` (Apache License 2.0). They are staged into `build/package/licenses/` `v1.10.1` (Apache License 2.0). They are staged into `build/package/licenses/`
by `obs-adapter/CMakeLists.txt` on every build, alongside this plugin's own by `obs-adapter/CMakeLists.txt` on every build, alongside this plugin's own
Apache-2.0 `LICENSE` (this project's own first-party code was relicensed from GPL-2.0 `LICENSE`.
GPL-2.0 to Apache-2.0 to match).
## A correction to the design doc
The design doc's open questions say:
> `client-sdk-cpp`'s bundled `LICENSE.md` (~28 distinct third-party license
> blocks — Google WebRTC, OpenH264, etc.) must ship inside the plugin package
**No such file exists at `v1.10.1`.** Checked, on 2026-09-06:
- The five release archives for this tag (`livekit-sdk-<triple>-1.10.1.tar.gz`
/ `.zip`) contain only `include/`, `lib/`, `bin/` and
`share/livekit/build-info.json`. No licence file of any kind.
- The repository at tag `v1.10.1` has `LICENSE` (Apache-2.0, 10142 bytes) and
`NOTICE` (553 bytes) at its root. There is no `LICENSE.md`, no `NOTICE.md`,
and no `THIRD_PARTY_LICENSES` file.
So what ships here is the Apache-2.0 licence and notice, which is what
actually exists upstream. **The aggregated third-party notice the design doc
expected — covering the WebRTC/OpenH264/etc. code statically linked inside
`liblivekit_ffi.so` — has not been located and is not being shipped.** That
is a real, open licensing question for whoever signs off on distributing
release binaries, not something this packaging step has resolved. Worth
raising upstream, or asking counsel whether the Apache-2.0 NOTICE alone
suffices for a binary redistribution of that library.