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/constructor_magic.h"
22 
23 namespace webrtc {
24 
25 class PipeWireType {
26  public:
27   spa_type_media_type media_type;
28   spa_type_media_subtype media_subtype;
29   spa_type_format_video format_video;
30   spa_type_video_format video_format;
31 };
32 
33 class BaseCapturerPipeWire : public DesktopCapturer {
34  public:
35   enum CaptureSourceType { Screen = 1, Window };
36 
37   explicit BaseCapturerPipeWire(CaptureSourceType source_type);
38   ~BaseCapturerPipeWire() override;
39 
40   // DesktopCapturer interface.
41   void Start(Callback* delegate) override;
42   void CaptureFrame() override;
43   bool GetSourceList(SourceList* sources) override;
44   bool SelectSource(SourceId id) override;
45 
46  private:
47   // PipeWire types -->
48   pw_core* pw_core_ = nullptr;
49   pw_type* pw_core_type_ = nullptr;
50   pw_stream* pw_stream_ = nullptr;
51   pw_remote* pw_remote_ = nullptr;
52   pw_loop* pw_loop_ = nullptr;
53   pw_thread_loop* pw_main_loop_ = nullptr;
54   PipeWireType* pw_type_ = nullptr;
55 
56   spa_hook spa_stream_listener_ = {};
57   spa_hook spa_remote_listener_ = {};
58 
59   pw_stream_events pw_stream_events_ = {};
60   pw_remote_events pw_remote_events_ = {};
61 
62   spa_video_info_raw* spa_video_format_ = nullptr;
63 
64   gint32 pw_fd_ = -1;
65 
66   CaptureSourceType capture_source_type_ =
67       BaseCapturerPipeWire::CaptureSourceType::Screen;
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   DesktopSize desktop_size_ = {};
83   DesktopCaptureOptions options_ = {};
84 
85   uint8_t* current_frame_ = nullptr;
86   Callback* callback_ = nullptr;
87 
88   bool portal_init_failed_ = false;
89 
90   void InitPortal();
91   void InitPipeWire();
92   void InitPipeWireTypes();
93 
94   void CreateReceivingStream();
95   void HandleBuffer(pw_buffer* buffer);
96 
97   void ConvertRGBxToBGRx(uint8_t* frame, uint32_t size);
98 
99   static void OnStateChanged(void* data,
100                              pw_remote_state old_state,
101                              pw_remote_state state,
102                              const char* error);
103   static void OnStreamStateChanged(void* data,
104                                    pw_stream_state old_state,
105                                    pw_stream_state state,
106                                    const char* error_message);
107 
108   static void OnStreamFormatChanged(void* data, const struct spa_pod* format);
109   static void OnStreamProcess(void* data);
110   static void OnNewBuffer(void* data, uint32_t id);
111 
112   guint SetupRequestResponseSignal(const gchar* object_path,
113                                    GDBusSignalCallback callback);
114 
115   static void OnProxyRequested(GObject* object,
116                                GAsyncResult* result,
117                                gpointer user_data);
118 
119   static gchar* PrepareSignalHandle(GDBusConnection* connection,
120                                     const gchar* token);
121 
122   void SessionRequest();
123   static void OnSessionRequested(GDBusProxy *proxy,
124                                  GAsyncResult* result,
125                                  gpointer user_data);
126   static void OnSessionRequestResponseSignal(GDBusConnection* connection,
127                                              const gchar* sender_name,
128                                              const gchar* object_path,
129                                              const gchar* interface_name,
130                                              const gchar* signal_name,
131                                              GVariant* parameters,
132                                              gpointer user_data);
133 
134   void SourcesRequest();
135   static void OnSourcesRequested(GDBusProxy *proxy,
136                                  GAsyncResult* result,
137                                  gpointer user_data);
138   static void OnSourcesRequestResponseSignal(GDBusConnection* connection,
139                                              const gchar* sender_name,
140                                              const gchar* object_path,
141                                              const gchar* interface_name,
142                                              const gchar* signal_name,
143                                              GVariant* parameters,
144                                              gpointer user_data);
145 
146   void StartRequest();
147   static void OnStartRequested(GDBusProxy *proxy,
148                                GAsyncResult* result,
149                                gpointer user_data);
150   static void OnStartRequestResponseSignal(GDBusConnection* connection,
151                                            const gchar* sender_name,
152                                            const gchar* object_path,
153                                            const gchar* interface_name,
154                                            const gchar* signal_name,
155                                            GVariant* parameters,
156                                            gpointer user_data);
157 
158   void OpenPipeWireRemote();
159   static void OnOpenPipeWireRemoteRequested(GDBusProxy *proxy,
160                                             GAsyncResult* result,
161                                             gpointer user_data);
162 
163   RTC_DISALLOW_COPY_AND_ASSIGN(BaseCapturerPipeWire);
164 };
165 
166 }  // namespace webrtc
167 
168 #endif  // MODULES_DESKTOP_CAPTURE_LINUX_BASE_CAPTURER_PIPEWIRE_H_
169