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 #include "modules/desktop_capture/linux/wayland/screen_capture_portal_interface.h"
11 
12 #include <string>
13 
14 #include "modules/portal/xdg_desktop_portal_utils.h"
15 #include "rtc_base/logging.h"
16 
17 namespace webrtc {
18 namespace xdg_portal {
19 
RequestSessionUsingProxy(GAsyncResult * result)20 void ScreenCapturePortalInterface::RequestSessionUsingProxy(
21     GAsyncResult* result) {
22   Scoped<GError> error;
23   GDBusProxy* proxy = g_dbus_proxy_new_finish(result, error.receive());
24   if (!proxy) {
25     // Ignore the error caused by user cancelling the request via `cancellable_`
26     if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
27       return;
28     RTC_LOG(LS_ERROR) << "Failed to get a proxy for the portal: "
29                       << error->message;
30     OnPortalDone(RequestResponse::kError);
31     return;
32   }
33 
34   RTC_LOG(LS_INFO) << "Successfully created proxy for the portal.";
35   RequestSession(proxy);
36 }
37 
OnSessionRequestResult(GDBusProxy * proxy,GAsyncResult * result)38 void ScreenCapturePortalInterface::OnSessionRequestResult(
39     GDBusProxy* proxy,
40     GAsyncResult* result) {
41   Scoped<GError> error;
42   Scoped<GVariant> variant(
43       g_dbus_proxy_call_finish(proxy, result, error.receive()));
44   if (!variant) {
45     // Ignore the error caused by user cancelling the request via `cancellable_`
46     if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
47       return;
48     RTC_LOG(LS_ERROR) << "Failed to request session: " << error->message;
49     OnPortalDone(RequestResponse::kError);
50     return;
51   }
52 
53   RTC_LOG(LS_INFO) << "Initializing the session.";
54 
55   Scoped<char> handle;
56   g_variant_get_child(variant.get(), /*index=*/0, /*format_string=*/"o",
57                       &handle);
58   if (!handle) {
59     RTC_LOG(LS_ERROR) << "Failed to initialize the session.";
60     OnPortalDone(RequestResponse::kError);
61     return;
62   }
63 }
64 
RegisterSessionClosedSignalHandler(const SessionClosedSignalHandler session_close_signal_handler,GVariant * parameters,GDBusConnection * connection,std::string & session_handle,guint & session_closed_signal_id)65 void ScreenCapturePortalInterface::RegisterSessionClosedSignalHandler(
66     const SessionClosedSignalHandler session_close_signal_handler,
67     GVariant* parameters,
68     GDBusConnection* connection,
69     std::string& session_handle,
70     guint& session_closed_signal_id) {
71   uint32_t portal_response = 2;
72   Scoped<GVariant> response_data;
73   g_variant_get(parameters, /*format_string=*/"(u@a{sv})", &portal_response,
74                 response_data.receive());
75 
76   if (RequestResponseFromPortalResponse(portal_response) !=
77       RequestResponse::kSuccess) {
78     RTC_LOG(LS_ERROR) << "Failed to request the session subscription.";
79     OnPortalDone(RequestResponse::kError);
80     return;
81   }
82 
83   Scoped<GVariant> g_session_handle(
84       g_variant_lookup_value(response_data.get(), /*key=*/"session_handle",
85                              /*expected_type=*/nullptr));
86   session_handle = g_variant_get_string(
87       /*value=*/g_session_handle.get(), /*length=*/nullptr);
88 
89   if (session_handle.empty()) {
90     RTC_LOG(LS_ERROR) << "Could not get session handle despite valid response";
91     OnPortalDone(RequestResponse::kError);
92     return;
93   }
94 
95   session_closed_signal_id = g_dbus_connection_signal_subscribe(
96       connection, kDesktopBusName, kSessionInterfaceName, /*member=*/"Closed",
97       session_handle.c_str(), /*arg0=*/nullptr, G_DBUS_SIGNAL_FLAGS_NONE,
98       session_close_signal_handler, this, /*user_data_free_func=*/nullptr);
99 }
100 
OnStartRequestResult(GDBusProxy * proxy,GAsyncResult * result)101 void ScreenCapturePortalInterface::OnStartRequestResult(GDBusProxy* proxy,
102                                                         GAsyncResult* result) {
103   Scoped<GError> error;
104   Scoped<GVariant> variant(
105       g_dbus_proxy_call_finish(proxy, result, error.receive()));
106   if (!variant) {
107     if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
108       return;
109     RTC_LOG(LS_ERROR) << "Failed to start the portal session: "
110                       << error->message;
111     OnPortalDone(RequestResponse::kError);
112     return;
113   }
114 
115   Scoped<char> handle;
116   g_variant_get_child(variant.get(), 0, "o", handle.receive());
117   if (!handle) {
118     RTC_LOG(LS_ERROR) << "Failed to initialize the start portal session.";
119     OnPortalDone(RequestResponse::kError);
120     return;
121   }
122 
123   RTC_LOG(LS_INFO) << "Subscribed to the start signal.";
124 }
125 
126 }  // namespace xdg_portal
127 }  // namespace webrtc
128