diff --git a/modules/desktop_capture/desktop_capturer.h b/modules/desktop_capture/desktop_capturer.h index d3164258ec..197bfd3b4c 100644 --- a/modules/desktop_capture/desktop_capturer.h +++ b/modules/desktop_capture/desktop_capturer.h @@ -144,6 +144,8 @@ class RTC_EXPORT DesktopCapturer { #if defined(WEBRTC_USE_PIPEWIRE) || defined(WEBRTC_USE_X11) static bool IsRunningUnderWayland(); + + virtual void UpdateResolution(uint32_t width, uint32_t height){}; #endif // defined(WEBRTC_USE_PIPEWIRE) || defined(WEBRTC_USE_X11) #if defined(WEBRTC_USE_GIO) diff --git a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc index 678f350f89..4aafa2a007 100644 --- a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc +++ b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc @@ -58,6 +58,13 @@ void BaseCapturerPipeWire::OnScreenCastSessionClosed() { } } +void BaseCapturerPipeWire::UpdateResolution(uint32_t width, uint32_t height) { + if (!capturer_failed_) { + options_.screencast_stream()->UpdateScreenCastStreamResolution(width, + height); + } +} + void BaseCapturerPipeWire::Start(Callback* callback) { RTC_DCHECK(!callback_); RTC_DCHECK(callback); diff --git a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h index b6f4ba8a1a..b6a8816cdb 100644 --- a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h +++ b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h @@ -45,6 +45,7 @@ class BaseCapturerPipeWire : public DesktopCapturer, uint32_t stream_node_id, int fd) override; void OnScreenCastSessionClosed() override; + void UpdateResolution(uint32_t width, uint32_t height) override; xdg_portal::SessionDetails GetSessionDetails(); diff --git a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc index deb85a8580..56469235be 100644 --- a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc +++ b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc @@ -89,6 +89,7 @@ class SharedScreenCastStreamPrivate { int fd, uint32_t width = 0, uint32_t height = 0); + void UpdateScreenCastStreamResolution(uint32_t width, uint32_t height); void StopScreenCastStream(); std::unique_ptr CaptureFrame(); std::unique_ptr CaptureCursor(); @@ -130,6 +131,13 @@ class SharedScreenCastStreamPrivate { // Version of the library used to run our code PipeWireVersion pw_client_version_; + // Resolution parameters. + uint32_t width_ = 0; + uint32_t height_ = 0; + webrtc::Mutex resolution_lock_; + // Resolution changes are processed during buffer processing. + bool pending_resolution_change_ RTC_GUARDED_BY(&resolution_lock_) = false; + // event handlers pw_core_events pw_core_events_ = {}; pw_stream_events pw_stream_events_ = {}; @@ -329,18 +337,24 @@ void SharedScreenCastStreamPrivate::OnRenegotiateFormat(void* data, uint64_t) { spa_pod_builder builder = spa_pod_builder{buffer, sizeof(buffer)}; std::vector params; + struct spa_rectangle resolution = + SPA_RECTANGLE(that->width_, that->height_); + webrtc::MutexLock lock(&that->resolution_lock_); for (uint32_t format : {SPA_VIDEO_FORMAT_BGRA, SPA_VIDEO_FORMAT_RGBA, SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_RGBx}) { if (!that->modifiers_.empty()) { - params.push_back(BuildFormat(&builder, format, that->modifiers_, - /*resolution=*/nullptr)); + params.push_back(BuildFormat( + &builder, format, that->modifiers_, + that->pending_resolution_change_ ? &resolution : nullptr)); } - params.push_back(BuildFormat(&builder, format, /*modifiers=*/{}, - /*resolution=*/nullptr)); + params.push_back(BuildFormat( + &builder, format, /*modifiers=*/{}, + that->pending_resolution_change_ ? &resolution : nullptr)); } pw_stream_update_params(that->pw_stream_, params.data(), params.size()); + that->pending_resolution_change_ = false; } } @@ -374,6 +388,8 @@ bool SharedScreenCastStreamPrivate::StartScreenCastStream( int fd, uint32_t width, uint32_t height) { + width_ = width; + height_ = height; #if defined(WEBRTC_DLOPEN_PIPEWIRE) StubPathMap paths; @@ -502,6 +518,35 @@ bool SharedScreenCastStreamPrivate::StartScreenCastStream( return true; } +RTC_NO_SANITIZE("cfi-icall") +void SharedScreenCastStreamPrivate::UpdateScreenCastStreamResolution( + uint32_t width, + uint32_t height) { + if (!width || !height) { + RTC_LOG(LS_WARNING) << "Bad resolution specified: " << width << "x" + << height; + return; + } + if (!pw_main_loop_) { + RTC_LOG(LS_WARNING) << "No main pipewire loop, ignoring resolution change"; + return; + } + if (!renegotiate_) { + RTC_LOG(LS_WARNING) << "Can not renegotiate stream params, ignoring " + << "resolution change"; + return; + } + if (width_ != width || height_ != height) { + width_ = width; + height_ = height; + { + webrtc::MutexLock lock(&resolution_lock_); + pending_resolution_change_ = true; + } + pw_loop_signal_event(pw_thread_loop_get_loop(pw_main_loop_), renegotiate_); + } +} + void SharedScreenCastStreamPrivate::StopScreenCastStream() { if (pw_stream_) { pw_stream_disconnect(pw_stream_); @@ -751,6 +796,11 @@ bool SharedScreenCastStream::StartScreenCastStream(uint32_t stream_node_id, return private_->StartScreenCastStream(stream_node_id, fd, width, height); } +void SharedScreenCastStream::UpdateScreenCastStreamResolution(uint32_t width, + uint32_t height) { + private_->UpdateScreenCastStreamResolution(width, height); +} + void SharedScreenCastStream::StopScreenCastStream() { private_->StopScreenCastStream(); } diff --git a/modules/desktop_capture/linux/wayland/shared_screencast_stream.h b/modules/desktop_capture/linux/wayland/shared_screencast_stream.h index e8b79cb4ec..66a3f45bdb 100644 --- a/modules/desktop_capture/linux/wayland/shared_screencast_stream.h +++ b/modules/desktop_capture/linux/wayland/shared_screencast_stream.h @@ -34,6 +34,7 @@ class RTC_EXPORT SharedScreenCastStream int fd, uint32_t width = 0, uint32_t height = 0); + void UpdateScreenCastStreamResolution(uint32_t width, uint32_t height); void StopScreenCastStream(); // Below functions return the most recent information we get from a