Skip to main content

C++ quickstart

Get started with LiveKit using the C++ SDK.

Overview

The C++ SDK connects native desktop, server, robotics, and embedded applications to LiveKit rooms.

Supported platforms

The SDK is built and released for the following platforms:

PlatformArchitecture
Windowsx64
Linuxx86_64 and ARM
macOSx86_64 and ARM
Nvidia JetsonARM
Raspberry PiARM

If no prebuilt release asset matches your platform, LiveKitSDK.cmake fails during CMake configure. In that case, build the SDK from source and use LIVEKIT_LOCAL_SDK_DIR.

Install the C++ SDK

The easiest way to consume the SDK is to use a prebuilt release. The C++ example collection  includes a CMake helper  that downloads the matching prebuilt SDK archive during CMake configure and makes find_package(LiveKit CONFIG REQUIRED) work. It also lets you point at a local C++ SDK install.

  1. Copy cmake/LiveKitSDK.cmake  into your project's cmake/ directory.

  2. Include the helper in your app's CMakeLists.txt file:

    cmake_minimum_required(VERSION 3.20)
    project(livekit_cpp_quickstart LANGUAGES CXX)
    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
    if(LIVEKIT_LOCAL_SDK_DIR)
    list(PREPEND CMAKE_PREFIX_PATH "${LIVEKIT_LOCAL_SDK_DIR}")
    else()
    include(LiveKitSDK)
    livekit_sdk_setup(
    VERSION "${LIVEKIT_SDK_VERSION}"
    SDK_DIR "${CMAKE_BINARY_DIR}/_deps/livekit-sdk"
    GITHUB_TOKEN "$ENV{GITHUB_TOKEN}"
    )
    endif()
    find_package(LiveKit CONFIG REQUIRED)
    add_executable(example example.cpp)
    target_link_libraries(example PRIVATE LiveKit::livekit)
  3. Configure and build your project:

    cmake -S . -B build -DLIVEKIT_SDK_VERSION=latest
    cmake --build build
    Pin SDK versions

    Use a fixed version from the official C++ SDK releases page  for reproducible builds. The latest option queries the GitHub API and may need GITHUB_TOKEN in CI to avoid rate limits.

Use a local SDK build

You may want to use a local SDK build to use a specific version of the SDK that is not yet released, or to test local changes to the SDK. To build the SDK from source, clone the C++ SDK repository  with submodules and install it to a local prefix:

git clone --recurse-submodules https://github.com/livekit/client-sdk-cpp.git
cd client-sdk-cpp
# Build the SDK:
# --bundle installs the SDK bundle using 'cmake --install'
# --prefix specifies where to install the SDK
./build.sh release --bundle --prefix "$HOME/livekit-sdk"

Then configure your app with the local install prefix:

cmake -S . -B build -DLIVEKIT_LOCAL_SDK_DIR="$HOME/livekit-sdk"
cmake --build build

Connecting to LiveKit

The following example connects to a room and publishes synthetic audio and video tracks. It generates a sine wave and a moving color pattern so you can verify publishing without device capture.

For a production app, make the following changes:

  • Generate tokens on your server instead of embedding tokens in the app.
  • Replace synthetic media generation with your own camera and microphone capture. For a complete SDL-based example, see simple_room .

Run an example

  1. Create a file named example.cpp with the following content:

    #include <atomic>
    #include <chrono>
    #include <cmath>
    #include <csignal>
    #include <cstdint>
    #include <cstdlib>
    #include <exception>
    #include <iostream>
    #include <memory>
    #include <thread>
    #include <vector>
    #include "livekit/livekit.h"
    namespace {
    std::atomic<bool> g_running{true};
    void handleSignal(int) { g_running.store(false); }
    void generateAudio(const std::shared_ptr<livekit::AudioSource>& audio_source) {
    constexpr int kSampleRate = 48000;
    constexpr int kChannels = 1;
    constexpr int kSamplesPer10Ms = kSampleRate / 100;
    constexpr double kFrequencyHz = 440.0;
    constexpr double kPi = 3.14159265358979323846;
    std::uint64_t sample_index = 0;
    while (g_running.load()) {
    std::vector<std::int16_t> samples(kSamplesPer10Ms * kChannels);
    for (int i = 0; i < kSamplesPer10Ms; ++i) {
    const double t = static_cast<double>(sample_index++) / kSampleRate;
    const double value = std::sin(2.0 * kPi * kFrequencyHz * t);
    samples[i] = static_cast<std::int16_t>(value * 16000.0);
    }
    livekit::AudioFrame frame(std::move(samples), kSampleRate, kChannels, kSamplesPer10Ms);
    audio_source->captureFrame(frame);
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
    }
    void generateVideo(const std::shared_ptr<livekit::VideoSource>& video_source) {
    constexpr int kWidth = 1280;
    constexpr int kHeight = 720;
    constexpr int kFps = 30;
    int frame_count = 0;
    while (g_running.load()) {
    auto frame = livekit::VideoFrame::create(kWidth, kHeight, livekit::VideoBufferType::RGBA);
    std::uint8_t* pixels = frame.data();
    const auto hue = static_cast<std::uint8_t>((frame_count * 2) % 256);
    for (int y = 0; y < kHeight; ++y) {
    for (int x = 0; x < kWidth; ++x) {
    const int offset = (y * kWidth + x) * 4;
    pixels[offset] = static_cast<std::uint8_t>((x * 255) / kWidth);
    pixels[offset + 1] = static_cast<std::uint8_t>((y * 255) / kHeight);
    pixels[offset + 2] = hue;
    pixels[offset + 3] = 255;
    }
    }
    video_source->captureFrame(frame);
    ++frame_count;
    std::this_thread::sleep_for(std::chrono::milliseconds(1000 / kFps));
    }
    }
    } // namespace
    int main() {
    const char* url = std::getenv("LIVEKIT_URL");
    const char* token = std::getenv("LIVEKIT_TOKEN");
    if (url == nullptr || token == nullptr) {
    std::cerr << "Set LIVEKIT_URL and LIVEKIT_TOKEN environment variables\n";
    return 1;
    }
    std::signal(SIGINT, handleSignal);
    livekit::initialize(livekit::LogLevel::Info);
    auto room = std::make_unique<livekit::Room>();
    livekit::RoomOptions room_options;
    room_options.auto_subscribe = true;
    if (!room->connect(url, token, room_options)) {
    std::cerr << "Failed to connect\n";
    livekit::shutdown();
    return 1;
    }
    std::cout << "Connected to room\n";
    auto audio_source = std::make_shared<livekit::AudioSource>(48000, 1);
    auto audio_track = livekit::LocalAudioTrack::createLocalAudioTrack("audio", audio_source);
    livekit::TrackPublishOptions audio_options;
    audio_options.source = livekit::TrackSource::SOURCE_MICROPHONE;
    try {
    if (auto lp = room->localParticipant().lock()) {
    lp->publishTrack(audio_track, audio_options);
    }
    else
    {
    std::cerr << "Failed to get local participant\n";
    return 1;
    }
    std::cout << "Published audio track\n";
    } catch (const std::exception& error) {
    std::cerr << "Failed to publish audio: " << error.what() << "\n";
    return 1;
    }
    auto video_source = std::make_shared<livekit::VideoSource>(1280, 720);
    auto video_track = livekit::LocalVideoTrack::createLocalVideoTrack("video", video_source);
    livekit::TrackPublishOptions video_options;
    video_options.source = livekit::TrackSource::SOURCE_CAMERA;
    try {
    if (auto lp = room->localParticipant().lock()) {
    lp->publishTrack(video_track, video_options);
    }
    else
    {
    std::cerr << "Failed to get local participant\n";
    return 1;
    }
    std::cout << "Published video track\n";
    } catch (const std::exception& error) {
    std::cerr << "Failed to publish video: " << error.what() << "\n";
    return 1;
    }
    std::thread audio_thread(generateAudio, audio_source);
    std::thread video_thread(generateVideo, video_source);
    std::cout << "Streaming synthetic audio and video. Press Ctrl+C to stop.\n";
    while (g_running.load()) {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    if (audio_thread.joinable()) {
    audio_thread.join();
    }
    if (video_thread.joinable()) {
    video_thread.join();
    }
    room.reset();
    livekit::shutdown();
    return 0;
    }
  2. Set environment variables with your LiveKit server URL and access token:

    export LIVEKIT_URL=wss://your-livekit-server.com
    export LIVEKIT_TOKEN=your-access-token
  3. Run the example:

    ./build/example

    The program connects to a LiveKit room and streams a 440 Hz sine wave audio tone and an animated color gradient video. Press Ctrl+C to stop.

Capturing real media

The SDK accepts raw audio and video frames from your application. It doesn't open the camera or microphone for you. For physical device capture, see the simple_room  example, which uses SDL3.

Permissions and entitlements

Most C++ applications don't need operating system permission prompts unless the app accesses physical microphones, cameras, screens, or other devices. Headless or synthetic sources don't require special device permissions.

Microphone or camera capture:

Operating systemRequired permissions
macOSAdd NSMicrophoneUsageDescription and NSCameraUsageDescription to your app bundle when applicable.
Windows/LinuxDevice permissions are typically managed by the OS, desktop session, container runtime, or user group membership.

Screen capture:

Operating systemRequired permissions
macOSAdd Screen Recording permission for your app in System Settings.
Windows/LinuxScreen capture permissions are typically managed by the OS, desktop session, display server, or portal implementation.

Next steps

The following resources are useful for getting started with LiveKit on C++.