|
| 1 | +# AGENTS.md — LiveKit C++ Client SDK |
| 2 | + |
| 3 | +## Project Overview |
| 4 | + |
| 5 | +This is **client-sdk-cpp**, the official LiveKit C++ client SDK. It wraps a Rust core (`client-sdk-rust/`) via a protobuf-based FFI bridge. All WebRTC, networking, and media logic lives in Rust; the C++ layer provides an ergonomic API for C++ consumers. |
| 6 | + |
| 7 | +## Architecture |
| 8 | + |
| 9 | +### Core Principle |
| 10 | +Rust owns as much of the business logic as possible. If a feature may be used by another SDK it should be implemented in Rust. Since this is an SDK, |
| 11 | +ensure backwards compatibility is maintained when possible. |
| 12 | + |
| 13 | + |
| 14 | +### Platform Support |
| 15 | +The SDK must be supported on the following platforms: |
| 16 | +1. windows x64 |
| 17 | +2. linux x86_64 |
| 18 | +3. linux arm64 |
| 19 | +3. macOS x86_64 |
| 20 | +4. macOS arm64 |
| 21 | + |
| 22 | + |
| 23 | +SDK features follow pattern: |
| 24 | + |
| 25 | +1. Serialize a protobuf `FfiRequest` message. |
| 26 | +2. Send it to Rust via `FfiClient::instance().sendRequest(req)`. |
| 27 | +3. Receive a synchronous `FfiResponse` or an asynchronous `FfiEvent` callback. |
| 28 | +4. Expose the result through the C++ API. |
| 29 | + |
| 30 | +When making larger scale changes, check with the developer before committing to architecture changes involving changes to the `client-sdk-rust/` submodule. |
| 31 | + |
| 32 | +### Directory Layout |
| 33 | + |
| 34 | +| Path | Description | |
| 35 | +|------|-------------| |
| 36 | +| `include/livekit/` | Public API headers (what SDK consumers include) | |
| 37 | +| `src/` | Implementation files and internal-only headers (`ffi_client.h`, `lk_log.h`, etc.) | |
| 38 | +| `src/tests/` | Google Test integration and stress tests | |
| 39 | +| `examples/` | In-tree example applications | |
| 40 | +| `bridge/` | **Deprecated** C-style bridge layer — do not add new functionality | |
| 41 | +| `client-sdk-rust/` | Git submodule holding the Rust core of the SDK| |
| 42 | +| `client-sdk-rust/livekit-ffi/protocol/*.proto` | FFI contract (protobuf definitions, read-only reference) | |
| 43 | +| `cmake/` | Build helpers (`protobuf.cmake`, `spdlog.cmake`, `LiveKitConfig.cmake.in`) | |
| 44 | +| `docker/` | Dockerfile for CI and SDK distribution images | |
| 45 | +| `.github/workflows/` | GitHub Actions CI workflows | |
| 46 | + |
| 47 | +### Key Types |
| 48 | + |
| 49 | +- **`FfiClient`** — Singleton that sends FFI requests to Rust and dispatches event callbacks. Defined in `src/ffi_client.h` (internal). |
| 50 | +- **`FfiHandle`** — RAII wrapper for Rust-owned resource handles; drop releases the FFI resource. |
| 51 | +- **`Room`** — Central object for connecting to a LiveKit server room. |
| 52 | +- **`RoomDelegate`** — Virtual callback interface for room lifecycle events. |
| 53 | +- **`SubscriptionThreadDispatcher`** — Owns callback registrations and per-subscription reader threads for audio, video, and data tracks. `Room` delegates callback management here. |
| 54 | +- **`LocalParticipant` / `RemoteParticipant`** — Participant objects for publishing and receiving tracks. |
| 55 | + |
| 56 | +## Build |
| 57 | +for building, use the build.sh script for Linux and macOS, and the build.cmd script for Windows. Do not invoke CMake directly. |
| 58 | + |
| 59 | +``` |
| 60 | +./build.sh debug # Debug build |
| 61 | +./build.sh debug-tests # Debug build with tests |
| 62 | +./build.sh debug-examples # Debug build with examples |
| 63 | +./build.sh release # Release build |
| 64 | +./build.sh release-tests # Release build with tests |
| 65 | +./build.sh release-examples # Release build with examples |
| 66 | +./build.sh build-all # All of the above |
| 67 | +./build.sh clean # Clean build artifacts |
| 68 | +./build.sh clean-all # Full clean (C++ + Rust targets) |
| 69 | +``` |
| 70 | + |
| 71 | +**Requirements:** CMake 3.20+, C++17, Rust toolchain (cargo), protoc. On macOS: `brew install cmake ninja protobuf abseil spdlog`. On Linux: see the CI workflow for apt packages. |
| 72 | + |
| 73 | +### SDK Packaging |
| 74 | + |
| 75 | +``` |
| 76 | +./build.sh release --bundle --prefix /path/to/install |
| 77 | +``` |
| 78 | + |
| 79 | +This installs headers, libraries, and CMake config files so downstream projects can use `find_package(LiveKit CONFIG)`. |
| 80 | + |
| 81 | +## Coding Conventions |
| 82 | + |
| 83 | +### Copyright Header |
| 84 | + |
| 85 | +All source files must have the LiveKit Apache 2.0 copyright header. Use the current year for new files. Do not copyright externally pulled/cloned files. |
| 86 | + |
| 87 | +### Logging |
| 88 | + |
| 89 | +- Use `LK_LOG_*` macros from `src/lk_log.h` (internal header, **not** public API). |
| 90 | +- `LK_LOG_ERROR` — when something is broken. |
| 91 | +- `LK_LOG_WARN` — when something is unexpected but recoverable. |
| 92 | +- `LK_LOG_INFO` — initialization, critical state changes. |
| 93 | +- `LK_LOG_DEBUG` — potentially useful diagnostic info. |
| 94 | +- Do not spam logs. Keep it concise. |
| 95 | +- In production/internal SDK code, do not use `std::cout`, `std::cerr`, `printf`, or raw spdlog calls; use the logging APIs instead. Tests may use standard streams sparingly for ad hoc diagnostics when appropriate. |
| 96 | +- The public logging API is `include/livekit/logging.h` (`setLogLevel`, `setLogCallback`). spdlog is a **private** dependency — it must never leak into public headers. |
| 97 | + |
| 98 | +### Public API Surface |
| 99 | + |
| 100 | +- Keep public APIs small. Minimize what goes into `include/livekit/`. |
| 101 | +- Never introduce backwards compatibility breaking changes to the public API. |
| 102 | +- `lk_log.h` lives under `src/` (internal). The public-facing logging API is `include/livekit/logging.h`. |
| 103 | +- spdlog must not appear in any public header or installed header. |
| 104 | + |
| 105 | +### Error Handling |
| 106 | + |
| 107 | +- Throw exceptions for broken/unrecoverable states. |
| 108 | +- Use `LK_LOG_WARN` for non-fatal unexpected conditions. |
| 109 | +- Use `Result<T, E>` for operations that can fail with typed errors (e.g., data track publish/subscribe). |
| 110 | + |
| 111 | +### Git Practices |
| 112 | + |
| 113 | +- Use `git mv` when moving or renaming files. |
| 114 | + |
| 115 | +### CMake |
| 116 | + |
| 117 | +- spdlog is linked **PRIVATE** to the `livekit` target. It must not appear in exported/installed dependencies. |
| 118 | +- protobuf is vendored via FetchContent on non-Windows platforms; Windows uses vcpkg. |
| 119 | +- The CMake install produces a `find_package(LiveKit CONFIG)`-compatible package with `LiveKitConfig.cmake`, `LiveKitTargets.cmake`, and `LiveKitConfigVersion.cmake`. |
| 120 | + |
| 121 | +### Readability and Performance |
| 122 | +Code should be easy to read and understand. If a sacrifice is made for performance or readability, it should be documented. |
| 123 | +## Dependencies |
| 124 | + |
| 125 | +| Dependency | Scope | Notes | |
| 126 | +|------------|-------|-------| |
| 127 | +| protobuf | Private (built-in) | Vendored via FetchContent (Unix) or vcpkg (Windows) | |
| 128 | +| spdlog | **Private** | FetchContent or system package; must NOT leak into public API | |
| 129 | +| client-sdk-rust | Build-time | Git submodule, built via cargo during CMake build | |
| 130 | +| Google Test | Test only | FetchContent in `src/tests/CMakeLists.txt` | |
| 131 | + |
| 132 | +## Testing |
| 133 | + |
| 134 | +Tests are under `src/tests/` using Google Test: |
| 135 | + |
| 136 | +``` |
| 137 | +./build.sh debug-tests |
| 138 | +cd build-debug && ctest |
| 139 | +``` |
| 140 | + |
| 141 | +Integration tests (`src/tests/integration/`) cover: room connections, callbacks, data tracks, RPC, logging, audio processing, and the subscription thread dispatcher. |
| 142 | + |
| 143 | +When adding new client facing functionality, add a new test case to the existing test suite. |
| 144 | +When adding new client facing functionality, add benchmarking to understand the limitations of the new functionality. |
| 145 | + |
| 146 | +## Formatting |
| 147 | +Adhere to the formatting rules if TODO: @alan |
| 148 | + |
| 149 | +## Deprecated / Out of Scope |
| 150 | + |
| 151 | +- **`bridge/`** (`livekit_bridge`) is deprecated. Do not add new functionality to it. |
| 152 | + |
| 153 | +## Common Pitfalls |
| 154 | + |
| 155 | +- A `Room` with `auto_subscribe = false` will never receive remote audio/video frames — this is almost never what you want. |
| 156 | +- A single participant cannot subscribe to its own tracks as "remote." Testing sender/receiver requires two separate room connections with distinct identities. |
| 157 | +- macOS dylibs require `install_name_tool` fixups for `@rpath` — the CMakeLists.txt handles this automatically. Do not manually adjust RPATH unless you understand the implications. |
| 158 | +- When consuming the installed SDK, use `-DLIVEKIT_LOCAL_SDK_DIR=/path/to/sdk` to point cmake at a local install instead of downloading a release tarball. |
0 commit comments