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