diff --git a/.nanpa/properly_set_is_screencast.kdl b/.nanpa/properly_set_is_screencast.kdl index 6a383f11..45e93cba 100644 --- a/.nanpa/properly_set_is_screencast.kdl +++ b/.nanpa/properly_set_is_screencast.kdl @@ -1,4 +1,4 @@ -patch type="added" "Set is_screencast on VideoTrackSource creation" package="webrtc-sys" -patch type="added" "Set is_screencast on NativeVideoSource creation" package="libwebrtc" -patch type="added" "Extend NewVideoSourceRequest with is_screencast" package="livekit-ffi" -patch type="changed" "Use new NativeVideoSource constructor in examples" package="examples" +patch type="added" "Add a setter for is_screencast in InternalSource" package="webrtc-sys" +patch type="added" "Expose set_is_screencast in NativeVideoSource" package="libwebrtc" +patch type="added" "Extend enum_dispatch to create functions that don't have a return type" package="livekit-protocol" +patch type="added" "Set is_screencast in publish_track when the source is Screenshare" package="livekit" diff --git a/examples/wgpu_room/src/logo_track.rs b/examples/wgpu_room/src/logo_track.rs index 564e8287..edb03465 100644 --- a/examples/wgpu_room/src/logo_track.rs +++ b/examples/wgpu_room/src/logo_track.rs @@ -47,10 +47,10 @@ pub struct LogoTrack { impl LogoTrack { pub fn new(room: Arc) -> Self { Self { - rtc_source: NativeVideoSource::new( - VideoResolution { width: FB_WIDTH as u32, height: FB_HEIGHT as u32 }, - false, - ), + rtc_source: NativeVideoSource::new(VideoResolution { + width: FB_WIDTH as u32, + height: FB_HEIGHT as u32, + }), room, handle: None, } diff --git a/libwebrtc/src/native/video_source.rs b/libwebrtc/src/native/video_source.rs index d2796feb..ad115b2b 100644 --- a/libwebrtc/src/native/video_source.rs +++ b/libwebrtc/src/native/video_source.rs @@ -50,12 +50,11 @@ struct VideoSourceInner { } impl NativeVideoSource { - pub fn new(resolution: VideoResolution, is_screencast: bool) -> NativeVideoSource { + pub fn new(resolution: VideoResolution) -> NativeVideoSource { let source = Self { - sys_handle: vt_sys::ffi::new_video_track_source( - &vt_sys::ffi::VideoResolution::from(resolution.clone()), - is_screencast, - ), + sys_handle: vt_sys::ffi::new_video_track_source(&vt_sys::ffi::VideoResolution::from( + resolution.clone(), + )), inner: Arc::new(Mutex::new(VideoSourceInner { captured_frames: 0 })), }; @@ -114,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 9e11ca3a..28d16983 100644 --- a/libwebrtc/src/video_source.rs +++ b/libwebrtc/src/video_source.rs @@ -36,6 +36,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"))] @@ -58,13 +62,13 @@ pub mod native { impl Default for NativeVideoSource { fn default() -> Self { - Self::new(VideoResolution::default(), false) + Self::new(VideoResolution::default()) } } impl NativeVideoSource { - pub fn new(resolution: VideoResolution, is_screencast: bool) -> Self { - Self { handle: vs_imp::NativeVideoSource::new(resolution, is_screencast) } + pub fn new(resolution: VideoResolution) -> Self { + Self { handle: vs_imp::NativeVideoSource::new(resolution) } } pub fn capture_frame>(&self, frame: &VideoFrame) { @@ -74,6 +78,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-ffi/protocol/video_frame.proto b/livekit-ffi/protocol/video_frame.proto index dd640d8f..19d31d7b 100644 --- a/livekit-ffi/protocol/video_frame.proto +++ b/livekit-ffi/protocol/video_frame.proto @@ -49,7 +49,6 @@ message NewVideoSourceRequest { // Used to determine which encodings to use + simulcast layers // Most of the time it corresponds to the source resolution required VideoSourceResolution resolution = 2; - optional bool is_screencast = 3; } message NewVideoSourceResponse { required OwnedVideoSource source = 1; } diff --git a/livekit-ffi/src/livekit.proto.rs b/livekit-ffi/src/livekit.proto.rs index 2c276c93..f4718591 100644 --- a/livekit-ffi/src/livekit.proto.rs +++ b/livekit-ffi/src/livekit.proto.rs @@ -1,4 +1,5 @@ // @generated +// This file is @generated by prost-build. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct FrameCryptor { @@ -302,11 +303,11 @@ impl EncryptionState { /// # Safety /// The foreign language is responsable for disposing handles /// Forgetting to dispose the handle may lead to memory leaks -/// +/// /// Dropping a handle doesn't necessarily mean that the object is destroyed if it is still used /// on the FfiServer (Atomic reference counting) -/// -/// When refering to a handle without owning it, we just use a uint32 without this message. +/// +/// When refering to a handle without owning it, we just use a uint32 without this message. /// (the variable name is suffixed with "_handle") #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -1765,8 +1766,6 @@ pub struct NewVideoSourceRequest { /// Most of the time it corresponds to the source resolution #[prost(message, required, tag="2")] pub resolution: VideoSourceResolution, - #[prost(bool, optional, tag="3")] - pub is_screencast: ::core::option::Option, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -3455,7 +3454,7 @@ pub struct NewAudioSourceResponse { #[prost(message, required, tag="1")] pub source: OwnedAudioSource, } -/// Push a frame to an AudioSource +/// Push a frame to an AudioSource /// The data provided must be available as long as the client receive the callback. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -4009,7 +4008,7 @@ pub struct RpcMethodInvocationEvent { // that it receives from the server. // // Therefore, the ffi client is easier to implement if there is less handles to manage. -// +// // - We are mainly using FfiHandle on info messages (e.g: RoomInfo, TrackInfo, etc...) // For this reason, info are only sent once, at creation (We're not using them for updates, we can infer them from // events on the client implementation). diff --git a/livekit-ffi/src/server/video_source.rs b/livekit-ffi/src/server/video_source.rs index 4c6d68e1..79f0cfee 100644 --- a/livekit-ffi/src/server/video_source.rs +++ b/livekit-ffi/src/server/video_source.rs @@ -37,7 +37,6 @@ impl FfiVideoSource { use livekit::webrtc::video_source::native::NativeVideoSource; let video_source = NativeVideoSource::new( new_source.resolution.into(), - new_source.is_screencast(), ); RtcVideoSource::Native(video_source) } diff --git a/livekit-protocol/src/enum_dispatch.rs b/livekit-protocol/src/enum_dispatch.rs index 87702793..1e6f8aae 100644 --- a/livekit-protocol/src/enum_dispatch.rs +++ b/livekit-protocol/src/enum_dispatch.rs @@ -1,4 +1,4 @@ -// Copyright 2023 LiveKit, Inc. +// Copyright 2023-2025 LiveKit, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -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 ad0db760..814734e2 100644 --- a/livekit/src/room/participant/local_participant.rs +++ b/livekit/src/room/participant/local_participant.rs @@ -1,4 +1,4 @@ -// Copyright 2023 LiveKit, Inc. +// Copyright 2023-2025 LiveKit, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -232,6 +232,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 8b7af667..d41704c9 100644 --- a/webrtc-sys/include/livekit/video_track.h +++ b/webrtc-sys/include/livekit/video_track.h @@ -91,7 +91,7 @@ class VideoTrackSource { * resolution set to (0, 0) means no resolution/optional, the source will * guess the resolution at the first captured frame. */ - InternalSource(const VideoResolution& resolution, bool is_screencast); + InternalSource(const VideoResolution& resolution); ~InternalSource() override; bool is_screencast() const override; @@ -100,6 +100,7 @@ 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_; @@ -109,7 +110,7 @@ class VideoTrackSource { }; public: - VideoTrackSource(const VideoResolution& resolution, bool is_screencast); + VideoTrackSource(const VideoResolution& resolution); VideoResolution video_resolution() const; @@ -118,13 +119,14 @@ class VideoTrackSource { rtc::scoped_refptr get() const; + void set_is_screencast(bool is_screencast) const; + private: rtc::scoped_refptr source_; }; std::shared_ptr new_video_track_source( - const VideoResolution& resolution, - bool is_screencast); + const VideoResolution& resolution); static std::shared_ptr video_to_media( std::shared_ptr track) { diff --git a/webrtc-sys/src/video_track.cpp b/webrtc-sys/src/video_track.cpp index f1f5071d..0f3931da 100644 --- a/webrtc-sys/src/video_track.cpp +++ b/webrtc-sys/src/video_track.cpp @@ -105,18 +105,21 @@ std::shared_ptr new_native_video_sink( } VideoTrackSource::InternalSource::InternalSource( - const VideoResolution& resolution, - bool is_screencast) - : rtc::AdaptedVideoTrackSource(4), - resolution_(resolution), - is_screencast_(is_screencast) {} + const VideoResolution& resolution) + : rtc::AdaptedVideoTrackSource(4), resolution_(resolution) {} VideoTrackSource::InternalSource::~InternalSource() {} bool VideoTrackSource::InternalSource::is_screencast() const { + webrtc::MutexLock lock(&mutex_); return is_screencast_; } +void VideoTrackSource::InternalSource::set_is_screencast(bool is_screencast) { + webrtc::MutexLock lock(&mutex_); + is_screencast_ = is_screencast; +} + absl::optional VideoTrackSource::InternalSource::needs_denoising() const { return false; } @@ -178,9 +181,8 @@ bool VideoTrackSource::InternalSource::on_captured_frame( return true; } -VideoTrackSource::VideoTrackSource(const VideoResolution& resolution, - bool is_screencast) { - source_ = rtc::make_ref_counted(resolution, is_screencast); +VideoTrackSource::VideoTrackSource(const VideoResolution& resolution) { + source_ = rtc::make_ref_counted(resolution); } VideoResolution VideoTrackSource::video_resolution() const { @@ -193,15 +195,18 @@ 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); +} + rtc::scoped_refptr VideoTrackSource::get() const { return source_; } std::shared_ptr new_video_track_source( - const VideoResolution& resolution, - bool is_screencast) { - return std::make_shared(resolution, is_screencast); + const VideoResolution& resolution) { + return std::make_shared(resolution); } } // namespace livekit diff --git a/webrtc-sys/src/video_track.rs b/webrtc-sys/src/video_track.rs index 92c92089..fbf76ba8 100644 --- a/webrtc-sys/src/video_track.rs +++ b/webrtc-sys/src/video_track.rs @@ -67,10 +67,8 @@ pub mod ffi { fn video_resolution(self: &VideoTrackSource) -> VideoResolution; fn on_captured_frame(self: &VideoTrackSource, frame: &UniquePtr) -> bool; - fn new_video_track_source( - resolution: &VideoResolution, - is_screencast: bool, - ) -> SharedPtr; + 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; fn _shared_video_track() -> SharedPtr;