# LiveKitSDK.cmake # # Downloads the prebuilt LiveKit C++ SDK (livekit/client-sdk-cpp) release # asset for the host OS/arch, extracts it, and points # `find_package(LiveKit CONFIG REQUIRED)` at it. # # Adapted from livekit-examples/cpp-example-collection's cmake/LiveKitSDK.cmake # (fetched 2026-09-06). Deliberate changes from the upstream reference: # # 1. VERSION must be an exact release number. The upstream helper accepted # VERSION "latest" and resolved it through the GitHub releases API at # configure time. That is exactly what this project must not do: the # design doc calls for a pinned release tag, treating version bumps as # deliberate work (the SDK is young and ships roughly weekly). Dropping # the "latest" path also removes a GitHub-API call -- and its rate # limiting / GITHUB_TOKEN plumbing -- from every CI configure. # 2. Exports LIVEKIT_SDK_RUNTIME_LIBS: the shared libraries that must be # staged next to the built OBS plugin module for it to load at runtime # (liblivekit + liblivekit_ffi). Upstream examples run out of the build # tree and never needed this; a redistributable OBS plugin does. # 3. Exports LIVEKIT_SDK_INCLUDE_DIR / _LIB_DIR / _BIN_DIR for packaging. # # Usage: # list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") # include(LiveKitSDK) # livekit_sdk_setup(VERSION "1.10.1" SDK_DIR "${CMAKE_BINARY_DIR}/_deps/livekit-sdk") # find_package(LiveKit CONFIG REQUIRED) include_guard(GLOBAL) # -------------------- Host detection -------------------- function(_lk_detect_host out_os out_arch) if(WIN32) set(_os "windows") elseif(APPLE) set(_os "macos") elseif(UNIX) set(_os "linux") else() message(FATAL_ERROR "LiveKitSDK: unsupported host OS") endif() # Prefer the *target* processor when cross-compiling is expressed through # CMAKE_OSX_ARCHITECTURES (macOS CI runners are arm64 but may target x64). set(_proc "${CMAKE_HOST_SYSTEM_PROCESSOR}") if(APPLE AND CMAKE_OSX_ARCHITECTURES) list(LENGTH CMAKE_OSX_ARCHITECTURES _n_arch) if(_n_arch GREATER 1) message(FATAL_ERROR "LiveKitSDK: CMAKE_OSX_ARCHITECTURES lists ${_n_arch} architectures " "(${CMAKE_OSX_ARCHITECTURES}). client-sdk-cpp ships single-arch " "dylibs only, so universal binaries are not supported. Build one " "architecture at a time.") endif() list(GET CMAKE_OSX_ARCHITECTURES 0 _proc) endif() string(TOLOWER "${_proc}" _proc_l) if(_proc_l MATCHES "^(x86_64|amd64)$") set(_arch "x64") elseif(_proc_l MATCHES "^(arm64|aarch64)$") set(_arch "arm64") else() message(FATAL_ERROR "LiveKitSDK: unsupported host arch: ${_proc}") endif() set(${out_os} "${_os}" PARENT_SCOPE) set(${out_arch} "${_arch}" PARENT_SCOPE) endfunction() function(_lk_default_triple out_triple) _lk_detect_host(_os _arch) if(_os STREQUAL "linux") # NOT the generic "linux-" asset, despite the name. That one is # built on Ubuntu 24.04 and needs GLIBC_2.38 and GLIBCXX_3.4.32: linking # it on Ubuntu 22.04 fails outright ("undefined reference to # std::ios_base_library_init()@GLIBCXX_3.4.32", "__isoc23_strtol@GLIBC_2.38"), # which is exactly what happened when CI landed on a 22.04 runner. # The ubuntu-22.04 asset needs at most GLIBC_2.35 / GLIBCXX_3.4.30, so it # links and runs on 22.04 AND on everything newer -- the right floor for a # plugin that gets handed to directors as a binary. set(${out_triple} "ubuntu-22.04-${_arch}" PARENT_SCOPE) else() set(${out_triple} "${_os}-${_arch}" PARENT_SCOPE) endif() endfunction() function(_lk_archive_ext out_ext) if(WIN32) set(${out_ext} "zip" PARENT_SCOPE) else() set(${out_ext} "tar.gz" PARENT_SCOPE) endif() endfunction() # -------------------- Public entrypoint -------------------- # livekit_sdk_setup( # VERSION REQUIRED, exact -- "latest" is rejected # SDK_DIR REQUIRED, where the archive is extracted # [REPO ] default: livekit/client-sdk-cpp # [SHA256 ] optional: verify the downloaded archive # [TRIPLE ] optional override (e.g. ubuntu-24.04-x64) # [DOWNLOAD_DIR ] default: /_downloads # [NO_DOWNLOAD] fail instead of downloading if absent # ) function(livekit_sdk_setup) set(options NO_DOWNLOAD) set(oneValueArgs VERSION SDK_DIR REPO SHA256 TRIPLE DOWNLOAD_DIR) cmake_parse_arguments(LK "${options}" "${oneValueArgs}" "" ${ARGN}) if(NOT LK_VERSION) message(FATAL_ERROR "livekit_sdk_setup: VERSION is required") endif() if(LK_VERSION STREQUAL "latest") message(FATAL_ERROR "livekit_sdk_setup: VERSION=\"latest\" is deliberately not supported. " "This project pins an exact client-sdk-cpp release; see the comment at " "the top of cmake/LiveKitSDK.cmake.") endif() if(NOT LK_VERSION MATCHES "^[0-9]+\\.[0-9]+\\.[0-9]+$") message(FATAL_ERROR "livekit_sdk_setup: VERSION must be x.y.z, got '${LK_VERSION}'") endif() if(NOT LK_SDK_DIR) message(FATAL_ERROR "livekit_sdk_setup: SDK_DIR is required") endif() if(NOT LK_REPO) set(LK_REPO "livekit/client-sdk-cpp") endif() if(NOT LK_DOWNLOAD_DIR) set(LK_DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/_downloads") endif() if(NOT LK_TRIPLE) _lk_default_triple(LK_TRIPLE) endif() _lk_archive_ext(_ext) set(_archive "livekit-sdk-${LK_TRIPLE}-${LK_VERSION}.${_ext}") set(_url "https://github.com/${LK_REPO}/releases/download/v${LK_VERSION}/${_archive}") set(_archive_path "${LK_DOWNLOAD_DIR}/${_archive}") # The archive contains a single top-level folder named after the asset. set(_extracted_root "${LK_SDK_DIR}/livekit-sdk-${LK_TRIPLE}-${LK_VERSION}") file(MAKE_DIRECTORY "${LK_DOWNLOAD_DIR}") file(MAKE_DIRECTORY "${LK_SDK_DIR}") if(NOT EXISTS "${_extracted_root}/lib/cmake") if(LK_NO_DOWNLOAD) message(FATAL_ERROR "LiveKitSDK: SDK not found at:\n ${_extracted_root}\nand NO_DOWNLOAD was set.") endif() message(STATUS "LiveKitSDK: downloading ${_url}") if(LK_SHA256) file(DOWNLOAD "${_url}" "${_archive_path}" SHOW_PROGRESS TLS_VERIFY ON EXPECTED_HASH "SHA256=${LK_SHA256}" STATUS _st LOG _log) else() file(DOWNLOAD "${_url}" "${_archive_path}" SHOW_PROGRESS TLS_VERIFY ON STATUS _st LOG _log) endif() list(GET _st 0 _code) list(GET _st 1 _msg) if(NOT _code EQUAL 0) file(REMOVE "${_archive_path}") message(STATUS "LiveKitSDK: download log:\n${_log}") message(FATAL_ERROR "LiveKitSDK: download failed\nURL: ${_url}\nStatus: ${_code}\nMessage: ${_msg}\n" "If this triple has no release asset, pass TRIPLE explicitly.") endif() # Remove any previous partial extraction. file(REMOVE_RECURSE "${_extracted_root}") message(STATUS "LiveKitSDK: extracting ${_archive_path}") file(ARCHIVE_EXTRACT INPUT "${_archive_path}" DESTINATION "${LK_SDK_DIR}") endif() if(NOT EXISTS "${_extracted_root}/lib/cmake/LiveKit/LiveKitConfig.cmake") message(FATAL_ERROR "LiveKitSDK: extracted SDK does not look valid (missing " "lib/cmake/LiveKit/LiveKitConfig.cmake)\nExpected under: ${_extracted_root}") endif() # Make find_package(LiveKit CONFIG REQUIRED) work in the caller's scope. list(PREPEND CMAKE_PREFIX_PATH "${_extracted_root}") set(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH}" PARENT_SCOPE) set(LiveKit_DIR "${_extracted_root}/lib/cmake/LiveKit" PARENT_SCOPE) # --- Runtime libraries, for staging next to the plugin module ------------ # Windows keeps the DLLs in bin/ and the import libs in lib/; the Unix # platforms put the shared objects directly in lib/. if(WIN32) file(GLOB _runtime_libs "${_extracted_root}/bin/*.dll") elseif(APPLE) file(GLOB _runtime_libs "${_extracted_root}/lib/*.dylib") else() file(GLOB _runtime_libs "${_extracted_root}/lib/*.so" "${_extracted_root}/lib/*.so.*") endif() if(NOT _runtime_libs) message(FATAL_ERROR "LiveKitSDK: found no runtime shared libraries under ${_extracted_root}. " "The release layout may have changed for version ${LK_VERSION}.") endif() set(LIVEKIT_SDK_EXTRACTED_ROOT "${_extracted_root}" CACHE PATH "LiveKit SDK extracted root" FORCE) set(LIVEKIT_SDK_INCLUDE_DIR "${_extracted_root}/include" CACHE PATH "LiveKit SDK include dir" FORCE) set(LIVEKIT_SDK_LIB_DIR "${_extracted_root}/lib" CACHE PATH "LiveKit SDK lib dir" FORCE) set(LIVEKIT_SDK_BIN_DIR "${_extracted_root}/bin" CACHE PATH "LiveKit SDK bin dir" FORCE) set(LIVEKIT_SDK_RUNTIME_LIBS "${_runtime_libs}" CACHE STRING "LiveKit SDK runtime shared libraries" FORCE) set(LIVEKIT_SDK_URL_USED "${_url}" CACHE STRING "LiveKit SDK URL used" FORCE) set(LIVEKIT_SDK_VERSION_RESOLVED "${LK_VERSION}" CACHE STRING "LiveKit SDK version" FORCE) set(LIVEKIT_SDK_TRIPLE_USED "${LK_TRIPLE}" CACHE STRING "LiveKit SDK triple" FORCE) message(STATUS "LiveKitSDK: using SDK ${LK_VERSION} (${LK_TRIPLE}) at ${_extracted_root}") endfunction()