feat: point the fleet at wss LiveKit room uwh-telhai

Publish and subscribe over wss://livekit.uni-wh.de:7800 and refuse
cleartext ws://. Conference room is uwh-telhai. Includes the uncommitted
encoded H.264 publish path, Rally hairpin, and KMS wall overlay.
This commit is contained in:
root
2026-10-11 00:48:50 +00:00
parent ef9573c294
commit 95bb7c50ee
89 changed files with 9883 additions and 243 deletions
+15
View File
@@ -0,0 +1,15 @@
# livekit-ffi-backpressure.patch
Apply on livekit/rust-sdks (webrtc-sys VAAPI + VideoTrackSource).
1. VideoSource: latest-wins pending slot — at most one OnFrame in flight;
a new capture overwrites pending instead of pushing another I420 onto
EncoderQueue.
2. VAAPI H264 Encode: drop delta frames older than 1 frame period, or
Encode calls closer than 8 ms (queue drain), *before* ToI420.
Logs `VAAPI encode sample delay_ms=` every 90 frames so the clock
domain is visible in the cameras journal.
Rebuild: `CC=clang CXX=clang++ cargo build --release -p livekit-ffi`
Install: copy `target/release/liblivekit_ffi.so` to `native/` and set
`LIVEKIT_LIB_PATH` (see systemd drop-in `ffi-backpressure.conf`).
+210
View File
@@ -0,0 +1,210 @@
diff --git a/livekit-ffi/src/server/video_source.rs b/livekit-ffi/src/server/video_source.rs
index ee1410a..b2ff9ca 100644
--- a/livekit-ffi/src/server/video_source.rs
+++ b/livekit-ffi/src/server/video_source.rs
@@ -88,7 +88,9 @@ impl FfiVideoSource {
buffer,
};
- source.capture_frame(&frame);
+ // false = adapter / in-flight cap dropped the frame (do not
+ // treat as an FFI error; the source is still valid).
+ let _forwarded = source.capture_frame(&frame);
}
_ => {}
}
diff --git a/webrtc-sys/include/livekit/video_track.h b/webrtc-sys/include/livekit/video_track.h
index 4146c45..733d110 100644
--- a/webrtc-sys/include/livekit/video_track.h
+++ b/webrtc-sys/include/livekit/video_track.h
@@ -18,6 +18,7 @@
#include <atomic>
#include <memory>
+#include <optional>
#include "api/media_stream_interface.h"
#include "api/video/video_frame.h"
@@ -127,6 +128,10 @@ class VideoTrackSource {
std::shared_ptr<livekit::EncodedRateControlState> rate_control_state_ =
std::make_shared<livekit::EncodedRateControlState>();
bool is_screencast_;
+ int64_t last_forwarded_us_ = 0;
+ // Latest-wins: at most one OnFrame in flight; new captures overwrite.
+ bool forwarding_ = false;
+ std::optional<webrtc::VideoFrame> pending_frame_;
};
public:
diff --git a/webrtc-sys/src/vaapi/h264_encoder_impl.cpp b/webrtc-sys/src/vaapi/h264_encoder_impl.cpp
index 5a3b76e..8c7ce11 100644
--- a/webrtc-sys/src/vaapi/h264_encoder_impl.cpp
+++ b/webrtc-sys/src/vaapi/h264_encoder_impl.cpp
@@ -189,18 +189,6 @@ int32_t VAAPIH264EncoderWrapper::Encode(
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
}
- webrtc::scoped_refptr<I420BufferInterface> frame_buffer =
- input_frame.video_frame_buffer()->ToI420();
- if (!frame_buffer) {
- RTC_LOG(LS_ERROR) << "Failed to convert "
- << VideoFrameBufferTypeToString(
- input_frame.video_frame_buffer()->type())
- << " image to I420. Can't encode frame.";
- return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE;
- }
- RTC_CHECK(frame_buffer->type() == VideoFrameBuffer::Type::kI420 ||
- frame_buffer->type() == VideoFrameBuffer::Type::kI420A);
-
bool is_keyframe_needed = false;
if (configuration_.key_frame_request && configuration_.sending) {
is_keyframe_needed = true;
@@ -214,20 +202,67 @@ int32_t VAAPIH264EncoderWrapper::Encode(
configuration_.key_frame_request = false;
}
- RTC_DCHECK_EQ(configuration_.width, frame_buffer->width());
- RTC_DCHECK_EQ(configuration_.height, frame_buffer->height());
-
if (!configuration_.sending) {
return WEBRTC_VIDEO_CODEC_NO_OUTPUT;
}
if (frame_types != nullptr) {
- // Skip frame?
if ((*frame_types)[0] == VideoFrameType::kEmptyFrame) {
return WEBRTC_VIDEO_CODEC_NO_OUTPUT;
}
}
+ // Drop stale/burst delta frames BEFORE ToI420.
+ // 1) Age: capture older than 1 frame period (was 3; that never fired).
+ // 2) Burst: Encode called closer than 8 ms = EncoderQueue draining.
+ // Mirror: livekit-cameras latency.should_drop_stale_vaapi_frame /
+ // should_drop_encoder_queue_depth.
+ const int fps = std::max(
+ 1, static_cast<int>(configuration_.max_frame_rate > 0.0f
+ ? configuration_.max_frame_rate
+ : codec_.maxFramerate));
+ const int64_t now_us = webrtc::TimeMicros();
+ const int64_t capture_us = input_frame.timestamp_us();
+ const int64_t delay_us = (capture_us > 0) ? (now_us - capture_us) : 0;
+ encode_count_++;
+ if (encode_count_ % 90 == 1) {
+ RTC_LOG(LS_WARNING) << "VAAPI encode sample delay_ms=" << delay_us / 1000
+ << " now_us=" << now_us << " capture_us=" << capture_us
+ << " fps=" << fps << " n=" << encode_count_;
+ }
+ if (!send_key_frame) {
+ const int64_t max_delay_us = 1000000 / fps; // 1 frame
+ const bool stale =
+ capture_us > 0 && now_us - capture_us > max_delay_us;
+ const bool burst =
+ last_encode_us_ != 0 && now_us - last_encode_us_ < 8000;
+ if (stale || burst) {
+ RTC_LOG(LS_WARNING) << "VAAPI H264 drop "
+ << (stale ? "stale" : "burst")
+ << " frame delay_ms=" << delay_us / 1000
+ << " dt_ms=" << (now_us - last_encode_us_) / 1000
+ << " fps=" << fps;
+ last_encode_us_ = now_us;
+ return WEBRTC_VIDEO_CODEC_OK;
+ }
+ }
+ last_encode_us_ = now_us;
+
+ webrtc::scoped_refptr<I420BufferInterface> frame_buffer =
+ input_frame.video_frame_buffer()->ToI420();
+ if (!frame_buffer) {
+ RTC_LOG(LS_ERROR) << "Failed to convert "
+ << VideoFrameBufferTypeToString(
+ input_frame.video_frame_buffer()->type())
+ << " image to I420. Can't encode frame.";
+ return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE;
+ }
+ RTC_CHECK(frame_buffer->type() == VideoFrameBuffer::Type::kI420 ||
+ frame_buffer->type() == VideoFrameBuffer::Type::kI420A);
+
+ RTC_DCHECK_EQ(configuration_.width, frame_buffer->width());
+ RTC_DCHECK_EQ(configuration_.height, frame_buffer->height());
+
std::vector<uint8_t> output;
encoder_->Encode(VA_FOURCC_I420, frame_buffer->DataY(), frame_buffer->DataU(),
frame_buffer->DataV(), send_key_frame, output);
@@ -267,6 +302,7 @@ VideoEncoder::EncoderInfo VAAPIH264EncoderWrapper::GetEncoderInfo() const {
info.implementation_name = "VAAPI H264 Encoder";
info.scaling_settings = VideoEncoder::ScalingSettings::kOff;
info.is_hardware_accelerated = true;
+ info.has_trusted_rate_controller = false;
info.supports_simulcast = false;
info.preferred_pixel_formats = {VideoFrameBuffer::Type::kI420};
return info;
diff --git a/webrtc-sys/src/vaapi/h264_encoder_impl.h b/webrtc-sys/src/vaapi/h264_encoder_impl.h
index dc26355..bce1681 100644
--- a/webrtc-sys/src/vaapi/h264_encoder_impl.h
+++ b/webrtc-sys/src/vaapi/h264_encoder_impl.h
@@ -76,6 +76,8 @@ class VAAPIH264EncoderWrapper : public VideoEncoder {
const SdpVideoFormat format_;
H264Profile profile_ = H264Profile::kProfileConstrainedBaseline;
H264Level level_ = H264Level::kLevel1_b;
+ int64_t last_encode_us_ = 0;
+ int encode_count_ = 0;
};
} // namespace webrtc
diff --git a/webrtc-sys/src/video_track.cpp b/webrtc-sys/src/video_track.cpp
index 92410b9..89e6791 100644
--- a/webrtc-sys/src/video_track.cpp
+++ b/webrtc-sys/src/video_track.cpp
@@ -165,6 +165,7 @@ VideoResolution VideoTrackSource::InternalSource::video_resolution() const {
bool VideoTrackSource::InternalSource::on_captured_frame(
const webrtc::VideoFrame& frame,
const FrameMetadata& frame_metadata) {
+ {
webrtc::MutexLock lock(&mutex_);
int64_t aligned_timestamp_us = timestamp_aligner_.TranslateTimestamp(
@@ -235,13 +236,37 @@ bool VideoTrackSource::InternalSource::on_captured_frame(
frame_metadata.has_packet_trailer ? frame_metadata.frame_id : 0);
}
- OnFrame(webrtc::VideoFrame::Builder()
- .set_video_frame_buffer(buffer)
- .set_rotation(rotation)
- .set_timestamp_us(aligned_timestamp_us)
- .build());
+ webrtc::VideoFrame built = webrtc::VideoFrame::Builder()
+ .set_video_frame_buffer(buffer)
+ .set_rotation(rotation)
+ .set_timestamp_us(aligned_timestamp_us)
+ .build();
+
+ // Latest-wins depth cap (max_queued=1). A capture that arrives while
+ // OnFrame is in flight overwrites pending_frame_ instead of pushing
+ // another I420 onto EncoderQueue.
+ // Mirror: livekit-cameras latency.should_drop_encoder_queue_depth.
+ pending_frame_ = std::move(built);
+ if (forwarding_) {
+ return true;
+ }
+ forwarding_ = true;
+ last_forwarded_us_ = aligned_timestamp_us;
+ }
- return true;
+ for (;;) {
+ std::optional<webrtc::VideoFrame> to_send;
+ {
+ webrtc::MutexLock lock(&mutex_);
+ if (!pending_frame_) {
+ forwarding_ = false;
+ return true;
+ }
+ to_send = std::move(pending_frame_);
+ pending_frame_.reset();
+ }
+ OnFrame(*to_send);
+ }
}
void VideoTrackSource::InternalSource::set_packet_trailer_handler(