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

Bug#1032794: marked as done ([pre-approval] qtwebengine-opensource-src 5.15.13 for bookworm?)



Your message dated Wed, 29 Mar 2023 22:56:27 +0200
with message-id <ZCSl+1s+4zi+NqLI@ramacher.at>
and subject line Re: Bug#1032794: [pre-approval] qtwebengine-opensource-src 5.15.13 for bookworm?
has caused the Debian Bug report #1032794,
regarding [pre-approval] qtwebengine-opensource-src 5.15.13 for bookworm?
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
1032794: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1032794
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
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?

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.

--
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édric 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ónio 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 && \

Attachment: upstream.diff.gz
Description: application/gzip

Attachment: signature.asc
Description: PGP signature


--- End Message ---
--- Begin Message ---
On 2023-03-23 23:42:01 +0100, Sebastian Ramacher wrote:
> Control: tags -1 confirmed
> 
> On 2023-03-23 21:22:55 +0300, Dmitry Shachnev wrote:
> > Control: tags -1 -moreinfo
> > 
> > Hi Sebastian!
> > 
> > On Tue, Mar 21, 2023 at 10:46:52PM +0100, Sebastian Ramacher wrote:
> > > Do both reverse dependencies build fine with the new version of
> > > qtwebengine-opensource-src?
> > 
> > Yes. Just checked in an Ubuntu PPA:
> > 
> > https://launchpad.net/~ci-train-ppa-service/+archive/ubuntu/4979/+packages
> > 
> > > > 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.
> > 
> > Okay, reverted that change in debian/bullseye branch. Attaching the new
> > diff for packaging.
> > 
> > As I used 5.15.13+dfsg-1 for experimental upload, I changed the version
> > in debian/bullseye branch to 5.15.13+dfsg-1~deb12u1. Does that work, or
> > I should use some different version?
> 
> The version is fine. Please go ahead.

Thanks, unblocked.

Cheers
-- 
Sebastian Ramacher

--- End Message ---

Reply to: