diff --git a/.nanpa/properly_set_is_screencast.kdl b/.nanpa/properly_set_is_screencast.kdl new file mode 100644 index 000000000..45e93cbad --- /dev/null +++ b/.nanpa/properly_set_is_screencast.kdl @@ -0,0 +1,4 @@ +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/libwebrtc/src/native/video_source.rs b/libwebrtc/src/native/video_source.rs index aea801ecb..ad115b2b6 100644 --- a/libwebrtc/src/native/video_source.rs +++ b/libwebrtc/src/native/video_source.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. @@ -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 4efb9e365..28d169832 100644 --- a/libwebrtc/src/video_source.rs +++ b/libwebrtc/src/video_source.rs @@ -1,4 +1,4 @@ -// Copyright 2024 LiveKit, Inc. +// Copyright 2024-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. @@ -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"))] @@ -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-protocol/src/enum_dispatch.rs b/livekit-protocol/src/enum_dispatch.rs index 877027930..1e6f8aae0 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 ad0db760c..814734e2e 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 f60c3dd91..d41704c9a 100644 --- a/webrtc-sys/include/livekit/video_track.h +++ b/webrtc-sys/include/livekit/video_track.h @@ -1,5 +1,5 @@ /* - * Copyright 2023 LiveKit + * Copyright 2023-2025 LiveKit * * Licensed under the Apache License, Version 2.0 (the “License”); * you may not use this file except in compliance with the License. @@ -87,10 +87,11 @@ std::shared_ptr new_native_video_sink( class VideoTrackSource { class InternalSource : public rtc::AdaptedVideoTrackSource { public: - InternalSource(const VideoResolution& - resolution); // (0, 0) means no resolution/optional, the - // source will guess the resolution at the - // first captured frame + /* + * resolution set to (0, 0) means no resolution/optional, the source will + * guess the resolution at the first captured frame. + */ + InternalSource(const VideoResolution& resolution); ~InternalSource() override; bool is_screencast() const override; @@ -99,11 +100,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_; rtc::TimestampAligner timestamp_aligner_; VideoResolution resolution_; + bool is_screencast_; }; public: @@ -116,6 +119,8 @@ class VideoTrackSource { rtc::scoped_refptr get() const; + void set_is_screencast(bool is_screencast) const; + private: rtc::scoped_refptr source_; }; diff --git a/webrtc-sys/src/video_track.cpp b/webrtc-sys/src/video_track.cpp index 45e07dcae..0f3931da1 100644 --- a/webrtc-sys/src/video_track.cpp +++ b/webrtc-sys/src/video_track.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 LiveKit + * Copyright 2023-2025 LiveKit * * Licensed under the Apache License, Version 2.0 (the “License”); * you may not use this file except in compliance with the License. @@ -111,7 +111,13 @@ VideoTrackSource::InternalSource::InternalSource( 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; } absl::optional VideoTrackSource::InternalSource::needs_denoising() const { @@ -189,6 +195,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); +} + rtc::scoped_refptr VideoTrackSource::get() const { return source_; diff --git a/webrtc-sys/src/video_track.rs b/webrtc-sys/src/video_track.rs index 09fd22309..fbf76ba86 100644 --- a/webrtc-sys/src/video_track.rs +++ b/webrtc-sys/src/video_track.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. @@ -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;