blob: 829cbf9464345b3afe9c91cae84d2ea5ad18f262 [file] [log] [blame]
/*
* Copyright 2020 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_XDG_DESKTOP_PORTAL_BASE_H_
#define MODULES_DESKTOP_CAPTURE_LINUX_XDG_DESKTOP_PORTAL_BASE_H_
#include <gio/gio.h>
#include <map>
#include <memory>
#include <vector>
#include "modules/desktop_capture/desktop_geometry.h"
#include "modules/desktop_capture/linux/pipewire_base.h"
#include "api/ref_counted_base.h"
#include "api/scoped_refptr.h"
#include "rtc_base/callback.h"
#include "rtc_base/constructor_magic.h"
namespace webrtc {
struct ConnectionData;
class UserData;
class RTC_EXPORT XdgDesktopPortalBase : public rtc::RefCountedBase {
public:
enum class CaptureSourceType : uint32_t {
kScreen = 0b01,
kWindow = 0b10,
kAny = 0b11
};
XdgDesktopPortalBase();
~XdgDesktopPortalBase();
static rtc::scoped_refptr<XdgDesktopPortalBase> CreateDefault();
// Initializes a screen sharing request for a web page identified with a
// id. This id is later used to associate it with ConnectionData structure
// where we keep all the necessary information about the DBus communication.
//
// This starts a series of DBus calls:
// 1) SessionRequest - requests a session, which will be associated with
// this screen sharing request, passing a handle for identification so
// we can watch for success/failure.
// 2) SourceRequest - requests what content we want to share on given
// session (either monitor, screen or both)
// 3) StartRequest - requests to
// start sharing, which in return will give us information about stream
// (stream id and resolution).
// 4) OpenPipeWireRemote - requests a file descriptor which we can use
// for initialization of PipeWire on the client side and start receiving
// content.
void InitPortal(rtc::Callback1<void, bool> callback,
XdgDesktopPortalBase::CaptureSourceType requested_type,
int32_t id);
void CloseConnection(const absl::optional<int32_t>& id);
void SetConnectionStreamingOnWeb(const absl::optional<int32_t>& id);
bool IsConnectionInitialized(const absl::optional<int32_t>& id) const;
bool IsConnectionStreamingOnWeb(const absl::optional<int32_t>& id) const;
PipeWireBase* GetPipeWireBase(const absl::optional<int32_t>& id) const;
// Current ID serves for the DesktopCapturerOption to identify portal call
// from the client itself so we can skip an additional call which would be
// made upon preview dialog confirmation (e.g. Chromium).
absl::optional<int32_t> CurrentConnectionId() const;
void SetCurrentConnectionId(const absl::optional<int32_t>& id);
ConnectionData* GetConnectionData(const absl::optional<int32_t>& id) const;
private:
// Methods are defined in the same order in which they are being called
guint SetupRequestResponseSignal(const gchar* object_path,
GDBusSignalCallback callback,
UserData* data);
static void OnProxyRequested(GObject* object,
GAsyncResult* result,
gpointer user_data);
static gchar* PrepareSignalHandle(GDBusConnection* connection,
const gchar* token);
void SessionRequest(UserData* data);
static void OnSessionRequested(GDBusConnection* connection,
GAsyncResult* result,
gpointer user_data);
static void OnSessionRequestResponseSignal(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(UserData* data);
static void OnSourcesRequested(GDBusConnection* connection,
GAsyncResult* result,
gpointer user_data);
static void OnSourcesRequestResponseSignal(GDBusConnection* connection,
const gchar* sender_name,
const gchar* object_path,
const gchar* interface_name,
const gchar* signal_name,
GVariant* parameters,
gpointer user_data);
void StartRequest(UserData* data);
static void OnStartRequested(GDBusConnection* connection,
GAsyncResult* result,
gpointer user_data);
static void OnStartRequestResponseSignal(GDBusConnection* connection,
const gchar* sender_name,
const gchar* object_path,
const gchar* interface_name,
const gchar* signal_name,
GVariant* parameters,
gpointer user_data);
void OpenPipeWireRemote(UserData* data);
static void OnOpenPipeWireRemoteRequested(GDBusConnection* connection,
GAsyncResult* result,
gpointer user_data);
absl::optional<int32_t> current_connection_id_;
std::map<int32_t, std::unique_ptr<ConnectionData>> connection_data_map_;
RTC_DISALLOW_COPY_AND_ASSIGN(XdgDesktopPortalBase);
};
// This class represents each screen sharing request, which consists from a
// series of DBus calls, where we need to remember the session handle and
// parameters of the returned stream (id, resolution).
struct RTC_EXPORT ConnectionData {
explicit ConnectionData(int32_t id);
~ConnectionData();
bool operator=(const int32_t id) { return id_ == id; }
gint32 pw_fd_ = -1;
XdgDesktopPortalBase::CaptureSourceType capture_source_type_ =
XdgDesktopPortalBase::CaptureSourceType::kAny;
XdgDesktopPortalBase::CaptureSourceType requested_source_type_ =
XdgDesktopPortalBase::CaptureSourceType::kAny;
GDBusConnection* connection_ = nullptr;
GDBusProxy* proxy_ = nullptr;
gchar* portal_handle_ = nullptr;
gchar* session_handle_ = nullptr;
gchar* sources_handle_ = nullptr;
gchar* start_handle_ = nullptr;
guint session_request_signal_id_ = 0;
guint sources_request_signal_id_ = 0;
guint start_request_signal_id_ = 0;
DesktopSize desktop_size_ = {};
guint32 stream_id_ = 0;
int32_t id_;
bool already_used_ = false;
bool portal_init_failed_ = false;
bool web_streaming_ = false;
std::vector<rtc::Callback1<void, bool>> callbacks_;
rtc::Callback2<void, bool, int32_t> pw_callback_;
std::unique_ptr<PipeWireBase> pw_base_;
};
// Structure which is used as user_data property in GLib async calls, where we
// need to pass two values. One is ID of the web page requesting screen sharing
// and the other is pointer to the XdgDesktopPortalBase object.
class UserData {
public:
UserData(int32_t id, XdgDesktopPortalBase* xdp) {
data_id_ = id;
xdp_ = xdp;
}
int32_t GetDataId() const { return data_id_; }
XdgDesktopPortalBase* GetXdgDesktopPortalBase() const { return xdp_; }
private:
int32_t data_id_ = 0;
XdgDesktopPortalBase* xdp_ = nullptr;
};
} // namespace webrtc
#endif // MODULES_DESKTOP_CAPTURE_LINUX_XDG_DESKTOP_PORTAL_BASE_H_