From b04977c7b13c095dc43271af420c947cb18e73d6 Mon Sep 17 00:00:00 2001 From: Iason Paraskevopoulos Date: Sat, 22 Nov 2025 10:35:50 +0000 Subject: [PATCH] Set is_screencast on publish_track Makes InternalSource's is_screencast configurable. Setting it improves the latency when sharing screen content. --- libwebrtc/src/native/video_source.rs | 4 ++++ libwebrtc/src/video_source.rs | 8 +++++++ livekit-protocol/src/enum_dispatch.rs | 14 +++++++++++ .../src/room/participant/local_participant.rs | 7 ++++++ webrtc-sys/include/livekit/video_track.h | 4 ++++ webrtc-sys/src/video_track.cpp | 23 +++++++++++++++---- webrtc-sys/src/video_track.rs | 1 + 7 files changed, 56 insertions(+), 5 deletions(-) diff --git a/libwebrtc/src/native/video_source.rs b/libwebrtc/src/native/video_source.rs index 91a59df99..9388e5d04 100644 --- a/libwebrtc/src/native/video_source.rs +++ b/libwebrtc/src/native/video_source.rs @@ -113,4 +113,8 @@ impl NativeVideoSource { pub fn video_resolution(&self) -> VideoResolution { self.sys_handle.video_resolution().into() } + + pub fn set_is_screencast(&self, is_screencast: bool) { + self.sys_handle.set_is_screencast(is_screencast); + } } diff --git a/libwebrtc/src/video_source.rs b/libwebrtc/src/video_source.rs index d73491748..43739e22c 100644 --- a/libwebrtc/src/video_source.rs +++ b/libwebrtc/src/video_source.rs @@ -43,6 +43,10 @@ impl RtcVideoSource { [Native]; pub fn video_resolution(self: &Self) -> VideoResolution; ); + enum_dispatch!( + [Native]; + pub fn set_is_screencast(self: &Self, is_screencast: bool); + ); } #[cfg(not(target_arch = "wasm32"))] @@ -81,6 +85,10 @@ pub mod native { pub fn video_resolution(&self) -> VideoResolution { self.handle.video_resolution() } + + pub fn set_is_screencast(&self, is_screencast: bool) { + self.handle.set_is_screencast(is_screencast); + } } } diff --git a/livekit-protocol/src/enum_dispatch.rs b/livekit-protocol/src/enum_dispatch.rs index 0268b2829..6bd4f83e1 100644 --- a/livekit-protocol/src/enum_dispatch.rs +++ b/livekit-protocol/src/enum_dispatch.rs @@ -33,9 +33,23 @@ macro_rules! enum_dispatch { } }; + // Handle functions without a return type + (@fnc [$($variant:ident),+]: $vis:vis fn $fnc:ident($self:ident: $sty:ty $(, $arg:ident: $t:ty)*)) => { + #[inline] + $vis fn $fnc($self: $sty, $($arg: $t),*) { + enum_dispatch!(@match [$($variant),+]: $fnc, $self, ($($arg,)*)) + } + }; + ($variants:tt; $($vis:vis fn $fnc:ident$args:tt -> $ret:ty;)+) => { $( enum_dispatch!(@fnc $variants: $vis fn $fnc$args -> $ret); )+ }; + + ($variants:tt; $($vis:vis fn $fnc:ident$args:tt;)+) => { + $( + enum_dispatch!(@fnc $variants: $vis fn $fnc$args); + )+ + }; } diff --git a/livekit/src/room/participant/local_participant.rs b/livekit/src/room/participant/local_participant.rs index a9a2320fd..168f47ad8 100644 --- a/livekit/src/room/participant/local_participant.rs +++ b/livekit/src/room/participant/local_participant.rs @@ -262,6 +262,13 @@ impl LocalParticipant { encodings = compute_video_encodings(req.width, req.height, &options); req.layers = video_layers_from_encodings(req.width, req.height, &encodings); + + match options.source { + TrackSource::Screenshare => { + video_track.rtc_source().set_is_screencast(true); + } + _ => {} + } } LocalTrack::Audio(_audio_track) => { // Setup audio encoding diff --git a/webrtc-sys/include/livekit/video_track.h b/webrtc-sys/include/livekit/video_track.h index 06a6cf1ec..5c72a8dd1 100644 --- a/webrtc-sys/include/livekit/video_track.h +++ b/webrtc-sys/include/livekit/video_track.h @@ -99,11 +99,13 @@ class VideoTrackSource { bool remote() const override; VideoResolution video_resolution() const; bool on_captured_frame(const webrtc::VideoFrame& frame); + void set_is_screencast(bool is_screencast); private: mutable webrtc::Mutex mutex_; webrtc::TimestampAligner timestamp_aligner_; VideoResolution resolution_; + bool is_screencast_; }; public: @@ -116,6 +118,8 @@ class VideoTrackSource { webrtc::scoped_refptr get() const; + void set_is_screencast(bool is_screencast) const; + private: webrtc::scoped_refptr source_; }; diff --git a/webrtc-sys/src/video_track.cpp b/webrtc-sys/src/video_track.cpp index 46b2bd78d..73f73687d 100644 --- a/webrtc-sys/src/video_track.cpp +++ b/webrtc-sys/src/video_track.cpp @@ -48,9 +48,10 @@ VideoTrack::~VideoTrack() { void VideoTrack::add_sink(const std::shared_ptr& sink) const { webrtc::MutexLock lock(&mutex_); - track()->AddOrUpdateSink(sink.get(), - webrtc::VideoSinkWants()); // TODO(theomonnom): Expose - // VideoSinkWants to Rust? + track()->AddOrUpdateSink( + sink.get(), + webrtc::VideoSinkWants()); // TODO(theomonnom): Expose + // VideoSinkWants to Rust? sinks_.push_back(sink); } @@ -106,12 +107,20 @@ std::shared_ptr new_native_video_sink( VideoTrackSource::InternalSource::InternalSource( const VideoResolution& resolution) - : webrtc::AdaptedVideoTrackSource(4), resolution_(resolution) {} + : webrtc::AdaptedVideoTrackSource(4), + resolution_(resolution), + is_screencast_(false) {} VideoTrackSource::InternalSource::~InternalSource() {} bool VideoTrackSource::InternalSource::is_screencast() const { - return false; + webrtc::MutexLock lock(&mutex_); + return is_screencast_; +} + +void VideoTrackSource::InternalSource::set_is_screencast(bool is_screencast) { + webrtc::MutexLock lock(&mutex_); + is_screencast_ = is_screencast; } std::optional VideoTrackSource::InternalSource::needs_denoising() const { @@ -189,6 +198,10 @@ bool VideoTrackSource::on_captured_frame( return source_->on_captured_frame(rtc_frame); } +void VideoTrackSource::set_is_screencast(bool is_screencast) const { + source_->set_is_screencast(is_screencast); +} + webrtc::scoped_refptr VideoTrackSource::get() const { return source_; diff --git a/webrtc-sys/src/video_track.rs b/webrtc-sys/src/video_track.rs index 11071d56b..3fe8903ee 100644 --- a/webrtc-sys/src/video_track.rs +++ b/webrtc-sys/src/video_track.rs @@ -67,6 +67,7 @@ pub mod ffi { fn video_resolution(self: &VideoTrackSource) -> VideoResolution; fn on_captured_frame(self: &VideoTrackSource, frame: &UniquePtr) -> bool; + fn set_is_screencast(self: &VideoTrackSource, is_screencast: bool); fn new_video_track_source(resolution: &VideoResolution) -> SharedPtr; fn video_to_media(track: SharedPtr) -> SharedPtr; unsafe fn media_to_video(track: SharedPtr) -> SharedPtr;