Skip to content

integrate livekit capture source-clock and source-pattern - #274

Open
stephen-derosa wants to merge 3 commits into
mainfrom
sderosa/initial-capture-source
Open

stephen-derosa wants to merge 3 commits into
mainfrom
sderosa/initial-capture-source

Conversation

@stephen-derosa

Copy link
Copy Markdown
Collaborator

integrate the livekit capture source-clock and source-pattern.

This is from #227 with the gstreamer and device sources stripped.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

3 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

Comment thread CMakeLists.txt

option(LIVEKIT_BUILD_EXAMPLES "Build LiveKit examples" OFF)
option(LIVEKIT_BUILD_TESTS "Build LiveKit tests" OFF)
option(LIVEKIT_ENABLE_CAPTURE "Build the Rust FFI with pattern and clock capture sources" OFF)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Release bundles cannot create capture sources

Official release builds leave LIVEKIT_ENABLE_CAPTURE off, so CaptureSource::create cannot create either built-in source. The release workflow uses release-examples, not the capture-enabled test presets.

Learn more

The public capture factories are always compiled, but the Rust implementation is gated by this CMake option. The official release workflow builds using the release-examples preset, which does not enable it. Consumers of a clean release bundle therefore cannot use either advertised source.

Example: A release built through ./build.sh release-examples --bundle includes CaptureSource::create, but awaiting a pattern-source creation future fails because the Rust FFI was built without capture-pattern.

Recommended fix: Enable the capture features in release and example presets, including the presets used by .github/workflows/make-release.yml and .github/workflows/builds.yml, or make capture support the default while explicitly allowing opt-out.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread CMakeLists.txt
-DPROTOC_PATH=${Protobuf_PROTOC_EXECUTABLE}
-DRUST_TARGET=${RUST_TARGET_TRIPLE}
-DGCC_LIB_DIR=${GCC_LIB_DIR}
-DCARGO_FEATURES=${LIVEKIT_CARGO_FEATURES}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Capture-enabled builds can reuse disabled FFI

When separate build directories share a Rust target, LIVEKIT_ENABLE_CAPTURE can change without rebuilding its existing FFI artifact. The new build advertises capture support while CaptureSource::create still uses the disabled library.

Learn more

The Rust library output path is shared across configurations with the same Rust profile, but the custom command only tracks Rust source files. A second build directory can see the first one's existing artifact as up to date despite requesting different Cargo features. The generated kCaptureEnabled constant then describes CMake configuration, not the library actually loaded.

Example: Build a capture-disabled Debug configuration, then configure a different Debug build directory with LIVEKIT_ENABLE_CAPTURE=ON and build without changing Rust sources. Its FFI output already exists, so Cargo is skipped and pattern creation fails despite kCaptureEnabled == true.

Recommended fix: Give each feature configuration its own Rust target/output directory, or add a feature-specific stamp that forces Cargo to run whenever the feature selection differs from the library's actual build. Ensure header generation and the selected FFI artifact use the same feature set.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Capture build dependencies can become stale, and the public class layout introduces ABI constraints that should be addressed.

4 open findings
What changed in this PR

Adds GPU-backed pattern and clock capture sources through the Rust FFI.

Changes:

  • Introduces the public CaptureSource API and FFI lifecycle handling.
  • Enables capture features in test presets and adds unit, integration, and stress tests.
  • Documents capture configuration, publishing, and lifecycle behavior.
File Description
src/​tests/​unit/​test_capture_source.cpp Tests invalid configurations.
src/​tests/​stress/​test_capture_source_stress.cpp Measures capture throughput.
src/​tests/​integration/​test_capture_source.cpp Tests end-to-end publishing.
src/​ffi_client.h Declares capture creation support.
src/​ffi_client.cpp Handles capture FFI requests and events.
src/​capture_source.cpp Implements capture sources.
scripts/​generate-docs.sh Includes capture documentation.
include/​livekit/​video_source.h Supports adopting capture handles.
include/​livekit/​livekit.h Exposes the capture API.
include/​livekit/​capture_source.h Defines the public capture API.
docs/​README.md Links capture documentation.
docs/​capture-sources.md Documents capture usage.
docs/​building.md Documents the build option.
CMakePresets.json Enables capture for test presets.
CMakeLists.txt Configures and builds capture support.
build.h.in Exposes capture availability.
AGENTS.md Documents capture architecture and threading.
.gitattributes Configures preset-file whitespace handling.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread CMakeLists.txt
set(LIVEKIT_CARGO_FEATURES "")
set(LIVEKIT_CAPTURE_ENABLED 0)
if(LIVEKIT_ENABLE_CAPTURE)
set(LIVEKIT_CARGO_FEATURES "capture-pattern,capture-clock")
Comment on lines +218 to +222
FfiHandle handle_;
CaptureSourceKind kind_ = CaptureSourceKind::Pixel;
int width_ = 0;
int height_ = 0;
std::optional<VideoCodec> codec_;
Comment thread docs/capture-sources.md Outdated
Comment thread include/livekit/capture_source.h Outdated
stephen-derosa and others added 2 commits October 7, 2026 15:17
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Clarify which build presets enable LIVEKIT_ENABLE_CAPTURE and the requirements for source creation.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Comment on lines +107 to +108
VideoSource(FfiHandle&& handle, int width, int height) noexcept
: handle_(std::move(handle)), width_(width), height_(height) {}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be exposed as public API? Do we have precedent for passing in a FfiHandle in elsewhere?

Comment on lines +54 to +58
do { \
if constexpr (!kCaptureEnabled) { \
GTEST_SKIP() << "livekit-ffi built without the 'capture' feature; configure with -DLIVEKIT_ENABLE_CAPTURE=ON"; \
} \
} while (false)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit smelly, I feel like there's gotta be a better way to check if capture is enabled. Might be worth researching C++ best practices on dynamic library availability checking

using namespace std::chrono_literals;
if constexpr (!kCaptureEnabled) {
GTEST_SKIP() << "capture sources are disabled in this build";
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/// @param config Clock source configuration.
/// @return A future that resolves to the created capture source.
/// @throws CaptureSourceError When awaiting the future if creation fails.
static std::future<std::shared_ptr<CaptureSource>> create(ClockVideoSourceConfig config);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Help me understand why these should be async via the std::future, I get there's some async required to set things up under the hood, but compared to something like local_video_track that's synchronous: https://github.com/livekit/client-sdk-cpp/blob/main/include/livekit/local_video_track.h#L66-L67

Additionally, every example of it being called in this PR (test code, or example docs) immediately calls .get()

Not a critical comment, but am curious/want to make sure API is aligned

Comment thread CMakeLists.txt

option(LIVEKIT_BUILD_EXAMPLES "Build LiveKit examples" OFF)
option(LIVEKIT_BUILD_TESTS "Build LiveKit tests" OFF)
option(LIVEKIT_ENABLE_CAPTURE "Build the Rust FFI with pattern and clock capture sources" OFF)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LIVEKIT_ENABLE_CAPTURE -> LIVEKIT_BUILD_CAPTURE?

Also should we have additional CI release artifacts with capture? like <SDK>_capture.tar.gz

Comment thread build.h.in
namespace livekit {

/// @brief Whether the Rust FFI was built with capture-source support.
inline constexpr bool kCaptureEnabled = "@LIVEKIT_CAPTURE_ENABLED@"[0] == '1';

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer #define LIVEKIT_CAPTURE_ENABLED over a global bool, even though more out dated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants