1 /* 2 * Copyright 2022 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #ifndef MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_SCREENCAST_PORTAL_H_ 12 #define MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_SCREENCAST_PORTAL_H_ 13 14 #include <gio/gio.h> 15 16 #include <string> 17 18 #include "modules/desktop_capture/desktop_capture_types.h" 19 #include "modules/desktop_capture/linux/wayland/screen_capture_portal_interface.h" 20 #include "modules/portal/portal_request_response.h" 21 #include "modules/portal/xdg_desktop_portal_utils.h" 22 #include "modules/portal/xdg_session_details.h" 23 24 namespace webrtc { 25 26 class ScreenCastPortal : public xdg_portal::ScreenCapturePortalInterface { 27 public: 28 using ProxyRequestResponseHandler = void (*)(GObject* object, 29 GAsyncResult* result, 30 gpointer user_data); 31 32 using SourcesRequestResponseSignalHandler = 33 void (*)(GDBusConnection* connection, 34 const char* sender_name, 35 const char* object_path, 36 const char* interface_name, 37 const char* signal_name, 38 GVariant* parameters, 39 gpointer user_data); 40 41 // Values are set based on cursor mode property in 42 // xdg-desktop-portal/screencast 43 // https://github.com/flatpak/xdg-desktop-portal/blob/master/data/org.freedesktop.portal.ScreenCast.xml 44 enum class CursorMode : uint32_t { 45 // Mouse cursor will not be included in any form 46 kHidden = 0b01, 47 // Mouse cursor will be part of the screen content 48 kEmbedded = 0b10, 49 // Mouse cursor information will be send separately in form of metadata 50 kMetadata = 0b100 51 }; 52 53 // Values are set based on persist mode property in 54 // xdg-desktop-portal/screencast 55 // https://github.com/flatpak/xdg-desktop-portal/blob/master/data/org.freedesktop.portal.ScreenCast.xml 56 enum class PersistMode : uint32_t { 57 // Do not allow to restore stream 58 kDoNotPersist = 0b00, 59 // The restore token is valid as long as the application is alive. It's 60 // stored in memory and revoked when the application closes its DBus 61 // connection 62 kTransient = 0b01, 63 // The restore token is stored in disk and is valid until the user manually 64 // revokes it 65 kPersistent = 0b10 66 }; 67 68 // Interface that must be implemented by the ScreenCastPortal consumers. 69 class PortalNotifier { 70 public: 71 virtual void OnScreenCastRequestResult(xdg_portal::RequestResponse result, 72 uint32_t stream_node_id, 73 int fd) = 0; 74 virtual void OnScreenCastSessionClosed() = 0; 75 76 protected: 77 PortalNotifier() = default; 78 virtual ~PortalNotifier() = default; 79 }; 80 81 ScreenCastPortal(CaptureType type, PortalNotifier* notifier); 82 ScreenCastPortal(CaptureType type, 83 PortalNotifier* notifier, 84 ProxyRequestResponseHandler proxy_request_response_handler, 85 SourcesRequestResponseSignalHandler 86 sources_request_response_signal_handler, 87 gpointer user_data, 88 // TODO(chromium:1291247): Remove the default option once 89 // downstream has been adjusted. 90 bool prefer_cursor_embedded = false); 91 92 ~ScreenCastPortal(); 93 94 // Initialize ScreenCastPortal with series of DBus calls where we try to 95 // obtain all the required information, like PipeWire file descriptor and 96 // PipeWire stream node ID. 97 // 98 // The observer will return whether the communication with xdg-desktop-portal 99 // was successful and only then you will be able to get all the required 100 // information in order to continue working with PipeWire. 101 void Start() override; 102 void Stop() override; 103 xdg_portal::SessionDetails GetSessionDetails() override; 104 105 // Method to notify the reason for failure of a portal request. 106 void OnPortalDone(xdg_portal::RequestResponse result) override; 107 108 // Sends a create session request to the portal. 109 void RequestSession(GDBusProxy* proxy) override; 110 111 // Set of methods leveraged by remote desktop portal to setup a common session 112 // with screen cast portal. 113 void SetSessionDetails(const xdg_portal::SessionDetails& session_details); 114 uint32_t pipewire_stream_node_id(); 115 void SourcesRequest(); 116 void OpenPipeWireRemote(); 117 118 // ScreenCast specific methods for stream restoration 119 void SetPersistMode(ScreenCastPortal::PersistMode mode); 120 void SetRestoreToken(const std::string& token); 121 std::string RestoreToken() const; 122 123 private: 124 // Values are set based on source type property in 125 // xdg-desktop-portal/screencast 126 // https://github.com/flatpak/xdg-desktop-portal/blob/master/data/org.freedesktop.portal.ScreenCast.xml 127 enum class CaptureSourceType : uint32_t { 128 kScreen = 0b01, 129 kWindow = 0b10, 130 kAnyScreenContent = kScreen | kWindow 131 }; 132 static CaptureSourceType ToCaptureSourceType(CaptureType type); 133 134 PortalNotifier* notifier_; 135 136 // A PipeWire stream ID of stream we will be connecting to 137 uint32_t pw_stream_node_id_ = 0; 138 // A file descriptor of PipeWire socket 139 int pw_fd_ = -1; 140 // Restore token that can be used to restore previous session 141 std::string restore_token_; 142 143 CaptureSourceType capture_source_type_ = 144 ScreenCastPortal::CaptureSourceType::kScreen; 145 146 CursorMode cursor_mode_ = CursorMode::kMetadata; 147 148 PersistMode persist_mode_ = ScreenCastPortal::PersistMode::kDoNotPersist; 149 150 ProxyRequestResponseHandler proxy_request_response_handler_; 151 SourcesRequestResponseSignalHandler sources_request_response_signal_handler_; 152 gpointer user_data_; 153 154 GDBusConnection* connection_ = nullptr; 155 GDBusProxy* proxy_ = nullptr; 156 GCancellable* cancellable_ = nullptr; 157 std::string portal_handle_; 158 std::string session_handle_; 159 std::string sources_handle_; 160 std::string start_handle_; 161 guint session_request_signal_id_ = 0; 162 guint sources_request_signal_id_ = 0; 163 guint start_request_signal_id_ = 0; 164 guint session_closed_signal_id_ = 0; 165 166 void UnsubscribeSignalHandlers(); 167 static void OnProxyRequested(GObject* object, 168 GAsyncResult* result, 169 gpointer user_data); 170 static void OnSessionRequested(GDBusProxy* proxy, 171 GAsyncResult* result, 172 gpointer user_data); 173 static void OnSessionRequestResponseSignal(GDBusConnection* connection, 174 const char* sender_name, 175 const char* object_path, 176 const char* interface_name, 177 const char* signal_name, 178 GVariant* parameters, 179 gpointer user_data); 180 static void OnSessionClosedSignal(GDBusConnection* connection, 181 const char* sender_name, 182 const char* object_path, 183 const char* interface_name, 184 const char* signal_name, 185 GVariant* parameters, 186 gpointer user_data); 187 static void OnSourcesRequested(GDBusProxy* proxy, 188 GAsyncResult* result, 189 gpointer user_data); 190 static void OnSourcesRequestResponseSignal(GDBusConnection* connection, 191 const char* sender_name, 192 const char* object_path, 193 const char* interface_name, 194 const char* signal_name, 195 GVariant* parameters, 196 gpointer user_data); 197 198 void StartRequest(); 199 static void OnStartRequested(GDBusProxy* proxy, 200 GAsyncResult* result, 201 gpointer user_data); 202 static void OnStartRequestResponseSignal(GDBusConnection* connection, 203 const char* sender_name, 204 const char* object_path, 205 const char* interface_name, 206 const char* signal_name, 207 GVariant* parameters, 208 gpointer user_data); 209 210 static void OnOpenPipeWireRemoteRequested(GDBusProxy* proxy, 211 GAsyncResult* result, 212 gpointer user_data); 213 }; 214 215 } // namespace webrtc 216 217 #endif // MODULES_DESKTOP_CAPTURE_LINUX_WAYLAND_SCREENCAST_PORTAL_H_ 218