cmake_minimum_required(VERSION 3.19)

project(obs-streamer-tools-plugin
    VERSION 0.1.0
    DESCRIPTION "OBS Studio source plugin for streamer-tools camera feeds"
    LANGUAGES C CXX
)

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
    set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()

enable_testing()

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/common")

# --- OBS SDK ---------------------------------------------------------------
# Linux gets libobs from the distribution (Ubuntu's libobs-dev ships real
# libobsConfig.cmake), and that path is left exactly as it was.
#
# macOS and Windows have no such package, so they use obs-plugintemplate's
# buildspec bootstrap, trimmed: it downloads the pinned obs-deps bundle and
# the pinned obs-studio source, then builds and installs just `libobs`. See
# buildspec.json for why the OBS pin is deliberately low, and
# cmake/common/buildspec_common.cmake for every change from upstream.
#
# STPLUGIN_BOOTSTRAP_OBS=OFF falls back to plain find_package(libobs), for a
# developer who already has an OBS SDK on their prefix path and does not want
# a from-source libobs build.
option(STPLUGIN_BOOTSTRAP_OBS "Download and build libobs from source (macOS/Windows)" ON)

# Fallbacks for imported targets that were exported under a different
# configuration name than the one being built, lifted from
# obs-plugintemplate's cmake/common/bootstrap.cmake. Without these, an
# imported libobs exported as (say) RelWithDebInfo fails a Release build with
# "IMPORTED_LOCATION or IMPORTED_IMPLIB not set for imported target
# OBS::libobs configuration Release".
set(CMAKE_MAP_IMPORTED_CONFIG_RELEASE Release RelWithDebInfo MinSizeRel None "")
set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO RelWithDebInfo Release MinSizeRel None "")
set(CMAKE_MAP_IMPORTED_CONFIG_MINSIZEREL MinSizeRel Release RelWithDebInfo None "")
set(CMAKE_MAP_IMPORTED_CONFIG_DEBUG Debug RelWithDebInfo Release MinSizeRel None "")

include(osconfig)
if(STPLUGIN_BOOTSTRAP_OBS AND (OS_MACOS OR OS_WINDOWS))
    if(OS_MACOS)
        # client-sdk-cpp ships single-arch dylibs, so this plugin is built for
        # one architecture even though the libobs it links is universal.
        if(NOT CMAKE_OSX_ARCHITECTURES)
            set(CMAKE_OSX_ARCHITECTURES "${CMAKE_HOST_SYSTEM_PROCESSOR}" CACHE STRING "" FORCE)
        endif()
        if(NOT CMAKE_OSX_DEPLOYMENT_TARGET)
            set(CMAKE_OSX_DEPLOYMENT_TARGET "13.0" CACHE STRING "" FORCE)
        endif()
    endif()
    include(buildspec)
endif()

# --- LiveKit C++ client SDK -------------------------------------------------
# Pinned, prebuilt release of livekit/client-sdk-cpp, downloaded and unpacked
# by cmake/LiveKitSDK.cmake, then consumed through its own CMake package
# config as the LiveKit::livekit imported target. See the design doc's
# "Resolved (2026-09-07)" section: an exact pin, never "latest".
set(STPLUGIN_LIVEKIT_SDK_VERSION "1.10.1" CACHE STRING
    "Pinned livekit/client-sdk-cpp release version")
set(STPLUGIN_LIVEKIT_SDK_TRIPLE "" CACHE STRING
    "Override the client-sdk-cpp release triple (e.g. ubuntu-24.04-x64); empty = autodetect")
set(STPLUGIN_LIVEKIT_SDK_DIR "${CMAKE_BINARY_DIR}/_deps/livekit-sdk" CACHE PATH
    "Directory the client-sdk-cpp release archive is extracted into (point at a persistent path to cache it across CI builds)")

# Pinned SHA256 checksums for the client-sdk-cpp v1.10.1 release archives,
# so the download in cmake/LiveKitSDK.cmake is verified the same way the
# obs-deps bootstrap next to it already is (see
# cmake/common/buildspec_common.cmake ~line 324). Each hash below was
# computed by downloading the real GitHub release asset and running
# `sha256sum` on it (2026-09-06/07) -- none of these were guessed or copied
# from an unverified source. To add a hash for a new version or triple:
#   curl -LO https://github.com/livekit/client-sdk-cpp/releases/download/v<VERSION>/livekit-sdk-<TRIPLE>-<VERSION>.<tar.gz|zip>
#   sha256sum livekit-sdk-<TRIPLE>-<VERSION>.*
# Covers every triple _lk_default_triple() can resolve to for this pinned
# version: Linux (ubuntu-22.04-x64/arm64), macOS (macos-x64/arm64) and
# Windows (windows-x64). Verified by extracting each archive
# (tar tzf / unzip -l) and confirming a real LiveKitConfig.cmake inside --
# only Linux was also verified by an actual local CMake configure+build in
# this environment; macOS and Windows were downloaded and hashed but not
# build-tested here.
set(_stplugin_livekit_sha256_1.10.1_ubuntu-22.04-x64   "6f4fc8143f36952d42bfd5ff8d1782cf6211ba8fd6b055877e9ef85441d66324")
set(_stplugin_livekit_sha256_1.10.1_ubuntu-22.04-arm64 "399677167b474b7f107c6937904ea01898c9ec8da648cbed669387e599c6ea45")
set(_stplugin_livekit_sha256_1.10.1_macos-x64          "7102655c1f2947be4b06a95f9fafa1a11379219328e82ad875e5ebccfc9ac7e3")
set(_stplugin_livekit_sha256_1.10.1_macos-arm64        "0822af7014519a473c5b5cd019bde58c26cc2bfe5b78e4a790395ead232dc55b")
set(_stplugin_livekit_sha256_1.10.1_windows-x64        "b9fc6b2865298d7e3d032205d7e74fb9628cfe55a2ed28cb657db0a481cd518c")

include(LiveKitSDK)
if(STPLUGIN_LIVEKIT_SDK_TRIPLE)
    set(_stplugin_livekit_triple "${STPLUGIN_LIVEKIT_SDK_TRIPLE}")
else()
    # Mirrors LiveKitSDK.cmake's own autodetection so the checksum lookup
    # below matches whatever triple livekit_sdk_setup() will actually
    # resolve to and download.
    _lk_default_triple(_stplugin_livekit_triple)
endif()

set(_stplugin_livekit_sha256_var
    "_stplugin_livekit_sha256_${STPLUGIN_LIVEKIT_SDK_VERSION}_${_stplugin_livekit_triple}")
if(DEFINED ${_stplugin_livekit_sha256_var})
    set(_stplugin_livekit_sha256 "${${_stplugin_livekit_sha256_var}}")
else()
    set(_stplugin_livekit_sha256 "")
    message(WARNING
        "LiveKitSDK: no pinned SHA256 for triple '${_stplugin_livekit_triple}' "
        "at version ${STPLUGIN_LIVEKIT_SDK_VERSION} -- the downloaded archive "
        "will NOT be integrity-checked. Compute one (see the comment above "
        "this block) and add it to CMakeLists.txt.")
endif()

if(STPLUGIN_LIVEKIT_SDK_TRIPLE)
    livekit_sdk_setup(
        VERSION "${STPLUGIN_LIVEKIT_SDK_VERSION}"
        SDK_DIR "${STPLUGIN_LIVEKIT_SDK_DIR}"
        TRIPLE "${STPLUGIN_LIVEKIT_SDK_TRIPLE}"
        SHA256 "${_stplugin_livekit_sha256}"
    )
else()
    livekit_sdk_setup(
        VERSION "${STPLUGIN_LIVEKIT_SDK_VERSION}"
        SDK_DIR "${STPLUGIN_LIVEKIT_SDK_DIR}"
        SHA256 "${_stplugin_livekit_sha256}"
    )
endif()
find_package(LiveKit CONFIG REQUIRED)

add_subdirectory(core)

find_package(libobs QUIET)

# The imported OBS::libobs target can come back without a location. OBS 30.0.2
# installs libobsTargets.cmake but not the per-configuration
# libobsTargets-<config>.cmake alongside it when libobs is built on its own,
# and CMake then fails at generate time with:
#
#   IMPORTED_LOCATION or IMPORTED_IMPLIB not set for imported target
#   "OBS::libobs" configuration "Release".
#
# Repair it here rather than fighting OBS's export machinery: the library the
# bootstrap just built is in a known place, and pointing the imported target
# at it is exactly what the missing file would have done. Distribution
# packages (Ubuntu's libobs-dev) export a complete target and never take this
# path.
if(libobs_FOUND AND TARGET OBS::libobs)
    get_target_property(_stplugin_obs_location OBS::libobs IMPORTED_LOCATION)
    get_target_property(_stplugin_obs_location_release OBS::libobs IMPORTED_LOCATION_RELEASE)
    get_target_property(_stplugin_obs_implib OBS::libobs IMPORTED_IMPLIB)
    get_target_property(_stplugin_obs_implib_release OBS::libobs IMPORTED_IMPLIB_RELEASE)
    if(NOT _stplugin_obs_location
       AND NOT _stplugin_obs_location_release
       AND NOT _stplugin_obs_implib
       AND NOT _stplugin_obs_implib_release)
        set(_stplugin_deps "${CMAKE_CURRENT_SOURCE_DIR}/.deps")
        if(APPLE)
            set(_stplugin_obs_binary "${_stplugin_deps}/Frameworks/libobs.framework/Versions/A/libobs")
            if(NOT EXISTS "${_stplugin_obs_binary}")
                set(_stplugin_obs_binary "${_stplugin_deps}/Frameworks/libobs.framework/libobs")
            endif()
            if(EXISTS "${_stplugin_obs_binary}")
                set_target_properties(
                    OBS::libobs
                    PROPERTIES
                        IMPORTED_LOCATION "${_stplugin_obs_binary}"
                        INTERFACE_INCLUDE_DIRECTORIES "${_stplugin_deps}/Frameworks/libobs.framework/Headers"
                )
                message(STATUS "OBS::libobs had no imported location; pointed it at ${_stplugin_obs_binary}")
            endif()
        elseif(WIN32)
            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" NO_DEFAULT_PATH)
            if(_stplugin_obs_implib_found)
                set_target_properties(OBS::libobs PROPERTIES IMPORTED_IMPLIB "${_stplugin_obs_implib_found}")
                if(_stplugin_obs_dll_found)
                    set_target_properties(OBS::libobs PROPERTIES IMPORTED_LOCATION "${_stplugin_obs_dll_found}")
                endif()
                message(STATUS "OBS::libobs had no imported location; pointed it at ${_stplugin_obs_implib_found}")
            endif()
        endif()
    endif()
endif()

if(libobs_FOUND)
    message(STATUS "libobs found (${libobs_DIR}) -- building OBS adapter module")
    add_subdirectory(obs-adapter)
else()
    message(WARNING "libobs NOT found -- skipping OBS adapter module; core library still builds/tests")
endif()
