[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1032794: [pre-approval] qtwebengine-opensource-src 5.15.13 for bookworm?



Control: tags -1 moreinfo

On 2023-03-11 21:04:14 +0300, Dmitry Shachnev wrote:
> Package: release.debian.org
> Severity: wishlist
> 
> Dear Release Team,
> 
> Qt WebEngine 5.15 LTS branch has a new patch release, 5.15.13.
> 
> It mostly contains backports for security fixes from upstream Chromium,
> and some other minor fixes.
> 
> This particular release does not have any ABI changes, but per our
> team practice we bump the name of provided virtual ABI package from
> qtwebengine-abi-5-15-12 to qtwebengine-abi-5-15-13. This will require a
> no-change rebuild of two reverse dependencies (qtwebview-opensource-src
> and angelfish). Is that acceptable for bookworm?

Do both reverse dependencies build fine with the new version of
qtwebengine-opensource-src?

> I am attaching a git diff of my packaging and an upstream git diff.
> Upstream diff is large, but it's mostly security/CVE fixes, as can be
> seen in the commit messages (the relevant commits are starting from
> 2022-12-22):
> 
> https://code.qt.io/cgit/qt/qtwebengine-chromium.git/log/?h=87-based
> 
> I have also included a patch from bug #1005824 to build with pipewire
> support. If a new release is acceptable but that patch is not, I can
> remove it.

We are past the point of adding new features. Please postpone this
change to trixie.

Cheers

> 
> --
> Dmitry Shachnev

> diff --git a/debian/changelog b/debian/changelog
> index 9f4762d..afa565a 100644
> --- a/debian/changelog
> +++ b/debian/changelog
> @@ -1,3 +1,19 @@
> +qtwebengine-opensource-src (5.15.13+dfsg-1) UNRELEASED; urgency=medium
> +
> +  [ Dmitry Shachnev ]
> +  * New upstream release.
> +  * Update SUBMODULE_COMMIT for the new release.
> +  * Remove copyright section for debian/missing-sources/jszip-2.4.0.
> +  * Build with pipewire support (closes: #1005824).
> +    - Backport upstream patch to improve screen sharing with PipeWire
> +      on Wayland and to add support for PipeWire 0.3.
> +    - Thanks Pirate Praveen and C�ic Hannotier!
> +  * Bump ABI version to qtwebengine-abi-5-15-13.
> +  * Drop gcc-12.patch, included in the new release.
> +  * Refresh debian/patches/python3.patch.
> +
> + -- Debian Qt/KDE Maintainers <debian-qt-kde@lists.debian.org>  Sat, 11 Feb 2023 13:19:26 +0400
> +
>  qtwebengine-opensource-src (5.15.12+dfsg-3) unstable; urgency=medium
>  
>    * Add debian/90qtwebengine-dictionaries-path.conf.
> diff --git a/debian/control b/debian/control
> index 827e12c..72d1c65 100644
> --- a/debian/control
> +++ b/debian/control
> @@ -39,6 +39,7 @@ Build-Depends: binutils (>= 2.32-8~),
>                 libopenjp2-7-dev,
>                 libopus-dev (>= 1.3.1),
>                 libpci-dev,
> +               libpipewire-0.3-dev,
>                 libpng-dev,
>                 libprotobuf-dev,
>                 libpulse-dev,
> @@ -158,7 +159,7 @@ Description: Web content engine library for Qt
>  Package: libqt5webenginecore5
>  Architecture: amd64 arm64 armhf i386 mips64el mipsel
>  Multi-Arch: same
> -Provides: qtwebengine-abi-5-15-12
> +Provides: qtwebengine-abi-5-15-13
>  Depends: libqt5webengine-data (= ${source:Version}),
>           sse2-support [i386],
>           ${misc:Depends},
> diff --git a/debian/copyright b/debian/copyright
> index 01fc92e..f8e99e9 100644
> --- a/debian/copyright
> +++ b/debian/copyright
> @@ -120,10 +120,6 @@ Files: src/3rdparty/ninja/*
>  Copyright: 2011-2018 Google Inc.
>  License: Apache-2.0
>  
> -Files: debian/missing-sources/jszip-2.4.0/*
> -Copyright: 2009-2014 Stuart Knightley, David Duponchel, Franz Buchinger, Ant� Afonso
> -License: MIT or GPL-3
> -
>  ## BEGIN AUTO GENERATED BLOCK
>  
>  Files: examples/webengine/quicknanobrowser/icons/3rdparty/*
> diff --git a/debian/libqt5webengine5.symbols b/debian/libqt5webengine5.symbols
> index 2dcf53f..a555804 100644
> --- a/debian/libqt5webengine5.symbols
> +++ b/debian/libqt5webengine5.symbols
> @@ -1,6 +1,6 @@
>  # SymbolsHelper-Confirmed: 5.15.5 amd64
>  libQt5WebEngine.so.5 libqt5webengine5 #MINVER#
> -| libqt5webengine5 #MINVER#, qtwebengine-abi-5-15-12
> +| libqt5webengine5 #MINVER#, qtwebengine-abi-5-15-13
>  * Build-Depends-Package: qtwebengine5-dev
>   Qt_5.0@Qt_5.0 5.7.1
>   Qt_5.10@Qt_5.10 5.10.1
> diff --git a/debian/libqt5webenginecore5.symbols b/debian/libqt5webenginecore5.symbols
> index 286c991..58e1462 100644
> --- a/debian/libqt5webenginecore5.symbols
> +++ b/debian/libqt5webenginecore5.symbols
> @@ -1,6 +1,6 @@
>  # SymbolsHelper-Confirmed: 5.15.10 amd64 arm64 armhf i386 mips64el mipsel
>  libQt5WebEngineCore.so.5 libqt5webenginecore5 #MINVER#
> -| libqt5webenginecore5 #MINVER#, qtwebengine-abi-5-15-12
> +| libqt5webenginecore5 #MINVER#, qtwebengine-abi-5-15-13
>  * Build-Depends-Package: qtwebengine5-dev
>   (optional=gold)Qt_5.0@Qt_5.0 5.7.1
>   (optional=gold)Qt_5.10@Qt_5.10 5.10.1
> diff --git a/debian/libqt5webenginewidgets5.symbols b/debian/libqt5webenginewidgets5.symbols
> index ec9760b..4773255 100644
> --- a/debian/libqt5webenginewidgets5.symbols
> +++ b/debian/libqt5webenginewidgets5.symbols
> @@ -1,6 +1,6 @@
>  # SymbolsHelper-Confirmed: 5.15.3 amd64 mips64el
>  libQt5WebEngineWidgets.so.5 libqt5webenginewidgets5 #MINVER#
> -| libqt5webenginewidgets5 #MINVER#, qtwebengine-abi-5-15-12
> +| libqt5webenginewidgets5 #MINVER#, qtwebengine-abi-5-15-13
>  * Build-Depends-Package: qtwebengine5-dev
>   Qt_5.0@Qt_5.0 5.7.1
>   Qt_5.10@Qt_5.10 5.10.1
> diff --git a/debian/patches/gcc-12.patch b/debian/patches/gcc-12.patch
> deleted file mode 100644
> index c7f43fe..0000000
> --- a/debian/patches/gcc-12.patch
> +++ /dev/null
> @@ -1,15 +0,0 @@
> -Description: fix build with GCC 12
> -Origin: upstream skia, https://chromium.googlesource.com/skia/+/cd397f3c4738beb6
> -Last-Update: 2022-06-26
> -
> ---- a/src/3rdparty/chromium/third_party/skia/src/utils/SkParseColor.cpp
> -+++ b/src/3rdparty/chromium/third_party/skia/src/utils/SkParseColor.cpp
> -@@ -8,6 +8,8 @@
> - 
> - #include "include/utils/SkParse.h"
> - 
> -+#include <iterator>
> -+
> - static constexpr const char* gColorNames[] = {
> -     "aliceblue",
> -     "antiquewhite",
> diff --git a/debian/patches/pipewire-0.3.patch b/debian/patches/pipewire-0.3.patch
> new file mode 100644
> index 0000000..7854392
> --- /dev/null
> +++ b/debian/patches/pipewire-0.3.patch
> @@ -0,0 +1,1792 @@
> +Description: add support for PipeWire 0.3
> +Origin: upstream webrtc, commits:
> + - https://webrtc.googlesource.com/src/+/40c3ea5c7146cb7e
> + - https://webrtc.googlesource.com/src/+/c3c81297365b6a29
> +Bug: https://bugs.debian.org/1005824
> +Last-Update: 2023-02-11
> +
> +--- a/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/BUILD.gn
> ++++ b/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/BUILD.gn
> +@@ -11,6 +11,11 @@ import("//build/config/ui.gni")
> + import("//tools/generate_stubs/rules.gni")
> + import("../../webrtc.gni")
> + 
> ++if (rtc_use_pipewire) {
> ++  assert(rtc_pipewire_version == "0.2" || rtc_pipewire_version == "0.3",
> ++         "Unsupported PipeWire version")
> ++}
> ++
> + use_desktop_capture_differ_sse2 = current_cpu == "x86" || current_cpu == "x64"
> + 
> + config("x11_config") {
> +@@ -200,22 +205,41 @@ if (is_linux || is_chromeos) {
> +       ]
> +     }
> + 
> +-    if (rtc_link_pipewire) {
> ++    if (rtc_pipewire_version == "0.3") {
> +       pkg_config("pipewire") {
> +-        packages = [ "libpipewire-0.2" ]
> ++        packages = [ "libpipewire-0.3" ]
> ++        if (!rtc_link_pipewire) {
> ++          ignore_libs = true
> ++        }
> +       }
> +     } else {
> ++      pkg_config("pipewire") {
> ++        packages = [ "libpipewire-0.2" ]
> ++        if (!rtc_link_pipewire) {
> ++          ignore_libs = true
> ++        }
> ++      }
> ++    }
> ++
> ++    if (!rtc_link_pipewire) {
> +       # When libpipewire is not directly linked, use stubs to allow for dlopening of
> +       # the binary.
> +       generate_stubs("pipewire_stubs") {
> +-        configs = [ "../../:common_config" ]
> ++        configs = [
> ++          "../../:common_config",
> ++          ":pipewire",
> ++        ]
> +         deps = [ "../../rtc_base" ]
> +         extra_header = "linux/pipewire_stub_header.fragment"
> +         logging_function = "RTC_LOG(LS_VERBOSE)"
> +         logging_include = "rtc_base/logging.h"
> +         output_name = "linux/pipewire_stubs"
> +         path_from_source = "modules/desktop_capture/linux"
> +-        sigs = [ "linux/pipewire.sigs" ]
> ++        if (rtc_pipewire_version == "0.3") {
> ++          sigs = [ "linux/pipewire03.sigs" ]
> ++        } else {
> ++          sigs = [ "linux/pipewire02.sigs" ]
> ++        }
> +       }
> +     }
> + 
> +@@ -506,6 +530,7 @@ rtc_library("desktop_capture_generic") {
> +   absl_deps = [
> +     "//third_party/abseil-cpp/absl/memory",
> +     "//third_party/abseil-cpp/absl/strings",
> ++    "//third_party/abseil-cpp/absl/types:optional",
> +   ]
> + 
> +   if (rtc_use_x11_extensions) {
> +@@ -526,20 +551,15 @@ rtc_library("desktop_capture_generic") {
> +     sources += [
> +       "linux/base_capturer_pipewire.cc",
> +       "linux/base_capturer_pipewire.h",
> +-      "linux/screen_capturer_pipewire.cc",
> +-      "linux/screen_capturer_pipewire.h",
> +-      "linux/window_capturer_pipewire.cc",
> +-      "linux/window_capturer_pipewire.h",
> +     ]
> + 
> +     configs += [
> +       ":pipewire_config",
> +       ":gio",
> ++      ":pipewire",
> +     ]
> + 
> +-    if (rtc_link_pipewire) {
> +-      configs += [ ":pipewire" ]
> +-    } else {
> ++    if (!rtc_link_pipewire) {
> +       deps += [ ":pipewire_stubs" ]
> +     }
> +   }
> +--- a/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc
> ++++ b/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc
> +@@ -14,8 +14,14 @@
> + #include <glib-object.h>
> + #include <spa/param/format-utils.h>
> + #include <spa/param/props.h>
> ++#if !PW_CHECK_VERSION(0, 3, 0)
> + #include <spa/param/video/raw-utils.h>
> + #include <spa/support/type-map.h>
> ++#endif
> ++
> ++#include <sys/ioctl.h>
> ++#include <sys/mman.h>
> ++#include <sys/syscall.h>
> + 
> + #include <memory>
> + #include <utility>
> +@@ -30,7 +36,11 @@
> + #include "modules/desktop_capture/linux/pipewire_stubs.h"
> + 
> + using modules_desktop_capture_linux::InitializeStubs;
> +-using modules_desktop_capture_linux::kModulePipewire;
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++using modules_desktop_capture_linux::kModulePipewire03;
> ++#else
> ++using modules_desktop_capture_linux::kModulePipewire02;
> ++#endif
> + using modules_desktop_capture_linux::StubPathMap;
> + #endif  // defined(WEBRTC_DLOPEN_PIPEWIRE)
> + 
> +@@ -47,10 +57,157 @@ const char kScreenCastInterfaceName[] =
> + const int kBytesPerPixel = 4;
> + 
> + #if defined(WEBRTC_DLOPEN_PIPEWIRE)
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++const char kPipeWireLib[] = "libpipewire-0.3.so.0";
> ++#else
> + const char kPipeWireLib[] = "libpipewire-0.2.so.1";
> + #endif
> ++#endif
> + 
> + // static
> ++struct dma_buf_sync {
> ++  uint64_t flags;
> ++};
> ++#define DMA_BUF_SYNC_READ (1 << 0)
> ++#define DMA_BUF_SYNC_START (0 << 2)
> ++#define DMA_BUF_SYNC_END (1 << 2)
> ++#define DMA_BUF_BASE 'b'
> ++#define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
> ++
> ++static void SyncDmaBuf(int fd, uint64_t start_or_end) {
> ++  struct dma_buf_sync sync = {0};
> ++
> ++  sync.flags = start_or_end | DMA_BUF_SYNC_READ;
> ++
> ++  while (true) {
> ++    int ret;
> ++    ret = ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync);
> ++    if (ret == -1 && errno == EINTR) {
> ++      continue;
> ++    } else if (ret == -1) {
> ++      RTC_LOG(LS_ERROR) << "Failed to synchronize DMA buffer: "
> ++                        << g_strerror(errno);
> ++      break;
> ++    } else {
> ++      break;
> ++    }
> ++  }
> ++}
> ++
> ++class ScopedBuf {
> ++ public:
> ++  ScopedBuf() {}
> ++  ScopedBuf(unsigned char* map, int map_size, bool is_dma_buf, int fd)
> ++      : map_(map), map_size_(map_size), is_dma_buf_(is_dma_buf), fd_(fd) {}
> ++  ~ScopedBuf() {
> ++    if (map_ != MAP_FAILED) {
> ++      if (is_dma_buf_) {
> ++        SyncDmaBuf(fd_, DMA_BUF_SYNC_END);
> ++      }
> ++      munmap(map_, map_size_);
> ++    }
> ++  }
> ++
> ++  operator bool() { return map_ != MAP_FAILED; }
> ++
> ++  void initialize(unsigned char* map, int map_size, bool is_dma_buf, int fd) {
> ++    map_ = map;
> ++    map_size_ = map_size;
> ++    is_dma_buf_ = is_dma_buf;
> ++    fd_ = fd;
> ++  }
> ++
> ++  unsigned char* get() { return map_; }
> ++
> ++ protected:
> ++  unsigned char* map_ = nullptr;
> ++  int map_size_;
> ++  bool is_dma_buf_;
> ++  int fd_;
> ++};
> ++
> ++template <class T>
> ++class Scoped {
> ++ public:
> ++  Scoped() {}
> ++  explicit Scoped(T* val) { ptr_ = val; }
> ++  ~Scoped() { RTC_NOTREACHED(); }
> ++
> ++  T* operator->() { return ptr_; }
> ++
> ++  bool operator!() { return ptr_ == nullptr; }
> ++
> ++  T* get() { return ptr_; }
> ++
> ++  T** receive() {
> ++    RTC_CHECK(!ptr_);
> ++    return &ptr_;
> ++  }
> ++
> ++  Scoped& operator=(T* val) {
> ++    ptr_ = val;
> ++    return *this;
> ++  }
> ++
> ++ protected:
> ++  T* ptr_ = nullptr;
> ++};
> ++
> ++template <>
> ++Scoped<GError>::~Scoped() {
> ++  if (ptr_) {
> ++    g_error_free(ptr_);
> ++  }
> ++}
> ++
> ++template <>
> ++Scoped<gchar>::~Scoped() {
> ++  if (ptr_) {
> ++    g_free(ptr_);
> ++  }
> ++}
> ++
> ++template <>
> ++Scoped<GVariant>::~Scoped() {
> ++  if (ptr_) {
> ++    g_variant_unref(ptr_);
> ++  }
> ++}
> ++
> ++template <>
> ++Scoped<GVariantIter>::~Scoped() {
> ++  if (ptr_) {
> ++    g_variant_iter_free(ptr_);
> ++  }
> ++}
> ++
> ++template <>
> ++Scoped<GDBusMessage>::~Scoped() {
> ++  if (ptr_) {
> ++    g_object_unref(ptr_);
> ++  }
> ++}
> ++
> ++template <>
> ++Scoped<GUnixFDList>::~Scoped() {
> ++  if (ptr_) {
> ++    g_object_unref(ptr_);
> ++  }
> ++}
> ++
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++void BaseCapturerPipeWire::OnCoreError(void* data,
> ++                                       uint32_t id,
> ++                                       int seq,
> ++                                       int res,
> ++                                       const char* message) {
> ++  BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data);
> ++  RTC_DCHECK(that);
> ++
> ++  RTC_LOG(LS_ERROR) << "PipeWire remote error: " << message;
> ++}
> ++#else
> ++// static
> + void BaseCapturerPipeWire::OnStateChanged(void* data,
> +                                           pw_remote_state old_state,
> +                                           pw_remote_state state,
> +@@ -64,7 +221,7 @@ void BaseCapturerPipeWire::OnStateChange
> +       break;
> +     case PW_REMOTE_STATE_CONNECTED:
> +       RTC_LOG(LS_INFO) << "PipeWire remote state: connected.";
> +-      that->CreateReceivingStream();
> ++      that->pw_stream_ = that->CreateReceivingStream();
> +       break;
> +     case PW_REMOTE_STATE_CONNECTING:
> +       RTC_LOG(LS_INFO) << "PipeWire remote state: connecting.";
> +@@ -74,6 +231,7 @@ void BaseCapturerPipeWire::OnStateChange
> +       break;
> +   }
> + }
> ++#endif
> + 
> + // static
> + void BaseCapturerPipeWire::OnStreamStateChanged(void* data,
> +@@ -83,6 +241,18 @@ void BaseCapturerPipeWire::OnStreamState
> +   BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data);
> +   RTC_DCHECK(that);
> + 
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  switch (state) {
> ++    case PW_STREAM_STATE_ERROR:
> ++      RTC_LOG(LS_ERROR) << "PipeWire stream state error: " << error_message;
> ++      break;
> ++    case PW_STREAM_STATE_PAUSED:
> ++    case PW_STREAM_STATE_STREAMING:
> ++    case PW_STREAM_STATE_UNCONNECTED:
> ++    case PW_STREAM_STATE_CONNECTING:
> ++      break;
> ++  }
> ++#else
> +   switch (state) {
> +     case PW_STREAM_STATE_ERROR:
> +       RTC_LOG(LS_ERROR) << "PipeWire stream state error: " << error_message;
> +@@ -97,36 +267,74 @@ void BaseCapturerPipeWire::OnStreamState
> +     case PW_STREAM_STATE_STREAMING:
> +       break;
> +   }
> ++#endif
> + }
> + 
> + // static
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++void BaseCapturerPipeWire::OnStreamParamChanged(void* data,
> ++                                                uint32_t id,
> ++                                                const struct spa_pod* format) {
> ++#else
> + void BaseCapturerPipeWire::OnStreamFormatChanged(void* data,
> +                                                  const struct spa_pod* format) {
> ++#endif
> +   BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data);
> +   RTC_DCHECK(that);
> + 
> +   RTC_LOG(LS_INFO) << "PipeWire stream format changed.";
> + 
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  if (!format || id != SPA_PARAM_Format) {
> ++#else
> +   if (!format) {
> +     pw_stream_finish_format(that->pw_stream_, /*res=*/0, /*params=*/nullptr,
> +                             /*n_params=*/0);
> ++#endif
> +     return;
> +   }
> + 
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  spa_format_video_raw_parse(format, &that->spa_video_format_);
> ++#else
> +   that->spa_video_format_ = new spa_video_info_raw();
> +   spa_format_video_raw_parse(format, that->spa_video_format_,
> +                              &that->pw_type_->format_video);
> ++#endif
> + 
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  auto width = that->spa_video_format_.size.width;
> ++  auto height = that->spa_video_format_.size.height;
> ++#else
> +   auto width = that->spa_video_format_->size.width;
> +   auto height = that->spa_video_format_->size.height;
> ++#endif
> +   auto stride = SPA_ROUND_UP_N(width * kBytesPerPixel, 4);
> +   auto size = height * stride;
> + 
> ++  that->desktop_size_ = DesktopSize(width, height);
> ++
> +   uint8_t buffer[1024] = {};
> +   auto builder = spa_pod_builder{buffer, sizeof(buffer)};
> + 
> +   // Setup buffers and meta header for new format.
> +-  const struct spa_pod* params[2];
> ++  const struct spa_pod* params[3];
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_add_object(
> ++      &builder, SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
> ++      SPA_PARAM_BUFFERS_size, SPA_POD_Int(size), SPA_PARAM_BUFFERS_stride,
> ++      SPA_POD_Int(stride), SPA_PARAM_BUFFERS_buffers,
> ++      SPA_POD_CHOICE_RANGE_Int(8, 1, 32)));
> ++  params[1] = reinterpret_cast<spa_pod*>(spa_pod_builder_add_object(
> ++      &builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, SPA_PARAM_META_type,
> ++      SPA_POD_Id(SPA_META_Header), SPA_PARAM_META_size,
> ++      SPA_POD_Int(sizeof(struct spa_meta_header))));
> ++  params[2] = reinterpret_cast<spa_pod*>(spa_pod_builder_add_object(
> ++      &builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, SPA_PARAM_META_type,
> ++      SPA_POD_Id(SPA_META_VideoCrop), SPA_PARAM_META_size,
> ++      SPA_POD_Int(sizeof(struct spa_meta_region))));
> ++  pw_stream_update_params(that->pw_stream_, params, 3);
> ++#else
> +   params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_object(
> +       &builder,
> +       // id to enumerate buffer requirements
> +@@ -155,8 +363,18 @@ void BaseCapturerPipeWire::OnStreamForma
> +       // Size: size of the metadata, specified as integer (i)
> +       ":", that->pw_core_type_->param_meta.size, "i",
> +       sizeof(struct spa_meta_header)));
> +-
> +-  pw_stream_finish_format(that->pw_stream_, /*res=*/0, params, /*n_params=*/2);
> ++  params[2] = reinterpret_cast<spa_pod*>(spa_pod_builder_object(
> ++      &builder,
> ++      // id to enumerate supported metadata
> ++      that->pw_core_type_->param.idMeta, that->pw_core_type_->param_meta.Meta,
> ++      // Type: specified as id or enum (I)
> ++      ":", that->pw_core_type_->param_meta.type, "I",
> ++      that->pw_core_type_->meta.VideoCrop,
> ++      // Size: size of the metadata, specified as integer (i)
> ++      ":", that->pw_core_type_->param_meta.size, "i",
> ++      sizeof(struct spa_meta_video_crop)));
> ++  pw_stream_finish_format(that->pw_stream_, /*res=*/0, params, /*n_params=*/3);
> ++#endif
> + }
> + 
> + // static
> +@@ -164,15 +382,26 @@ void BaseCapturerPipeWire::OnStreamProce
> +   BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data);
> +   RTC_DCHECK(that);
> + 
> +-  pw_buffer* buf = nullptr;
> ++  struct pw_buffer* next_buffer;
> ++  struct pw_buffer* buffer = nullptr;
> + 
> +-  if (!(buf = pw_stream_dequeue_buffer(that->pw_stream_))) {
> ++  next_buffer = pw_stream_dequeue_buffer(that->pw_stream_);
> ++  while (next_buffer) {
> ++    buffer = next_buffer;
> ++    next_buffer = pw_stream_dequeue_buffer(that->pw_stream_);
> ++
> ++    if (next_buffer) {
> ++      pw_stream_queue_buffer(that->pw_stream_, buffer);
> ++    }
> ++  }
> ++
> ++  if (!buffer) {
> +     return;
> +   }
> + 
> +-  that->HandleBuffer(buf);
> ++  that->HandleBuffer(buffer);
> + 
> +-  pw_stream_queue_buffer(that->pw_stream_, buf);
> ++  pw_stream_queue_buffer(that->pw_stream_, buffer);
> + }
> + 
> + BaseCapturerPipeWire::BaseCapturerPipeWire(CaptureSourceType source_type)
> +@@ -183,6 +412,7 @@ BaseCapturerPipeWire::~BaseCapturerPipeW
> +     pw_thread_loop_stop(pw_main_loop_);
> +   }
> + 
> ++#if !PW_CHECK_VERSION(0, 3, 0)
> +   if (pw_type_) {
> +     delete pw_type_;
> +   }
> +@@ -190,30 +420,41 @@ BaseCapturerPipeWire::~BaseCapturerPipeW
> +   if (spa_video_format_) {
> +     delete spa_video_format_;
> +   }
> ++#endif
> + 
> +   if (pw_stream_) {
> +     pw_stream_destroy(pw_stream_);
> +   }
> + 
> ++#if !PW_CHECK_VERSION(0, 3, 0)
> +   if (pw_remote_) {
> +     pw_remote_destroy(pw_remote_);
> +   }
> ++#endif
> + 
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  if (pw_core_) {
> ++    pw_core_disconnect(pw_core_);
> ++  }
> ++
> ++  if (pw_context_) {
> ++    pw_context_destroy(pw_context_);
> ++  }
> ++#else
> +   if (pw_core_) {
> +     pw_core_destroy(pw_core_);
> +   }
> ++#endif
> + 
> +   if (pw_main_loop_) {
> +     pw_thread_loop_destroy(pw_main_loop_);
> +   }
> + 
> ++#if !PW_CHECK_VERSION(0, 3, 0)
> +   if (pw_loop_) {
> +     pw_loop_destroy(pw_loop_);
> +   }
> +-
> +-  if (current_frame_) {
> +-    free(current_frame_);
> +-  }
> ++#endif
> + 
> +   if (start_request_signal_id_) {
> +     g_dbus_connection_signal_unsubscribe(connection_, start_request_signal_id_);
> +@@ -228,18 +469,16 @@ BaseCapturerPipeWire::~BaseCapturerPipeW
> +   }
> + 
> +   if (session_handle_) {
> +-    GDBusMessage* message = g_dbus_message_new_method_call(
> +-        kDesktopBusName, session_handle_, kSessionInterfaceName, "Close");
> +-    if (message) {
> +-      GError* error = nullptr;
> +-      g_dbus_connection_send_message(connection_, message,
> ++    Scoped<GDBusMessage> message(g_dbus_message_new_method_call(
> ++        kDesktopBusName, session_handle_, kSessionInterfaceName, "Close"));
> ++    if (message.get()) {
> ++      Scoped<GError> error;
> ++      g_dbus_connection_send_message(connection_, message.get(),
> +                                      G_DBUS_SEND_MESSAGE_FLAGS_NONE,
> +-                                     /*out_serial=*/nullptr, &error);
> +-      if (error) {
> ++                                     /*out_serial=*/nullptr, error.receive());
> ++      if (error.get()) {
> +         RTC_LOG(LS_ERROR) << "Failed to close the session: " << error->message;
> +-        g_error_free(error);
> +       }
> +-      g_object_unref(message);
> +     }
> +   }
> + 
> +@@ -274,7 +513,11 @@ void BaseCapturerPipeWire::InitPipeWire(
> +   StubPathMap paths;
> + 
> +   // Check if the PipeWire library is available.
> +-  paths[kModulePipewire].push_back(kPipeWireLib);
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  paths[kModulePipewire03].push_back(kPipeWireLib);
> ++#else
> ++  paths[kModulePipewire02].push_back(kPipeWireLib);
> ++#endif
> +   if (!InitializeStubs(paths)) {
> +     RTC_LOG(LS_ERROR) << "Failed to load the PipeWire library and symbols.";
> +     portal_init_failed_ = true;
> +@@ -284,16 +527,46 @@ void BaseCapturerPipeWire::InitPipeWire(
> + 
> +   pw_init(/*argc=*/nullptr, /*argc=*/nullptr);
> + 
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  pw_main_loop_ = pw_thread_loop_new("pipewire-main-loop", nullptr);
> ++
> ++  pw_thread_loop_lock(pw_main_loop_);
> ++
> ++  pw_context_ =
> ++      pw_context_new(pw_thread_loop_get_loop(pw_main_loop_), nullptr, 0);
> ++  if (!pw_context_) {
> ++    RTC_LOG(LS_ERROR) << "Failed to create PipeWire context";
> ++    return;
> ++  }
> ++
> ++  pw_core_ = pw_context_connect(pw_context_, nullptr, 0);
> ++  if (!pw_core_) {
> ++    RTC_LOG(LS_ERROR) << "Failed to connect PipeWire context";
> ++    return;
> ++  }
> ++#else
> +   pw_loop_ = pw_loop_new(/*properties=*/nullptr);
> +   pw_main_loop_ = pw_thread_loop_new(pw_loop_, "pipewire-main-loop");
> + 
> ++  pw_thread_loop_lock(pw_main_loop_);
> ++
> +   pw_core_ = pw_core_new(pw_loop_, /*properties=*/nullptr);
> +   pw_core_type_ = pw_core_get_type(pw_core_);
> +   pw_remote_ = pw_remote_new(pw_core_, nullptr, /*user_data_size=*/0);
> + 
> +   InitPipeWireTypes();
> ++#endif
> + 
> +   // Initialize event handlers, remote end and stream-related.
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  pw_core_events_.version = PW_VERSION_CORE_EVENTS;
> ++  pw_core_events_.error = &OnCoreError;
> ++
> ++  pw_stream_events_.version = PW_VERSION_STREAM_EVENTS;
> ++  pw_stream_events_.state_changed = &OnStreamStateChanged;
> ++  pw_stream_events_.param_changed = &OnStreamParamChanged;
> ++  pw_stream_events_.process = &OnStreamProcess;
> ++#else
> +   pw_remote_events_.version = PW_VERSION_REMOTE_EVENTS;
> +   pw_remote_events_.state_changed = &OnStateChanged;
> + 
> +@@ -301,19 +574,33 @@ void BaseCapturerPipeWire::InitPipeWire(
> +   pw_stream_events_.state_changed = &OnStreamStateChanged;
> +   pw_stream_events_.format_changed = &OnStreamFormatChanged;
> +   pw_stream_events_.process = &OnStreamProcess;
> ++#endif
> ++
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  pw_core_add_listener(pw_core_, &spa_core_listener_, &pw_core_events_, this);
> + 
> ++  pw_stream_ = CreateReceivingStream();
> ++  if (!pw_stream_) {
> ++    RTC_LOG(LS_ERROR) << "Failed to create PipeWire stream";
> ++    return;
> ++  }
> ++#else
> +   pw_remote_add_listener(pw_remote_, &spa_remote_listener_, &pw_remote_events_,
> +                          this);
> +   pw_remote_connect_fd(pw_remote_, pw_fd_);
> ++#endif
> + 
> +   if (pw_thread_loop_start(pw_main_loop_) < 0) {
> +     RTC_LOG(LS_ERROR) << "Failed to start main PipeWire loop";
> +     portal_init_failed_ = true;
> +   }
> + 
> ++  pw_thread_loop_unlock(pw_main_loop_);
> ++
> +   RTC_LOG(LS_INFO) << "PipeWire remote opened.";
> + }
> + 
> ++#if !PW_CHECK_VERSION(0, 3, 0)
> + void BaseCapturerPipeWire::InitPipeWireTypes() {
> +   spa_type_map* map = pw_core_type_->map;
> +   pw_type_ = new PipeWireType();
> +@@ -323,23 +610,44 @@ void BaseCapturerPipeWire::InitPipeWireT
> +   spa_type_format_video_map(map, &pw_type_->format_video);
> +   spa_type_video_format_map(map, &pw_type_->video_format);
> + }
> ++#endif
> + 
> +-void BaseCapturerPipeWire::CreateReceivingStream() {
> ++pw_stream* BaseCapturerPipeWire::CreateReceivingStream() {
> ++#if !PW_CHECK_VERSION(0, 3, 0)
> ++  if (pw_remote_get_state(pw_remote_, nullptr) != PW_REMOTE_STATE_CONNECTED) {
> ++    RTC_LOG(LS_ERROR) << "Cannot create pipewire stream";
> ++    return nullptr;
> ++  }
> ++#endif
> +   spa_rectangle pwMinScreenBounds = spa_rectangle{1, 1};
> +-  spa_rectangle pwScreenBounds =
> +-      spa_rectangle{static_cast<uint32_t>(desktop_size_.width()),
> +-                    static_cast<uint32_t>(desktop_size_.height())};
> +-
> +-  spa_fraction pwFrameRateMin = spa_fraction{0, 1};
> +-  spa_fraction pwFrameRateMax = spa_fraction{60, 1};
> ++  spa_rectangle pwMaxScreenBounds = spa_rectangle{UINT32_MAX, UINT32_MAX};
> + 
> +   pw_properties* reuseProps =
> +       pw_properties_new_string("pipewire.client.reuse=1");
> +-  pw_stream_ = pw_stream_new(pw_remote_, "webrtc-consume-stream", reuseProps);
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  auto stream = pw_stream_new(pw_core_, "webrtc-consume-stream", reuseProps);
> ++#else
> ++  auto stream = pw_stream_new(pw_remote_, "webrtc-consume-stream", reuseProps);
> ++#endif
> + 
> +   uint8_t buffer[1024] = {};
> +   const spa_pod* params[1];
> +   spa_pod_builder builder = spa_pod_builder{buffer, sizeof(buffer)};
> ++
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_add_object(
> ++      &builder, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
> ++      SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
> ++      SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
> ++      SPA_FORMAT_VIDEO_format,
> ++      SPA_POD_CHOICE_ENUM_Id(5, SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_RGBx,
> ++                             SPA_VIDEO_FORMAT_RGBA, SPA_VIDEO_FORMAT_BGRx,
> ++                             SPA_VIDEO_FORMAT_BGRA),
> ++      SPA_FORMAT_VIDEO_size,
> ++      SPA_POD_CHOICE_RANGE_Rectangle(&pwMinScreenBounds, &pwMinScreenBounds,
> ++                                     &pwMaxScreenBounds),
> ++      0));
> ++#else
> +   params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_object(
> +       &builder,
> +       // id to enumerate formats
> +@@ -349,69 +657,218 @@ void BaseCapturerPipeWire::CreateReceivi
> +       // then allowed formats are enumerated (e) and the format is undecided (u)
> +       // to allow negotiation
> +       ":", pw_type_->format_video.format, "Ieu", pw_type_->video_format.BGRx,
> +-      SPA_POD_PROP_ENUM(2, pw_type_->video_format.RGBx,
> +-                        pw_type_->video_format.BGRx),
> ++      SPA_POD_PROP_ENUM(
> ++          4, pw_type_->video_format.RGBx, pw_type_->video_format.BGRx,
> ++          pw_type_->video_format.RGBA, pw_type_->video_format.BGRA),
> +       // Video size: specified as rectangle (R), preferred size is specified as
> +       // first parameter, then allowed size is defined as range (r) from min and
> +       // max values and the format is undecided (u) to allow negotiation
> +-      ":", pw_type_->format_video.size, "Rru", &pwScreenBounds, 2,
> +-      &pwMinScreenBounds, &pwScreenBounds,
> +-      // Frame rate: specified as fraction (F) and set to minimum frame rate
> +-      // value
> +-      ":", pw_type_->format_video.framerate, "F", &pwFrameRateMin,
> +-      // Max frame rate: specified as fraction (F), preferred frame rate is set
> +-      // to maximum value, then allowed frame rate is defined as range (r) from
> +-      // min and max values and it is undecided (u) to allow negotiation
> +-      ":", pw_type_->format_video.max_framerate, "Fru", &pwFrameRateMax, 2,
> +-      &pwFrameRateMin, &pwFrameRateMax));
> ++      ":", pw_type_->format_video.size, "Rru", &pwMinScreenBounds,
> ++      SPA_POD_PROP_MIN_MAX(&pwMinScreenBounds, &pwMaxScreenBounds)));
> ++#endif
> + 
> +-  pw_stream_add_listener(pw_stream_, &spa_stream_listener_, &pw_stream_events_,
> ++  pw_stream_add_listener(stream, &spa_stream_listener_, &pw_stream_events_,
> +                          this);
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  if (pw_stream_connect(stream, PW_DIRECTION_INPUT, pw_stream_node_id_,
> ++                        PW_STREAM_FLAG_AUTOCONNECT, params, 1) != 0) {
> ++#else
> +   pw_stream_flags flags = static_cast<pw_stream_flags>(
> +-      PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE |
> +-      PW_STREAM_FLAG_MAP_BUFFERS);
> +-  if (pw_stream_connect(pw_stream_, PW_DIRECTION_INPUT, /*port_path=*/nullptr,
> ++      PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE);
> ++  if (pw_stream_connect(stream, PW_DIRECTION_INPUT, /*port_path=*/nullptr,
> +                         flags, params,
> +                         /*n_params=*/1) != 0) {
> ++#endif
> +     RTC_LOG(LS_ERROR) << "Could not connect receiving stream.";
> +     portal_init_failed_ = true;
> +-    return;
> ++    return nullptr;
> +   }
> ++
> ++  return stream;
> + }
> + 
> + void BaseCapturerPipeWire::HandleBuffer(pw_buffer* buffer) {
> +   spa_buffer* spaBuffer = buffer->buffer;
> +-  void* src = nullptr;
> ++  ScopedBuf map;
> ++  uint8_t* src = nullptr;
> ++
> ++  if (spaBuffer->datas[0].chunk->size == 0) {
> ++    RTC_LOG(LS_ERROR) << "Failed to get video stream: Zero size.";
> ++    return;
> ++  }
> ++
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  if (spaBuffer->datas[0].type == SPA_DATA_MemFd ||
> ++      spaBuffer->datas[0].type == SPA_DATA_DmaBuf) {
> ++#else
> ++  if (spaBuffer->datas[0].type == pw_core_type_->data.MemFd ||
> ++      spaBuffer->datas[0].type == pw_core_type_->data.DmaBuf) {
> ++#endif
> ++    map.initialize(
> ++        static_cast<uint8_t*>(
> ++            mmap(nullptr,
> ++                 spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset,
> ++                 PROT_READ, MAP_PRIVATE, spaBuffer->datas[0].fd, 0)),
> ++        spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset,
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++        spaBuffer->datas[0].type == SPA_DATA_DmaBuf,
> ++#else
> ++        spaBuffer->datas[0].type == pw_core_type_->data.DmaBuf,
> ++#endif
> ++        spaBuffer->datas[0].fd);
> ++
> ++    if (!map) {
> ++      RTC_LOG(LS_ERROR) << "Failed to mmap the memory: "
> ++                        << std::strerror(errno);
> ++      return;
> ++    }
> ++
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++    if (spaBuffer->datas[0].type == SPA_DATA_DmaBuf) {
> ++#else
> ++    if (spaBuffer->datas[0].type == pw_core_type_->data.DmaBuf) {
> ++#endif
> ++      SyncDmaBuf(spaBuffer->datas[0].fd, DMA_BUF_SYNC_START);
> ++    }
> ++
> ++    src = SPA_MEMBER(map.get(), spaBuffer->datas[0].mapoffset, uint8_t);
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  } else if (spaBuffer->datas[0].type == SPA_DATA_MemPtr) {
> ++#else
> ++  } else if (spaBuffer->datas[0].type == pw_core_type_->data.MemPtr) {
> ++#endif
> ++    src = static_cast<uint8_t*>(spaBuffer->datas[0].data);
> ++  }
> ++
> ++  if (!src) {
> ++    return;
> ++  }
> ++
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  struct spa_meta_region* video_metadata =
> ++      static_cast<struct spa_meta_region*>(spa_buffer_find_meta_data(
> ++          spaBuffer, SPA_META_VideoCrop, sizeof(*video_metadata)));
> ++#else
> ++  struct spa_meta_video_crop* video_metadata =
> ++      static_cast<struct spa_meta_video_crop*>(
> ++          spa_buffer_find_meta(spaBuffer, pw_core_type_->meta.VideoCrop));
> ++#endif
> + 
> +-  if (!(src = spaBuffer->datas[0].data)) {
> ++  // Video size from metadata is bigger than an actual video stream size.
> ++  // The metadata are wrong or we should up-scale the video...in both cases
> ++  // just quit now.
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  if (video_metadata && (video_metadata->region.size.width >
> ++                             static_cast<uint32_t>(desktop_size_.width()) ||
> ++                         video_metadata->region.size.height >
> ++                             static_cast<uint32_t>(desktop_size_.height()))) {
> ++#else
> ++  if (video_metadata && (video_metadata->width > desktop_size_.width() ||
> ++                         video_metadata->height > desktop_size_.height())) {
> ++#endif
> ++    RTC_LOG(LS_ERROR) << "Stream metadata sizes are wrong!";
> +     return;
> +   }
> + 
> +-  uint32_t maxSize = spaBuffer->datas[0].maxsize;
> +-  int32_t srcStride = spaBuffer->datas[0].chunk->stride;
> +-  if (srcStride != (desktop_size_.width() * kBytesPerPixel)) {
> ++  // Use video metadata when video size from metadata is set and smaller than
> ++  // video stream size, so we need to adjust it.
> ++  bool video_is_full_width = true;
> ++  bool video_is_full_height = true;
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  if (video_metadata && video_metadata->region.size.width != 0 &&
> ++      video_metadata->region.size.height != 0) {
> ++    if (video_metadata->region.size.width <
> ++        static_cast<uint32_t>(desktop_size_.width())) {
> ++      video_is_full_width = false;
> ++    } else if (video_metadata->region.size.height <
> ++               static_cast<uint32_t>(desktop_size_.height())) {
> ++      video_is_full_height = false;
> ++    }
> ++  }
> ++#else
> ++  if (video_metadata && video_metadata->width != 0 &&
> ++      video_metadata->height != 0) {
> ++    if (video_metadata->width < desktop_size_.width()) {
> ++    } else if (video_metadata->height < desktop_size_.height()) {
> ++      video_is_full_height = false;
> ++    }
> ++  }
> ++#endif
> ++
> ++  DesktopSize video_size_prev = video_size_;
> ++  if (!video_is_full_height || !video_is_full_width) {
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++    video_size_ = DesktopSize(video_metadata->region.size.width,
> ++                              video_metadata->region.size.height);
> ++#else
> ++    video_size_ = DesktopSize(video_metadata->width, video_metadata->height);
> ++#endif
> ++  } else {
> ++    video_size_ = desktop_size_;
> ++  }
> ++
> ++  webrtc::MutexLock lock(&current_frame_lock_);
> ++  if (!current_frame_ || !video_size_.equals(video_size_prev)) {
> ++    current_frame_ = std::make_unique<uint8_t[]>(
> ++        video_size_.width() * video_size_.height() * kBytesPerPixel);
> ++  }
> ++
> ++  const int32_t dst_stride = video_size_.width() * kBytesPerPixel;
> ++  const int32_t src_stride = spaBuffer->datas[0].chunk->stride;
> ++
> ++  if (src_stride != (desktop_size_.width() * kBytesPerPixel)) {
> +     RTC_LOG(LS_ERROR) << "Got buffer with stride different from screen stride: "
> +-                      << srcStride
> ++                      << src_stride
> +                       << " != " << (desktop_size_.width() * kBytesPerPixel);
> +     portal_init_failed_ = true;
> ++
> +     return;
> +   }
> + 
> +-  if (!current_frame_) {
> +-    current_frame_ = static_cast<uint8_t*>(malloc(maxSize));
> +-  }
> +-  RTC_DCHECK(current_frame_ != nullptr);
> ++  // Adjust source content based on metadata video position
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  if (!video_is_full_height &&
> ++      (video_metadata->region.position.y + video_size_.height() <=
> ++       desktop_size_.height())) {
> ++    src += src_stride * video_metadata->region.position.y;
> ++  }
> ++  const int x_offset =
> ++      !video_is_full_width &&
> ++              (video_metadata->region.position.x + video_size_.width() <=
> ++               desktop_size_.width())
> ++          ? video_metadata->region.position.x * kBytesPerPixel
> ++          : 0;
> ++#else
> ++  if (!video_is_full_height &&
> ++      (video_metadata->y + video_size_.height() <= desktop_size_.height())) {
> ++    src += src_stride * video_metadata->y;
> ++  }
> ++
> ++  const int x_offset =
> ++      !video_is_full_width &&
> ++              (video_metadata->x + video_size_.width() <= desktop_size_.width())
> ++          ? video_metadata->x * kBytesPerPixel
> ++          : 0;
> ++#endif
> + 
> +-  // If both sides decided to go with the RGBx format we need to convert it to
> +-  // BGRx to match color format expected by WebRTC.
> +-  if (spa_video_format_->format == pw_type_->video_format.RGBx) {
> +-    uint8_t* tempFrame = static_cast<uint8_t*>(malloc(maxSize));
> +-    std::memcpy(tempFrame, src, maxSize);
> +-    ConvertRGBxToBGRx(tempFrame, maxSize);
> +-    std::memcpy(current_frame_, tempFrame, maxSize);
> +-    free(tempFrame);
> +-  } else {
> +-    std::memcpy(current_frame_, src, maxSize);
> ++  uint8_t* dst = current_frame_.get();
> ++  for (int i = 0; i < video_size_.height(); ++i) {
> ++    // Adjust source content based on crop video position if needed
> ++    src += x_offset;
> ++    std::memcpy(dst, src, dst_stride);
> ++    // If both sides decided to go with the RGBx format we need to convert it to
> ++    // BGRx to match color format expected by WebRTC.
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++    if (spa_video_format_.format == SPA_VIDEO_FORMAT_RGBx ||
> ++        spa_video_format_.format == SPA_VIDEO_FORMAT_RGBA) {
> ++#else
> ++    if (spa_video_format_->format == pw_type_->video_format.RGBx ||
> ++        spa_video_format_->format == pw_type_->video_format.RGBA) {
> ++#endif
> ++      ConvertRGBxToBGRx(dst, dst_stride);
> ++    }
> ++    src += src_stride - x_offset;
> ++    dst += dst_stride;
> +   }
> + }
> + 
> +@@ -441,14 +898,13 @@ void BaseCapturerPipeWire::OnProxyReques
> +   BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(user_data);
> +   RTC_DCHECK(that);
> + 
> +-  GError* error = nullptr;
> +-  GDBusProxy *proxy = g_dbus_proxy_new_finish(result, &error);
> ++  Scoped<GError> error;
> ++  GDBusProxy* proxy = g_dbus_proxy_new_finish(result, error.receive());
> +   if (!proxy) {
> +-    if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
> ++    if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
> +       return;
> +     RTC_LOG(LS_ERROR) << "Failed to create a proxy for the screen cast portal: "
> +                       << error->message;
> +-    g_error_free(error);
> +     that->portal_init_failed_ = true;
> +     return;
> +   }
> +@@ -462,38 +918,36 @@ void BaseCapturerPipeWire::OnProxyReques
> + // static
> + gchar* BaseCapturerPipeWire::PrepareSignalHandle(GDBusConnection* connection,
> +                                                  const gchar* token) {
> +-  gchar* sender = g_strdup(g_dbus_connection_get_unique_name(connection) + 1);
> +-  for (int i = 0; sender[i]; i++) {
> +-    if (sender[i] == '.') {
> +-      sender[i] = '_';
> ++  Scoped<gchar> sender(
> ++      g_strdup(g_dbus_connection_get_unique_name(connection) + 1));
> ++  for (int i = 0; sender.get()[i]; i++) {
> ++    if (sender.get()[i] == '.') {
> ++      sender.get()[i] = '_';
> +     }
> +   }
> + 
> +-  gchar* handle = g_strconcat(kDesktopRequestObjectPath, "/", sender, "/",
> ++  gchar* handle = g_strconcat(kDesktopRequestObjectPath, "/", sender.get(), "/",
> +                               token, /*end of varargs*/ nullptr);
> +-  g_free(sender);
> + 
> +   return handle;
> + }
> + 
> + void BaseCapturerPipeWire::SessionRequest() {
> +   GVariantBuilder builder;
> +-  gchar* variant_string;
> ++  Scoped<gchar> variant_string;
> + 
> +   g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
> +   variant_string =
> +       g_strdup_printf("webrtc_session%d", g_random_int_range(0, G_MAXINT));
> +   g_variant_builder_add(&builder, "{sv}", "session_handle_token",
> +-                        g_variant_new_string(variant_string));
> +-  g_free(variant_string);
> ++                        g_variant_new_string(variant_string.get()));
> +   variant_string = g_strdup_printf("webrtc%d", g_random_int_range(0, G_MAXINT));
> +   g_variant_builder_add(&builder, "{sv}", "handle_token",
> +-                        g_variant_new_string(variant_string));
> ++                        g_variant_new_string(variant_string.get()));
> + 
> +-  portal_handle_ = PrepareSignalHandle(connection_, variant_string);
> ++  portal_handle_ = PrepareSignalHandle(connection_, variant_string.get());
> +   session_request_signal_id_ = SetupRequestResponseSignal(
> +       portal_handle_, OnSessionRequestResponseSignal);
> +-  g_free(variant_string);
> + 
> +   RTC_LOG(LS_INFO) << "Screen cast session requested.";
> +   g_dbus_proxy_call(
> +@@ -509,22 +963,21 @@ void BaseCapturerPipeWire::OnSessionRequ
> +   BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(user_data);
> +   RTC_DCHECK(that);
> + 
> +-  GError* error = nullptr;
> +-  GVariant* variant = g_dbus_proxy_call_finish(proxy, result, &error);
> ++  Scoped<GError> error;
> ++  Scoped<GVariant> variant(
> ++      g_dbus_proxy_call_finish(proxy, result, error.receive()));
> +   if (!variant) {
> +-    if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
> ++    if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
> +       return;
> +     RTC_LOG(LS_ERROR) << "Failed to create a screen cast session: "
> +                       << error->message;
> +-    g_error_free(error);
> +     that->portal_init_failed_ = true;
> +     return;
> +   }
> +   RTC_LOG(LS_INFO) << "Initializing the screen cast session.";
> + 
> +-  gchar* handle = nullptr;
> +-  g_variant_get_child(variant, 0, "o", &handle);
> +-  g_variant_unref(variant);
> ++  Scoped<gchar> handle;
> ++  g_variant_get_child(variant.get(), 0, "o", &handle);
> +   if (!handle) {
> +     RTC_LOG(LS_ERROR) << "Failed to initialize the screen cast session.";
> +     if (that->session_request_signal_id_) {
> +@@ -536,8 +989,6 @@ void BaseCapturerPipeWire::OnSessionRequ
> +     return;
> +   }
> + 
> +-  g_free(handle);
> +-
> +   RTC_LOG(LS_INFO) << "Subscribing to the screen cast session.";
> + }
> + 
> +@@ -557,11 +1008,11 @@ void BaseCapturerPipeWire::OnSessionRequ
> +       << "Received response for the screen cast session subscription.";
> + 
> +   guint32 portal_response;
> +-  GVariant* response_data;
> +-  g_variant_get(parameters, "(u@a{sv})", &portal_response, &response_data);
> +-  g_variant_lookup(response_data, "session_handle", "s",
> ++  Scoped<GVariant> response_data;
> ++  g_variant_get(parameters, "(u@a{sv})", &portal_response,
> ++                response_data.receive());
> ++  g_variant_lookup(response_data.get(), "session_handle", "s",
> +                    &that->session_handle_);
> +-  g_variant_unref(response_data);
> + 
> +   if (!that->session_handle_ || portal_response) {
> +     RTC_LOG(LS_ERROR)
> +@@ -575,23 +1026,23 @@ void BaseCapturerPipeWire::OnSessionRequ
> + 
> + void BaseCapturerPipeWire::SourcesRequest() {
> +   GVariantBuilder builder;
> +-  gchar* variant_string;
> ++  Scoped<gchar> variant_string;
> + 
> +   g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
> +   // We want to record monitor content.
> +-  g_variant_builder_add(&builder, "{sv}", "types",
> +-                        g_variant_new_uint32(capture_source_type_));
> ++  g_variant_builder_add(
> ++      &builder, "{sv}", "types",
> ++      g_variant_new_uint32(static_cast<uint32_t>(capture_source_type_)));
> +   // We don't want to allow selection of multiple sources.
> +   g_variant_builder_add(&builder, "{sv}", "multiple",
> +                         g_variant_new_boolean(false));
> +   variant_string = g_strdup_printf("webrtc%d", g_random_int_range(0, G_MAXINT));
> +   g_variant_builder_add(&builder, "{sv}", "handle_token",
> +-                        g_variant_new_string(variant_string));
> ++                        g_variant_new_string(variant_string.get()));
> + 
> +-  sources_handle_ = PrepareSignalHandle(connection_, variant_string);
> ++  sources_handle_ = PrepareSignalHandle(connection_, variant_string.get());
> +   sources_request_signal_id_ = SetupRequestResponseSignal(
> +       sources_handle_, OnSourcesRequestResponseSignal);
> +-  g_free(variant_string);
> + 
> +   RTC_LOG(LS_INFO) << "Requesting sources from the screen cast session.";
> +   g_dbus_proxy_call(
> +@@ -608,22 +1059,21 @@ void BaseCapturerPipeWire::OnSourcesRequ
> +   BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(user_data);
> +   RTC_DCHECK(that);
> + 
> +-  GError* error = nullptr;
> +-  GVariant* variant = g_dbus_proxy_call_finish(proxy, result, &error);
> ++  Scoped<GError> error;
> ++  Scoped<GVariant> variant(
> ++      g_dbus_proxy_call_finish(proxy, result, error.receive()));
> +   if (!variant) {
> +-    if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
> ++    if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
> +       return;
> +     RTC_LOG(LS_ERROR) << "Failed to request the sources: " << error->message;
> +-    g_error_free(error);
> +     that->portal_init_failed_ = true;
> +     return;
> +   }
> + 
> +   RTC_LOG(LS_INFO) << "Sources requested from the screen cast session.";
> + 
> +-  gchar* handle = nullptr;
> +-  g_variant_get_child(variant, 0, "o", &handle);
> +-  g_variant_unref(variant);
> ++  Scoped<gchar> handle;
> ++  g_variant_get_child(variant.get(), 0, "o", handle.receive());
> +   if (!handle) {
> +     RTC_LOG(LS_ERROR) << "Failed to initialize the screen cast session.";
> +     if (that->sources_request_signal_id_) {
> +@@ -635,8 +1085,6 @@ void BaseCapturerPipeWire::OnSourcesRequ
> +     return;
> +   }
> + 
> +-  g_free(handle);
> +-
> +   RTC_LOG(LS_INFO) << "Subscribed to sources signal.";
> + }
> + 
> +@@ -668,17 +1116,16 @@ void BaseCapturerPipeWire::OnSourcesRequ
> + 
> + void BaseCapturerPipeWire::StartRequest() {
> +   GVariantBuilder builder;
> +-  gchar* variant_string;
> ++  Scoped<gchar> variant_string;
> + 
> +   g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
> +   variant_string = g_strdup_printf("webrtc%d", g_random_int_range(0, G_MAXINT));
> +   g_variant_builder_add(&builder, "{sv}", "handle_token",
> +-                        g_variant_new_string(variant_string));
> ++                        g_variant_new_string(variant_string.get()));
> + 
> +-  start_handle_ = PrepareSignalHandle(connection_, variant_string);
> ++  start_handle_ = PrepareSignalHandle(connection_, variant_string.get());
> +   start_request_signal_id_ =
> +       SetupRequestResponseSignal(start_handle_, OnStartRequestResponseSignal);
> +-  g_free(variant_string);
> + 
> +   // "Identifier for the application window", this is Wayland, so not "x11:...".
> +   const gchar parent_window[] = "";
> +@@ -698,23 +1145,22 @@ void BaseCapturerPipeWire::OnStartReques
> +   BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(user_data);
> +   RTC_DCHECK(that);
> + 
> +-  GError* error = nullptr;
> +-  GVariant* variant = g_dbus_proxy_call_finish(proxy, result, &error);
> ++  Scoped<GError> error;
> ++  Scoped<GVariant> variant(
> ++      g_dbus_proxy_call_finish(proxy, result, error.receive()));
> +   if (!variant) {
> +-    if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
> ++    if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
> +       return;
> +     RTC_LOG(LS_ERROR) << "Failed to start the screen cast session: "
> +                       << error->message;
> +-    g_error_free(error);
> +     that->portal_init_failed_ = true;
> +     return;
> +   }
> + 
> +   RTC_LOG(LS_INFO) << "Initializing the start of the screen cast session.";
> + 
> +-  gchar* handle = nullptr;
> +-  g_variant_get_child(variant, 0, "o", &handle);
> +-  g_variant_unref(variant);
> ++  Scoped<gchar> handle;
> ++  g_variant_get_child(variant.get(), 0, "o", handle.receive());
> +   if (!handle) {
> +     RTC_LOG(LS_ERROR)
> +         << "Failed to initialize the start of the screen cast session.";
> +@@ -727,8 +1173,6 @@ void BaseCapturerPipeWire::OnStartReques
> +     return;
> +   }
> + 
> +-  g_free(handle);
> +-
> +   RTC_LOG(LS_INFO) << "Subscribed to the start signal.";
> + }
> + 
> +@@ -746,9 +1190,10 @@ void BaseCapturerPipeWire::OnStartReques
> + 
> +   RTC_LOG(LS_INFO) << "Start signal received.";
> +   guint32 portal_response;
> +-  GVariant* response_data;
> +-  GVariantIter* iter = nullptr;
> +-  g_variant_get(parameters, "(u@a{sv})", &portal_response, &response_data);
> ++  Scoped<GVariant> response_data;
> ++  Scoped<GVariantIter> iter;
> ++  g_variant_get(parameters, "(u@a{sv})", &portal_response,
> ++                response_data.receive());
> +   if (portal_response || !response_data) {
> +     RTC_LOG(LS_ERROR) << "Failed to start the screen cast session.";
> +     that->portal_init_failed_ = true;
> +@@ -758,28 +1203,28 @@ void BaseCapturerPipeWire::OnStartReques
> +   // Array of PipeWire streams. See
> +   // https://github.com/flatpak/xdg-desktop-portal/blob/master/data/org.freedesktop.portal.ScreenCast.xml
> +   // documentation for <method name="Start">.
> +-  if (g_variant_lookup(response_data, "streams", "a(ua{sv})", &iter)) {
> +-    GVariant* variant;
> ++  if (g_variant_lookup(response_data.get(), "streams", "a(ua{sv})",
> ++                       iter.receive())) {
> ++    Scoped<GVariant> variant;
> + 
> +-    while (g_variant_iter_next(iter, "@(ua{sv})", &variant)) {
> ++    while (g_variant_iter_next(iter.get(), "@(ua{sv})", variant.receive())) {
> +       guint32 stream_id;
> +-      gint32 width;
> +-      gint32 height;
> +-      GVariant* options;
> ++      guint32 type;
> ++      Scoped<GVariant> options;
> + 
> +-      g_variant_get(variant, "(u@a{sv})", &stream_id, &options);
> +-      RTC_DCHECK(options != nullptr);
> ++      g_variant_get(variant.get(), "(u@a{sv})", &stream_id, options.receive());
> ++      RTC_DCHECK(options.get());
> + 
> +-      g_variant_lookup(options, "size", "(ii)", &width, &height);
> ++      if (g_variant_lookup(options.get(), "source_type", "u", &type)) {
> ++        that->capture_source_type_ =
> ++            static_cast<BaseCapturerPipeWire::CaptureSourceType>(type);
> ++      }
> + 
> +-      that->desktop_size_.set(width, height);
> ++      that->pw_stream_node_id_ = stream_id;
> + 
> +-      g_variant_unref(options);
> +-      g_variant_unref(variant);
> ++      break;
> +     }
> +   }
> +-  g_variant_iter_free(iter);
> +-  g_variant_unref(response_data);
> + 
> +   that->OpenPipeWireRemote();
> + }
> +@@ -807,35 +1252,30 @@ void BaseCapturerPipeWire::OnOpenPipeWir
> +   BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(user_data);
> +   RTC_DCHECK(that);
> + 
> +-  GError* error = nullptr;
> +-  GUnixFDList* outlist = nullptr;
> +-  GVariant* variant = g_dbus_proxy_call_with_unix_fd_list_finish(
> +-      proxy, &outlist, result, &error);
> ++  Scoped<GError> error;
> ++  Scoped<GUnixFDList> outlist;
> ++  Scoped<GVariant> variant(g_dbus_proxy_call_with_unix_fd_list_finish(
> ++      proxy, outlist.receive(), result, error.receive()));
> +   if (!variant) {
> +-    if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
> ++    if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
> +       return;
> +     RTC_LOG(LS_ERROR) << "Failed to open the PipeWire remote: "
> +                       << error->message;
> +-    g_error_free(error);
> +     that->portal_init_failed_ = true;
> +     return;
> +   }
> + 
> +   gint32 index;
> +-  g_variant_get(variant, "(h)", &index);
> ++  g_variant_get(variant.get(), "(h)", &index);
> + 
> +-  if ((that->pw_fd_ = g_unix_fd_list_get(outlist, index, &error)) == -1) {
> ++  if ((that->pw_fd_ =
> ++           g_unix_fd_list_get(outlist.get(), index, error.receive())) == -1) {
> +     RTC_LOG(LS_ERROR) << "Failed to get file descriptor from the list: "
> +                       << error->message;
> +-    g_error_free(error);
> +-    g_variant_unref(variant);
> +     that->portal_init_failed_ = true;
> +     return;
> +   }
> + 
> +-  g_variant_unref(variant);
> +-  g_object_unref(outlist);
> +-
> +   that->InitPipeWire();
> + }
> + 
> +@@ -854,15 +1294,18 @@ void BaseCapturerPipeWire::CaptureFrame(
> +     return;
> +   }
> + 
> ++  webrtc::MutexLock lock(&current_frame_lock_);
> +   if (!current_frame_) {
> +     callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
> +     return;
> +   }
> + 
> +-  std::unique_ptr<DesktopFrame> result(new BasicDesktopFrame(desktop_size_));
> ++  DesktopSize frame_size = video_size_;
> ++
> ++  std::unique_ptr<DesktopFrame> result(new BasicDesktopFrame(frame_size));
> +   result->CopyPixelsFrom(
> +-      current_frame_, (desktop_size_.width() * kBytesPerPixel),
> +-      DesktopRect::MakeWH(desktop_size_.width(), desktop_size_.height()));
> ++      current_frame_.get(), (frame_size.width() * kBytesPerPixel),
> ++      DesktopRect::MakeWH(frame_size.width(), frame_size.height()));
> +   if (!result) {
> +     callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
> +     return;
> +@@ -887,4 +1330,11 @@ bool BaseCapturerPipeWire::SelectSource(
> +   return true;
> + }
> + 
> ++// static
> ++std::unique_ptr<DesktopCapturer> BaseCapturerPipeWire::CreateRawCapturer(
> ++    const DesktopCaptureOptions& options) {
> ++  return std::make_unique<BaseCapturerPipeWire>(
> ++      BaseCapturerPipeWire::CaptureSourceType::kAny);
> ++}
> ++
> + }  // namespace webrtc
> +--- a/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h
> ++++ b/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h
> +@@ -10,18 +10,23 @@
> + 
> + #ifndef MODULES_DESKTOP_CAPTURE_LINUX_BASE_CAPTURER_PIPEWIRE_H_
> + #define MODULES_DESKTOP_CAPTURE_LINUX_BASE_CAPTURER_PIPEWIRE_H_
> +-
> + #include <gio/gio.h>
> + #define typeof __typeof__
> + #include <pipewire/pipewire.h>
> + #include <spa/param/video/format-utils.h>
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++#include <spa/utils/result.h>
> ++#endif
> + 
> ++#include "absl/types/optional.h"
> + #include "modules/desktop_capture/desktop_capture_options.h"
> + #include "modules/desktop_capture/desktop_capturer.h"
> + #include "rtc_base/constructor_magic.h"
> ++#include "rtc_base/synchronization/mutex.h"
> + 
> + namespace webrtc {
> + 
> ++#if !PW_CHECK_VERSION(0, 3, 0)
> + class PipeWireType {
> +  public:
> +   spa_type_media_type media_type;
> +@@ -29,14 +34,25 @@ class PipeWireType {
> +   spa_type_format_video format_video;
> +   spa_type_video_format video_format;
> + };
> ++#endif
> + 
> + class BaseCapturerPipeWire : public DesktopCapturer {
> +  public:
> +-  enum CaptureSourceType { Screen = 1, Window };
> ++  // Values are set based on source type property in
> ++  // xdg-desktop-portal/screencast
> ++  // https://github.com/flatpak/xdg-desktop-portal/blob/master/data/org.freedesktop.portal.ScreenCast.xml
> ++  enum class CaptureSourceType : uint32_t {
> ++    kScreen = 0b01,
> ++    kWindow = 0b10,
> ++    kAny = 0b11
> ++  };
> + 
> +   explicit BaseCapturerPipeWire(CaptureSourceType source_type);
> +   ~BaseCapturerPipeWire() override;
> + 
> ++  static std::unique_ptr<DesktopCapturer> CreateRawCapturer(
> ++      const DesktopCaptureOptions& options);
> ++
> +   // DesktopCapturer interface.
> +   void Start(Callback* delegate) override;
> +   void CaptureFrame() override;
> +@@ -45,6 +61,21 @@ class BaseCapturerPipeWire : public Desk
> + 
> +  private:
> +   // PipeWire types -->
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  struct pw_context* pw_context_ = nullptr;
> ++  struct pw_core* pw_core_ = nullptr;
> ++  struct pw_stream* pw_stream_ = nullptr;
> ++  struct pw_thread_loop* pw_main_loop_ = nullptr;
> ++
> ++  spa_hook spa_core_listener_;
> ++  spa_hook spa_stream_listener_;
> ++
> ++  // event handlers
> ++  pw_core_events pw_core_events_ = {};
> ++  pw_stream_events pw_stream_events_ = {};
> ++
> ++  struct spa_video_info_raw spa_video_format_;
> ++#else
> +   pw_core* pw_core_ = nullptr;
> +   pw_type* pw_core_type_ = nullptr;
> +   pw_stream* pw_stream_ = nullptr;
> +@@ -60,11 +91,13 @@ class BaseCapturerPipeWire : public Desk
> +   pw_remote_events pw_remote_events_ = {};
> + 
> +   spa_video_info_raw* spa_video_format_ = nullptr;
> ++#endif
> + 
> ++  guint32 pw_stream_node_id_ = 0;
> +   gint32 pw_fd_ = -1;
> + 
> +   CaptureSourceType capture_source_type_ =
> +-      BaseCapturerPipeWire::CaptureSourceType::Screen;
> ++      BaseCapturerPipeWire::CaptureSourceType::kScreen;
> + 
> +   // <-- end of PipeWire types
> + 
> +@@ -79,10 +112,12 @@ class BaseCapturerPipeWire : public Desk
> +   guint sources_request_signal_id_ = 0;
> +   guint start_request_signal_id_ = 0;
> + 
> ++  DesktopSize video_size_;
> +   DesktopSize desktop_size_ = {};
> +   DesktopCaptureOptions options_ = {};
> + 
> +-  uint8_t* current_frame_ = nullptr;
> ++  webrtc::Mutex current_frame_lock_;
> ++  std::unique_ptr<uint8_t[]> current_frame_;
> +   Callback* callback_ = nullptr;
> + 
> +   bool portal_init_failed_ = false;
> +@@ -91,21 +126,32 @@ class BaseCapturerPipeWire : public Desk
> +   void InitPipeWire();
> +   void InitPipeWireTypes();
> + 
> +-  void CreateReceivingStream();
> ++  pw_stream* CreateReceivingStream();
> +   void HandleBuffer(pw_buffer* buffer);
> + 
> +   void ConvertRGBxToBGRx(uint8_t* frame, uint32_t size);
> + 
> ++#if PW_CHECK_VERSION(0, 3, 0)
> ++  static void OnCoreError(void* data,
> ++                          uint32_t id,
> ++                          int seq,
> ++                          int res,
> ++                          const char* message);
> ++  static void OnStreamParamChanged(void* data,
> ++                                   uint32_t id,
> ++                                   const struct spa_pod* format);
> ++#else
> +   static void OnStateChanged(void* data,
> +                              pw_remote_state old_state,
> +                              pw_remote_state state,
> +                              const char* error);
> ++  static void OnStreamFormatChanged(void* data, const struct spa_pod* format);
> ++#endif
> +   static void OnStreamStateChanged(void* data,
> +                                    pw_stream_state old_state,
> +                                    pw_stream_state state,
> +                                    const char* error_message);
> + 
> +-  static void OnStreamFormatChanged(void* data, const struct spa_pod* format);
> +   static void OnStreamProcess(void* data);
> +   static void OnNewBuffer(void* data, uint32_t id);
> + 
> +--- a/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire.sigs
> ++++ /dev/null
> +@@ -1,44 +0,0 @@
> +-// Copyright 2018 The WebRTC project authors. All rights reserved.
> +-// Use of this source code is governed by a BSD-style license that can be
> +-// found in the LICENSE file.
> +-
> +-//------------------------------------------------
> +-// Functions from PipeWire used in capturer code.
> +-//------------------------------------------------
> +-
> +-// core.h
> +-void pw_core_destroy(pw_core *core);
> +-pw_type *pw_core_get_type(pw_core *core);
> +-pw_core * pw_core_new(pw_loop *main_loop, pw_properties *props);
> +-
> +-// loop.h
> +-void pw_loop_destroy(pw_loop *loop);
> +-pw_loop * pw_loop_new(pw_properties *properties);
> +-
> +-// pipewire.h
> +-void pw_init(int *argc, char **argv[]);
> +-
> +-// properties.h
> +-pw_properties * pw_properties_new_string(const char *args);
> +-
> +-// remote.h
> +-void pw_remote_add_listener(pw_remote *remote, spa_hook *listener, const pw_remote_events *events, void *data);
> +-int pw_remote_connect_fd(pw_remote *remote, int fd);
> +-void pw_remote_destroy(pw_remote *remote);
> +-pw_remote * pw_remote_new(pw_core *core, pw_properties *properties, size_t user_data_size);
> +-
> +-// stream.h
> +-void pw_stream_add_listener(pw_stream *stream, spa_hook *listener, const pw_stream_events *events, void *data);
> +-int pw_stream_connect(pw_stream *stream, enum pw_direction direction, const char *port_path, enum pw_stream_flags flags, const spa_pod **params, uint32_t n_params);
> +-pw_buffer *pw_stream_dequeue_buffer(pw_stream *stream);
> +-void pw_stream_destroy(pw_stream *stream);
> +-void pw_stream_finish_format(pw_stream *stream, int res, const spa_pod **params, uint32_t n_params);
> +-pw_stream * pw_stream_new(pw_remote *remote, const char *name, pw_properties *props);
> +-int pw_stream_queue_buffer(pw_stream *stream, pw_buffer *buffer);
> +-int pw_stream_set_active(pw_stream *stream, bool active);
> +-
> +-// thread-loop.h
> +-void pw_thread_loop_destroy(pw_thread_loop *loop);
> +-pw_thread_loop * pw_thread_loop_new(pw_loop *loop, const char *name);
> +-int pw_thread_loop_start(pw_thread_loop *loop);
> +-void pw_thread_loop_stop(pw_thread_loop *loop);
> +--- /dev/null
> ++++ b/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire02.sigs
> +@@ -0,0 +1,47 @@
> ++// Copyright 2018 The WebRTC project authors. All rights reserved.
> ++// Use of this source code is governed by a BSD-style license that can be
> ++// found in the LICENSE file.
> ++
> ++//------------------------------------------------
> ++// Functions from PipeWire used in capturer code.
> ++//------------------------------------------------
> ++
> ++// core.h
> ++void pw_core_destroy(pw_core *core);
> ++pw_type *pw_core_get_type(pw_core *core);
> ++pw_core * pw_core_new(pw_loop *main_loop, pw_properties *props);
> ++
> ++// loop.h
> ++void pw_loop_destroy(pw_loop *loop);
> ++pw_loop * pw_loop_new(pw_properties *properties);
> ++
> ++// pipewire.h
> ++void pw_init(int *argc, char **argv[]);
> ++
> ++// properties.h
> ++pw_properties * pw_properties_new_string(const char *args);
> ++
> ++// remote.h
> ++void pw_remote_add_listener(pw_remote *remote, spa_hook *listener, const pw_remote_events *events, void *data);
> ++int pw_remote_connect_fd(pw_remote *remote, int fd);
> ++void pw_remote_destroy(pw_remote *remote);
> ++pw_remote * pw_remote_new(pw_core *core, pw_properties *properties, size_t user_data_size);
> ++enum pw_remote_state pw_remote_get_state(pw_remote *remote, const char **error);
> ++
> ++// stream.h
> ++void pw_stream_add_listener(pw_stream *stream, spa_hook *listener, const pw_stream_events *events, void *data);
> ++int pw_stream_connect(pw_stream *stream, enum pw_direction direction, const char *port_path, enum pw_stream_flags flags, const spa_pod **params, uint32_t n_params);
> ++pw_buffer *pw_stream_dequeue_buffer(pw_stream *stream);
> ++void pw_stream_destroy(pw_stream *stream);
> ++void pw_stream_finish_format(pw_stream *stream, int res, const spa_pod **params, uint32_t n_params);
> ++pw_stream * pw_stream_new(pw_remote *remote, const char *name, pw_properties *props);
> ++int pw_stream_queue_buffer(pw_stream *stream, pw_buffer *buffer);
> ++int pw_stream_set_active(pw_stream *stream, bool active);
> ++
> ++// thread-loop.h
> ++void pw_thread_loop_destroy(pw_thread_loop *loop);
> ++pw_thread_loop * pw_thread_loop_new(pw_loop *loop, const char *name);
> ++int pw_thread_loop_start(pw_thread_loop *loop);
> ++void pw_thread_loop_stop(pw_thread_loop *loop);
> ++void pw_thread_loop_lock(struct pw_thread_loop *loop);
> ++void pw_thread_loop_unlock(struct pw_thread_loop *loop);
> +--- /dev/null
> ++++ b/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire03.sigs
> +@@ -0,0 +1,46 @@
> ++// Copyright 2018 The WebRTC project authors. All rights reserved.
> ++// Use of this source code is governed by a BSD-style license that can be
> ++// found in the LICENSE file.
> ++
> ++//------------------------------------------------
> ++// Functions from PipeWire used in capturer code.
> ++//------------------------------------------------
> ++
> ++// core.h
> ++int pw_core_disconnect(pw_core *core);
> ++
> ++// loop.h
> ++void pw_loop_destroy(pw_loop *loop);
> ++pw_loop * pw_loop_new(const spa_dict *props);
> ++
> ++
> ++// pipewire.h
> ++void pw_init(int *argc, char **argv[]);
> ++
> ++// properties.h
> ++pw_properties * pw_properties_new_string(const char *args);
> ++
> ++// stream.h
> ++void pw_stream_add_listener(pw_stream *stream, spa_hook *listener, const pw_stream_events *events, void *data);
> ++int pw_stream_connect(pw_stream *stream, enum pw_direction direction, uint32_t target_id, enum pw_stream_flags flags, const spa_pod **params, uint32_t n_params);
> ++pw_buffer *pw_stream_dequeue_buffer(pw_stream *stream);
> ++void pw_stream_destroy(pw_stream *stream);
> ++pw_stream * pw_stream_new(pw_core *core, const char *name, pw_properties *props);
> ++int pw_stream_queue_buffer(pw_stream *stream, pw_buffer *buffer);
> ++int pw_stream_set_active(pw_stream *stream, bool active);
> ++int pw_stream_update_params(pw_stream *stream, const spa_pod **params, uint32_t n_params);
> ++
> ++// thread-loop.h
> ++void pw_thread_loop_destroy(pw_thread_loop *loop);
> ++pw_thread_loop * pw_thread_loop_new(const char *name, const spa_dict *props);
> ++int pw_thread_loop_start(pw_thread_loop *loop);
> ++void pw_thread_loop_stop(pw_thread_loop *loop);
> ++void pw_thread_loop_lock(pw_thread_loop *loop);
> ++void pw_thread_loop_unlock(pw_thread_loop *loop);
> ++pw_loop * pw_thread_loop_get_loop(pw_thread_loop *loop);
> ++
> ++
> ++// context.h
> ++void pw_context_destroy(pw_context *context);
> ++pw_context *pw_context_new(pw_loop *main_loop, pw_properties *props, size_t user_data_size);
> ++pw_core * pw_context_connect(pw_context *context, pw_properties *properties, size_t user_data_size);
> +--- a/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.cc
> ++++ /dev/null
> +@@ -1,29 +0,0 @@
> +-/*
> +- *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
> +- *
> +- *  Use of this source code is governed by a BSD-style license
> +- *  that can be found in the LICENSE file in the root of the source
> +- *  tree. An additional intellectual property rights grant can be found
> +- *  in the file PATENTS.  All contributing project authors may
> +- *  be found in the AUTHORS file in the root of the source tree.
> +- */
> +-
> +-#include "modules/desktop_capture/linux/screen_capturer_pipewire.h"
> +-
> +-#include <memory>
> +-
> +-
> +-namespace webrtc {
> +-
> +-ScreenCapturerPipeWire::ScreenCapturerPipeWire()
> +-    : BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::Screen) {}
> +-ScreenCapturerPipeWire::~ScreenCapturerPipeWire() {}
> +-
> +-// static
> +-std::unique_ptr<DesktopCapturer>
> +-ScreenCapturerPipeWire::CreateRawScreenCapturer(
> +-    const DesktopCaptureOptions& options) {
> +-  return std::make_unique<ScreenCapturerPipeWire>();
> +-}
> +-
> +-}  // namespace webrtc
> +--- a/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.h
> ++++ /dev/null
> +@@ -1,33 +0,0 @@
> +-/*
> +- *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
> +- *
> +- *  Use of this source code is governed by a BSD-style license
> +- *  that can be found in the LICENSE file in the root of the source
> +- *  tree. An additional intellectual property rights grant can be found
> +- *  in the file PATENTS.  All contributing project authors may
> +- *  be found in the AUTHORS file in the root of the source tree.
> +- */
> +-
> +-#ifndef MODULES_DESKTOP_CAPTURE_LINUX_SCREEN_CAPTURER_PIPEWIRE_H_
> +-#define MODULES_DESKTOP_CAPTURE_LINUX_SCREEN_CAPTURER_PIPEWIRE_H_
> +-
> +-#include <memory>
> +-
> +-#include "modules/desktop_capture/linux/base_capturer_pipewire.h"
> +-
> +-namespace webrtc {
> +-
> +-class ScreenCapturerPipeWire : public BaseCapturerPipeWire {
> +- public:
> +-  ScreenCapturerPipeWire();
> +-  ~ScreenCapturerPipeWire() override;
> +-
> +-  static std::unique_ptr<DesktopCapturer> CreateRawScreenCapturer(
> +-      const DesktopCaptureOptions& options);
> +-
> +-  RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerPipeWire);
> +-};
> +-
> +-}  // namespace webrtc
> +-
> +-#endif  // MODULES_DESKTOP_CAPTURE_LINUX_SCREEN_CAPTURER_PIPEWIRE_H_
> +--- a/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.cc
> ++++ /dev/null
> +@@ -1,29 +0,0 @@
> +-/*
> +- *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
> +- *
> +- *  Use of this source code is governed by a BSD-style license
> +- *  that can be found in the LICENSE file in the root of the source
> +- *  tree. An additional intellectual property rights grant can be found
> +- *  in the file PATENTS.  All contributing project authors may
> +- *  be found in the AUTHORS file in the root of the source tree.
> +- */
> +-
> +-#include "modules/desktop_capture/linux/window_capturer_pipewire.h"
> +-
> +-#include <memory>
> +-
> +-
> +-namespace webrtc {
> +-
> +-WindowCapturerPipeWire::WindowCapturerPipeWire()
> +-    : BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::Window) {}
> +-WindowCapturerPipeWire::~WindowCapturerPipeWire() {}
> +-
> +-// static
> +-std::unique_ptr<DesktopCapturer>
> +-WindowCapturerPipeWire::CreateRawWindowCapturer(
> +-    const DesktopCaptureOptions& options) {
> +-  return std::make_unique<WindowCapturerPipeWire>();
> +-}
> +-
> +-}  // namespace webrtc
> +--- a/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.h
> ++++ /dev/null
> +@@ -1,33 +0,0 @@
> +-/*
> +- *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
> +- *
> +- *  Use of this source code is governed by a BSD-style license
> +- *  that can be found in the LICENSE file in the root of the source
> +- *  tree. An additional intellectual property rights grant can be found
> +- *  in the file PATENTS.  All contributing project authors may
> +- *  be found in the AUTHORS file in the root of the source tree.
> +- */
> +-
> +-#ifndef MODULES_DESKTOP_CAPTURE_LINUX_WINDOW_CAPTURER_PIPEWIRE_H_
> +-#define MODULES_DESKTOP_CAPTURE_LINUX_WINDOW_CAPTURER_PIPEWIRE_H_
> +-
> +-#include <memory>
> +-
> +-#include "modules/desktop_capture/linux/base_capturer_pipewire.h"
> +-
> +-namespace webrtc {
> +-
> +-class WindowCapturerPipeWire : public BaseCapturerPipeWire {
> +- public:
> +-  WindowCapturerPipeWire();
> +-  ~WindowCapturerPipeWire() override;
> +-
> +-  static std::unique_ptr<DesktopCapturer> CreateRawWindowCapturer(
> +-      const DesktopCaptureOptions& options);
> +-
> +-  RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerPipeWire);
> +-};
> +-
> +-}  // namespace webrtc
> +-
> +-#endif  // MODULES_DESKTOP_CAPTURE_LINUX_WINDOW_CAPTURER_PIPEWIRE_H_
> +--- a/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/screen_capturer_linux.cc
> ++++ b/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/screen_capturer_linux.cc
> +@@ -14,7 +14,7 @@
> + #include "modules/desktop_capture/desktop_capturer.h"
> + 
> + #if defined(WEBRTC_USE_PIPEWIRE)
> +-#include "modules/desktop_capture/linux/screen_capturer_pipewire.h"
> ++#include "modules/desktop_capture/linux/base_capturer_pipewire.h"
> + #endif  // defined(WEBRTC_USE_PIPEWIRE)
> + 
> + #if defined(WEBRTC_USE_X11)
> +@@ -28,7 +28,7 @@ std::unique_ptr<DesktopCapturer> Desktop
> +     const DesktopCaptureOptions& options) {
> + #if defined(WEBRTC_USE_PIPEWIRE)
> +   if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) {
> +-    return ScreenCapturerPipeWire::CreateRawScreenCapturer(options);
> ++    return BaseCapturerPipeWire::CreateRawCapturer(options);
> +   }
> + #endif  // defined(WEBRTC_USE_PIPEWIRE)
> + 
> +--- a/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/window_capturer_linux.cc
> ++++ b/src/3rdparty/chromium/third_party/webrtc/modules/desktop_capture/window_capturer_linux.cc
> +@@ -14,7 +14,7 @@
> + #include "modules/desktop_capture/desktop_capturer.h"
> + 
> + #if defined(WEBRTC_USE_PIPEWIRE)
> +-#include "modules/desktop_capture/linux/window_capturer_pipewire.h"
> ++#include "modules/desktop_capture/linux/base_capturer_pipewire.h"
> + #endif  // defined(WEBRTC_USE_PIPEWIRE)
> + 
> + #if defined(WEBRTC_USE_X11)
> +@@ -28,7 +28,7 @@ std::unique_ptr<DesktopCapturer> Desktop
> +     const DesktopCaptureOptions& options) {
> + #if defined(WEBRTC_USE_PIPEWIRE)
> +   if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) {
> +-    return WindowCapturerPipeWire::CreateRawWindowCapturer(options);
> ++    return BaseCapturerPipeWire::CreateRawCapturer(options);
> +   }
> + #endif  // defined(WEBRTC_USE_PIPEWIRE)
> + 
> +--- a/src/3rdparty/chromium/third_party/webrtc/webrtc.gni
> ++++ b/src/3rdparty/chromium/third_party/webrtc/webrtc.gni
> +@@ -117,6 +117,10 @@ declare_args() {
> +   # Set this to link PipeWire directly instead of using the dlopen.
> +   rtc_link_pipewire = false
> + 
> ++  # Set this to use certain PipeWire version
> ++  # Currently we support PipeWire 0.2 (default) and PipeWire 0.3
> ++  rtc_pipewire_version = "0.2"
> ++
> +   # Enable to use the Mozilla internal settings.
> +   build_with_mozilla = false
> + 
> diff --git a/debian/patches/python3.patch b/debian/patches/python3.patch
> index 9837209..1ed6e4c 100644
> --- a/debian/patches/python3.patch
> +++ b/debian/patches/python3.patch
> @@ -109,7 +109,7 @@ Forwarded: not-needed
>       return(true)
>  --- a/src/buildtools/configure.json
>  +++ b/src/buildtools/configure.json
> -@@ -295,9 +295,9 @@
> +@@ -301,9 +301,9 @@
>               "label": "system ninja",
>               "type": "detectNinja"
>           },
> @@ -122,7 +122,7 @@ Forwarded: not-needed
>               "log": "location"
>           },
>           "webengine-winversion": {
> -@@ -374,7 +374,7 @@
> +@@ -380,7 +380,7 @@
>                            && features.webengine-gperf
>                            && features.webengine-bison
>                            && features.webengine-flex
> @@ -131,7 +131,7 @@ Forwarded: not-needed
>                            && features.webengine-nodejs
>                            && (!config.sanitizer || features.webengine-sanitizer)
>                            && (!config.linux || features.pkg-config)
> -@@ -400,7 +400,7 @@
> +@@ -406,7 +406,7 @@
>                            && features.webengine-gperf
>                            && features.webengine-bison
>                            && features.webengine-flex
> @@ -140,7 +140,7 @@ Forwarded: not-needed
>                            && (!config.sanitizer || features.webengine-sanitizer)
>                            && (!config.linux || features.pkg-config)
>                            && (!config.linux || features.webengine-host-pkg-config)
> -@@ -423,12 +423,12 @@
> +@@ -429,12 +429,12 @@
>               "autoDetect": "features.private_tests",
>               "output": [ "privateFeature" ]
>           },
> diff --git a/debian/patches/series b/debian/patches/series
> index 9b396af..3b8f52b 100644
> --- a/debian/patches/series
> +++ b/debian/patches/series
> @@ -23,5 +23,5 @@ mips64el-bad-define.patch
>  mipsel-syscall-ranges.patch
>  mips64el-kernel_stat64.patch
>  armhf-no-thumb.patch
> -gcc-12.patch
>  disable-catapult.patch
> +pipewire-0.3.patch
> diff --git a/debian/rules b/debian/rules
> index 0cbc395..0cb0ced 100755
> --- a/debian/rules
> +++ b/debian/rules
> @@ -44,6 +44,7 @@ config_args = -proprietary-codecs \
>                -system-opus \
>                -system-webp \
>                -system-webengine-icu \
> +              -webengine-webrtc-pipewire \
>                -webengine-kerberos
>  
>  touch_files = src/3rdparty/chromium/third_party/devtools-frontend/src/front_end/third_party/lighthouse/lighthouse-dt-bundle.js \
> @@ -200,7 +201,7 @@ get-orig-source:
>  	@set -eux && \
>  	TEMPDIR=$$(mktemp -d) && \
>  	VERSION=${DEB_VERSION_UPSTREAM:+dfsg=} && \
> -	SUBMODULE_COMMIT=e0fd3a5d3ce79d43dee6e0bad16a71123d9a14b3 && \
> +	SUBMODULE_COMMIT=e48df7803c7c98b0b2471c94057d32e44a301ad5 && \
>  	echo "$${GET_FILES_EXCLUDED}" >$${TEMPDIR}/get_files_excluded.py && \
>  	cd $${TEMPDIR} && \
>  	wget https://github.com/qt/qtwebengine/archive/v$${VERSION}-lts.tar.gz && \





-- 
Sebastian Ramacher


Reply to: