1 /*
2  *  Copyright 2018 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_BASE_CAPTURER_PIPEWIRE_H_
12 #define MODULES_DESKTOP_CAPTURE_LINUX_BASE_CAPTURER_PIPEWIRE_H_
13 
14 #include <gio/gio.h>
15 #define typeof __typeof__
16 #include <pipewire/pipewire.h>
17 #include <spa/param/video/format-utils.h>
18 
19 #include "modules/desktop_capture/desktop_capture_options.h"
20 #include "modules/desktop_capture/desktop_capturer.h"
21 #include "rtc_base/constructormagic.h"
22 
23 namespace webrtc {
24 
25 class BaseCapturerPipeWire : public DesktopCapturer {
26  public:
27   enum CaptureSourceType : uint32_t {
28     kScreen = 0b01,
29     kWindow = 0b10,
30     kAny = 0b11
31   };
32 
33   explicit BaseCapturerPipeWire(CaptureSourceType source_type);
34   ~BaseCapturerPipeWire() override;
35 
36   // DesktopCapturer interface.
37   void Start(Callback* delegate) override;
38   void CaptureFrame() override;
39   bool GetSourceList(SourceList* sources) override;
40   bool SelectSource(SourceId id) override;
41 
42   static std::unique_ptr<DesktopCapturer> CreateRawScreenCapturer(
43       const DesktopCaptureOptions& options);
44 
45   static std::unique_ptr<DesktopCapturer> CreateRawWindowCapturer(
46       const DesktopCaptureOptions& options);
47 
48  private:
49   // PipeWire types -->
50   pw_context* pw_context_ = nullptr;
51   pw_core* pw_core_ = nullptr;
52   pw_stream* pw_stream_ = nullptr;
53   pw_thread_loop* pw_main_loop_ = nullptr;
54 
55   spa_hook spa_core_listener_ = {};
56   spa_hook spa_stream_listener_ = {};
57 
58   pw_core_events pw_core_events_ = {};
59   pw_stream_events pw_stream_events_ = {};
60 
61   struct spa_video_info_raw spa_video_format_;
62 
63   guint32 pw_stream_node_id_ = 0;
64   gint32 pw_fd_ = -1;
65 
66   CaptureSourceType capture_source_type_ =
67       BaseCapturerPipeWire::CaptureSourceType::kAny;
68 
69   // <-- end of PipeWire types
70 
71   GDBusConnection* connection_ = nullptr;
72   GDBusProxy* proxy_ = nullptr;
73   GCancellable *cancellable_ = nullptr;
74   gchar* portal_handle_ = nullptr;
75   gchar* session_handle_ = nullptr;
76   gchar* sources_handle_ = nullptr;
77   gchar* start_handle_ = nullptr;
78   guint session_request_signal_id_ = 0;
79   guint sources_request_signal_id_ = 0;
80   guint start_request_signal_id_ = 0;
81 
82   bool video_metadata_use_ = false;
83   DesktopSize video_size_;
84   DesktopSize desktop_size_ = {};
85   DesktopCaptureOptions options_ = {};
86 
87   rtc::CriticalSection current_frame_lock_;
88   std::unique_ptr<uint8_t[]> current_frame_;
89   Callback* callback_ = nullptr;
90 
91   bool portal_init_failed_ = false;
92 
93   void InitPortal();
94   void InitPipeWire();
95 
96   pw_stream* CreateReceivingStream();
97   void HandleBuffer(pw_buffer* buffer);
98 
99   void ConvertRGBxToBGRx(uint8_t* frame, uint32_t size);
100 
101   static void OnCoreError(void *data,
102                           uint32_t id,
103                           int seq,
104                           int res,
105                           const char *message);
106   static void OnStreamParamChanged(void *data,
107                                    uint32_t id,
108                                    const struct spa_pod *format);
109   static void OnStreamStateChanged(void* data,
110                                    pw_stream_state old_state,
111                                    pw_stream_state state,
112                                    const char* error_message);
113   static void OnStreamProcess(void* data);
114   static void OnNewBuffer(void* data, uint32_t id);
115 
116   guint SetupRequestResponseSignal(const gchar* object_path,
117                                    GDBusSignalCallback callback);
118 
119   static void OnProxyRequested(GObject* object,
120                                GAsyncResult* result,
121                                gpointer user_data);
122 
123   static gchar* PrepareSignalHandle(GDBusConnection* connection,
124                                     const gchar* token);
125 
126   void SessionRequest();
127   static void OnSessionRequested(GDBusProxy *proxy,
128                                  GAsyncResult* result,
129                                  gpointer user_data);
130   static void OnSessionRequestResponseSignal(GDBusConnection* connection,
131                                              const gchar* sender_name,
132                                              const gchar* object_path,
133                                              const gchar* interface_name,
134                                              const gchar* signal_name,
135                                              GVariant* parameters,
136                                              gpointer user_data);
137 
138   void SourcesRequest();
139   static void OnSourcesRequested(GDBusProxy *proxy,
140                                  GAsyncResult* result,
141                                  gpointer user_data);
142   static void OnSourcesRequestResponseSignal(GDBusConnection* connection,
143                                              const gchar* sender_name,
144                                              const gchar* object_path,
145                                              const gchar* interface_name,
146                                              const gchar* signal_name,
147                                              GVariant* parameters,
148                                              gpointer user_data);
149 
150   void StartRequest();
151   static void OnStartRequested(GDBusProxy *proxy,
152                                GAsyncResult* result,
153                                gpointer user_data);
154   static void OnStartRequestResponseSignal(GDBusConnection* connection,
155                                            const gchar* sender_name,
156                                            const gchar* object_path,
157                                            const gchar* interface_name,
158                                            const gchar* signal_name,
159                                            GVariant* parameters,
160                                            gpointer user_data);
161 
162   void OpenPipeWireRemote();
163   static void OnOpenPipeWireRemoteRequested(GDBusProxy *proxy,
164                                             GAsyncResult* result,
165                                             gpointer user_data);
166 
167   RTC_DISALLOW_COPY_AND_ASSIGN(BaseCapturerPipeWire);
168 };
169 
170 }  // namespace webrtc
171 
172 #endif  // MODULES_DESKTOP_CAPTURE_LINUX_BASE_CAPTURER_PIPEWIRE_H_
173