PipeWire capturer: disconnect receiving stream on Xdp::Session::Closed signal

When screencast session is closed, there won't be any other stream we
can reconnect to and in that case we are supposed to disconnect our
stream to prevent accidentally connecting to any other stream in case it
gets assigned same node ID from PipeWire

Bug: webrtc:13429
Change-Id: Iec8e93a108c789c32cb93e1460e693fabc247491
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/241086
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
Commit-Queue: Alexander Cooper <alcooper@chromium.org>
Cr-Commit-Position: refs/heads/main@{#35728}
diff --git a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc
index 3f93393..8cc3957 100644
--- a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc
+++ b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc
@@ -870,9 +870,39 @@
     return;
   }
 
+  that->session_closed_signal_id_ = g_dbus_connection_signal_subscribe(
+      that->connection_, kDesktopBusName, kSessionInterfaceName, "Closed",
+      that->session_handle_, /*arg0=*/nullptr, G_DBUS_SIGNAL_FLAGS_NONE,
+      OnSessionClosedSignal, that, /*user_data_free_func=*/nullptr);
+
   that->SourcesRequest();
 }
 
+// static
+void BaseCapturerPipeWire::OnSessionClosedSignal(GDBusConnection* connection,
+                                                 const gchar* sender_name,
+                                                 const gchar* object_path,
+                                                 const gchar* interface_name,
+                                                 const gchar* signal_name,
+                                                 GVariant* parameters,
+                                                 gpointer user_data) {
+  BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(user_data);
+  RTC_DCHECK(that);
+
+  RTC_LOG(LS_INFO) << "Received closed signal from session.";
+
+  if (that->pw_stream_) {
+    pw_stream_disconnect(that->pw_stream_);
+  }
+
+  // Unsubscribe from the signal and free the session handle to avoid calling
+  // Session::Close from the destructor since it's already closed
+  g_dbus_connection_signal_unsubscribe(that->connection_,
+                                       that->session_closed_signal_id_);
+  g_free(that->session_handle_);
+  that->session_handle_ = nullptr;
+}
+
 void BaseCapturerPipeWire::SourcesRequest() {
   GVariantBuilder builder;
   Scoped<gchar> variant_string;
diff --git a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h
index 91c863e..65c9fd3 100644
--- a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h
+++ b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.h
@@ -104,6 +104,7 @@
   guint session_request_signal_id_ = 0;
   guint sources_request_signal_id_ = 0;
   guint start_request_signal_id_ = 0;
+  guint session_closed_signal_id_ = 0;
 
   int64_t modifier_;
   DesktopSize video_size_;
@@ -166,6 +167,13 @@
                                              const gchar* signal_name,
                                              GVariant* parameters,
                                              gpointer user_data);
+  static void OnSessionClosedSignal(GDBusConnection* connection,
+                                    const gchar* sender_name,
+                                    const gchar* object_path,
+                                    const gchar* interface_name,
+                                    const gchar* signal_name,
+                                    GVariant* parameters,
+                                    gpointer user_data);
 
   void SourcesRequest();
   static void OnSourcesRequested(GDBusProxy* proxy,
diff --git a/modules/desktop_capture/linux/wayland/pipewire.sigs b/modules/desktop_capture/linux/wayland/pipewire.sigs
index 7a74c7f..06a97b8 100644
--- a/modules/desktop_capture/linux/wayland/pipewire.sigs
+++ b/modules/desktop_capture/linux/wayland/pipewire.sigs
@@ -24,6 +24,7 @@
 // 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);
+int pw_stream_disconnect(pw_stream *stream);
 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);