diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 00000000..7f702cd3 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,16 @@ +{ + "permissions": { + "allow": [ + "Bash(gh search *)", + "Bash(curl *)", + "Bash(git *)", + "Bash(sudo *)", + "Bash(apt-get *)", + "Bash(apt *)", + "Bash(dpkg *)", + "Bash(rpm *)", + "Bash(yum *)", + "Bash(zypper *)" + ] + } +} diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index 5de560a3..eb223af9 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -254,6 +254,6 @@ To verify you have all dependencies linked correctly: ## Need Help? -- See `README_BUILD.md` for complete build instructions +- See [`docs/building.md`](docs/building.md) for complete build instructions - Check `CMakeLists.txt` lines 287-381 for the exact CMake configuration - Open an issue at: https://github.com/livekit/client-sdk-cpp/issues diff --git a/README.md b/README.md index 665f0042..a736002e 100644 --- a/README.md +++ b/README.md @@ -8,634 +8,238 @@ -# C++ SDK for LiveKit +# C++ client SDK for LiveKit Use this SDK to add realtime video, audio and data features to your C++ app. By connecting to LiveKit Cloud or a self-hosted server, you can quickly build applications such as multi-modal AI, live streaming, or video calls with just a few lines of code. -## Requirements -- **CMake** ≥ 3.20 -- **Rust / Cargo** (latest stable toolchain) -- **Git LFS** (required for examples) - Some example data files (e.g., audio assets) are stored using Git LFS. - You must install Git LFS before cloning or pulling the repo if you want to run the examples. -- **livekit-cli** install livekit-cli by following the [official LiveKit docs](https://docs.livekit.io/intro/basics/cli/start/) -- **livekit-server** install livekit-server by following the [official LiveKit docs](https://docs.livekit.io/transport/self-hosting/local/) +[![Builds](https://github.com/livekit/client-sdk-cpp/actions/workflows/builds.yml/badge.svg?branch=main)](https://github.com/livekit/client-sdk-cpp/actions/workflows/builds.yml) +[![Tests](https://github.com/livekit/client-sdk-cpp/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/livekit/client-sdk-cpp/actions/workflows/tests.yml) -**Platform-Specific Requirements:** +## Docs -### For Building the SDK: -- **Windows:** Visual Studio 2019+, vcpkg -- **Linux:** `sudo apt install libprotobuf-dev libssl-dev` (protobuf 3.x) -- **macOS:** `brew install protobuf` (protobuf 3.x) +- LiveKit docs: [docs.livekit.io](https://docs.livekit.io) +- [SDK reference](https://docs.livekit.io/reference/client-sdk-cpp/) +- [Repository docs](./docs/README.md) -### For Using the Pre-built SDK: -- **Windows:** All dependencies included (DLLs bundled) - ready to use -- **Linux:** Requires `libprotobuf` and `libssl-dev`; deploy `liblivekit_ffi.so` with your executable -- **macOS:** Requires `protobuf`; deploy `liblivekit_ffi.dylib` with your executable +## Using Real-time SDK -> **Note**: If the SDK was built with Protobuf 6.0+, you also need `libabsl-dev` (Linux) or `abseil` (macOS). +This project uses [CMake](https://cmake.org/) for building the SDK itself and for consuming as a library. The +[**cpp-example-collection**](https://github.com/livekit-examples/cpp-example-collection) contains a [LiveKitSDK.cmake](https://github.com/livekit-examples/cpp-example-collection/blob/main/cmake/LiveKitSDK.cmake) +which downloads a prebuilt release at CMake configure time — no source build +required. -## Clone the Repository - -Make sure to initialize the Rust submodule (`client-sdk-rust`): +If you do want to build from source, the short version is: ```bash -# Option 1: Clone with submodules in one step git clone --recurse-submodules https://github.com/livekit/client-sdk-cpp.git - -# Option 2: Clone first, then initialize submodules -git clone https://github.com/livekit/client-sdk-cpp.git cd client-sdk-cpp -git submodule update --init --recursive - -# Note: If running tests, pull Git LFS to bring in test data: -git lfs pull -``` - -## Building - -### Quick Build (Using Build Scripts) - -**Linux/macOS:** -```bash -./build.sh clean # Clean CMake build artifacts + local-install -./build.sh clean-all # Deep clean (C++ + Rust + local-install + generated files) -./build.sh debug # Build Debug version -./build.sh release # Build Release version -./build.sh debug-examples # Build Debug with examples -./build.sh release-examples # Build Release with examples -./build.sh debug-tests # Build Debug with tests -./build.sh debug-all # Build Debug with tests + examples -./build.sh release-tests # Build Release with tests -./build.sh release-all # Build Release with tests + examples -``` -**Windows** -Using build scripts: -```powershell -.\build.cmd clean # Clean CMake build artifacts + local-install -.\build.cmd clean-all # Deep clean (C++ + Rust + local-install + generated files) -.\build.cmd debug # Build Debug version -.\build.cmd release # Build Release version -.\build.cmd debug-examples # Build Debug with examples -.\build.cmd release-examples # Build Release with examples -.\build.cmd debug-tests # Build Debug with tests -.\build.cmd debug-all # Build Debug with tests + examples -.\build.cmd release-tests # Build Release with tests -.\build.cmd release-all # Build Release with tests + examples -``` - -The build scripts pass an explicit job count to `cmake --build --parallel`. Set -`CMAKE_BUILD_PARALLEL_LEVEL` to override the default detected logical CPU count. - -### Windows build using cmake/vcpkg -```bash -cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE="$PWD/vcpkg/scripts/buildsystems/vcpkg.cmake" # Generate Makefiles in build folder -# Build (Release or Debug) -cmake --build build --config Release -# or: -cmake --build build --config Debug -# Clean CMake build artifacts -Remove-Item -Recurse -Force build -``` -Note (Windows), This assumes vcpkg is checked out in the repo root at `.\vcpkg\`. -You must install protobuf via vcpkg (so CMake can find ProtobufConfig.cmake and protoc), for example: -```bash -.\vcpkg\vcpkg install protobuf:x64-windows -``` - -### Advanced Build (Using CMake Presets) - -For more control and platform-specific builds, see the detailed instructions in [README_BUILD.md](README_BUILD.md). - -**Prerequisites (Windows only):** -- Set `VCPKG_ROOT` environment variable pointing to your vcpkg installation - -```powershell -# Windows PowerShell -$env:VCPKG_ROOT = "C:\path\to\vcpkg" -``` - -**Prerequisites (Linux/macOS):** -- Install system dependencies (see above) - -**Quick start:** -```bash -# Windows -cmake --preset windows-release -cmake --build --preset windows-release - -# Linux -cmake --preset linux-release -cmake --build --preset linux-release - -# macOS -cmake --preset macos-release -cmake --build --preset macos-release -``` - -**For complete build instructions, troubleshooting, and platform-specific notes, see [README_BUILD.md](README_BUILD.md)** - -### Building with Docker -The Docker setup is split into a reusable base image and an SDK image layered on top of it. - **NOTE:** this has only been tested on Linux -```bash -docker build -t livekit-cpp-sdk-base . -f docker/Dockerfile.base -docker build --build-arg BASE_IMAGE=livekit-cpp-sdk-base -t livekit-cpp-sdk . -f docker/Dockerfile.sdk -docker run -it --network host livekit-cpp-sdk:latest bash -``` - -__NOTE:__ if you are building your own Dockerfile, you will likely need to set the same `ENV` variables as in `docker/Dockerfile.base`, but to the relevant directories: -```bash -export CC=$HOME/gcc-14/bin/gcc -export CXX=$HOME/gcc-14/bin/g++ -export LD_LIBRARY_PATH=$HOME/gcc-14/lib64:$LD_LIBRARY_PATH -export PATH=$HOME/.cargo/bin:$PATH -export PATH=$HOME/cmake-3.31/bin:$PATH -``` - -## Run Example - -### Prerequisites - -Ensure one of the `*-examples` build script options was run prior. - -### Generate Tokens -Before running any participant, create JWT tokens with the proper identity and room name, example -```bash -lk token create -r test -i your_own_identity --join --valid-for 99999h --dev --room=your_own_room -``` - -### SimpleRoom - -```bash -./build-release/cpp-example-collection-build/simple_room/SimpleRoom --url $URL --token -``` - -You can also provide the URL and token via environment variables: -```bash -export LIVEKIT_URL=ws://localhost:7880 -export LIVEKIT_TOKEN= -./build-release/cpp-example-collection-build/simple_room/SimpleRoom +./build.sh release # or .\build.cmd release on Windows ``` -**End-to-End Encryption (E2EE)** -You can enable E2E encryption for the streams via --enable_e2ee and --e2ee_key flags, -by running the following cmds in two terminals or computers. **Note, jwt_token needs to be different identity** -```bash -./build-release/cpp-example-collection-build/simple_room/SimpleRoom --url $URL --token --enable_e2ee --e2ee_key="your_key" -``` -**Note**, **all participants must use the exact same E2EE configuration and shared key.** -If the E2EE keys do not match between participants: -- Media cannot be decrypted -- Video tracks will appear as a black screen -- Audio will be silent -- No explicit error may be shown at the UI level - -Press Ctrl-C to exit the example. - -### SimpleRpc -The SimpleRpc example demonstrates how to: -- Connect multiple participants to the same LiveKit room -- Register RPC handlers (e.g., arrival, square-root, divide, long-calculation) -- Send RPC requests from one participant to another -- Handle success, application errors, unsupported methods, and timeouts -- Observe round-trip times (RTT) for each RPC call - -#### Generate Tokens -Before running any participant, create JWT tokens with **caller**, **greeter** and **math-genius** identities and room name. -```bash -lk token create -r test -i caller --join --valid-for 99999h --dev --room=your_own_room -lk token create -r test -i greeter --join --valid-for 99999h --dev --room=your_own_room -lk token create -r test -i math-genius --join --valid-for 99999h --dev --room=your_own_room -``` - -#### Start Participants -Every participant is run as a separate terminal process, note --role needs to match the token identity. -```bash -./build-release/cpp-example-collection-build/simple_rpc/SimpleRpc --url $URL --token --role=math-genius -``` -The caller will automatically: -- Wait for the greeter and math-genius to join -- Perform RPC calls -- Print round-trip times -- Annotate expected successes or expected failures - -### SimpleDataStream -- The SimpleDataStream example demonstrates how to: -- Connect multiple participants to the same LiveKit room -- Register text stream and byte stream handlers by topic (e.g. "chat", "files") -- Send a text stream (chat message) from one participant to another -- Send a byte stream (file/image) from one participant to another -- Attach custom stream metadata (e.g. sent_ms) via stream attributes -- Measure and print one-way latency on the receiver using sender timestamps -- Receive streamed chunks and reconstruct the full payload on the receiver - -#### Generate Tokens -Before running any participant, create JWT tokens with caller and greeter identities and your room name. -```bash -lk token create -r test -i caller --join --valid-for 99999h --dev --room=your_own_room -lk token create -r test -i greeter --join --valid-for 99999h --dev --room=your_own_room -``` - -#### Start Participants -Start the receiver first (so it registers stream handlers before messages arrive): -```bash -./build-release/cpp-example-collection-build/simple_data_stream/SimpleDataStream --url $URL --token -``` -On another terminal or computer, start the sender -```bash -./build-release/cpp-example-collection-build/simple_data_stream/SimpleDataStream --url $URL --token -``` - -**Sender** (e.g. greeter) -- Waits for the peer, then sends a text stream ("chat") and a file stream ("files") with timestamps and metadata, logging stream IDs and send times. - -**Receiver** (e.g. caller) -- Registers handlers for text and file streams, logs stream events, computes one-way latency, and saves the received file locally. +You'll need `cmake` ≥ 3.20, a stable Rust toolchain, and platform-specific build +deps (`protobuf`, `abseil`, `openssl` on Linux). See the [Building](docs/building.md) guide +for full prerequisites table, Docker recipe, CMake presets, and troubleshooting. +## Hello, LiveKit -## Logging +Here is a minimal example of the `main` function for sending and receiving video and data track frames. The [sender](https://github.com/livekit-examples/cpp-example-collection/blob/main/hello_livekit/sender/main.cpp) plays the role of a robot or camera, publishing video and data track frames every 100 ms; the [receiver](https://github.com/livekit-examples/cpp-example-collection/blob/main/hello_livekit/receiver/main.cpp) stands in for the cloud service or operator UI, logging every frame it sees. In a production system the synthetic video would be a robot's perception output and the data track would carry sensor readings or operator commands, but the connection and publishing pattern is the same. Full source for both processes lives in the [cpp-example-collection](https://github.com/livekit-examples/cpp-example-collection/tree/main/hello_livekit) repo. -The SDK uses [spdlog](https://github.com/gabime/spdlog) internally but does -**not** expose it in public headers. All log output goes through a thin public -API in ``. +The sender creates tracks and publishes data. -### Two-tier filtering - -| Tier | When | How | Cost | -|------|------|-----|------| -| **Compile-time** | CMake configure | `-DLIVEKIT_LOG_LEVEL=WARN` | Zero -- calls below the level are stripped from the binary | -| **Runtime** | Any time after `initialize()` | `livekit::setLogLevel(LogLevel::Warn)` | Minimal -- a level check before formatting | - -#### Compile-time level (`LIVEKIT_LOG_LEVEL`) - -Set once when you configure CMake. Calls below this threshold are completely -removed by the preprocessor -- no format-string evaluation, no function call. - -```bash -# Development (default): keep everything available -cmake -DLIVEKIT_LOG_LEVEL=TRACE .. - -# Release: strip TRACE / DEBUG / INFO -cmake -DLIVEKIT_LOG_LEVEL=WARN .. - -# Production: only ERROR and CRITICAL survive -cmake -DLIVEKIT_LOG_LEVEL=ERROR .. -``` - -Valid values: `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `CRITICAL`, `OFF`. - -#### Runtime level (`setLogLevel`) - -Among the levels that survived compilation you can still filter at runtime -without rebuilding: +**Initialize LiveKit and connect to the room** ```cpp -#include - -livekit::initialize(); // default level: Info -livekit::setLogLevel(livekit::LogLevel::Debug); // show more detail -livekit::setLogLevel(livekit::LogLevel::Warn); // suppress info chatter -``` +// get your url and token from env vars, args, etc +const std::string url = "wss://hello.livekit.cloud"; +const std::string token = "sender_token"; -### Custom log callback +// Start the LiveKit SDK before creating rooms or tracks. +livekit::initialize(LogLevel::Info, LogSink::kConsole); -Replace the default stderr sink with your own handler. This is the integration -point for frameworks like ROS2 (`RCLCPP_*` macros), Android logcat, or any -structured-logging pipeline: +// set your room options, here we will use defaults +livekit::RoomOptions options; -```cpp -#include - -livekit::initialize(); -livekit::setLogLevel(livekit::LogLevel::Trace); - -livekit::setLogCallback( - [](livekit::LogLevel level, - const std::string &logger_name, - const std::string &message) { - // Route to your framework, e.g.: - // RCLCPP_INFO(get_logger(), "[%s] %s", logger_name.c_str(), message.c_str()); - myLogger.log(level, logger_name, message); - }); - -// Pass nullptr to restore the default stderr sink: -livekit::setLogCallback(nullptr); +// Create the room & connect to the room using a server URL and participant token. +auto room = std::make_unique(); +if (!room->connect(url, token, options)) { + std::cerr << "Failed to connect to LiveKit\n"; + return 1; +} ``` -See [`cpp-example-collection/logging_levels/custom_sinks.cpp`](cpp-example-collection/logging_levels/custom_sinks.cpp) -for three copy-paste-ready patterns: **file logger**, **JSON structured lines**, -and a **ROS2 bridge** that maps `LogLevel` to `RCLCPP_*` macros. - -### Available log levels - -| Level | Typical use | -|-------|-------------| -| `Trace` | Per-frame / per-packet detail (very noisy) | -| `Debug` | Diagnostic info useful during development | -| `Info` | Normal operational messages (connection, track events) | -| `Warn` | Unexpected but recoverable situations | -| `Error` | Failures that affect functionality | -| `Critical` | Unrecoverable errors | -| `Off` | Suppress all output | - ---- - -## Tracing - -The SDK includes built-in support for [Chromium tracing](https://www.chromium.org/developers/how-tos/trace-event-profiling-tool/), allowing you to capture detailed performance traces for debugging and optimization. - -### Basic Usage +**Create the VideoSource, which provides frames to the VideoTrack, then create and publish the VideoTrack** ```cpp -#include +// get the local participant to create tracks +auto* participant = room->localParticipant(); -// Start tracing to a file -livekit::startTracing("trace.json"); - -// ... run your application ... - -// Stop tracing and flush to file -livekit::stopTracing(); +// Publish a synthetic camera track named "camera0" backed by a VideoSource. +auto video_source = std::make_shared(640, 480); +auto video_track = participant->publishVideoTrack("camera0", video_source, TrackSource::SOURCE_CAMERA); +if (!video_track) { + std::cerr << "Failed to publish video track\n"; + return 1; +} ``` -### Filtering by Category - -You can optionally filter which categories to trace: +**Create and publish the DataTrack** ```cpp -// Trace only specific categories (supports wildcards) -livekit::startTracing("trace.json", {"livekit.*", "webrtc.*"}); +// Publish a data track named "app-data" for app messages. +auto data_track_result = participant->publishDataTrack("app-data"); +if (!data_track_result) { + std::cerr << "Failed to publish data track\n"; + return 1; +} +auto data_track = data_track_result.value(); ``` -### Viewing Traces - -Open the generated trace file in one of these viewers: - -1. **Chrome**: Navigate to `chrome://tracing` and click "Load" to open the trace file -2. **Perfetto**: Go to https://ui.perfetto.dev and drag-drop your trace file - ---- - -## Integration & Stress Tests - -The SDK includes integration and stress tests using Google Test (gtest). - -### Build Tests - -**Linux/macOS:** -```bash -./build.sh debug-tests # Build Debug with tests -./build.sh release-tests # Build Release with tests -``` - -**Windows:** -```powershell -.\build.cmd debug-tests -.\build.cmd release-tests -``` - -### Run Tests - -After building, run tests using ctest or directly: - -```bash -# Run all tests via ctest -cd build-debug -ctest --output-on-failure - -# Or run test executables directly -./build-debug/bin/livekit_integration_tests -./build-debug/bin/livekit_stress_tests - -# Run specific test suites -./build-debug/bin/livekit_integration_tests --gtest_filter="*Rpc*" -./build-debug/bin/livekit_stress_tests --gtest_filter="*MaxPayloadStress*" -``` - -### Test Types - -| Executable | Description | -|------------|-------------| -| `livekit_integration_tests` | Quick tests (~1-2 minutes) for SDK functionality | -| `livekit_stress_tests` | Long-running tests (configurable, default 1 hour) | - -### Integration & Stress Test Environment Variables - -The integration and stress test suites (data tracks, RPC, media multistream, -etc.) require a LiveKit server and two participant tokens: - -```bash -# Required -export LIVEKIT_URL="ws://localhost:7880" # or wss://your-server.livekit.cloud -export LIVEKIT_TOKEN_A="" -export LIVEKIT_TOKEN_B="" - -# Optional (for stress tests) -export RPC_STRESS_DURATION_SECONDS=3600 # Test duration (default: 1 hour) -export RPC_STRESS_CALLER_THREADS=4 # Concurrent caller threads (default: 4) -``` - -**Generate tokens for the test suites:** - -The easiest path is to source the helper script, which will mint both -participant tokens against a local `livekit-server --dev` and export -`LIVEKIT_TOKEN_A`, `LIVEKIT_TOKEN_B`, and `LIVEKIT_URL` for the current shell: - -```bash -source .token_helpers/set_data_track_test_tokens.bash -``` - -To generate tokens manually instead (e.g. against a non-default server): - -```bash -export LIVEKIT_TOKEN_A="$(lk token create --api-key devkey --api-secret secret -i cpp-test-a \ - --join --valid-for 99999h --room cpp_data_track_test \ - --grant '{"canPublish":true,"canSubscribe":true,"canPublishData":true}' \ - --token-only)" -export LIVEKIT_TOKEN_B="$(lk token create --api-key devkey --api-secret secret -i cpp-test-b \ - --join --valid-for 99999h --room cpp_data_track_test \ - --grant '{"canPublish":true,"canSubscribe":true,"canPublishData":true}' \ - --token-only)" -``` - -### Test Coverage - -- **SDK Initialization**: Initialize/shutdown lifecycle -- **Room**: Room creation, options, connection -- **Audio Frame**: Frame creation, manipulation, edge cases -- **RPC**: Round-trip calls, max payload (15KB), timeouts, errors, concurrent calls -- **Stress Tests**: High throughput, bidirectional RPC, memory pressure - -## Recommended Setup -### macOS -```bash -brew install cmake protobuf rust -``` +**Publish video and data track frames every 100ms** -### Ubuntu / Debian -```bash -sudo apt update -sudo apt install -y cmake protobuf-compiler build-essential -curl https://sh.rustup.rs -sSf | sh -``` +```cpp +int count = 0; -## Development Tips -### Update Rust version -```bash -cd client-sdk-cpp -git fetch origin -git switch -c try-rust-main origin/main +while (true) +{ + // create a 640x480 RGBA video frame + auto vf = livekit::VideoFrame::create(640, 480, VideoBufferType::RGBA); -# Sync submodule URLs and check out what origin/main pins (recursively): -git submodule sync --recursive -git submodule update --init --recursive --checkout + // capture the frame. This publishes the frame on VideoTrack camera0 + video_source->captureFrame(vf); -# Now, in case the nested submodule under yuv-sys didn’t materialize, force it explicitly: -cd .. -git -C client-sdk-rust/yuv-sys submodule sync --recursive -git -C client-sdk-rust/yuv-sys submodule update --init --recursive --checkout + const std::string message = "hello #" + std::to_string(count); + const auto now_microsec = + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); -# Sanity check: -git submodule status --recursive -``` + // create and push stamped DataTrackFrame + const livekit::DataTrackFrame frame{ + std::vector(message.begin(), message.end()), + now_microsec, + }; -### If yuv-sys fails to build -```bash -cargo clean -p yuv-sys -cargo build -p yuv-sys -vv -``` + // optionally, capture the result + auto push_result = data_track->tryPush(frame); + if (!push_result) { + const auto& error = push_result.error(); + std::cerr << "[warn] Failed to push data frame: code=" << static_cast(error.code) + << " message=" << error.message << "\n"; + } -### Full clean (Rust + C++ build folders) -In some cases, you may need to perform a full clean that deletes all build artifacts from both the Rust and C++ folders, plus the local install folder: -```bash -./build.sh clean-all + std::this_thread::sleep_for(std::chrono::milliseconds(100)); +} ``` -## Quality Checks - -This SDK leverages various tools and checks to ensure the highest quality of the code. +The receiver side setup is the same, except now we set callbacks to the relevant tracks. -### Clang Tools +**Initialize LiveKit and Connect to the room** -- `clang-tidy`: static analysis checks to catch common C++ pitfalls. See [.clang-tidy](./.clang-tidy) for the list of current checks (enforced in CI on PR) -- `clang-format`: code formatting and style consistency. See [.clang-format](./.clang-format) for the list of style configurations (enforced in CI on PR) - -> **Note**: For Windows, `clang-tidy` is not currently supported for this project because the Visual Studio CMake generator does not produce the compile_commands.json database that `clang-tidy` requires. Similarly, `clang-format` must be installed and run manually on Windows, referencing the root `.clang-format` file. - -To run locally, first install the following: - -**macOS:** - -```bash -brew install llvm -``` +```cpp +// get your url and token from env vars, args, etc +const std::string url = "wss://hello.livekit.cloud"; +const std::string token = "receiver_token"; -This installs `clang-format`, `clang-tidy`, and `run-clang-tidy`. Homebrew may ask you to add `/opt/homebrew/opt/llvm/bin` to your `PATH`. +// Start the LiveKit SDK before creating rooms or tracks. +livekit::initialize(LogLevel::Info, LogSink::kConsole); -**Linux:** +// set your room options, here we use the defaults +livekit::RoomOptions options; -```bash -# Ubuntu / Debian: -sudo apt-get install clang-format clang-tidy clang-tools +// Create the room & connect to the room using a server URL and participant token. +auto room = std::make_unique(); +if (!room->connect(url, token, options)) { + std::cerr << "Failed to connect to LiveKit\n"; + return 1; +} ``` -**Pre-commit hook** +**Set callbacks for new video and data frames** -```bash -printf '#!/bin/sh\nFILES=$(git diff --cached --name-only --diff-filter=ACMR -- "*.c" "*.cc" "*.cpp" "*.cxx" "*.h" "*.hpp" "*.hxx")\n[ -z "$FILES" ] && exit 0\necho "$FILES" | xargs ./scripts/clang-format.sh --fix\necho "$FILES" | xargs git add\n' > .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit -``` - -To run `clang-tidy`: - -1. Generate `compile_commands.json` and the protobuf headers via a release build: - -```bash -./build.sh release -``` +```cpp +// the identity of the participant sending video and data frames +const std::string sender_identity = "sender_identity"; -1. Run the clang-tidy wrapper, which uses the same file set, regex filters, and `.clang-tidy` config as CI: +// Set the callback for new video frames from the sender's "camera0" VideoTrack +room->setOnVideoFrameCallback(sender_identity, "camera0", [](const VideoFrame& frame, std::int64_t) { + std::cout << "video frame: " << frame.width() << "x" << frame.height() << "\n"; +}); -```bash -./scripts/clang-tidy.sh +// Set the callback for new frames on the sender's "app-data" DataTrack +room->addOnDataFrameCallback(sender_identity, "app-data", + [](const std::vector& payload, std::optional) { + const std::string message(payload.begin(), payload.end()); + std::cout << "data message: " << message << "\n"; + }); ``` -The wrapper forwards extra arguments to `run-clang-tidy`, examples below: +For end-to-end samples and a fuller set of demos, see the [cpp-example-collection repo](https://github.com/livekit-examples/cpp-example-collection). -```bash -./scripts/clang-tidy.sh -j 4 # Change number of cores used -./scripts/clang-tidy.sh -checks='-*,misc-const-correctness' # Only run certain checks -./scripts/clang-tidy.sh -fix # Apply fixes automatically -``` +## Features -Output is captured to `clang-tidy.log` at the repo root. This is done as a convenience feature, as often times the terminal buffer is not large enough for all the output. +- Connect to LiveKit rooms (Cloud or self-hosted) +- Receive remote audio/video tracks +- Publish local audio/video tracks +- Data tracks (low-level) and data streams (high-level) +- RPC between participants +- End-to-end encryption (E2EE) +- Hardware-accelerated codecs (via the underlying Rust SDK) +- Chromium-style tracing for performance debugging -To run `clang-format`: +Supported platforms: **Linux** (x64, arm64), **macOS** (12.3+, Apple Silicon +& Intel), **Windows** (x64). -```bash -./scripts/clang-format.sh -``` +## Logging & tracing -With no arguments, runs `clang-format` against every relevant file in the repository against defined `.clang-format` rules. +The SDK uses a thin public logging API in `` with both +compile-time and runtime filtering. Plug your own sink in (file, JSON, +syslog, ROS2 `RCLCPP_*`) via `setLogCallback`. See +[docs/logging.md](docs/logging.md). -Pass flags or paths as needed, examples below: +Chromium-format performance traces can be captured with `startTracing` / +`stopTracing` and viewed in `chrome://tracing` or +[ui.perfetto.dev](https://ui.perfetto.dev). See [docs/tracing.md](docs/tracing.md). -```bash -./scripts/clang-format.sh --fix # Rewrite files in place -./scripts/clang-format.sh src/room.cpp include/livekit/room.h # Check just these files -./scripts/clang-format.sh --fix src/room.cpp # Fix just this file -``` +## Testing -Output is captured to `clang-format.log` at the repo root. +Integration and stress test suites live under `src/tests/`. Build them with +`./build.sh debug-tests`, point `LIVEKIT_URL` + two participant tokens at a +local `livekit-server --dev`, and run via `ctest` or directly. See +[docs/testing.md](docs/testing.md). -### Memory Checks +## Developer tools -Run valgrind on various examples or tests to check for memory leaks and other issues. +`clang-tidy`, `clang-format`, `valgrind`, and Doxygen are all wired up via +scripts under [`scripts/`](scripts/). Set up the pre-commit auto-formatter +with: ```bash -valgrind --leak-check=full ./build-debug/bin/livekit_integration_tests -valgrind --leak-check=full ./build-debug/bin/livekit_stress_tests +./scripts/install-pre-commit.sh ``` -## Running locally +See [docs/tools.md](docs/tools.md) for the rest. -1. Install the livekit-server -https://docs.livekit.io/transport/self-hosting/local/ - -Start the livekit-server with data tracks enabled: -```bash -LIVEKIT_CONFIG="enable_data_tracks: true" livekit-server --dev -``` +## Deprecation -```bash -# generate tokens, do for all participants -lk token create \ - --api-key devkey \ - --api-secret secret \ - -i robot \ - --join \ - --valid-for 99999h \ - --room robo_room \ - --grant '{"canPublish":true,"canSubscribe":true,"canPublishData":true}' -``` +| Component | Removed on | +| ----------------------------------------------------------------- | ---------- | +| `livekit_bridge` (bridge/ folder) — migrate to the base SDK | 2026-06-01 | +| `setOn*FrameCallback` with `TrackSource` — use track name instead | 2026-06-01 | +| Public-header symbols that don't follow `camelBack()` | 2026-06-01 | -## Deprecation +## Contributing -- livekit_bridge (bridge/ folder) is deprecated. Avoid using it. Migrate to the base SDK. This will be removed on 06/01/2026. -- setOn*FrameCallback with TrackSource is deprecated. Use track name instead. This will be removed on 06/01/2026. -- All public headers that do not follow `camelBack()` case. This will be removed on 06/01/2026. +PRs welcome. Issues: .
- + - + diff --git a/README_BUILD.md b/README_BUILD.md deleted file mode 100644 index 0c061bb2..00000000 --- a/README_BUILD.md +++ /dev/null @@ -1,338 +0,0 @@ -# Build Guide - -## Prerequisites - -### Required Tools -1. **CMake** (>= 3.20) -2. **Rust and Cargo** - For building the Rust FFI layer -3. **C++ Compiler** - - Windows: Visual Studio 2019 or later - - Linux: GCC 9+ or Clang 10+ - - macOS: Xcode 12+ - -### Dependency Management - -This project uses different dependency management strategies per platform: - -| Platform | Package Manager | Dependencies | -|----------|-----------------|-------------| -| Windows | vcpkg (bundled) | protobuf, abseil (DLLs included in distribution) | -| Linux | apt/dnf | `libprotobuf-dev libabsl-dev libssl-dev` | -| macOS | Homebrew | `protobuf abseil` | - -#### Windows: Install vcpkg - -```powershell -git clone https://github.com/microsoft/vcpkg.git -cd vcpkg -.\bootstrap-vcpkg.bat -$env:VCPKG_ROOT = "$(Get-Location)" -``` - -#### Linux: Install Dependencies - -```bash -# Ubuntu/Debian -sudo apt update && sudo apt install -y \ - build-essential cmake ninja-build pkg-config \ - llvm-dev libclang-dev clang \ - libprotobuf-dev protobuf-compiler libabsl-dev \ - libssl-dev libva-dev libdrm-dev libgbm-dev libx11-dev libgl1-mesa-dev -``` - -#### macOS: Install Dependencies - -```bash -brew install cmake ninja protobuf abseil -``` - -## Quick Start - -### Method 1: Using Build Scripts (Recommended) - -The project provides `build.cmd` (Windows) and `build.sh` (Linux/macOS) scripts for simplified building. - -**Windows:** -```powershell -# Set vcpkg root (required for Windows) -$env:VCPKG_ROOT = "C:\path\to\vcpkg" - -# Build Release version -.\build.cmd release - -# Build Release with examples -.\build.cmd release-examples - -# Build Debug version -.\build.cmd debug - -# Build Debug with examples -.\build.cmd debug-examples - -# Clean build artifacts -.\build.cmd clean - -# Full clean (C++ + Rust + generated files) -.\build.cmd clean-all -``` - -**Linux:** -```bash -# Install system dependencies first (see Prerequisites above) - -# Build Release version -./build.sh release - -# Build Release with examples -./build.sh release-examples - -# Build Debug version -./build.sh debug - -# Build Debug with examples -./build.sh debug-examples - -# Clean build artifacts -./build.sh clean - -# Full clean -./build.sh clean-all -``` - -**macOS:** -```bash -# Install Homebrew dependencies first (see Prerequisites above) - -# Build Release version -./build.sh release - -# Build Release with examples -./build.sh release-examples - -# Build Debug version -./build.sh debug - -# Build Debug with examples -./build.sh debug-examples -``` - -#### Important Notes for Linux - -Before building on Linux (especially Ubuntu/WSL), you may need to set environment variables to avoid common build errors. - -**Set Build Environment Variables:** -```bash -# Suppress deprecated warnings from WebRTC (required for newer GCC versions) -export CXXFLAGS="-Wno-deprecated-declarations" -export CFLAGS="-Wno-deprecated-declarations" - -# Required for Rust bindgen to find libclang -export LIBCLANG_PATH=/usr/lib/llvm-14/lib # Adjust version as needed -``` - -**Common Issues:** - -1. **Missing proto files or client-sdk-rust directory** - - Solution: Initialize git submodules: - ```bash - git submodule update --init --recursive - ``` - -2. **Deprecated declaration errors during compilation** - - Cause: Newer GCC versions (12/13/14) are stricter with WebRTC legacy code - - Solution: Set `CXXFLAGS` and `CFLAGS` as shown above - -3. **Rust bindgen fails with "unable to find libclang"** - - Cause: Rust bindgen cannot locate libclang library - - Solution: Set `LIBCLANG_PATH` environment variable pointing to your LLVM installation - -### Method 2: Using vcpkg Manifest Mode - -vcpkg will automatically install all required dependencies based on `vcpkg.json`. - -**Windows:** -```powershell -# Configure project -cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=/scripts/buildsystems/vcpkg.cmake - -# Build -cmake --build build --config Release - -# Optional: Build with examples -cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=/scripts/buildsystems/vcpkg.cmake -DLIVEKIT_BUILD_EXAMPLES=ON -DVCPKG_MANIFEST_FEATURES=examples -cmake --build build --config Release -``` - -**Linux/macOS:** -```bash -# Configure project -cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE=Release - -# Build -cmake --build build - -# Optional: Build with examples -cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE=Release -DLIVEKIT_BUILD_EXAMPLES=ON -DVCPKG_MANIFEST_FEATURES=examples -cmake --build build -``` - -### Method 3: Manual Dependency Installation - -If you prefer not to use vcpkg, you can install dependencies manually: - -#### Required Dependencies -- **Protobuf** (>= 5.29) - - Windows: `vcpkg install protobuf:x64-windows` - - Linux: `sudo apt install libprotobuf-dev protobuf-compiler` - - macOS: `brew install protobuf` - -- **Abseil** (Required for Protobuf >= 6) - - Windows: `vcpkg install abseil:x64-windows` - - Linux: `sudo apt install libabsl-dev` - - macOS: `brew install abseil` - -- **OpenSSL** (Linux only) - - Linux: `sudo apt install libssl-dev` - -#### Build Command -```bash -cmake -B build -S . -DCMAKE_BUILD_TYPE=Release -cmake --build build -``` - -## Build Output - -After a successful build, you will find the following in the build directories: - -``` -build-release/ # Release build output -├── lib/ -│ ├── livekit.lib / liblivekit.a # Main SDK static library -│ ├── livekit_ffi.dll / .so / .dylib # Rust FFI dynamic library -│ └── (Windows only: protobuf, abseil DLLs) -├── include/ # Public headers (auto-synced) -│ └── livekit/ -└── bin/ # Example executables (with examples enabled) - ├── SimpleRoom - ├── SimpleRpc - ├── SimpleDataStream - └── liblivekit_ffi.so / .dylib # (Linux/macOS: copied for runtime) -``` - -## Integrating into Your Project - -### Using CMake - -```cmake -# Method 1: As a subdirectory -add_subdirectory(path/to/client-sdk-cpp) -target_link_libraries(your_target PRIVATE livekit) - -# Method 2: Using find_package (requires prior installation) -find_package(livekit REQUIRED) -target_link_libraries(your_target PRIVATE livekit) -``` - -### Manual Linking - -1. Add include path: `build/include` -2. Link static library: - - Windows: `build/lib/livekit.lib` - - Linux: `build/lib/liblivekit.a` - - macOS: `build/lib/liblivekit.a` -3. Link/Deploy Rust FFI dynamic library: - - Windows: Link `livekit_ffi.dll.lib`, deploy `livekit_ffi.dll` with your exe - - Linux: Deploy `liblivekit_ffi.so` in same directory as your executable - - macOS: Deploy `liblivekit_ffi.dylib` in same directory as your executable -4. Link platform-specific system libraries - -> **Important**: On Linux/macOS, the `.so`/`.dylib` must be in the same directory as your executable (RPATH is set to `$ORIGIN` / `@executable_path`). - -**Windows system libraries:** -``` -ntdll userenv winmm iphlpapi msdmo dmoguids wmcodecdspuuid -ws2_32 secur32 bcrypt crypt32 -``` - -**macOS frameworks:** -``` -CoreAudio AudioToolbox CoreFoundation Security CoreGraphics -CoreMedia VideoToolbox AVFoundation CoreVideo Foundation -AppKit QuartzCore OpenGL IOSurface Metal MetalKit ScreenCaptureKit -``` - -**Linux libraries:** -``` -OpenSSL::SSL OpenSSL::Crypto -``` - -## CMake Options - -| Option | Default | Description | -|--------|---------|-------------| -| `LIVEKIT_BUILD_EXAMPLES` | OFF | Build example applications | -| `LIVEKIT_VERSION` | "0.1.0" | SDK version number | -| `LIVEKIT_USE_VCPKG` | ON | Use vcpkg for dependency management | - -## Troubleshooting - -### Q: Rust code recompiles after modifying C++ code? -A: This has been fixed. Rust code only recompiles when Rust source files change or the Rust library doesn't exist. - -### Q: Cannot find Protobuf or other dependencies? -A: Make sure you're using the correct CMake toolchain file: -```bash --DCMAKE_TOOLCHAIN_FILE=/scripts/buildsystems/vcpkg.cmake -``` - -### Q: Linking fails on Linux? -A: Ensure you have OpenSSL development packages installed: -```bash -sudo apt install libssl-dev -``` - -### Q: How to clean the build? -A: Use the CMake-provided clean targets: -```bash -# Clean CMake build artifacts -cmake --build build --target clean - -# Clean Rust build artifacts -cmake --build build --target cargo_clean - -# Clean generated protobuf files -cmake --build build --target clean_generated - -# Complete clean (including deletion of build directory) -cmake --build build --target clean_all -``` - -## Example Applications - -Example applications are located in the `examples/` directory: - -- **SimpleRoom** - Basic room connection and audio/video handling -- **SimpleRpc** - RPC call examples -- **SimpleDataStream** - Data stream transmission examples - -Please refer to the README in each example directory for more details. - -## Platform-Specific Notes - -### Windows -- Recommended: Visual Studio 2019 or later -- Architecture: x64 - -### macOS -- Requires macOS 12.3+ (ScreenCaptureKit support) -- Requires Xcode Command Line Tools - -### Linux -- Tested on: Ubuntu 20.04+ -- Requires complete development toolchain - -## Support - -- GitHub Issues: https://github.com/livekit/client-sdk-cpp/issues -- LiveKit Documentation: https://docs.livekit.io/ - diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..fd06e209 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,14 @@ +# Repository Documentation + +Additional documentation for the SDK. + +- [Building](building.md) — prerequisites, build scripts, CMake presets, + vcpkg, Docker, integration into your CMake project, troubleshooting. +- [Logging](logging.md) — compile-time vs runtime filtering, log levels, + custom sinks (file, JSON, ROS2 `RCLCPP_*` macros). +- [Tracing](tracing.md) — Chromium-format performance traces, viewing in + `chrome://tracing` and Perfetto. +- [Testing](testing.md) — unit, integration, and stress test suites; env + vars; token-helper script for local `livekit-server --dev` runs. +- [Developer tools](tools.md) — `clang-tidy`, `clang-format`, `valgrind`, + Doxygen, pre-commit hook, Rust submodule recovery tips. diff --git a/docs/building.md b/docs/building.md new file mode 100644 index 00000000..9b1234bb --- /dev/null +++ b/docs/building.md @@ -0,0 +1,369 @@ +# Build guide + +This document covers everything you need to build the LiveKit C++ SDK from +source: requirements, cloning the repository, the build scripts, advanced +CMake/vcpkg flows, and Docker. + +For a quick `clone + build` recipe, see the main README. This guide is the +long form. + +## Prerequisites + +### Common to all platforms + +- **CMake** ≥ 3.20 +- **Rust / Cargo** — latest stable toolchain (for building the Rust FFI layer). + Install via [rustup](https://rustup.rs/). +- **Git LFS** — required for examples that pull test media assets. +- **Protobuf** ≥ 5.29 +- **Abseil** — always required (used by Protobuf 5.x+) + +### Platform-specific toolchains + +| Platform | Compiler | Package manager | +|----------|----------|-----------------| +| Windows | Visual Studio 2019+ (MSBuild or Ninja) | vcpkg (see below) | +| Linux | GCC 9+ or Clang 10+ | `apt` / `dnf` (or vcpkg) | +| macOS | Xcode 12+ (macOS 12.3+ for ScreenCaptureKit) | Homebrew (or vcpkg) | + +## Clone the repository + +The SDK depends on the [`client-sdk-rust`](https://github.com/livekit/rust-sdks) +submodule (recursive), so always clone with submodules: + +```bash +# Option 1: clone with submodules in one step +git clone --recurse-submodules https://github.com/livekit/client-sdk-cpp.git + +# Option 2: clone first, then initialize submodules +git clone https://github.com/livekit/client-sdk-cpp.git +cd client-sdk-cpp +git submodule update --init --recursive + +# Pull Git LFS assets if you want to run the integration tests: +git lfs pull +``` + +## Recommended setup + +These are the exact packages our CI uses. They will also work for examples. + +### macOS + +```bash +brew install cmake ninja protobuf abseil rust +``` + +### Ubuntu / Debian + +```bash +sudo apt update && sudo apt install -y \ + build-essential cmake ninja-build pkg-config \ + llvm-dev libclang-dev clang \ + libprotobuf-dev protobuf-compiler libabsl-dev \ + libssl-dev + +# Install Rust if you don't already have it +curl https://sh.rustup.rs -sSf | sh +``` + +If you plan to build the [example collection](https://github.com/livekit-examples/cpp-example-collection) +(SDL-based renderer + camera/mic capture), also install: + +```bash +sudo apt install -y \ + libva-dev libdrm-dev libgbm-dev libx11-dev libgl1-mesa-dev \ + libxext-dev libxcomposite-dev libxdamage-dev libxfixes-dev \ + libxrandr-dev libxi-dev libxkbcommon-dev \ + libasound2-dev libpulse-dev \ + libwayland-dev libdecor-0-dev +``` + +### Windows + +```powershell +# Set VCPKG_ROOT once and bootstrap vcpkg +git clone https://github.com/microsoft/vcpkg.git +.\vcpkg\bootstrap-vcpkg.bat +$env:VCPKG_ROOT = "$PWD\vcpkg" +``` + +CMake's vcpkg manifest mode (below) reads +`vcpkg.json` and installs the rest automatically the first time you configure. + +## Build scripts (recommended) + +The repo ships with `build.sh` (Linux/macOS) and `build.cmd` (Windows) that +wrap the right CMake preset for your platform and pick sensible defaults. + +**Linux/macOS:** +```bash +./build.sh release # Build Release +./build.sh debug # Build Debug +./build.sh release-examples # Release + examples +./build.sh debug-examples # Debug + examples +./build.sh release-tests # Release + tests +./build.sh debug-tests # Debug + tests +./build.sh release-all # Release + tests + examples +./build.sh debug-all # Debug + tests + examples +./build.sh clean # Clean CMake build artifacts + local-install +./build.sh clean-all # Deep clean (C++ + Rust + local-install + generated files) +``` + +**Windows:** +```powershell +.\build.cmd release +.\build.cmd debug +.\build.cmd release-examples +# ... same suffixes as build.sh +``` + +The build scripts pass an explicit job count to `cmake --build --parallel`. Set +`CMAKE_BUILD_PARALLEL_LEVEL` to override the auto-detected logical CPU count. + +## Advanced: CMake presets + +For more control, drive CMake directly via the presets in +[CMakePresets.json](../CMakePresets.json): + +```bash +# Linux +cmake --preset linux-release +cmake --build --preset linux-release + +# macOS +cmake --preset macos-release +cmake --build --preset macos-release + +# Windows +cmake --preset windows-release +cmake --build --preset windows-release +``` + +Windows requires `VCPKG_ROOT` to be set: + +```powershell +$env:VCPKG_ROOT = "C:\path\to\vcpkg" +``` + +## Advanced: vcpkg manifest mode + +vcpkg will automatically install all dependencies listed in +[vcpkg.json](../vcpkg.json) the first time you configure with its toolchain +file. + +**Windows:** +```powershell +cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=$env:VCPKG_ROOT\scripts\buildsystems\vcpkg.cmake +cmake --build build --config Release + +# With examples: +cmake -B build -S . ` + -DCMAKE_TOOLCHAIN_FILE=$env:VCPKG_ROOT\scripts\buildsystems\vcpkg.cmake ` + -DLIVEKIT_BUILD_EXAMPLES=ON -DVCPKG_MANIFEST_FEATURES=examples +cmake --build build --config Release +``` + +**Linux/macOS:** +```bash +cmake -B build -S . \ + -DCMAKE_TOOLCHAIN_FILE=/scripts/buildsystems/vcpkg.cmake \ + -DCMAKE_BUILD_TYPE=Release +cmake --build build + +# With examples: +cmake -B build -S . \ + -DCMAKE_TOOLCHAIN_FILE=/scripts/buildsystems/vcpkg.cmake \ + -DCMAKE_BUILD_TYPE=Release \ + -DLIVEKIT_BUILD_EXAMPLES=ON -DVCPKG_MANIFEST_FEATURES=examples +cmake --build build +``` + +## Building with Docker + +The Docker setup is split into a reusable base image (toolchain + system +deps) and an SDK image layered on top. **Tested on Linux only.** + +```bash +docker build -t livekit-cpp-sdk-base . -f docker/Dockerfile.base +docker build --build-arg BASE_IMAGE=livekit-cpp-sdk-base \ + -t livekit-cpp-sdk . -f docker/Dockerfile.sdk +docker run -it --network host livekit-cpp-sdk:latest bash +``` + +If you're authoring your own Dockerfile, mirror the `ENV` block in +[docker/Dockerfile.base](../docker/Dockerfile.base): + +```bash +export CC=$HOME/gcc-14/bin/gcc +export CXX=$HOME/gcc-14/bin/g++ +export LD_LIBRARY_PATH=$HOME/gcc-14/lib64:$LD_LIBRARY_PATH +export PATH=$HOME/.cargo/bin:$PATH +export PATH=$HOME/cmake-3.31/bin:$PATH +``` + +## CMake options + +| Option | Default | Description | +|--------|---------|-------------| +| `LIVEKIT_BUILD_EXAMPLES` | OFF | Build example applications | +| `LIVEKIT_USE_SYSTEM_PROTOBUF` | OFF | Use system Protobuf instead of vcpkg's | +| `LIVEKIT_LOG_LEVEL` | `TRACE` | Compile-time log threshold (see [logging.md](logging.md)) | +| `LIVEKIT_VERSION` | repo-derived | SDK version string baked into the binary | + +## Build output + +After a successful build: + +``` +build-release/ +├── lib/ +│ ├── liblivekit.{a,lib} # Main SDK static library +│ ├── liblivekit_ffi.{so,dylib} # Rust FFI dynamic library +│ └── livekit_ffi.dll, *.lib # (Windows) FFI DLL + import lib +├── include/ # Public headers (auto-synced) +│ └── livekit/ +└── bin/ # Example/test executables + └── liblivekit_ffi.{so,dylib} # (Linux/macOS: copied for runtime) +``` + +## Integrating into your project + +### Using CMake + +```cmake +# Method 1: as a subdirectory +add_subdirectory(path/to/client-sdk-cpp) +target_link_libraries(your_target PRIVATE livekit) + +# Method 2: find_package (after install) +find_package(livekit REQUIRED) +target_link_libraries(your_target PRIVATE livekit) +``` + +### Using prebuilt releases + +The easiest way to consume the SDK without building from source is via +the [cpp-example-collection](https://github.com/livekit-examples/cpp-example-collection) +helper, which downloads a release tarball at CMake configure time: + +```cmake +include(LiveKitSDK.cmake) # pins or auto-resolves a release +``` + +See the example collection's +[`LiveKitSDK.cmake`](https://github.com/livekit-examples/cpp-example-collection/blob/main/cmake/LiveKitSDK.cmake) +for the full pattern. + +### Manual linking + +1. Add include path: `build-release/include` +2. Link the static SDK library: + - Windows: `build-release/lib/livekit.lib` + - Linux: `build-release/lib/liblivekit.a` + - macOS: `build-release/lib/liblivekit.a` +3. Link/deploy the Rust FFI dynamic library: + - Windows: link `livekit_ffi.dll.lib`, deploy `livekit_ffi.dll` next to your `.exe` + - Linux: deploy `liblivekit_ffi.so` next to your executable + - macOS: deploy `liblivekit_ffi.dylib` next to your executable +4. Link platform system libraries (see below). + +> **Important:** On Linux/macOS the FFI shared library must live next to the +> executable. RPATH is set to `$ORIGIN` (Linux) / `@loader_path` (macOS). + +**Windows system libraries:** +``` +ntdll userenv winmm iphlpapi msdmo dmoguids wmcodecdspuuid +ws2_32 secur32 bcrypt crypt32 +``` + +**macOS frameworks:** +``` +CoreAudio AudioToolbox CoreFoundation Security CoreGraphics +CoreMedia VideoToolbox AVFoundation CoreVideo Foundation +AppKit QuartzCore OpenGL IOSurface Metal MetalKit ScreenCaptureKit +``` + +**Linux libraries:** +``` +OpenSSL::SSL OpenSSL::Crypto +``` + +### Runtime dependencies of prebuilt artifacts + +Whether protobuf / abseil / openssl need to be installed on the target +machine depends on how the SDK binary was built: + +- **Windows** release artifacts use vcpkg triplet `x64-windows-static-md` — + protobuf and abseil are statically linked into the DLLs; no runtime install + needed. +- **macOS** release artifacts (from our CI) do **not** dynamically depend on + protobuf / abseil / openssl. You can verify with `otool -L liblivekit.dylib`. +- **Linux** depends on packaging. Check with `ldd liblivekit_ffi.so`; if any + of those are listed, install the corresponding `-dev` (build) or runtime + package (`libprotobuf32` / `libabsl` / `libssl3`) as appropriate. + +## Troubleshooting + +### Missing proto files or `client-sdk-rust` directory + +Initialize submodules: +```bash +git submodule update --init --recursive +``` + +### Deprecated-declaration errors on Linux + +Newer GCC versions (12+) are stricter with the WebRTC legacy code in the +Rust submodule. If `./build.sh release` errors with `-Werror=deprecated-declarations`, +relax it for the build: + +```bash +export CXXFLAGS="-Wno-deprecated-declarations" +export CFLAGS="-Wno-deprecated-declarations" +``` + +### Rust bindgen fails with "unable to find libclang" + +Install `libclang-dev` (Ubuntu) or `llvm` (macOS Homebrew). bindgen normally +discovers libclang from the system paths once `libclang-dev` is installed; if +not, point `LIBCLANG_PATH` at your LLVM's `lib` directory (e.g. +`/usr/lib/llvm-18/lib` on Ubuntu 24.04). + +### Rust code recompiles after C++ edits + +This was a historical issue; Rust only recompiles now when Rust source files +change or the Rust library is missing. + +### Cannot find Protobuf or other dependencies + +Make sure you're passing the vcpkg toolchain file: +```bash +-DCMAKE_TOOLCHAIN_FILE=/scripts/buildsystems/vcpkg.cmake +``` + +### `clang-tidy` on Windows + +Not currently supported via our scripts — the Visual Studio (MSBuild) CMake +generator doesn't produce `compile_commands.json`. The Ninja generator does; +see [tools.md](tools.md). + +### How do I deep-clean? + +```bash +./build.sh clean-all # C++ + Rust + local-install + generated files +``` + +Or via CMake targets: + +```bash +cmake --build build --target clean # CMake artifacts +cmake --build build --target cargo_clean # Rust artifacts +cmake --build build --target clean_generated # Generated protobuf headers +cmake --build build --target clean_all # Full clean +``` + +## Support + +- GitHub Issues: +- LiveKit Docs: diff --git a/docs/logging.md b/docs/logging.md new file mode 100644 index 00000000..1889479c --- /dev/null +++ b/docs/logging.md @@ -0,0 +1,85 @@ +# Logging + +The SDK uses [spdlog](https://github.com/gabime/spdlog) internally but does +**not** expose it in public headers. All log output goes through a thin public +API in ``. + +## Two-tier filtering + +| Tier | When | How | Cost | +|------|------|-----|------| +| **Compile-time** | CMake configure | `-DLIVEKIT_LOG_LEVEL=WARN` | Zero — calls below the level are stripped from the binary | +| **Runtime** | Any time after `initialize()` | `livekit::setLogLevel(LogLevel::Warn)` | Minimal — a level check before formatting | + +### Compile-time level (`LIVEKIT_LOG_LEVEL`) + +Set once when you configure CMake. Calls below this threshold are completely +removed by the preprocessor — no format-string evaluation, no function call. + +```bash +# Development (default): keep everything available +cmake -DLIVEKIT_LOG_LEVEL=TRACE .. + +# Release: strip TRACE / DEBUG / INFO +cmake -DLIVEKIT_LOG_LEVEL=WARN .. + +# Production: only ERROR and CRITICAL survive +cmake -DLIVEKIT_LOG_LEVEL=ERROR .. +``` + +Valid values: `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `CRITICAL`, `OFF`. + +### Runtime level (`setLogLevel`) + +Among the levels that survived compilation you can still filter at runtime +without rebuilding: + +```cpp +#include + +livekit::initialize(); // default level: Info +livekit::setLogLevel(livekit::LogLevel::Debug); // show more detail +livekit::setLogLevel(livekit::LogLevel::Warn); // suppress info chatter +``` + +## Custom log callback + +Replace the default stderr sink with your own handler. This is the integration +point for frameworks like ROS2 (`RCLCPP_*` macros), Android logcat, or any +structured-logging pipeline: + +```cpp +#include + +livekit::initialize(); +livekit::setLogLevel(livekit::LogLevel::Trace); + +livekit::setLogCallback( + [](livekit::LogLevel level, + const std::string &logger_name, + const std::string &message) { + // Route to your framework, e.g.: + // RCLCPP_INFO(get_logger(), "[%s] %s", logger_name.c_str(), message.c_str()); + myLogger.log(level, logger_name, message); + }); + +// Pass nullptr to restore the default stderr sink: +livekit::setLogCallback(nullptr); +``` + +See the [`logging_levels/custom_sinks.cpp`](https://github.com/livekit-examples/cpp-example-collection/blob/main/logging_levels/custom_sinks.cpp) +example for three copy-paste-ready patterns: a **file logger**, **JSON +structured lines**, and a **ROS2 bridge** that maps `LogLevel` to `RCLCPP_*` +macros. + +## Available log levels + +| Level | Typical use | +|-------|-------------| +| `Trace` | Per-frame / per-packet detail (very noisy) | +| `Debug` | Diagnostic info useful during development | +| `Info` | Normal operational messages (connection, track events) | +| `Warn` | Unexpected but recoverable situations | +| `Error` | Failures that affect functionality | +| `Critical` | Unrecoverable errors | +| `Off` | Suppress all output | diff --git a/docs/testing.md b/docs/testing.md new file mode 100644 index 00000000..120baabb --- /dev/null +++ b/docs/testing.md @@ -0,0 +1,112 @@ +# Testing + +The SDK includes integration and stress tests using +[Google Test](https://github.com/google/googletest). + +## Building the test binaries + +**Linux/macOS:** +```bash +./build.sh debug-tests # Build Debug with tests +./build.sh release-tests # Build Release with tests +``` + +**Windows:** +```powershell +.\build.cmd debug-tests +.\build.cmd release-tests +``` + +## Running tests + +After building, run tests using `ctest` or invoke the binaries directly: + +```bash +# Run all tests via ctest +cd build-debug +ctest --output-on-failure + +# Or run test executables directly +./build-debug/bin/livekit_integration_tests +./build-debug/bin/livekit_stress_tests + +# Run specific test suites +./build-debug/bin/livekit_integration_tests --gtest_filter="*Rpc*" +./build-debug/bin/livekit_stress_tests --gtest_filter="*MaxPayloadStress*" +``` + +__Note:__ The tests require tokens and a running LiveKit server. See the section below for details. + +## Test binaries + +| Executable | Description | +|------------|-------------| +| `livekit_unit_tests` | Pure unit tests (no server required) | +| `livekit_integration_tests` | Quick tests (~1-2 minutes) for SDK functionality | +| `livekit_stress_tests` | Long-running tests (configurable, default 1 hour) | + +## Running a local LiveKit server for tests + +The integration and stress suites need a running LiveKit server. The easiest +path is `livekit-server --dev`, which uses the well-known dev API +key/secret (`devkey` / `secret`). + +Install [`livekit-server`](https://docs.livekit.io/home/self-hosting/local/) +and start it with data tracks enabled: + +```bash +livekit-server --dev +``` + +## Environment variables + +The integration and stress test suites (data tracks, RPC, media multistream, +etc.) require a server URL and two participant tokens: + +```bash +# Required +export LIVEKIT_URL="ws://localhost:7880" # or wss://your-server.livekit.cloud +export LIVEKIT_TOKEN_A="" +export LIVEKIT_TOKEN_B="" + +# Optional (for stress tests) +export RPC_STRESS_DURATION_SECONDS=3600 # Test duration (default: 1 hour) +export RPC_STRESS_CALLER_THREADS=4 # Concurrent caller threads (default: 4) +``` + +### Generating tokens for the test suites + +The easiest path is to source the helper script, which mints both +participant tokens against a local `livekit-server --dev` and exports +`LIVEKIT_TOKEN_A`, `LIVEKIT_TOKEN_B`, and `LIVEKIT_URL` for the current shell: + +```bash +source .token_helpers/set_data_track_test_tokens.bash +``` + +To generate tokens manually (e.g. against a non-default server), install +[`livekit-cli`](https://docs.livekit.io/home/cli/cli-setup/) and run: + +```bash +export LIVEKIT_TOKEN_A="$(lk token create --api-key devkey --api-secret secret -i cpp-test-a \ + --join --valid-for 99999h --room cpp_data_track_test \ + --grant '{"canPublish":true,"canSubscribe":true,"canPublishData":true}' \ + --token-only)" +export LIVEKIT_TOKEN_B="$(lk token create --api-key devkey --api-secret secret -i cpp-test-b \ + --join --valid-for 99999h --room cpp_data_track_test \ + --grant '{"canPublish":true,"canSubscribe":true,"canPublishData":true}' \ + --token-only)" +``` + +## Test coverage + +- **SDK initialization**: initialize / shutdown lifecycle. +- **Room**: room creation, options, connection. +- **Audio frame**: frame creation, manipulation, edge cases. +- **RPC**: round-trip calls, max payload (15 KB), timeouts, errors, concurrent calls. +- **Stress**: high throughput, bidirectional RPC, memory pressure. + +## Memory checks (valgrind) + +Run `valgrind` against the test binaries to check for memory leaks and other +issues. See [tools.md](tools.md) for the recipe. diff --git a/docs/tools.md b/docs/tools.md new file mode 100644 index 00000000..bbcd0124 --- /dev/null +++ b/docs/tools.md @@ -0,0 +1,163 @@ +# Developer tools + +This SDK uses several tools and checks to enforce code quality. All of these +are also enforced in CI on PRs. + +## Clang tools + +- **`clang-tidy`** — static analysis. See [.clang-tidy](../.clang-tidy) for the + enabled checks. Enforced in CI on PR. +- **`clang-format`** — code formatting and style consistency. See + [.clang-format](../.clang-format) for the rules. Enforced in CI on PR. + +> **Note (Windows):** `clang-tidy` is not currently driven by our scripts on +> Windows. The MSBuild CMake generator doesn't emit +> `compile_commands.json`, which `clang-tidy` requires. The Ninja generator +> does, so manual invocation is possible. `clang-format` similarly needs to be +> installed and run manually on Windows, pointing at the root `.clang-format`. + +### Install + +**macOS:** + +```bash +brew install llvm +``` + +This installs `clang-format`, `clang-tidy`, and `run-clang-tidy`. Homebrew may +ask you to add `/opt/homebrew/opt/llvm/bin` (Apple Silicon) or +`/usr/local/opt/llvm/bin` (Intel) to your `PATH`. + +**Linux (Ubuntu/Debian):** + +```bash +sudo apt-get install clang-format clang-tidy clang-tools +``` + +### Run `clang-tidy` + +1. Generate `compile_commands.json` and the protobuf headers via a release build: + + ```bash + ./build.sh release + ``` + +2. Run the wrapper, which uses the same file set, regex filters, and + `.clang-tidy` config as CI: + + ```bash + ./scripts/clang-tidy.sh + ``` + +The wrapper forwards extra arguments to `run-clang-tidy`: + +```bash +./scripts/clang-tidy.sh -j 4 # Number of cores +./scripts/clang-tidy.sh -checks='-*,misc-const-correctness' # Only specific checks +./scripts/clang-tidy.sh -fix # Apply fixes +``` + +Output is captured to `clang-tidy.log` at the repo root, since the terminal +buffer often can't hold all of it. + +### Run `clang-format` + +```bash +./scripts/clang-format.sh +``` + +With no arguments, runs against every relevant file in the repository against +the rules in `.clang-format`. + +```bash +./scripts/clang-format.sh --fix # Rewrite files in place +./scripts/clang-format.sh src/room.cpp include/livekit/room.h # Check just these files +./scripts/clang-format.sh --fix src/room.cpp # Fix just this file +``` + +Output is captured to `clang-format.log` at the repo root. + +--- + +## Pre-commit hook + +A simple pre-commit hook that auto-formats staged C/C++ files using the +project's `.clang-format` rules: + +```bash +./scripts/install-pre-commit.sh +``` + +This installs `.git/hooks/pre-commit`. Re-run after `git clone` on a fresh +checkout. + +--- + +## Memory checks (valgrind) + +Run `valgrind` against the integration or stress test binaries to check for +memory leaks and other issues: + +```bash +valgrind --leak-check=full ./build-debug/bin/livekit_integration_tests +valgrind --leak-check=full ./build-debug/bin/livekit_stress_tests +``` + +`valgrind` is Linux-only. On macOS, use `leaks` or Instruments instead. + +--- + +## API documentation (Doxygen) + +API reference is generated from headers using Doxygen. To rebuild locally: + +```bash +./scripts/generate-docs.sh +``` + +Output lands under `docs/doxygen/html/`. The deployed reference is at +[docs.livekit.io/reference/client-sdk-cpp/](https://docs.livekit.io/reference/client-sdk-cpp/). + +To view the generated documentation locally, open `docs/doxygen/html/index.html` in your browser. + +For details on the Doxygen configuration and CI pipeline, see the +[doxygen/](doxygen/) folder. + +--- + +## Development tips + +### Bump the pinned Rust submodule + +```bash +cd client-sdk-cpp +git fetch origin +git switch -c try-rust-main origin/main + +# Sync submodule URLs and check out what origin/main pins (recursively): +git submodule sync --recursive +git submodule update --init --recursive --checkout + +# If the nested submodule under yuv-sys didn't materialize, force it: +git -C client-sdk-rust/yuv-sys submodule sync --recursive +git -C client-sdk-rust/yuv-sys submodule update --init --recursive --checkout + +# Sanity check: +git submodule status --recursive +``` + +### If `yuv-sys` fails to build + +```bash +cargo clean -p yuv-sys +cargo build -p yuv-sys -vv +``` + +### Full clean (Rust + C++ build folders) + +To delete all build artifacts from both Rust and C++ folders, plus the +local-install folder: + +```bash +./build.sh clean-all +``` diff --git a/docs/tracing.md b/docs/tracing.md new file mode 100644 index 00000000..f74fa75c --- /dev/null +++ b/docs/tracing.md @@ -0,0 +1,35 @@ +# Tracing + +The SDK includes built-in support for [Chromium tracing](https://www.chromium.org/developers/how-tos/trace-event-profiling-tool/), +allowing you to capture detailed performance traces for debugging and +optimization. + +## Basic usage + +```cpp +#include + +// Start tracing to a file +livekit::startTracing("trace.json"); + +// ... run your application ... + +// Stop tracing and flush to file +livekit::stopTracing(); +``` + +## Filtering by category + +You can optionally filter which categories to trace: + +```cpp +// Trace only specific categories (supports wildcards) +livekit::startTracing("trace.json", {"livekit.*", "webrtc.*"}); +``` + +## Viewing traces + +Open the generated trace file in one of these viewers: + +- **Chrome**: navigate to `chrome://tracing` and click "Load" to open the trace file. +- **Perfetto**: open [ui.perfetto.dev](https://ui.perfetto.dev) and drag-drop your trace file. diff --git a/scripts/generate-docs.sh b/scripts/generate-docs.sh index cd373f1f..22d442a3 100755 --- a/scripts/generate-docs.sh +++ b/scripts/generate-docs.sh @@ -154,7 +154,7 @@ cp "$repo_root/docs/doxygen/Doxyfile" "$doxyfile_tmp" { echo "" echo "# Local override generated by scripts/generate-docs.sh" - echo "INPUT = include/livekit ${mainpage_rel} README_BUILD.md" + echo "INPUT = include/livekit ${mainpage_rel} docs/README.md docs/building.md docs/logging.md docs/tracing.md docs/testing.md docs/tools.md" echo "USE_MDFILE_AS_MAINPAGE = ${mainpage_rel}" } >>"$doxyfile_tmp" diff --git a/scripts/install-pre-commit.sh b/scripts/install-pre-commit.sh new file mode 100755 index 00000000..fa37da84 --- /dev/null +++ b/scripts/install-pre-commit.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# +# Copyright 2026 LiveKit +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# install-pre-commit.sh -- Install a git pre-commit hook that runs +# `scripts/clang-format.sh --fix` on staged C/C++ files. Re-stages any +# files the formatter rewrote so the commit includes the fixes. + +set -euo pipefail + +repo_root="$(git rev-parse --show-toplevel)" +hook_path="${repo_root}/.git/hooks/pre-commit" + +cat >"${hook_path}" <<'HOOK' +#!/bin/sh +# Auto-format staged C/C++ files using ./scripts/clang-format.sh --fix. +files=$(git diff --cached --name-only --diff-filter=ACMR \ + -- "*.c" "*.cc" "*.cpp" "*.cxx" "*.h" "*.hpp" "*.hxx") +[ -z "${files}" ] && exit 0 +echo "${files}" | xargs ./scripts/clang-format.sh --fix +echo "${files}" | xargs git add +HOOK + +chmod +x "${hook_path}" +echo "Installed pre-commit hook at ${hook_path}"
LiveKit Ecosystem
Agents SDKsPython · Node.js
LiveKit SDKsBrowser · Swift · Android · Flutter · React Native · Rust · Node.js · Python · Unity · Unity (WebGL) · ESP32 · C++
LiveKit SDKsBrowser · Swift · Android · Flutter · React Native · Rust · Node.js · Python · Unity · Unity (WebGL) · ESP32 · C++
Starter AppsPython Agent · TypeScript Agent · React App · SwiftUI App · Android App · Flutter App · React Native App · Web Embed
UI ComponentsReact · Android Compose · SwiftUI · Flutter
Server APIsNode.js · Golang · Ruby · Java/Kotlin · Python · Rust · PHP (community) · .NET (community)
Server APIsNode.js · Golang · Ruby · Java/Kotlin · Python · Rust · PHP (community) · .NET (community)
ResourcesDocs · Docs MCP Server · CLI · LiveKit Cloud
LiveKit Server OSSLiveKit server · Egress · Ingress · SIP
CommunityDeveloper Community · Slack · X · YouTube