wayland: Add a common interface for screencast and remote desktop portal

Change adapts the `base_capturer_pipewire` so that a portal can be
injected in the capturer. This allows the remoting to inject its
own portal for the purpose of capturing desktop stream as long
as the injected portal provides implementation of the new interface
that is added as part of this change.

Additionally, a method has been exposed on the capturer to get
details about the portal session so that the remoting
implementation can use the same underlying session for controlling
inputs on the remote host.

Finally, desktop capturer interface is extended with a generic
method `GetMetadata` that is used to retrieve session related
information by CRD and relay it over to its input injector. Clients
provide override for the method and it eventually invokes the
underlying `GetSessionDetails` method on the portal instance.

Bug: chromium:1291247
Change-Id: I0dbd154eb16d4149f967c4a818eea51e7e6eb9a9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/257000
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
Commit-Queue: Salman Malik <salmanmalik@google.com>
Cr-Commit-Position: refs/heads/main@{#36399}
diff --git a/modules/desktop_capture/BUILD.gn b/modules/desktop_capture/BUILD.gn
index 7499c16..580a886 100644
--- a/modules/desktop_capture/BUILD.gn
+++ b/modules/desktop_capture/BUILD.gn
@@ -6,6 +6,7 @@
 # in the file PATENTS.  All contributing project authors may
 # be found in the AUTHORS file in the root of the source tree.
 
+import("//build/config/linux/gtk/gtk.gni")
 import("//build/config/linux/pkg_config.gni")
 import("//build/config/ui.gni")
 import("//tools/generate_stubs/rules.gni")
@@ -266,6 +267,13 @@
       if (!rtc_link_pipewire) {
         defines += [ "WEBRTC_DLOPEN_PIPEWIRE" ]
       }
+
+      # Chromecast build config overrides `WEBRTC_USE_PIPEWIRE` even when
+      # `rtc_use_pipewire` is not set, which causes pipewire_config to not be
+      # included in targets. More details in: webrtc:13898
+      if (is_linux && !is_chromecast) {
+        defines += [ "WEBRTC_USE_GIO" ]
+      }
     }
   }
 }
@@ -369,7 +377,9 @@
     "window_finder.cc",
     "window_finder.h",
   ]
-
+  if (is_linux && !is_chromecast && rtc_use_pipewire) {
+    sources += [ "desktop_capture_metadata.h" ]
+  }
   if (is_mac) {
     sources += [
       "mac/desktop_configuration.h",
@@ -395,7 +405,6 @@
       ]
     }
   }
-
   if (rtc_use_x11_extensions || rtc_use_pipewire) {
     sources += [
       "mouse_cursor_monitor_linux.cc",
@@ -570,6 +579,7 @@
       "linux/wayland/mouse_cursor_monitor_pipewire.h",
       "linux/wayland/scoped_glib.cc",
       "linux/wayland/scoped_glib.h",
+      "linux/wayland/screen_capture_portal_interface.h",
       "linux/wayland/screencast_portal.cc",
       "linux/wayland/screencast_portal.h",
       "linux/wayland/screencast_stream_utils.cc",
@@ -578,6 +588,7 @@
       "linux/wayland/shared_screencast_stream.h",
       "linux/wayland/xdg_desktop_portal_utils.cc",
       "linux/wayland/xdg_desktop_portal_utils.h",
+      "linux/wayland/xdg_session_details.h",
     ]
 
     configs += [
diff --git a/modules/desktop_capture/desktop_and_cursor_composer.cc b/modules/desktop_capture/desktop_and_cursor_composer.cc
index 7ca0af0..355bfac 100644
--- a/modules/desktop_capture/desktop_and_cursor_composer.cc
+++ b/modules/desktop_capture/desktop_and_cursor_composer.cc
@@ -203,6 +203,12 @@
   return desktop_capturer_->IsOccluded(pos);
 }
 
+#if defined(WEBRTC_USE_GIO)
+DesktopCaptureMetadata DesktopAndCursorComposer::GetMetadata() {
+  return desktop_capturer_->GetMetadata();
+}
+#endif  // defined(WEBRTC_USE_GIO)
+
 void DesktopAndCursorComposer::OnCaptureResult(
     DesktopCapturer::Result result,
     std::unique_ptr<DesktopFrame> frame) {
diff --git a/modules/desktop_capture/desktop_and_cursor_composer.h b/modules/desktop_capture/desktop_and_cursor_composer.h
index edb764d..a078b3e 100644
--- a/modules/desktop_capture/desktop_and_cursor_composer.h
+++ b/modules/desktop_capture/desktop_and_cursor_composer.h
@@ -12,7 +12,9 @@
 #define MODULES_DESKTOP_CAPTURE_DESKTOP_AND_CURSOR_COMPOSER_H_
 
 #include <memory>
-
+#if defined(WEBRTC_USE_GIO)
+#include "modules/desktop_capture/desktop_capture_metadata.h"
+#endif  // defined(WEBRTC_USE_GIO)
 #include "modules/desktop_capture/desktop_capture_options.h"
 #include "modules/desktop_capture/desktop_capture_types.h"
 #include "modules/desktop_capture/desktop_capturer.h"
@@ -59,6 +61,9 @@
   bool SelectSource(SourceId id) override;
   bool FocusOnSelectedSource() override;
   bool IsOccluded(const DesktopVector& pos) override;
+#if defined(WEBRTC_USE_GIO)
+  DesktopCaptureMetadata GetMetadata() override;
+#endif  // defined(WEBRTC_USE_GIO)
 
   // MouseCursorMonitor::Callback interface.
   void OnMouseCursor(MouseCursor* cursor) override;
diff --git a/modules/desktop_capture/desktop_capture_metadata.h b/modules/desktop_capture/desktop_capture_metadata.h
new file mode 100644
index 0000000..faca156
--- /dev/null
+++ b/modules/desktop_capture/desktop_capture_metadata.h
@@ -0,0 +1,31 @@
+/*
+ *  Copyright (c) 2022 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_DESKTOP_CAPTURE_METADATA_H_
+#define MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURE_METADATA_H_
+
+#if defined(WEBRTC_USE_GIO)
+#include "modules/desktop_capture/linux/wayland/xdg_session_details.h"
+#endif  // defined(WEBRTC_USE_GIO)
+
+namespace webrtc {
+
+// Container for the metadata associated with a desktop capturer.
+struct DesktopCaptureMetadata {
+#if defined(WEBRTC_USE_GIO)
+  // Details about the XDG desktop session handle (used by wayland
+  // implementation in remoting)
+  xdg_portal::SessionDetails session_details;
+#endif  // defined(WEBRTC_USE_GIO)
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURE_METADATA_H_
diff --git a/modules/desktop_capture/desktop_capturer.h b/modules/desktop_capture/desktop_capturer.h
index 822a75d..d316425 100644
--- a/modules/desktop_capture/desktop_capturer.h
+++ b/modules/desktop_capture/desktop_capturer.h
@@ -19,6 +19,9 @@
 #include <type_traits>
 #include <vector>
 
+#if defined(WEBRTC_USE_GIO)
+#include "modules/desktop_capture/desktop_capture_metadata.h"
+#endif  // defined(WEBRTC_USE_GIO)
 #include "modules/desktop_capture/desktop_capture_types.h"
 #include "modules/desktop_capture/desktop_frame.h"
 #include "modules/desktop_capture/shared_memory.h"
@@ -143,6 +146,12 @@
   static bool IsRunningUnderWayland();
 #endif  // defined(WEBRTC_USE_PIPEWIRE) || defined(WEBRTC_USE_X11)
 
+#if defined(WEBRTC_USE_GIO)
+  // Populates implementation specific metadata into the passed in pointer.
+  // Classes can choose to override it or use the default no-op implementation.
+  virtual DesktopCaptureMetadata GetMetadata() { return {}; }
+#endif  // defined(WEBRTC_USE_GIO)
+
  protected:
   // CroppingWindowCapturer needs to create raw capturers without wrappers, so
   // the following two functions are protected.
diff --git a/modules/desktop_capture/desktop_capturer_differ_wrapper.cc b/modules/desktop_capture/desktop_capturer_differ_wrapper.cc
index 916d76f..77543e4 100644
--- a/modules/desktop_capture/desktop_capturer_differ_wrapper.cc
+++ b/modules/desktop_capture/desktop_capturer_differ_wrapper.cc
@@ -186,6 +186,12 @@
   return base_capturer_->IsOccluded(pos);
 }
 
+#if defined(WEBRTC_USE_GIO)
+DesktopCaptureMetadata DesktopCapturerDifferWrapper::GetMetadata() {
+  return base_capturer_->GetMetadata();
+}
+#endif  // defined(WEBRTC_USE_GIO)
+
 void DesktopCapturerDifferWrapper::OnCaptureResult(
     Result result,
     std::unique_ptr<DesktopFrame> input_frame) {
diff --git a/modules/desktop_capture/desktop_capturer_differ_wrapper.h b/modules/desktop_capture/desktop_capturer_differ_wrapper.h
index 1f70cef..6ebb5d7 100644
--- a/modules/desktop_capture/desktop_capturer_differ_wrapper.h
+++ b/modules/desktop_capture/desktop_capturer_differ_wrapper.h
@@ -12,7 +12,9 @@
 #define MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURER_DIFFER_WRAPPER_H_
 
 #include <memory>
-
+#if defined(WEBRTC_USE_GIO)
+#include "modules/desktop_capture/desktop_capture_metadata.h"
+#endif  // defined(WEBRTC_USE_GIO)
 #include "modules/desktop_capture/desktop_capture_types.h"
 #include "modules/desktop_capture/desktop_capturer.h"
 #include "modules/desktop_capture/desktop_frame.h"
@@ -52,7 +54,9 @@
   bool SelectSource(SourceId id) override;
   bool FocusOnSelectedSource() override;
   bool IsOccluded(const DesktopVector& pos) override;
-
+#if defined(WEBRTC_USE_GIO)
+  DesktopCaptureMetadata GetMetadata() override;
+#endif  // defined(WEBRTC_USE_GIO)
  private:
   // DesktopCapturer::Callback interface.
   void OnCaptureResult(Result result,
diff --git a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc
index ae26570..0fc90e0 100644
--- a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc
+++ b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc
@@ -21,14 +21,22 @@
 namespace {
 
 using xdg_portal::RequestResponse;
+using xdg_portal::ScreenCapturePortalInterface;
+using xdg_portal::SessionDetails;
 
 }  // namespace
 
 BaseCapturerPipeWire::BaseCapturerPipeWire(const DesktopCaptureOptions& options)
-    : options_(options) {
-  screencast_portal_ = std::make_unique<ScreenCastPortal>(
-      ScreenCastPortal::CaptureSourceType::kAnyScreenContent, this);
-}
+    : BaseCapturerPipeWire(
+          options,
+          std::make_unique<ScreenCastPortal>(
+              ScreenCastPortal::CaptureSourceType::kAnyScreenContent,
+              this)) {}
+
+BaseCapturerPipeWire::BaseCapturerPipeWire(
+    const DesktopCaptureOptions& options,
+    std::unique_ptr<ScreenCapturePortalInterface> portal)
+    : options_(options), portal_(std::move(portal)) {}
 
 BaseCapturerPipeWire::~BaseCapturerPipeWire() {}
 
@@ -56,7 +64,7 @@
 
   callback_ = callback;
 
-  screencast_portal_->Start();
+  portal_->Start();
 }
 
 void BaseCapturerPipeWire::CaptureFrame() {
@@ -97,4 +105,8 @@
   return true;
 }
 
+SessionDetails BaseCapturerPipeWire::GetSessionDetails() {
+  return portal_->GetSessionDetails();
+}
+
 }  // namespace webrtc
diff --git a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h
index e9d67d0..da0ce95 100644
--- a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h
+++ b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h
@@ -13,16 +13,21 @@
 
 #include "modules/desktop_capture/desktop_capture_options.h"
 #include "modules/desktop_capture/desktop_capturer.h"
+#include "modules/desktop_capture/linux/wayland/screen_capture_portal_interface.h"
 #include "modules/desktop_capture/linux/wayland/screencast_portal.h"
 #include "modules/desktop_capture/linux/wayland/shared_screencast_stream.h"
 #include "modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h"
+#include "modules/desktop_capture/linux/wayland/xdg_session_details.h"
 
 namespace webrtc {
 
 class BaseCapturerPipeWire : public DesktopCapturer,
                              public ScreenCastPortal::PortalNotifier {
  public:
-  BaseCapturerPipeWire(const DesktopCaptureOptions& options);
+  explicit BaseCapturerPipeWire(const DesktopCaptureOptions& options);
+  BaseCapturerPipeWire(
+      const DesktopCaptureOptions& options,
+      std::unique_ptr<xdg_portal::ScreenCapturePortalInterface> portal);
   ~BaseCapturerPipeWire() override;
 
   BaseCapturerPipeWire(const BaseCapturerPipeWire&) = delete;
@@ -40,11 +45,13 @@
                                  int fd) override;
   void OnScreenCastSessionClosed() override;
 
+  xdg_portal::SessionDetails GetSessionDetails();
+
  private:
   DesktopCaptureOptions options_ = {};
   Callback* callback_ = nullptr;
   bool capturer_failed_ = false;
-  std::unique_ptr<ScreenCastPortal> screencast_portal_;
+  std::unique_ptr<xdg_portal::ScreenCapturePortalInterface> portal_;
 };
 
 }  // namespace webrtc
diff --git a/modules/desktop_capture/linux/wayland/screen_capture_portal_interface.h b/modules/desktop_capture/linux/wayland/screen_capture_portal_interface.h
new file mode 100644
index 0000000..76cbd27
--- /dev/null
+++ b/modules/desktop_capture/linux/wayland/screen_capture_portal_interface.h
@@ -0,0 +1,30 @@
+/*
+ *  Copyright (c) 2022 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_WAYLAND_SCREEN_CAPTURE_PORTAL_INTERFACE_H_
+#define MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_SCREEN_CAPTURE_PORTAL_INTERFACE_H_
+
+#include "modules/desktop_capture/linux/wayland/xdg_session_details.h"
+
+namespace webrtc {
+namespace xdg_portal {
+
+// An interface for XDG desktop portals that can capture desktop/screen.
+class ScreenCapturePortalInterface {
+ public:
+  virtual ~ScreenCapturePortalInterface() {}
+  virtual xdg_portal::SessionDetails GetSessionDetails() = 0;
+  virtual void Start() = 0;
+};
+
+}  // namespace xdg_portal
+}  // namespace webrtc
+
+#endif  // MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_SCREEN_CAPTURE_PORTAL_INTERFACE_H_
diff --git a/modules/desktop_capture/linux/wayland/screencast_portal.cc b/modules/desktop_capture/linux/wayland/screencast_portal.cc
index bbf9339..ab516a7 100644
--- a/modules/desktop_capture/linux/wayland/screencast_portal.cc
+++ b/modules/desktop_capture/linux/wayland/screencast_portal.cc
@@ -112,6 +112,10 @@
                       cancellable_, this);
 }
 
+xdg_portal::SessionDetails ScreenCastPortal::GetSessionDetails() {
+  return {};  // No-op
+}
+
 void ScreenCastPortal::PortalFailed(RequestResponse result) {
   notifier_->OnScreenCastRequestResult(result, pw_stream_node_id_, pw_fd_);
 }
diff --git a/modules/desktop_capture/linux/wayland/screencast_portal.h b/modules/desktop_capture/linux/wayland/screencast_portal.h
index d29f773..3d86006 100644
--- a/modules/desktop_capture/linux/wayland/screencast_portal.h
+++ b/modules/desktop_capture/linux/wayland/screencast_portal.h
@@ -15,11 +15,13 @@
 
 #include <string>
 
+#include "modules/desktop_capture/linux/wayland/screen_capture_portal_interface.h"
 #include "modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h"
+#include "modules/desktop_capture/linux/wayland/xdg_session_details.h"
 
 namespace webrtc {
 
-class ScreenCastPortal {
+class ScreenCastPortal : public xdg_portal::ScreenCapturePortalInterface {
  public:
   using ProxyRequestResponseHandler = void (*)(GObject* object,
                                                GAsyncResult* result,
@@ -86,7 +88,8 @@
   // The observer will return whether the communication with xdg-desktop-portal
   // was successful and only then you will be able to get all the required
   // information in order to continue working with PipeWire.
-  void Start();
+  void Start() override;
+  xdg_portal::SessionDetails GetSessionDetails() override;
 
   // Method to notify the reason for failure of a portal request.
   void PortalFailed(xdg_portal::RequestResponse result);
diff --git a/modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h b/modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h
index 4fb058c..98979c1 100644
--- a/modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h
+++ b/modules/desktop_capture/linux/wayland/xdg_desktop_portal_utils.h
@@ -18,6 +18,7 @@
 #include <vector>
 
 #include "modules/desktop_capture/linux/wayland/scoped_glib.h"
+#include "modules/desktop_capture/linux/wayland/xdg_session_details.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/logging.h"
 
@@ -32,13 +33,6 @@
 constexpr char kRequestInterfaceName[] = "org.freedesktop.portal.Request";
 constexpr char kScreenCastInterfaceName[] = "org.freedesktop.portal.ScreenCast";
 
-struct SessionDetails {
-  GDBusProxy* proxy;
-  GCancellable* cancellable;
-  std::string session_handle;
-  uint32_t pipewire_stream_node_id;
-};
-
 using ProxyRequestCallback = void (*)(GObject*, GAsyncResult*, gpointer);
 using SessionRequestCallback = void (*)(GDBusProxy*, GAsyncResult*, gpointer);
 using SessionRequestResponseSignalHandler = void (*)(GDBusConnection*,
diff --git a/modules/desktop_capture/linux/wayland/xdg_session_details.h b/modules/desktop_capture/linux/wayland/xdg_session_details.h
new file mode 100644
index 0000000..b70ac4a
--- /dev/null
+++ b/modules/desktop_capture/linux/wayland/xdg_session_details.h
@@ -0,0 +1,33 @@
+/*
+ *  Copyright 2022 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_WAYLAND_XDG_SESSION_DETAILS_H_
+#define MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_XDG_SESSION_DETAILS_H_
+
+#include <gio/gio.h>
+
+#include <string>
+
+namespace webrtc {
+namespace xdg_portal {
+
+// Details of the session associated with XDG desktop portal session. Portal API
+// calls can be invoked by utilizing the information here.
+struct SessionDetails {
+  GDBusProxy* proxy = nullptr;
+  GCancellable* cancellable = nullptr;
+  std::string session_handle;
+  uint32_t pipewire_stream_node_id = 0;
+};
+
+}  // namespace xdg_portal
+}  // namespace webrtc
+
+#endif  // MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_XDG_SESSION_DETAILS_H_