diff --git a/cmake/common/buildspec_common.cmake b/cmake/common/buildspec_common.cmake index cea80de..7110635 100644 --- a/cmake/common/buildspec_common.cmake +++ b/cmake/common/buildspec_common.cmake @@ -68,6 +68,77 @@ function(_check_deps_version version) return(PROPAGATE found CMAKE_PREFIX_PATH) endfunction() +# _resolve_versioned_macos_sdk: return an SDK path whose *filename* carries the +# version number, e.g. .../MacOSX15.5.sdk. +# +# Not upstream. OBS's own cmake/macos/compilerconfig.cmake reads the SDK +# version by regex-matching "MacOSX..sdk" out of +# CMAKE_OSX_SYSROOT, and hard-fails if that does not match: +# +# string sub-command REGEX, mode MATCH needs at least 5 arguments +# Your macOS SDK version () is too low. +# +# With upstream's Xcode generator CMAKE_OSX_SYSROOT stays the literal string +# "macosx" and Xcode resolves it late, so the regex never runs against a real +# path. With Ninja -- which this project uses because CI has no Xcode -- CMake +# resolves it eagerly to whatever `xcrun --show-sdk-path` returns, and on a +# Command-Line-Tools-only install that is the UNVERSIONED symlink +# /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk. Hence this: prefer a +# versioned sibling if the toolchain ships one, and otherwise synthesise a +# correctly-named symlink to the same SDK. +function(_resolve_versioned_macos_sdk out_path) + set(${out_path} "" PARENT_SCOPE) + + execute_process( + COMMAND xcrun --show-sdk-path + OUTPUT_VARIABLE _sdk + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE _rc + ERROR_QUIET + ) + if(NOT _rc EQUAL 0 OR NOT _sdk) + return() + endif() + + # Already versioned: nothing to do. + get_filename_component(_sdk_name "${_sdk}" NAME) + if(_sdk_name MATCHES "^MacOSX[0-9]+\\.[0-9]+\\.sdk$") + set(${out_path} "${_sdk}" PARENT_SCOPE) + return() + endif() + + execute_process( + COMMAND xcrun --show-sdk-version + OUTPUT_VARIABLE _sdk_version + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE _rc + ERROR_QUIET + ) + if(NOT _rc EQUAL 0 OR NOT _sdk_version MATCHES "^([0-9]+)\\.([0-9]+)") + return() + endif() + set(_short "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}") + + # A versioned sibling next to the symlink is the common layout. + get_filename_component(_sdk_dir "${_sdk}" DIRECTORY) + if(EXISTS "${_sdk_dir}/MacOSX${_short}.sdk") + set(${out_path} "${_sdk_dir}/MacOSX${_short}.sdk" PARENT_SCOPE) + return() + endif() + + # Otherwise make one, inside our own dependency directory. + set(_link_dir "${dependencies_dir}/sdk") + file(MAKE_DIRECTORY "${_link_dir}") + set(_link "${_link_dir}/MacOSX${_short}.sdk") + if(NOT EXISTS "${_link}") + file(CREATE_LINK "${_sdk}" "${_link}" SYMBOLIC) + endif() + if(EXISTS "${_link}") + message(STATUS "Using synthesised versioned macOS SDK path: ${_link}") + set(${out_path} "${_link}" PARENT_SCOPE) + endif() +endfunction() + # _setup_obs_studio: Create obs-studio build project, then build libobs and obs-frontend-api function(_setup_obs_studio) if(NOT libobs_DIR) @@ -108,6 +179,10 @@ function(_setup_obs_studio) if(CMAKE_OSX_DEPLOYMENT_TARGET) list(APPEND _cmake_extra "-DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}") endif() + _resolve_versioned_macos_sdk(_sdk_path) + if(_sdk_path) + list(APPEND _cmake_extra "-DCMAKE_OSX_SYSROOT=${_sdk_path}") + endif() endif() message(STATUS "Configure ${label} (${arch})") diff --git a/obs-adapter/src/plugin-main.cpp b/obs-adapter/src/plugin-main.cpp index 3bdc14d..3b0876e 100644 --- a/obs-adapter/src/plugin-main.cpp +++ b/obs-adapter/src/plugin-main.cpp @@ -237,6 +237,11 @@ void workerLoop(CameraSource *self) } const bool config_changed = generation != connected_generation; + if (config_changed) { + // A settings change is an operator action: try again immediately, + // whatever the previous attempt's backoff had grown to. + backoff_ms = kBackoffStartMs; + } const bool needs_connect = !connected || config_changed || (self->session && (self->session->state() == SessionState::Failed || @@ -253,7 +258,11 @@ void workerLoop(CameraSource *self) if (!config.is_valid() || camera.empty()) { self->setStatus("not configured -- set the server URL, room, read key and camera"); connected_generation = generation; - backoff_ms = kBackoffStartMs; + // Back off like any other unsuccessful attempt, so an + // unconfigured source is not a once-a-second no-op forever. + // Filling the settings in bumps the generation and wakes this + // thread immediately, so the backoff costs no responsiveness. + backoff_ms = backoff_ms * 2 < kBackoffMaxMs ? backoff_ms * 2 : kBackoffMaxMs; } else { self->setStatus("connecting..."); const TokenResult token = self->api->requestToken(config);