1 # HG changeset patch |
1 diff -up firefox-83.0/browser/actors/WebRTCParent.jsm.pw6 firefox-83.0/browser/actors/WebRTCParent.jsm |
2 # Parent 5bd7b491505076dc38ba1efc7c406b9c53ba8389 |
2 --- firefox-83.0/browser/actors/WebRTCParent.jsm.pw6 2020-11-12 19:04:30.000000000 +0100 |
3 |
3 +++ firefox-83.0/browser/actors/WebRTCParent.jsm 2020-11-25 10:28:32.492865982 +0100 |
4 diff --git a/config/system-headers.mozbuild b/config/system-headers.mozbuild |
4 @@ -45,6 +45,9 @@ XPCOMUtils.defineLazyServiceGetter( |
5 --- a/config/system-headers.mozbuild |
5 "nsIOSPermissionRequest" |
6 +++ b/config/system-headers.mozbuild |
6 ); |
7 @@ -309,16 +309,17 @@ system_headers = [ |
|
8 'gdk/gdkkeysyms.h', |
|
9 'gdk/gdkprivate.h', |
|
10 'gdk/gdkwayland.h', |
|
11 'gdk/gdkx.h', |
|
12 'gdk-pixbuf/gdk-pixbuf.h', |
|
13 'Gestalt.h', |
|
14 'getopt.h', |
|
15 'gio/gio.h', |
|
16 + 'gio/gunixfdlist.h', |
|
17 'glibconfig.h', |
|
18 'glib.h', |
|
19 'glib-object.h', |
|
20 'glob.h', |
|
21 'gmodule.h', |
|
22 'gnome.h', |
|
23 'gnu/libc-version.h', |
|
24 'gps.h', |
|
25 @@ -602,16 +603,17 @@ system_headers = [ |
|
26 'pango/pangoxft.h', |
|
27 'pascal.h', |
|
28 'Patches.h', |
|
29 'Path.h', |
|
30 'pcfs/pc_dir.h', |
|
31 'Pgenerr.h', |
|
32 'PGenErr.h', |
|
33 'Ph.h', |
|
34 + 'pipewire/pipewire.h', |
|
35 'pixman.h', |
|
36 'pk11func.h', |
|
37 'pk11pqg.h', |
|
38 'pk11priv.h', |
|
39 'pk11pub.h', |
|
40 'pk11sdr.h', |
|
41 'pkcs11f.h', |
|
42 'pkcs11.h', |
|
43 diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/BUILD.gn b/third_party/libwebrtc/webrtc/modules/desktop_capture/BUILD.gn |
|
44 --- a/third_party/libwebrtc/webrtc/modules/desktop_capture/BUILD.gn |
|
45 +++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/BUILD.gn |
|
46 @@ -153,17 +153,17 @@ if (rtc_include_tests) { |
|
47 "../../test:test_support", |
|
48 ] |
|
49 } |
|
50 } |
|
51 |
7 |
52 if (is_linux) { |
8 +const PIPEWIRE_PORTAL_NAME = "####_PIPEWIRE_PORTAL_####"; |
53 if (rtc_use_pipewire) { |
9 +const PIPEWIRE_ID = 0xaffffff; |
54 pkg_config("pipewire") { |
10 + |
55 - packages = [ "libpipewire-0.2" ] |
11 class WebRTCParent extends JSWindowActorParent { |
56 + packages = [ "libpipewire-0.3" ] |
12 didDestroy() { |
|
13 webrtcUI.forgetStreamsFromBrowserContext(this.browsingContext); |
|
14 @@ -753,6 +756,8 @@ function prompt(aActor, aBrowser, aReque |
|
15 ); |
|
16 menupopup.appendChild(doc.createXULElement("menuseparator")); |
57 |
17 |
58 defines = [ "WEBRTC_USE_PIPEWIRE" ] |
18 + let isPipeWire = false; |
59 } |
19 + |
|
20 // Build the list of 'devices'. |
|
21 let monitorIndex = 1; |
|
22 for (let i = 0; i < devices.length; ++i) { |
|
23 @@ -774,6 +779,29 @@ function prompt(aActor, aBrowser, aReque |
|
24 } |
|
25 } else { |
|
26 name = device.name; |
|
27 + // When we share content by PipeWire add only one item to the device |
|
28 + // list. When it's selected PipeWire portal dialog is opened and |
|
29 + // user confirms actual window/screen sharing there. |
|
30 + // Don't mark it as scary as there's an extra confirmation step by |
|
31 + // PipeWire portal dialog. |
|
32 + if (name == PIPEWIRE_PORTAL_NAME && device.id == PIPEWIRE_ID) { |
|
33 + isPipeWire = true; |
|
34 + let name; |
|
35 + try { |
|
36 + name = stringBundle.getString("getUserMedia.sharePipeWirePortal.label"); |
|
37 + } catch (err) { |
|
38 + name = "Use operating system settings" |
|
39 + } |
|
40 + let item = addDeviceToList( |
|
41 + menupopup, |
|
42 + name, |
|
43 + i, |
|
44 + type |
|
45 + ); |
|
46 + item.deviceId = device.id; |
|
47 + item.mediaSource = type; |
|
48 + break; |
|
49 + } |
|
50 if (type == "application") { |
|
51 // The application names returned by the platform are of the form: |
|
52 // <window count>\x1e<application name> |
|
53 @@ -888,39 +916,41 @@ function prompt(aActor, aBrowser, aReque |
|
54 perms.EXPIRE_SESSION |
|
55 ); |
60 |
56 |
61 pkg_config("gio") { |
57 - video.deviceId = deviceId; |
62 packages = [ |
58 - let constraints = { |
63 "gio-2.0", |
59 - video: { mediaSource: type, deviceId: { exact: deviceId } }, |
64 "gio-unix-2.0", |
60 - }; |
65 diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_generic_gn/moz.build b/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_generic_gn/moz.build |
61 - chromeWin.navigator.mediaDevices.getUserMedia(constraints).then( |
66 --- a/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_generic_gn/moz.build |
62 - stream => { |
67 +++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_generic_gn/moz.build |
63 - if (video.deviceId != deviceId) { |
68 @@ -112,16 +112,39 @@ if CONFIG["OS_TARGET"] == "DragonFly": |
64 - // The user has selected a different device or closed the panel |
69 "/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/x_atom_cache.cc", |
65 - // before getUserMedia finished. |
70 "/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/x_error_trap.cc", |
66 - stream.getTracks().forEach(t => t.stop()); |
71 "/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/x_server_pixel_buffer.cc", |
67 - return; |
72 "/third_party/libwebrtc/webrtc/modules/desktop_capture/mouse_cursor_monitor_linux.cc", |
68 - } |
73 "/third_party/libwebrtc/webrtc/modules/desktop_capture/screen_capturer_linux.cc", |
69 - video.srcObject = stream; |
74 "/third_party/libwebrtc/webrtc/modules/desktop_capture/window_capturer_linux.cc" |
70 - video.stream = stream; |
75 ] |
71 - doc.getElementById("webRTC-preview").hidden = false; |
76 |
72 - video.onloadedmetadata = function(e) { |
77 +# PipeWire specific files |
73 - video.play(); |
78 +if CONFIG["OS_TARGET"] == "Linux": |
74 - }; |
79 + |
75 - }, |
80 + DEFINES["WEBRTC_USE_PIPEWIRE"] = "1" |
76 - err => { |
81 + |
77 - if ( |
82 + OS_LIBS += [ |
78 - err.name == "OverconstrainedError" && |
83 + "rt", |
79 - err.constraint == "deviceId" |
84 + "pipewire-0.3", |
80 - ) { |
85 + "glib-2.0", |
81 - // Window has disappeared since enumeration, which can happen. |
86 + "gio-2.0", |
82 - // No preview for you. |
87 + "gobject-2.0" |
83 - return; |
88 + ] |
84 + if (!isPipeWire) { |
89 + |
85 + video.deviceId = deviceId; |
90 + CXXFLAGS += CONFIG['TK_CFLAGS'] |
86 + let constraints = { |
91 + CXXFLAGS += [ "-I/usr/include/pipewire-0.3" ] |
87 + video: { mediaSource: type, deviceId: { exact: deviceId } }, |
92 + CXXFLAGS += [ "-I/usr/include/spa-0.2" ] |
88 + }; |
93 + |
89 + chromeWin.navigator.mediaDevices.getUserMedia(constraints).then( |
94 + UNIFIED_SOURCES += [ |
90 + stream => { |
95 + "/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc", |
91 + if (video.deviceId != deviceId) { |
96 + "/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.cc", |
92 + // The user has selected a different device or closed the panel |
97 + "/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.cc" |
93 + // before getUserMedia finished. |
98 + ] |
94 + stream.getTracks().forEach(t => t.stop()); |
99 + |
95 + return; |
100 if CONFIG["OS_TARGET"] == "FreeBSD": |
96 + } |
101 |
97 + video.srcObject = stream; |
102 DEFINES["USE_X11"] = "1" |
98 + video.stream = stream; |
103 DEFINES["WEBRTC_BSD"] = True |
99 + doc.getElementById("webRTC-preview").hidden = false; |
104 DEFINES["WEBRTC_POSIX"] = True |
100 + video.onloadedmetadata = function(e) { |
105 DEFINES["_FILE_OFFSET_BITS"] = "64" |
101 + video.play(); |
106 |
102 + }; |
107 OS_LIBS += [ |
103 + }, |
108 diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_options.h b/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_options.h |
104 + err => { |
109 --- a/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_options.h |
105 + if ( |
110 +++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/desktop_capture_options.h |
106 + err.name == "OverconstrainedError" && |
111 @@ -136,15 +136,15 @@ class DesktopCaptureOptions { |
107 + err.constraint == "deviceId" |
112 #if defined(USE_X11) |
108 + ) { |
113 bool use_update_notifications_ = false; |
109 + // Window has disappeared since enumeration, which can happen. |
114 #else |
110 + // No preview for you. |
115 bool use_update_notifications_ = true; |
111 + return; |
116 #endif |
112 + } |
117 bool disable_effects_ = true; |
113 + Cu.reportError( |
118 bool detect_updated_region_ = false; |
114 + `error in preview: ${err.message} ${err.constraint}` |
119 #if defined(WEBRTC_USE_PIPEWIRE) |
115 + ); |
120 - bool allow_pipewire_ = false; |
116 } |
121 + bool allow_pipewire_ = true; |
117 - Cu.reportError( |
122 #endif |
118 - `error in preview: ${err.message} ${err.constraint}` |
123 }; |
119 - ); |
124 |
120 - } |
125 } // namespace webrtc |
121 - ); |
126 |
122 + ); |
127 #endif // MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURE_OPTIONS_H_ |
123 + } |
128 diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc |
124 }; |
129 --- a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc |
125 menupopup.addEventListener("command", menupopup._commandEventListener); |
130 +++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc |
126 } |
131 @@ -10,18 +10,21 @@ |
127 diff -up firefox-83.0/browser/locales/en-US/chrome/browser/browser.properties.pw6 firefox-83.0/browser/locales/en-US/chrome/browser/browser.properties |
132 |
128 --- firefox-83.0/browser/locales/en-US/chrome/browser/browser.properties.pw6 2020-11-12 19:04:30.000000000 +0100 |
133 #include "modules/desktop_capture/linux/base_capturer_pipewire.h" |
129 +++ firefox-83.0/browser/locales/en-US/chrome/browser/browser.properties 2020-11-25 09:24:26.378857626 +0100 |
134 |
130 @@ -764,6 +764,7 @@ getUserMedia.selectWindowOrScreen.label= |
135 #include <gio/gunixfdlist.h> |
131 getUserMedia.selectWindowOrScreen.accesskey=W |
136 #include <glib-object.h> |
132 getUserMedia.pickWindowOrScreen.label = Select Window or Screen |
137 |
133 getUserMedia.shareEntireScreen.label = Entire screen |
138 #include <spa/param/format-utils.h> |
134 +getUserMedia.sharePipeWirePortal.label = Use operating system settings |
139 #include <spa/param/props.h> |
135 # LOCALIZATION NOTE (getUserMedia.shareMonitor.label): |
140 -#include <spa/param/video/raw-utils.h> |
136 # %S is screen number (digits 1, 2, etc) |
141 -#include <spa/support/type-map.h> |
137 # Example: Screen 1, Screen 2,.. |
142 + |
138 diff -up firefox-83.0/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc.pw6 firefox-83.0/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc |
143 +#include <linux/dma-buf.h> |
139 --- firefox-83.0/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc.pw6 2020-11-25 09:24:26.358857788 +0100 |
144 +#include <sys/mman.h> |
140 +++ firefox-83.0/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc 2020-11-25 09:24:26.378857626 +0100 |
145 +#include <sys/ioctl.h> |
141 @@ -879,17 +879,17 @@ void BaseCapturerPipeWire::CaptureFrame( |
146 +#include <sys/syscall.h> |
|
147 |
|
148 #include <memory> |
|
149 #include <utility> |
|
150 |
|
151 #include "modules/desktop_capture/desktop_capture_options.h" |
|
152 #include "modules/desktop_capture/desktop_capturer.h" |
|
153 #include "rtc_base/checks.h" |
|
154 #include "rtc_base/logging.h" |
|
155 @@ -31,181 +34,158 @@ namespace webrtc { |
|
156 const char kDesktopBusName[] = "org.freedesktop.portal.Desktop"; |
|
157 const char kDesktopObjectPath[] = "/org/freedesktop/portal/desktop"; |
|
158 const char kDesktopRequestObjectPath[] = |
|
159 "/org/freedesktop/portal/desktop/request"; |
|
160 const char kSessionInterfaceName[] = "org.freedesktop.portal.Session"; |
|
161 const char kRequestInterfaceName[] = "org.freedesktop.portal.Request"; |
|
162 const char kScreenCastInterfaceName[] = "org.freedesktop.portal.ScreenCast"; |
|
163 |
|
164 + |
|
165 // static |
|
166 -void BaseCapturerPipeWire::OnStateChanged(void* data, |
|
167 - pw_remote_state old_state, |
|
168 - pw_remote_state state, |
|
169 - const char* error_message) { |
|
170 - BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data); |
|
171 - RTC_DCHECK(that); |
|
172 +void BaseCapturerPipeWire::SyncDmaBuf(int fd, uint64_t start_or_end) { |
|
173 + struct dma_buf_sync sync = { 0 }; |
|
174 + |
|
175 + sync.flags = start_or_end | DMA_BUF_SYNC_READ; |
|
176 |
|
177 - switch (state) { |
|
178 - case PW_REMOTE_STATE_ERROR: |
|
179 - RTC_LOG(LS_ERROR) << "PipeWire remote state error: " << error_message; |
|
180 + while(true) { |
|
181 + int ret; |
|
182 + ret = ioctl (fd, DMA_BUF_IOCTL_SYNC, &sync); |
|
183 + if (ret == -1 && errno == EINTR) { |
|
184 + continue; |
|
185 + } else if (ret == -1) { |
|
186 + RTC_LOG(LS_ERROR) << "Failed to synchronize DMA buffer: " << g_strerror(errno); |
|
187 break; |
|
188 - case PW_REMOTE_STATE_CONNECTED: |
|
189 - RTC_LOG(LS_INFO) << "PipeWire remote state: connected."; |
|
190 - that->CreateReceivingStream(); |
|
191 + } else { |
|
192 break; |
|
193 - case PW_REMOTE_STATE_CONNECTING: |
|
194 - RTC_LOG(LS_INFO) << "PipeWire remote state: connecting."; |
|
195 - break; |
|
196 - case PW_REMOTE_STATE_UNCONNECTED: |
|
197 - RTC_LOG(LS_INFO) << "PipeWire remote state: unconnected."; |
|
198 - break; |
|
199 + } |
|
200 } |
|
201 } |
|
202 |
|
203 // static |
|
204 +void BaseCapturerPipeWire::OnCoreError(void *data, |
|
205 + uint32_t id, |
|
206 + int seq, |
|
207 + int res, |
|
208 + const char *message) { |
|
209 + RTC_LOG(LS_ERROR) << "core error: " << message; |
|
210 +} |
|
211 + |
|
212 +// static |
|
213 void BaseCapturerPipeWire::OnStreamStateChanged(void* data, |
|
214 pw_stream_state old_state, |
|
215 pw_stream_state state, |
|
216 const char* error_message) { |
|
217 BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data); |
|
218 RTC_DCHECK(that); |
|
219 |
|
220 switch (state) { |
|
221 case PW_STREAM_STATE_ERROR: |
|
222 RTC_LOG(LS_ERROR) << "PipeWire stream state error: " << error_message; |
|
223 break; |
|
224 - case PW_STREAM_STATE_CONFIGURE: |
|
225 - pw_stream_set_active(that->pw_stream_, true); |
|
226 - break; |
|
227 + case PW_STREAM_STATE_PAUSED: |
|
228 + case PW_STREAM_STATE_STREAMING: |
|
229 case PW_STREAM_STATE_UNCONNECTED: |
|
230 case PW_STREAM_STATE_CONNECTING: |
|
231 - case PW_STREAM_STATE_READY: |
|
232 - case PW_STREAM_STATE_PAUSED: |
|
233 - case PW_STREAM_STATE_STREAMING: |
|
234 break; |
|
235 } |
|
236 } |
|
237 |
|
238 // static |
|
239 -void BaseCapturerPipeWire::OnStreamFormatChanged(void* data, |
|
240 - const struct spa_pod* format) { |
|
241 +void BaseCapturerPipeWire::OnStreamParamChanged(void *data, uint32_t id, |
|
242 + const struct spa_pod *format) { |
|
243 BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data); |
|
244 RTC_DCHECK(that); |
|
245 |
|
246 - RTC_LOG(LS_INFO) << "PipeWire stream format changed."; |
|
247 + RTC_LOG(LS_INFO) << "PipeWire stream param changed."; |
|
248 |
|
249 - if (!format) { |
|
250 - pw_stream_finish_format(that->pw_stream_, /*res=*/0, /*params=*/nullptr, |
|
251 - /*n_params=*/0); |
|
252 + if (!format || id != SPA_PARAM_Format) { |
|
253 return; |
|
254 } |
|
255 |
|
256 - that->spa_video_format_ = new spa_video_info_raw(); |
|
257 - spa_format_video_raw_parse(format, that->spa_video_format_, |
|
258 - &that->pw_type_->format_video); |
|
259 + spa_format_video_raw_parse(format, &that->spa_video_format_); |
|
260 |
|
261 - auto width = that->spa_video_format_->size.width; |
|
262 - auto height = that->spa_video_format_->size.height; |
|
263 + auto width = that->spa_video_format_.size.width; |
|
264 + auto height = that->spa_video_format_.size.height; |
|
265 auto stride = SPA_ROUND_UP_N(width * kBytesPerPixel, 4); |
|
266 auto size = height * stride; |
|
267 |
|
268 + that->desktop_size_ = DesktopSize(width, height); |
|
269 + |
|
270 uint8_t buffer[1024] = {}; |
|
271 auto builder = spa_pod_builder{buffer, sizeof(buffer)}; |
|
272 |
|
273 // Setup buffers and meta header for new format. |
|
274 - const struct spa_pod* params[2]; |
|
275 - params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_object( |
|
276 - &builder, |
|
277 - // id to enumerate buffer requirements |
|
278 - that->pw_core_type_->param.idBuffers, |
|
279 - that->pw_core_type_->param_buffers.Buffers, |
|
280 - // Size: specified as integer (i) and set to specified size |
|
281 - ":", that->pw_core_type_->param_buffers.size, "i", size, |
|
282 - // Stride: specified as integer (i) and set to specified stride |
|
283 - ":", that->pw_core_type_->param_buffers.stride, "i", stride, |
|
284 - // Buffers: specifies how many buffers we want to deal with, set as |
|
285 - // integer (i) where preferred number is 8, then allowed number is defined |
|
286 - // as range (r) from min and max values and it is undecided (u) to allow |
|
287 - // negotiation |
|
288 - ":", that->pw_core_type_->param_buffers.buffers, "iru", 8, |
|
289 - SPA_POD_PROP_MIN_MAX(1, 32), |
|
290 - // Align: memory alignment of the buffer, set as integer (i) to specified |
|
291 - // value |
|
292 - ":", that->pw_core_type_->param_buffers.align, "i", 16)); |
|
293 - params[1] = reinterpret_cast<spa_pod*>(spa_pod_builder_object( |
|
294 - &builder, |
|
295 - // id to enumerate supported metadata |
|
296 - that->pw_core_type_->param.idMeta, that->pw_core_type_->param_meta.Meta, |
|
297 - // Type: specified as id or enum (I) |
|
298 - ":", that->pw_core_type_->param_meta.type, "I", |
|
299 - that->pw_core_type_->meta.Header, |
|
300 - // Size: size of the metadata, specified as integer (i) |
|
301 - ":", that->pw_core_type_->param_meta.size, "i", |
|
302 - sizeof(struct spa_meta_header))); |
|
303 - |
|
304 - pw_stream_finish_format(that->pw_stream_, /*res=*/0, params, /*n_params=*/2); |
|
305 + const struct spa_pod* params[3]; |
|
306 + params[0] = reinterpret_cast<spa_pod *>(spa_pod_builder_add_object(&builder, |
|
307 + SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers, |
|
308 + SPA_PARAM_BUFFERS_size, SPA_POD_Int(size), |
|
309 + SPA_PARAM_BUFFERS_stride, SPA_POD_Int(stride), |
|
310 + SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(8, 1, 32))); |
|
311 + params[1] = reinterpret_cast<spa_pod *>(spa_pod_builder_add_object(&builder, |
|
312 + SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, |
|
313 + SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Header), |
|
314 + SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_header)))); |
|
315 + params[2] = reinterpret_cast<spa_pod *>(spa_pod_builder_add_object(&builder, |
|
316 + SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, |
|
317 + SPA_PARAM_META_type, SPA_POD_Id (SPA_META_VideoCrop), |
|
318 + SPA_PARAM_META_size, SPA_POD_Int (sizeof(struct spa_meta_region)))); |
|
319 + pw_stream_update_params(that->pw_stream_, params, 3); |
|
320 } |
|
321 |
|
322 // static |
|
323 void BaseCapturerPipeWire::OnStreamProcess(void* data) { |
|
324 BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data); |
|
325 RTC_DCHECK(that); |
|
326 |
|
327 - pw_buffer* buf = nullptr; |
|
328 + struct pw_buffer *next_buffer; |
|
329 + struct pw_buffer *buffer = nullptr; |
|
330 |
|
331 - if (!(buf = pw_stream_dequeue_buffer(that->pw_stream_))) { |
|
332 + next_buffer = pw_stream_dequeue_buffer(that->pw_stream_); |
|
333 + while (next_buffer) { |
|
334 + buffer = next_buffer; |
|
335 + next_buffer = pw_stream_dequeue_buffer(that->pw_stream_); |
|
336 + |
|
337 + if (next_buffer) |
|
338 + pw_stream_queue_buffer (that->pw_stream_, buffer); |
|
339 + } |
|
340 + |
|
341 + if (!buffer) { |
|
342 return; |
|
343 } |
|
344 |
|
345 - that->HandleBuffer(buf); |
|
346 + that->HandleBuffer(buffer); |
|
347 |
|
348 - pw_stream_queue_buffer(that->pw_stream_, buf); |
|
349 + pw_stream_queue_buffer(that->pw_stream_, buffer); |
|
350 } |
|
351 |
|
352 BaseCapturerPipeWire::BaseCapturerPipeWire(CaptureSourceType source_type) |
|
353 : capture_source_type_(source_type) {} |
|
354 |
|
355 BaseCapturerPipeWire::~BaseCapturerPipeWire() { |
|
356 if (pw_main_loop_) { |
|
357 pw_thread_loop_stop(pw_main_loop_); |
|
358 } |
|
359 |
|
360 - if (pw_type_) { |
|
361 - delete pw_type_; |
|
362 - } |
|
363 - |
|
364 - if (spa_video_format_) { |
|
365 - delete spa_video_format_; |
|
366 - } |
|
367 - |
|
368 if (pw_stream_) { |
|
369 pw_stream_destroy(pw_stream_); |
|
370 } |
|
371 |
|
372 - if (pw_remote_) { |
|
373 - pw_remote_destroy(pw_remote_); |
|
374 + if (pw_core_) { |
|
375 + pw_core_disconnect(pw_core_); |
|
376 } |
|
377 |
|
378 - if (pw_core_) { |
|
379 - pw_core_destroy(pw_core_); |
|
380 + if (pw_context_) { |
|
381 + pw_context_destroy(pw_context_); |
|
382 } |
|
383 |
|
384 if (pw_main_loop_) { |
|
385 pw_thread_loop_destroy(pw_main_loop_); |
|
386 } |
|
387 |
|
388 - if (pw_loop_) { |
|
389 - pw_loop_destroy(pw_loop_); |
|
390 - } |
|
391 - |
|
392 - if (current_frame_) { |
|
393 - free(current_frame_); |
|
394 - } |
|
395 - |
|
396 if (start_request_signal_id_) { |
|
397 g_dbus_connection_signal_unsubscribe(connection_, start_request_signal_id_); |
|
398 } |
|
399 if (sources_request_signal_id_) { |
|
400 g_dbus_connection_signal_unsubscribe(connection_, |
|
401 sources_request_signal_id_); |
|
402 } |
|
403 if (session_request_signal_id_) { |
|
404 @@ -245,142 +225,220 @@ void BaseCapturerPipeWire::InitPortal() |
|
405 kDesktopBusName, kDesktopObjectPath, kScreenCastInterfaceName, |
|
406 /*cancellable=*/nullptr, |
|
407 reinterpret_cast<GAsyncReadyCallback>(OnProxyRequested), this); |
|
408 } |
|
409 |
|
410 void BaseCapturerPipeWire::InitPipeWire() { |
|
411 pw_init(/*argc=*/nullptr, /*argc=*/nullptr); |
|
412 |
|
413 - pw_loop_ = pw_loop_new(/*properties=*/nullptr); |
|
414 - pw_main_loop_ = pw_thread_loop_new(pw_loop_, "pipewire-main-loop"); |
|
415 + pw_main_loop_ = pw_thread_loop_new("pipewire-main-loop", nullptr); |
|
416 + pw_context_ = pw_context_new(pw_thread_loop_get_loop(pw_main_loop_), nullptr, 0); |
|
417 + if (!pw_context_) { |
|
418 + RTC_LOG(LS_ERROR) << "Failed to create PipeWire context"; |
|
419 + return; |
|
420 + } |
|
421 |
|
422 - pw_core_ = pw_core_new(pw_loop_, /*properties=*/nullptr); |
|
423 - pw_core_type_ = pw_core_get_type(pw_core_); |
|
424 - pw_remote_ = pw_remote_new(pw_core_, nullptr, /*user_data_size=*/0); |
|
425 - |
|
426 - InitPipeWireTypes(); |
|
427 + pw_core_ = pw_context_connect(pw_context_, nullptr, 0); |
|
428 + if (!pw_core_) { |
|
429 + RTC_LOG(LS_ERROR) << "Failed to connect PipeWire context"; |
|
430 + return; |
|
431 + } |
|
432 |
|
433 // Initialize event handlers, remote end and stream-related. |
|
434 - pw_remote_events_.version = PW_VERSION_REMOTE_EVENTS; |
|
435 - pw_remote_events_.state_changed = &OnStateChanged; |
|
436 + pw_core_events_.version = PW_VERSION_CORE_EVENTS; |
|
437 + pw_core_events_.error = &OnCoreError; |
|
438 |
|
439 pw_stream_events_.version = PW_VERSION_STREAM_EVENTS; |
|
440 pw_stream_events_.state_changed = &OnStreamStateChanged; |
|
441 - pw_stream_events_.format_changed = &OnStreamFormatChanged; |
|
442 + pw_stream_events_.param_changed = &OnStreamParamChanged; |
|
443 pw_stream_events_.process = &OnStreamProcess; |
|
444 |
|
445 - pw_remote_add_listener(pw_remote_, &spa_remote_listener_, &pw_remote_events_, |
|
446 - this); |
|
447 - pw_remote_connect_fd(pw_remote_, pw_fd_); |
|
448 + pw_core_add_listener(pw_core_, &spa_core_listener_, &pw_core_events_, this); |
|
449 + |
|
450 + pw_stream_ = CreateReceivingStream(); |
|
451 + if (!pw_stream_) { |
|
452 + RTC_LOG(LS_ERROR) << "Failed to create PipeWire stream"; |
|
453 + return; |
|
454 + } |
|
455 |
|
456 if (pw_thread_loop_start(pw_main_loop_) < 0) { |
|
457 RTC_LOG(LS_ERROR) << "Failed to start main PipeWire loop"; |
|
458 portal_init_failed_ = true; |
|
459 } |
|
460 } |
|
461 |
|
462 -void BaseCapturerPipeWire::InitPipeWireTypes() { |
|
463 - spa_type_map* map = pw_core_type_->map; |
|
464 - pw_type_ = new PipeWireType(); |
|
465 - |
|
466 - spa_type_media_type_map(map, &pw_type_->media_type); |
|
467 - spa_type_media_subtype_map(map, &pw_type_->media_subtype); |
|
468 - spa_type_format_video_map(map, &pw_type_->format_video); |
|
469 - spa_type_video_format_map(map, &pw_type_->video_format); |
|
470 -} |
|
471 +pw_stream* BaseCapturerPipeWire::CreateReceivingStream() { |
|
472 + spa_rectangle pwMinScreenBounds = spa_rectangle{1, 1}; |
|
473 + spa_rectangle pwMaxScreenBounds = spa_rectangle{INT32_MAX, INT32_MAX}; |
|
474 |
|
475 -void BaseCapturerPipeWire::CreateReceivingStream() { |
|
476 - spa_rectangle pwMinScreenBounds = spa_rectangle{1, 1}; |
|
477 - spa_rectangle pwScreenBounds = |
|
478 - spa_rectangle{static_cast<uint32_t>(desktop_size_.width()), |
|
479 - static_cast<uint32_t>(desktop_size_.height())}; |
|
480 + auto stream = pw_stream_new(pw_core_, "webrtc-pipewire-stream", nullptr); |
|
481 |
|
482 - spa_fraction pwFrameRateMin = spa_fraction{0, 1}; |
|
483 - spa_fraction pwFrameRateMax = spa_fraction{60, 1}; |
|
484 - |
|
485 - pw_properties* reuseProps = pw_properties_new("pipewire.client.reuse", "1", |
|
486 - /*end of varargs*/ nullptr); |
|
487 - pw_stream_ = pw_stream_new(pw_remote_, "webrtc-consume-stream", reuseProps); |
|
488 + if (!stream) { |
|
489 + RTC_LOG(LS_ERROR) << "Could not create receiving stream."; |
|
490 + return nullptr; |
|
491 + } |
|
492 |
|
493 uint8_t buffer[1024] = {}; |
|
494 - const spa_pod* params[1]; |
|
495 - spa_pod_builder builder = spa_pod_builder{buffer, sizeof(buffer)}; |
|
496 - params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_object( |
|
497 - &builder, |
|
498 - // id to enumerate formats |
|
499 - pw_core_type_->param.idEnumFormat, pw_core_type_->spa_format, "I", |
|
500 - pw_type_->media_type.video, "I", pw_type_->media_subtype.raw, |
|
501 - // Video format: specified as id or enum (I), preferred format is BGRx, |
|
502 - // then allowed formats are enumerated (e) and the format is undecided (u) |
|
503 - // to allow negotiation |
|
504 - ":", pw_type_->format_video.format, "Ieu", pw_type_->video_format.BGRx, |
|
505 - SPA_POD_PROP_ENUM(2, pw_type_->video_format.RGBx, |
|
506 - pw_type_->video_format.BGRx), |
|
507 - // Video size: specified as rectangle (R), preferred size is specified as |
|
508 - // first parameter, then allowed size is defined as range (r) from min and |
|
509 - // max values and the format is undecided (u) to allow negotiation |
|
510 - ":", pw_type_->format_video.size, "Rru", &pwScreenBounds, 2, |
|
511 - &pwMinScreenBounds, &pwScreenBounds, |
|
512 - // Frame rate: specified as fraction (F) and set to minimum frame rate |
|
513 - // value |
|
514 - ":", pw_type_->format_video.framerate, "F", &pwFrameRateMin, |
|
515 - // Max frame rate: specified as fraction (F), preferred frame rate is set |
|
516 - // to maximum value, then allowed frame rate is defined as range (r) from |
|
517 - // min and max values and it is undecided (u) to allow negotiation |
|
518 - ":", pw_type_->format_video.max_framerate, "Fru", &pwFrameRateMax, 2, |
|
519 - &pwFrameRateMin, &pwFrameRateMax)); |
|
520 + const spa_pod* params[2]; |
|
521 + spa_pod_builder builder = SPA_POD_BUILDER_INIT(buffer, sizeof (buffer)); |
|
522 |
|
523 - pw_stream_add_listener(pw_stream_, &spa_stream_listener_, &pw_stream_events_, |
|
524 - this); |
|
525 + params[0] = reinterpret_cast<spa_pod *>(spa_pod_builder_add_object(&builder, |
|
526 + SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, |
|
527 + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), |
|
528 + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), |
|
529 + SPA_FORMAT_VIDEO_format, SPA_POD_CHOICE_ENUM_Id(5, SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_RGBx, SPA_VIDEO_FORMAT_RGBA, |
|
530 + SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_BGRA), |
|
531 + SPA_FORMAT_VIDEO_size, SPA_POD_CHOICE_RANGE_Rectangle(&pwMinScreenBounds, |
|
532 + &pwMinScreenBounds, |
|
533 + &pwMaxScreenBounds), |
|
534 + 0)); |
|
535 + pw_stream_add_listener(stream, &spa_stream_listener_, &pw_stream_events_, this); |
|
536 + |
|
537 pw_stream_flags flags = static_cast<pw_stream_flags>( |
|
538 - PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE | |
|
539 - PW_STREAM_FLAG_MAP_BUFFERS); |
|
540 - if (pw_stream_connect(pw_stream_, PW_DIRECTION_INPUT, /*port_path=*/nullptr, |
|
541 - flags, params, |
|
542 - /*n_params=*/1) != 0) { |
|
543 + PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE); |
|
544 + |
|
545 + if (pw_stream_connect(stream, PW_DIRECTION_INPUT, pw_stream_node_id_, PW_STREAM_FLAG_AUTOCONNECT, params, 1) != 0) { |
|
546 RTC_LOG(LS_ERROR) << "Could not connect receiving stream."; |
|
547 portal_init_failed_ = true; |
|
548 - return; |
|
549 } |
|
550 + |
|
551 + return stream; |
|
552 } |
|
553 |
|
554 void BaseCapturerPipeWire::HandleBuffer(pw_buffer* buffer) { |
|
555 + struct spa_meta_region* video_crop; |
|
556 spa_buffer* spaBuffer = buffer->buffer; |
|
557 - void* src = nullptr; |
|
558 + uint8_t *map = nullptr; |
|
559 + uint8_t* src = nullptr; |
|
560 + uint8_t* dst = nullptr; |
|
561 + |
|
562 + if (spaBuffer->datas[0].chunk->size == 0) { |
|
563 + map = nullptr; |
|
564 + src = nullptr; |
|
565 + } else if (spaBuffer->datas[0].type == SPA_DATA_MemFd) { |
|
566 + map = static_cast<uint8_t*>(mmap( |
|
567 + nullptr, spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset, |
|
568 + PROT_READ, MAP_PRIVATE, spaBuffer->datas[0].fd, 0)); |
|
569 + |
|
570 + if (map == MAP_FAILED) { |
|
571 + RTC_LOG(LS_ERROR) << "Failed to mmap the memory: " << std::strerror(errno); |
|
572 + return; |
|
573 + } |
|
574 |
|
575 - if (!(src = spaBuffer->datas[0].data)) { |
|
576 + src = SPA_MEMBER(map, spaBuffer->datas[0].mapoffset, uint8_t); |
|
577 + } else if (spaBuffer->datas[0].type == SPA_DATA_DmaBuf) { |
|
578 + int fd; |
|
579 + fd = spaBuffer->datas[0].fd; |
|
580 + |
|
581 + map = static_cast<uint8_t*>(mmap( |
|
582 + nullptr, spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset, |
|
583 + PROT_READ, MAP_PRIVATE, fd, 0)); |
|
584 + |
|
585 + if (map == MAP_FAILED) { |
|
586 + RTC_LOG(LS_ERROR) << "Failed to mmap the memory: " << std::strerror(errno); |
|
587 + return; |
|
588 + } |
|
589 + |
|
590 + SyncDmaBuf(fd, DMA_BUF_SYNC_START); |
|
591 + |
|
592 + src = SPA_MEMBER(map, spaBuffer->datas[0].mapoffset, uint8_t); |
|
593 + } else if (spaBuffer->datas[0].type == SPA_DATA_MemPtr) { |
|
594 + map = nullptr; |
|
595 + src = static_cast<uint8_t*>(spaBuffer->datas[0].data); |
|
596 + } else { |
|
597 return; |
|
598 } |
|
599 |
|
600 - uint32_t maxSize = spaBuffer->datas[0].maxsize; |
|
601 - int32_t srcStride = spaBuffer->datas[0].chunk->stride; |
|
602 + if (!src) { |
|
603 + return; |
|
604 + } |
|
605 + |
|
606 + DesktopSize prev_crop_size = DesktopSize(0, 0); |
|
607 + if (video_crop_size_initialized_) { |
|
608 + prev_crop_size = video_crop_size_; |
|
609 + } |
|
610 + |
|
611 + if ((video_crop = static_cast<struct spa_meta_region*>( |
|
612 + spa_buffer_find_meta_data(spaBuffer, SPA_META_VideoCrop, sizeof(*video_crop))))) { |
|
613 + RTC_DCHECK(video_crop->region.size.width <= desktop_size_.width() && |
|
614 + video_crop->region.size.height <= desktop_size_.height()); |
|
615 + if ((video_crop->region.size.width != desktop_size_.width() || |
|
616 + video_crop->region.size.height != desktop_size_.height()) && video_crop->region.size.width && video_crop->region.size.height) { |
|
617 + video_crop_size_ = DesktopSize(video_crop->region.size.width, video_crop->region.size.height); |
|
618 + video_crop_size_initialized_ = true; |
|
619 + } else { |
|
620 + video_crop_size_initialized_ = false; |
|
621 + } |
|
622 + } else { |
|
623 + video_crop_size_initialized_ = false; |
|
624 + } |
|
625 + |
|
626 + size_t frame_size; |
|
627 + if (video_crop_size_initialized_) { |
|
628 + frame_size = |
|
629 + video_crop_size_.width() * video_crop_size_.height() * kBytesPerPixel; |
|
630 + } else { |
|
631 + frame_size = |
|
632 + desktop_size_.width() * desktop_size_.height() * kBytesPerPixel; |
|
633 + } |
|
634 + |
|
635 + if (!current_frame_ || |
|
636 + (video_crop_size_initialized_ && !video_crop_size_.equals(prev_crop_size))) { |
|
637 + current_frame_ = std::make_unique<uint8_t[]>(frame_size); |
|
638 + } |
|
639 + RTC_DCHECK(current_frame_ != nullptr); |
|
640 + |
|
641 + const int32_t dstStride = video_crop_size_initialized_ |
|
642 + ? video_crop_size_.width() * kBytesPerPixel |
|
643 + : desktop_size_.width() * kBytesPerPixel; |
|
644 + const int32_t srcStride = spaBuffer->datas[0].chunk->stride; |
|
645 + |
|
646 if (srcStride != (desktop_size_.width() * kBytesPerPixel)) { |
|
647 RTC_LOG(LS_ERROR) << "Got buffer with stride different from screen stride: " |
|
648 << srcStride |
|
649 << " != " << (desktop_size_.width() * kBytesPerPixel); |
|
650 portal_init_failed_ = true; |
|
651 return; |
|
652 } |
|
653 |
|
654 - if (!current_frame_) { |
|
655 - current_frame_ = static_cast<uint8_t*>(malloc(maxSize)); |
|
656 - } |
|
657 - RTC_DCHECK(current_frame_ != nullptr); |
|
658 + dst = current_frame_.get(); |
|
659 |
|
660 - // If both sides decided to go with the RGBx format we need to convert it to |
|
661 - // BGRx to match color format expected by WebRTC. |
|
662 - if (spa_video_format_->format == pw_type_->video_format.RGBx) { |
|
663 - uint8_t* tempFrame = static_cast<uint8_t*>(malloc(maxSize)); |
|
664 - std::memcpy(tempFrame, src, maxSize); |
|
665 - ConvertRGBxToBGRx(tempFrame, maxSize); |
|
666 - std::memcpy(current_frame_, tempFrame, maxSize); |
|
667 - free(tempFrame); |
|
668 - } else { |
|
669 - std::memcpy(current_frame_, src, maxSize); |
|
670 + // Adjust source content based on crop video position |
|
671 + if (video_crop_size_initialized_ && |
|
672 + (video_crop->region.position.y + video_crop_size_.height() <= desktop_size_.height())) { |
|
673 + for (int i = 0; i < video_crop->region.position.y; ++i) { |
|
674 + src += srcStride; |
|
675 + } |
|
676 + } |
|
677 + const int xOffset = |
|
678 + video_crop_size_initialized_ && (video_crop->region.position.x + video_crop_size_.width() <= |
|
679 + desktop_size_.width()) |
|
680 + ? video_crop->region.position.x * kBytesPerPixel |
|
681 + : 0; |
|
682 + const int height = video_crop_size_initialized_ ? video_crop_size_.height() : desktop_size_.height(); |
|
683 + for (int i = 0; i < height; ++i) { |
|
684 + // Adjust source content based on crop video position if needed |
|
685 + src += xOffset; |
|
686 + std::memcpy(dst, src, dstStride); |
|
687 + // If both sides decided to go with the RGBx format we need to convert it to |
|
688 + // BGRx to match color format expected by WebRTC. |
|
689 + if (spa_video_format_.format == SPA_VIDEO_FORMAT_RGBx || |
|
690 + spa_video_format_.format == SPA_VIDEO_FORMAT_RGBA) { |
|
691 + ConvertRGBxToBGRx(dst, dstStride); |
|
692 + } |
|
693 + src += srcStride - xOffset; |
|
694 + dst += dstStride; |
|
695 + } |
|
696 + |
|
697 + if (map) { |
|
698 + if (spaBuffer->datas[0].type == SPA_DATA_DmaBuf) { |
|
699 + SyncDmaBuf(spaBuffer->datas[0].fd, DMA_BUF_SYNC_END); |
|
700 + } |
|
701 + munmap(map, spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset); |
|
702 } |
|
703 } |
|
704 |
|
705 void BaseCapturerPipeWire::ConvertRGBxToBGRx(uint8_t* frame, uint32_t size) { |
|
706 // Change color format for KDE KWin which uses RGBx and not BGRx |
|
707 for (uint32_t i = 0; i < size; i += 4) { |
|
708 uint8_t tempR = frame[i]; |
|
709 uint8_t tempB = frame[i + 2]; |
|
710 @@ -720,20 +778,17 @@ void BaseCapturerPipeWire::OnStartReques |
|
711 guint32 stream_id; |
|
712 gint32 width; |
|
713 gint32 height; |
|
714 GVariant* options; |
|
715 |
|
716 g_variant_get(variant, "(u@a{sv})", &stream_id, &options); |
|
717 RTC_DCHECK(options != nullptr); |
|
718 |
|
719 - g_variant_lookup(options, "size", "(ii)", &width, &height); |
|
720 - |
|
721 - that->desktop_size_.set(width, height); |
|
722 - |
|
723 + that->pw_stream_node_id_ = stream_id; |
|
724 g_variant_unref(options); |
|
725 g_variant_unref(variant); |
|
726 } |
|
727 } |
|
728 g_variant_iter_free(iter); |
|
729 g_variant_unref(response_data); |
|
730 |
|
731 that->OpenPipeWireRemote(); |
|
732 @@ -808,20 +863,25 @@ void BaseCapturerPipeWire::CaptureFrame( |
|
733 return; |
|
734 } |
|
735 |
|
736 if (!current_frame_) { |
|
737 callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr); |
|
738 return; |
|
739 } |
|
740 |
|
741 - std::unique_ptr<DesktopFrame> result(new BasicDesktopFrame(desktop_size_)); |
|
742 + DesktopSize frame_size = desktop_size_; |
|
743 + if (video_crop_size_initialized_) { |
|
744 + frame_size = video_crop_size_; |
|
745 + } |
|
746 + |
|
747 + std::unique_ptr<DesktopFrame> result(new BasicDesktopFrame(frame_size)); |
|
748 result->CopyPixelsFrom( |
|
749 - current_frame_, (desktop_size_.width() * kBytesPerPixel), |
|
750 - DesktopRect::MakeWH(desktop_size_.width(), desktop_size_.height())); |
|
751 + current_frame_.get(), (frame_size.width() * kBytesPerPixel), |
|
752 + DesktopRect::MakeWH(frame_size.width(), frame_size.height())); |
|
753 if (!result) { |
|
754 callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr); |
|
755 return; |
|
756 } |
|
757 callback_->OnCaptureResult(Result::SUCCESS, std::move(result)); |
142 callback_->OnCaptureResult(Result::SUCCESS, std::move(result)); |
758 } |
143 } |
759 |
144 |
|
145 +#define PIPEWIRE_ID 0xaffffff |
|
146 +#define PIPEWIRE_NAME "####_PIPEWIRE_PORTAL_####" |
|
147 + |
760 bool BaseCapturerPipeWire::GetSourceList(SourceList* sources) { |
148 bool BaseCapturerPipeWire::GetSourceList(SourceList* sources) { |
761 @@ -832,9 +892,27 @@ bool BaseCapturerPipeWire::GetSourceList |
149 - RTC_DCHECK(sources->size() == 0); |
|
150 - // List of available screens is already presented by the xdg-desktop-portal. |
|
151 - // But we have to add an empty source as the code expects it. |
|
152 - sources->push_back({0}); |
|
153 + sources->push_back({PIPEWIRE_ID, 0, PIPEWIRE_NAME}); |
762 return true; |
154 return true; |
763 } |
155 } |
764 |
156 |
765 bool BaseCapturerPipeWire::SelectSource(SourceId id) { |
157 bool BaseCapturerPipeWire::SelectSource(SourceId id) { |
766 // Screen selection is handled by the xdg-desktop-portal. |
158 // Screen selection is handled by the xdg-desktop-portal. |
767 return true; |
159 - return true; |
|
160 + return id == PIPEWIRE_ID; |
768 } |
161 } |
769 |
162 |
770 +// static |
|
771 +std::unique_ptr<DesktopCapturer> |
|
772 +BaseCapturerPipeWire::CreateRawScreenCapturer( |
|
773 + const DesktopCaptureOptions& options) { |
|
774 + std::unique_ptr<BaseCapturerPipeWire> capturer = |
|
775 + std::make_unique<BaseCapturerPipeWire>(BaseCapturerPipeWire::CaptureSourceType::kAny); |
|
776 + return std::move(capturer);} |
|
777 + |
|
778 +// static |
|
779 +std::unique_ptr<DesktopCapturer> |
|
780 +BaseCapturerPipeWire::CreateRawWindowCapturer( |
|
781 + const DesktopCaptureOptions& options) { |
|
782 + |
|
783 + std::unique_ptr<BaseCapturerPipeWire> capturer = |
|
784 + std::make_unique<BaseCapturerPipeWire>(BaseCapturerPipeWire::CaptureSourceType::kAny); |
|
785 + return std::move(capturer); |
|
786 +} |
|
787 + |
|
788 } // namespace webrtc |
|
789 diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h |
|
790 --- a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h |
|
791 +++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h |
|
792 @@ -17,99 +17,103 @@ |
|
793 #include <spa/param/video/format-utils.h> |
|
794 |
|
795 #include "modules/desktop_capture/desktop_capture_options.h" |
|
796 #include "modules/desktop_capture/desktop_capturer.h" |
|
797 #include "rtc_base/constructormagic.h" |
|
798 |
|
799 namespace webrtc { |
|
800 |
|
801 -class PipeWireType { |
|
802 - public: |
|
803 - spa_type_media_type media_type; |
|
804 - spa_type_media_subtype media_subtype; |
|
805 - spa_type_format_video format_video; |
|
806 - spa_type_video_format video_format; |
|
807 -}; |
|
808 - |
|
809 class BaseCapturerPipeWire : public DesktopCapturer { |
|
810 public: |
|
811 - enum CaptureSourceType { Screen = 1, Window }; |
|
812 + enum CaptureSourceType : uint32_t { |
|
813 + kScreen = 0b01, |
|
814 + kWindow = 0b10, |
|
815 + kAny = 0b11 |
|
816 + }; |
|
817 |
|
818 explicit BaseCapturerPipeWire(CaptureSourceType source_type); |
|
819 ~BaseCapturerPipeWire() override; |
|
820 |
|
821 // DesktopCapturer interface. |
|
822 void Start(Callback* delegate) override; |
|
823 void CaptureFrame() override; |
|
824 bool GetSourceList(SourceList* sources) override; |
|
825 bool SelectSource(SourceId id) override; |
|
826 |
|
827 + static std::unique_ptr<DesktopCapturer> CreateRawScreenCapturer( |
|
828 + const DesktopCaptureOptions& options); |
|
829 + |
|
830 + static std::unique_ptr<DesktopCapturer> CreateRawWindowCapturer( |
|
831 + const DesktopCaptureOptions& options); |
|
832 + |
|
833 private: |
|
834 // PipeWire types --> |
|
835 + pw_context* pw_context_ = nullptr; |
|
836 pw_core* pw_core_ = nullptr; |
|
837 - pw_type* pw_core_type_ = nullptr; |
|
838 pw_stream* pw_stream_ = nullptr; |
|
839 - pw_remote* pw_remote_ = nullptr; |
|
840 - pw_loop* pw_loop_ = nullptr; |
|
841 pw_thread_loop* pw_main_loop_ = nullptr; |
|
842 - PipeWireType* pw_type_ = nullptr; |
|
843 |
|
844 + spa_hook spa_core_listener_ = {}; |
|
845 spa_hook spa_stream_listener_ = {}; |
|
846 - spa_hook spa_remote_listener_ = {}; |
|
847 |
|
848 + pw_core_events pw_core_events_ = {}; |
|
849 pw_stream_events pw_stream_events_ = {}; |
|
850 - pw_remote_events pw_remote_events_ = {}; |
|
851 |
|
852 - spa_video_info_raw* spa_video_format_ = nullptr; |
|
853 + struct spa_video_info_raw spa_video_format_; |
|
854 |
|
855 + guint32 pw_stream_node_id_ = 0; |
|
856 gint32 pw_fd_ = -1; |
|
857 |
|
858 CaptureSourceType capture_source_type_ = |
|
859 - BaseCapturerPipeWire::CaptureSourceType::Screen; |
|
860 + BaseCapturerPipeWire::CaptureSourceType::kAny; |
|
861 |
|
862 // <-- end of PipeWire types |
|
863 |
|
864 GDBusConnection* connection_ = nullptr; |
|
865 GDBusProxy* proxy_ = nullptr; |
|
866 gchar* portal_handle_ = nullptr; |
|
867 gchar* session_handle_ = nullptr; |
|
868 gchar* sources_handle_ = nullptr; |
|
869 gchar* start_handle_ = nullptr; |
|
870 guint session_request_signal_id_ = 0; |
|
871 guint sources_request_signal_id_ = 0; |
|
872 guint start_request_signal_id_ = 0; |
|
873 |
|
874 + bool video_crop_size_initialized_ = false; |
|
875 + DesktopSize video_crop_size_;; |
|
876 DesktopSize desktop_size_ = {}; |
|
877 DesktopCaptureOptions options_ = {}; |
|
878 |
|
879 - uint8_t* current_frame_ = nullptr; |
|
880 + std::unique_ptr<uint8_t[]> current_frame_; |
|
881 Callback* callback_ = nullptr; |
|
882 |
|
883 bool portal_init_failed_ = false; |
|
884 |
|
885 void InitPortal(); |
|
886 void InitPipeWire(); |
|
887 - void InitPipeWireTypes(); |
|
888 |
|
889 - void CreateReceivingStream(); |
|
890 + pw_stream* CreateReceivingStream(); |
|
891 void HandleBuffer(pw_buffer* buffer); |
|
892 |
|
893 void ConvertRGBxToBGRx(uint8_t* frame, uint32_t size); |
|
894 |
|
895 - static void OnStateChanged(void* data, |
|
896 - pw_remote_state old_state, |
|
897 - pw_remote_state state, |
|
898 - const char* error); |
|
899 + static void SyncDmaBuf(int fd, uint64_t start_or_end); |
|
900 + static void OnCoreError(void *data, |
|
901 + uint32_t id, |
|
902 + int seq, |
|
903 + int res, |
|
904 + const char *message); |
|
905 + static void OnStreamParamChanged(void *data, |
|
906 + uint32_t id, |
|
907 + const struct spa_pod *format); |
|
908 static void OnStreamStateChanged(void* data, |
|
909 pw_stream_state old_state, |
|
910 pw_stream_state state, |
|
911 const char* error_message); |
|
912 - |
|
913 - static void OnStreamFormatChanged(void* data, const struct spa_pod* format); |
|
914 static void OnStreamProcess(void* data); |
|
915 static void OnNewBuffer(void* data, uint32_t id); |
|
916 |
|
917 guint SetupRequestResponseSignal(const gchar* object_path, |
|
918 GDBusSignalCallback callback); |
|
919 |
|
920 static void OnProxyRequested(GObject* object, |
|
921 GAsyncResult* result, |
|
922 diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.cc b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.cc |
|
923 --- a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.cc |
|
924 +++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.cc |
|
925 @@ -10,17 +10,17 @@ |
|
926 |
|
927 #include "modules/desktop_capture/linux/screen_capturer_pipewire.h" |
|
928 |
|
929 #include <memory> |
|
930 |
|
931 namespace webrtc { |
|
932 |
|
933 ScreenCapturerPipeWire::ScreenCapturerPipeWire() |
|
934 - : BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::Screen) {} |
|
935 + : BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::kScreen) {} |
|
936 ScreenCapturerPipeWire::~ScreenCapturerPipeWire() {} |
|
937 |
|
938 // static |
163 // static |
939 std::unique_ptr<DesktopCapturer> |
|
940 ScreenCapturerPipeWire::CreateRawScreenCapturer( |
|
941 const DesktopCaptureOptions& options) { |
|
942 return std::make_unique<ScreenCapturerPipeWire>(); |
|
943 } |
|
944 diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.cc b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.cc |
|
945 --- a/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.cc |
|
946 +++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.cc |
|
947 @@ -10,17 +10,17 @@ |
|
948 |
|
949 #include "modules/desktop_capture/linux/window_capturer_pipewire.h" |
|
950 |
|
951 #include <memory> |
|
952 |
|
953 namespace webrtc { |
|
954 |
|
955 WindowCapturerPipeWire::WindowCapturerPipeWire() |
|
956 - : BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::Window) {} |
|
957 + : BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::kWindow) {} |
|
958 WindowCapturerPipeWire::~WindowCapturerPipeWire() {} |
|
959 |
|
960 // static |
|
961 std::unique_ptr<DesktopCapturer> |
|
962 WindowCapturerPipeWire::CreateRawWindowCapturer( |
|
963 const DesktopCaptureOptions& options) { |
|
964 return std::make_unique<WindowCapturerPipeWire>(); |
|
965 } |
|
966 diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/screen_capturer_linux.cc b/third_party/libwebrtc/webrtc/modules/desktop_capture/screen_capturer_linux.cc |
|
967 --- a/third_party/libwebrtc/webrtc/modules/desktop_capture/screen_capturer_linux.cc |
|
968 +++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/screen_capturer_linux.cc |
|
969 @@ -21,17 +21,17 @@ |
|
970 |
|
971 namespace webrtc { |
|
972 |
|
973 // static |
|
974 std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawScreenCapturer( |
|
975 const DesktopCaptureOptions& options) { |
|
976 #if defined(WEBRTC_USE_PIPEWIRE) |
|
977 if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) { |
|
978 - return ScreenCapturerPipeWire::CreateRawScreenCapturer(options); |
|
979 + return BaseCapturerPipeWire::CreateRawScreenCapturer(options); |
|
980 } |
|
981 #endif // defined(WEBRTC_USE_PIPEWIRE) |
|
982 |
|
983 #if defined(USE_X11) |
|
984 return ScreenCapturerX11::CreateRawScreenCapturer(options); |
|
985 #endif // defined(USE_X11) |
|
986 |
|
987 return nullptr; |
|
988 diff --git a/third_party/libwebrtc/webrtc/modules/desktop_capture/window_capturer_linux.cc b/third_party/libwebrtc/webrtc/modules/desktop_capture/window_capturer_linux.cc |
|
989 --- a/third_party/libwebrtc/webrtc/modules/desktop_capture/window_capturer_linux.cc |
|
990 +++ b/third_party/libwebrtc/webrtc/modules/desktop_capture/window_capturer_linux.cc |
|
991 @@ -21,17 +21,17 @@ |
|
992 |
|
993 namespace webrtc { |
|
994 |
|
995 // static |
|
996 std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawWindowCapturer( |
|
997 const DesktopCaptureOptions& options) { |
|
998 #if defined(WEBRTC_USE_PIPEWIRE) |
|
999 if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) { |
|
1000 - return WindowCapturerPipeWire::CreateRawWindowCapturer(options); |
|
1001 + return BaseCapturerPipeWire::CreateRawWindowCapturer(options); |
|
1002 } |
|
1003 #endif // defined(WEBRTC_USE_PIPEWIRE) |
|
1004 |
|
1005 #if defined(USE_X11) |
|
1006 return WindowCapturerX11::CreateRawWindowCapturer(options); |
|
1007 #endif // defined(USE_X11) |
|
1008 |
|
1009 return nullptr; |
|