Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ include(warnings)

option(LIVEKIT_BUILD_EXAMPLES "Build LiveKit examples" OFF)
option(LIVEKIT_BUILD_TESTS "Build LiveKit tests" OFF)
option(LIVEKIT_ENABLE_ENCODED_VIDEO "Enable encoded video support in the Rust FFI" OFF)

# vcpkg is only used on Windows; Linux/macOS use system package managers
if(WIN32)
Expand Down Expand Up @@ -148,6 +149,8 @@ endforeach()

add_custom_command(
OUTPUT ${PROTO_SRCS} ${PROTO_HDRS}
COMMAND ${CMAKE_COMMAND} -E rm -rf ${PROTO_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROTO_BINARY_DIR}
Comment on lines +151 to +152
COMMAND ${Protobuf_PROTOC_EXECUTABLE}
--proto_path=${FFI_PROTO_DIR}
--cpp_out=${PROTO_BINARY_DIR}
Expand Down Expand Up @@ -259,12 +262,16 @@ if(NOT CFG STREQUAL \"Debug\")
list(APPEND ARGS --release)
endif()

if(DEFINED CARGO_FEATURES AND NOT CARGO_FEATURES STREQUAL \"\")
list(APPEND ARGS --features \"\${CARGO_FEATURES}\")
endif()

if(DEFINED RUST_TARGET AND NOT RUST_TARGET STREQUAL \"\")
list(APPEND ARGS --target \"\${RUST_TARGET}\")
message(STATUS \"[run_cargo.cmake] Cross-compiling for target: \${RUST_TARGET}\")
endif()

message(STATUS \"[run_cargo.cmake] CFG=\${CFG} CARGO=\${CARGO} PROTOC=\${PROTOC_PATH}\")
message(STATUS \"[run_cargo.cmake] CFG=\${CFG} CARGO=\${CARGO} PROTOC=\${PROTOC_PATH} FEATURES=\${CARGO_FEATURES}\")
set(ENV{PROTOC} \"\${PROTOC_PATH}\")

if(DEFINED GCC_LIB_DIR AND NOT GCC_LIB_DIR STREQUAL \"\")
Expand Down Expand Up @@ -346,6 +353,11 @@ file(GLOB_RECURSE RUST_SOURCES
"${RUST_ROOT}/livekit-ffi/Cargo.toml"
)

set(LIVEKIT_RUST_FFI_FEATURES "")
if(LIVEKIT_ENABLE_ENCODED_VIDEO)
set(LIVEKIT_RUST_FFI_FEATURES "livekit-ffi/encoded-video")
endif()

add_custom_command(
OUTPUT "${RUST_LIB_DEBUG}" "${RUST_LIB_RELEASE}"
COMMAND "${CMAKE_COMMAND}"
Expand All @@ -355,6 +367,7 @@ add_custom_command(
-DPROTOC_PATH=${Protobuf_PROTOC_EXECUTABLE}
-DRUST_TARGET=${RUST_TARGET_TRIPLE}
-DGCC_LIB_DIR=${GCC_LIB_DIR}
-DCARGO_FEATURES=${LIVEKIT_RUST_FFI_FEATURES}
-P "${RUN_CARGO_SCRIPT}"
WORKING_DIRECTORY "${RUST_ROOT}"
DEPENDS ${RUST_SOURCES}
Expand Down Expand Up @@ -474,6 +487,8 @@ if(LIVEKIT_IS_TOPLEVEL)
# Copy public headers to build/include (build.h is already in include/livekit/)
add_custom_command(
TARGET livekit POST_BUILD
COMMAND ${CMAKE_COMMAND} -E rm -rf
${CMAKE_BINARY_DIR}/include/livekit
Comment on lines +483 to +484
COMMAND ${CMAKE_COMMAND} -E copy_directory
${LIVEKIT_ROOT_DIR}/include
${CMAKE_BINARY_DIR}/include
Expand Down Expand Up @@ -729,6 +744,9 @@ endif()


# Install public headers (includes generated build.h which is now in include/livekit/)
install(CODE
"file(REMOVE_RECURSE \"\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/livekit\")"
)
Comment on lines +740 to +742
install(DIRECTORY "${CMAKE_SOURCE_DIR}/include/"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp"
Expand Down
3 changes: 2 additions & 1 deletion build.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ set "PRESET=windows-release"
set "LIVEKIT_VERSION="
set "CMAKE_EXTRA_ARGS="
set "BUILD_PARALLEL_JOBS="
set "CMAKE_EXTRA_ARGS=-DLIVEKIT_ENABLE_ENCODED_VIDEO=ON"

REM ============================================================
REM Auto-detect LIBCLANG_PATH if not already set
Expand Down Expand Up @@ -105,7 +106,7 @@ if not defined CMD (
)

if defined LIVEKIT_VERSION (
set "CMAKE_EXTRA_ARGS=-DLIVEKIT_VERSION=%LIVEKIT_VERSION%"
set "CMAKE_EXTRA_ARGS=%CMAKE_EXTRA_ARGS% -DLIVEKIT_VERSION=%LIVEKIT_VERSION%"
echo ==^> Injecting LIVEKIT_VERSION=%LIVEKIT_VERSION%
)
goto dispatch
Expand Down
1 change: 1 addition & 0 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ configure() {
echo "==> Injecting LIVEKIT_VERSION=${LIVEKIT_VERSION}"
extra_args+=("-DLIVEKIT_VERSION=${LIVEKIT_VERSION}")
fi
extra_args+=("-DLIVEKIT_ENABLE_ENCODED_VIDEO=ON")
if [[ -n "${MACOS_ARCH}" ]]; then
echo "==> Setting CMAKE_OSX_ARCHITECTURES=${MACOS_ARCH}"
extra_args+=("-DCMAKE_OSX_ARCHITECTURES=${MACOS_ARCH}")
Expand Down
3 changes: 2 additions & 1 deletion include/livekit/livekit.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@
#include "livekit/audio_stream.h"
#include "livekit/build.h"
#include "livekit/e2ee.h"
// Note: "livekit/encoded_tcp_ingest.h" was removed per 'rm tcp ingest' commit.
#include "livekit/local_audio_track.h"
#include "livekit/local_participant.h"
#include "livekit/local_track_publication.h"
#include "livekit/local_video_track.h"
#include "livekit/logging.h"
#include "livekit/participant.h"
#include "livekit/platform_audio.h"
// Note: Add platform_audio.h if present in your project; omitted here since 'rm tcp ingest' side didn't include it.
#include "livekit/remote_participant.h"
Comment thread
stephen-derosa marked this conversation as resolved.
#include "livekit/remote_track_publication.h"
#include "livekit/room.h"
Expand Down
9 changes: 8 additions & 1 deletion include/livekit/room_event_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,14 @@ class LocalTrackPublication;
class RemoteTrackPublication;
class TrackPublication;

enum class VideoCodec;
enum class VideoCodec {
VP8 = 0,
H264 = 1,
AV1 = 2,
VP9 = 3,
H265 = 4,
};

enum class TrackSource;

/// Overall quality of a participant's connection.
Expand Down
68 changes: 63 additions & 5 deletions include/livekit/video_source.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@

#pragma once

#include <cstddef>
#include <cstdint>
#include <memory>
#include <mutex>
#include <optional>
#include <vector>

#include "livekit/ffi_handle.h"
#include "livekit/visibility.h"
Expand Down Expand Up @@ -53,8 +57,34 @@
std::optional<VideoFrameMetadata> metadata;
};

/// Represents a real-time video source that can accept frames from the
/// application and feed them into the LiveKit core.
struct EncodedVideoSourceOptions {
VideoCodec codec = VideoCodec::H264;

Check failure on line 61 in include/livekit/video_source.h

View workflow job for this annotation

GitHub Actions / C++ Checks / clang-tidy

clang-tidy (clang-diagnostic-error)

unknown type name 'VideoCodec'

Check failure on line 61 in include/livekit/video_source.h

View workflow job for this annotation

GitHub Actions / C++ Checks / clang-tidy

clang-tidy (clang-diagnostic-error)

unknown type name 'VideoCodec'
};

struct EncodedVideoFrameInfo {
bool is_keyframe = false;
bool has_sps_pps = false;
std::uint32_t width = 0;
std::uint32_t height = 0;
std::int64_t capture_time_us = 0;
};

class EncodedVideoSourceObserver {
public:
virtual ~EncodedVideoSourceObserver() = default;

virtual void onKeyframeRequested() {}
virtual void onTargetBitrate(std::uint32_t bitrate_bps,

Check failure on line 77 in include/livekit/video_source.h

View workflow job for this annotation

GitHub Actions / C++ Checks / clang-format

clang-format

code should be clang-formatted
double framerate_fps) {
(void)bitrate_bps;
(void)framerate_fps;
}
};

/**
* Represents a real-time video source that can accept frames from the
* application and feed them into the LiveKit core.
*/
class LIVEKIT_API VideoSource {
public:
/// Create a new native video source with a fixed resolution.
Expand All @@ -65,12 +95,14 @@
/// @throws std::runtime_error if the FFI call fails or the response
/// does not contain the expected new_video_source field.
VideoSource(int width, int height);
virtual ~VideoSource() = default;
VideoSource(int width, int height,

Check failure on line 98 in include/livekit/video_source.h

View workflow job for this annotation

GitHub Actions / C++ Checks / clang-format

clang-format

code should be clang-formatted
const EncodedVideoSourceOptions &encoded_options);

Check failure on line 99 in include/livekit/video_source.h

View workflow job for this annotation

GitHub Actions / C++ Checks / clang-format

clang-format

code should be clang-formatted

Check failure on line 99 in include/livekit/video_source.h

View workflow job for this annotation

GitHub Actions / C++ Checks / clang-format

clang-format

code should be clang-formatted
virtual ~VideoSource();

VideoSource(const VideoSource&) = delete;
VideoSource& operator=(const VideoSource&) = delete;
VideoSource(VideoSource&&) noexcept = default;
VideoSource& operator=(VideoSource&&) noexcept = default;
VideoSource(VideoSource&& other) noexcept;
VideoSource& operator=(VideoSource&& other) noexcept;
Comment on lines +106 to +107

/// Source resolution as declared at construction.
int width() const noexcept { return width_; }
Expand All @@ -89,10 +121,36 @@
void captureFrame(const VideoFrame& frame, std::int64_t timestamp_us = 0,
VideoRotation rotation = VideoRotation::VIDEO_ROTATION_0);

/**
* Push an encoded frame into an encoded video source.
*
* The source must have been created with EncodedVideoSourceOptions. Returns
* true when the frame was queued by the Rust/WebRTC layer and false when it
* was dropped because the internal queue was full.
*/
bool captureEncodedFrame(const std::uint8_t *data, std::size_t size,

Check failure on line 131 in include/livekit/video_source.h

View workflow job for this annotation

GitHub Actions / C++ Checks / clang-format

clang-format

code should be clang-formatted

Check failure on line 131 in include/livekit/video_source.h

View workflow job for this annotation

GitHub Actions / C++ Checks / clang-format

clang-format

code should be clang-formatted

Check failure on line 131 in include/livekit/video_source.h

View workflow job for this annotation

GitHub Actions / C++ Checks / clang-format

clang-format

code should be clang-formatted
const EncodedVideoFrameInfo &info);

Check failure on line 132 in include/livekit/video_source.h

View workflow job for this annotation

GitHub Actions / C++ Checks / clang-format

clang-format

code should be clang-formatted

Check failure on line 132 in include/livekit/video_source.h

View workflow job for this annotation

GitHub Actions / C++ Checks / clang-format

clang-format

code should be clang-formatted

bool captureEncodedFrame(const std::vector<std::uint8_t> &data,

Check failure on line 134 in include/livekit/video_source.h

View workflow job for this annotation

GitHub Actions / C++ Checks / clang-format

clang-format

code should be clang-formatted
const EncodedVideoFrameInfo &info) {
return captureEncodedFrame(data.data(), data.size(), info);
}

void setEncodedObserver(
std::shared_ptr<EncodedVideoSourceObserver> observer);

private:
void registerEncodedListener();
void unregisterEncodedListener() noexcept;
void handleEncodedEvent(const proto::FfiEvent &event) const;

Check failure on line 145 in include/livekit/video_source.h

View workflow job for this annotation

GitHub Actions / C++ Checks / clang-tidy

clang-tidy (clang-diagnostic-error)

use of undeclared identifier 'proto'

Check failure on line 145 in include/livekit/video_source.h

View workflow job for this annotation

GitHub Actions / C++ Checks / clang-tidy

clang-tidy (clang-diagnostic-error)

no type named 'FfiEvent' in namespace 'livekit::proto'

Check failure on line 145 in include/livekit/video_source.h

View workflow job for this annotation

GitHub Actions / C++ Checks / clang-tidy

clang-tidy (clang-diagnostic-error)

no type named 'FfiEvent' in namespace 'livekit::proto'

FfiHandle handle_; // owned FFI handle
int width_{0};
int height_{0};
bool encoded_{false};
int encoded_listener_id_{0};
mutable std::mutex encoded_observer_lock_;
std::shared_ptr<EncodedVideoSourceObserver> encoded_observer_;
};

} // namespace livekit
37 changes: 19 additions & 18 deletions src/ffi_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,24 +118,25 @@ std::optional<FfiClient::AsyncId> ExtractAsyncId(const proto::FfiEvent& event) {
case E::kSendBytes:
return event.send_bytes().async_id();

// data track async completions
case E::kPublishDataTrack:
return event.publish_data_track().async_id();

// NOT async completion:
case E::kRoomEvent:
case E::kTrackEvent:
case E::kVideoStreamEvent:
case E::kAudioStreamEvent:
case E::kByteStreamReaderEvent:
case E::kTextStreamReaderEvent:
case E::kDataTrackStreamEvent:
case E::kRpcMethodInvocation:
case E::kLogs:
case E::kPanic:
case E::MESSAGE_NOT_SET:
default:
return std::nullopt;
// data track async completions
case E::kPublishDataTrack:
return event.publish_data_track().async_id();

// NOT async completion:
case E::kRoomEvent:
case E::kTrackEvent:
case E::kVideoStreamEvent:
case E::kAudioStreamEvent:
case E::kByteStreamReaderEvent:
case E::kTextStreamReaderEvent:
case E::kDataTrackStreamEvent:
case E::kEncodedVideoSourceEvent:
case E::kRpcMethodInvocation:
case E::kLogs:
case E::kPanic:
case E::MESSAGE_NOT_SET:
default:
return std::nullopt;
Comment thread
stephen-derosa marked this conversation as resolved.
Outdated
}
}

Expand Down
Loading
Loading