A C++ SDK for Decart's realtime models. It speaks the same realtime + auth protocol as the JavaScript, Python, iOS, and Android SDKs, and is built on the official LiveKit C++ SDK for media transport.
Status: v0.1 — focused on realtime video transformation and authentication.
- Realtime — publish a video stream, get back the model-transformed stream, and steer it live with prompts and reference images.
- Auth — mint short-lived client tokens from a server-side API key.
- Native, header-light public API; LiveKit types only where you actually touch media.
- C++17 and CMake ≥ 3.20
- Platforms (from the LiveKit C++ SDK): Linux (x64/arm64), macOS 12.3+ (Apple Silicon & Intel), Windows (x64)
- Dependencies (resolved automatically — see below): LiveKit C++ SDK, IXWebSocket, nlohmann/json
include(FetchContent)
FetchContent_Declare(decart
GIT_REPOSITORY https://github.com/DecartAI/decart-cpp.git
GIT_TAG v0.1.0)
FetchContent_MakeAvailable(decart)
target_link_libraries(your_app PRIVATE decart::decart)The first configure downloads a prebuilt LiveKit release and fetches IXWebSocket /
nlohmann/json. Set DECART_LIVEKIT_VERSION to pin a LiveKit release, or
DECART_LIVEKIT_LOCAL_DIR to point at a local install. The LiveKit FFI runtime
library is copied next to your executable automatically via
decart_copy_livekit_runtime(your_app).
nlohmann-json and ixwebsocket are declared in vcpkg.json. Configure with the
vcpkg toolchain (LiveKit is still fetched as a prebuilt release):
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake
cmake --build buildadd_subdirectory(third_party/decart-cpp)
target_link_libraries(your_app PRIVATE decart::decart)You drive a livekit::VideoSource (push your camera/render frames into it); the
SDK publishes it and hands you the transformed frames.
#include <decart/decart.h>
#include <livekit/livekit.h>
decart::Client client; // reads DECART_API_KEY
auto model = decart::models::realtime("lucy-restyle-2");
auto source = std::make_shared<livekit::VideoSource>(model.width, model.height);
decart::ConnectOptions options;
options.model = model;
options.initialState.prompt = decart::Prompt{"A watercolor painting", /*enhance=*/true};
options.onConnectionState = [](decart::ConnectionState s) {
std::printf("state: %s\n", decart::toString(s));
};
options.onRemoteFrame = [](const livekit::VideoFrame& frame, std::int64_t /*ts_us*/) {
// Render `frame` (RGBA). Runs on a reader thread — keep it quick.
};
auto session = client.realtime().connect(source, options);
// Push frames into `source` from your capture/render loop:
// source->captureFrame(myFrame);
// Steer the model live:
session->setPrompt("Cyberpunk city");
session->disconnect();See examples/realtime_synthetic.cpp for a
complete, runnable program that publishes synthetic frames, and
examples/realtime_video.cpp to stream a real
video file through a model and save the transformed result (uses ffmpeg to
decode/encode):
DECART_API_KEY=... ./realtime_video input.mp4 output.mp4 "put them all in space" lucy-2.1Billing is tied to active generation — the seconds during which frames flow to
the model. You can establish the authenticated session and WebRTC media path
ahead of time and hold it idle at no cost by connecting with startMuted = true,
then unmute() when the user is ready. This removes startup latency from the
moment they hit Start. (An idle WebRTC track still emits keepalive frames, so
muting — not merely withholding captureFrame() — is what keeps a warmed session
unbilled.)
decart::ConnectOptions options;
options.model = model;
options.initialState.prompt = decart::Prompt{"A watercolor painting", /*enhance=*/true};
options.startMuted = true; // warm, but transmit nothing
auto session = client.realtime().connect(source, options); // authenticated, idle, unbilled
// ... later, when the user clicks Start:
session->unmute(); // generation (and billing) begins
// source->captureFrame(myFrame); // push frames from here on
// If the user cancels first, session->disconnect() — no charge.See examples/realtime_warmup.cpp for a complete,
runnable example.
Create a short-lived token server-side to hand to an untrusted client:
decart::Client client; // server-side API key
decart::CreateTokenOptions opts;
opts.expiresIn = 300; // seconds
opts.allowedModels = {"lucy-restyle-2"};
auto token = client.tokens().create(opts);
// token.apiKey -> "ek_...", token.expiresAt -> ISO-8601decart::ClientOptions options;
options.apiKey = "sk-..."; // or set DECART_API_KEY
options.baseUrl = "https://api.decart.ai"; // HTTP API (tokens)
options.realtimeBaseUrl = "wss://api3.decart.ai"; // signaling
options.integration = "my-app"; // included in the User-Agent
decart::Client client(options);Errors surface as decart::Exception (synchronous failures) carrying a structured
decart::Error{code, message}; asynchronous session errors are delivered to
ConnectOptions::onError.
A realtime session is two channels: a WebSocket signaling connection to Decart
that performs the room handshake and carries prompt/image control messages, and a
LiveKit (WebRTC) room that carries the media. The SDK opens the socket, joins,
publishes your VideoSource, subscribes to the inference server's output track, and
pumps decoded frames to your onRemoteFrame callback.
cmake --preset release # configure (downloads deps)
cmake --build --preset release # build library, examples, tests
ctest --preset release # run unit testsUseful options: DECART_BUILD_EXAMPLES, DECART_BUILD_TESTS,
DECART_LIVEKIT_VERSION (pin a LiveKit release), DECART_LIVEKIT_LOCAL_DIR
(use a local LiveKit install instead of downloading), and
DECART_BUILD_REALTIME=OFF for an auth/tokens-only build with no LiveKit
dependency (no Rust toolchain, no FFI download) — Client::realtime() is then
compiled out, leaving Client::tokens().
- Input frames are provided by you via
livekit::VideoSource(full control over your capture pipeline). Audio is not published in v0.1. - Reference images accept a local file path, a
data:URL, or raw base64. - Reconnection: LiveKit auto-recovers the media transport; the signaling
socket is single-shot in v0.1 (a drop after connect is surfaced via
onError). - Not yet included (planned):
checkConnectivitypreflight, audio, queue/image generation APIs, proxy mode.
MIT — see LICENSE.