]>
Commit | Line | Data |
---|---|---|
70c5ed0c JR |
1 | diff --git a/chromium/third_party/webrtc/modules/desktop_capture/BUILD.gn b/chromium/third_party/webrtc/modules/desktop_capture/BUILD.gn |
2 | index 5235512735d..8259442f811 100644 | |
3 | --- a/chromium/third_party/webrtc/modules/desktop_capture/BUILD.gn | |
4 | +++ b/chromium/third_party/webrtc/modules/desktop_capture/BUILD.gn | |
5 | @@ -11,6 +11,11 @@ import("//build/config/ui.gni") | |
6 | import("//tools/generate_stubs/rules.gni") | |
7 | import("../../webrtc.gni") | |
8 | ||
9 | +if (rtc_use_pipewire) { | |
10 | + assert(rtc_pipewire_version == "0.2" || rtc_pipewire_version == "0.3", | |
11 | + "Unsupported PipeWire version") | |
12 | +} | |
13 | + | |
14 | use_desktop_capture_differ_sse2 = current_cpu == "x86" || current_cpu == "x64" | |
15 | ||
16 | config("x11_config") { | |
17 | @@ -200,22 +205,41 @@ if (is_linux || is_chromeos) { | |
18 | ] | |
19 | } | |
20 | ||
21 | - if (rtc_link_pipewire) { | |
22 | + if (rtc_pipewire_version == "0.3") { | |
23 | pkg_config("pipewire") { | |
24 | - packages = [ "libpipewire-0.2" ] | |
25 | + packages = [ "libpipewire-0.3" ] | |
26 | + if (!rtc_link_pipewire) { | |
27 | + ignore_libs = true | |
28 | + } | |
29 | } | |
30 | } else { | |
31 | + pkg_config("pipewire") { | |
32 | + packages = [ "libpipewire-0.2" ] | |
33 | + if (!rtc_link_pipewire) { | |
34 | + ignore_libs = true | |
35 | + } | |
36 | + } | |
37 | + } | |
38 | + | |
39 | + if (!rtc_link_pipewire) { | |
40 | # When libpipewire is not directly linked, use stubs to allow for dlopening of | |
41 | # the binary. | |
42 | generate_stubs("pipewire_stubs") { | |
43 | - configs = [ "../../:common_config" ] | |
44 | + configs = [ | |
45 | + "../../:common_config", | |
46 | + ":pipewire", | |
47 | + ] | |
48 | deps = [ "../../rtc_base" ] | |
49 | extra_header = "linux/pipewire_stub_header.fragment" | |
50 | logging_function = "RTC_LOG(LS_VERBOSE)" | |
51 | logging_include = "rtc_base/logging.h" | |
52 | output_name = "linux/pipewire_stubs" | |
53 | path_from_source = "modules/desktop_capture/linux" | |
54 | - sigs = [ "linux/pipewire.sigs" ] | |
55 | + if (rtc_pipewire_version == "0.3") { | |
56 | + sigs = [ "linux/pipewire03.sigs" ] | |
57 | + } else { | |
58 | + sigs = [ "linux/pipewire02.sigs" ] | |
59 | + } | |
60 | } | |
61 | } | |
62 | ||
63 | @@ -506,6 +530,7 @@ rtc_library("desktop_capture_generic") { | |
64 | absl_deps = [ | |
65 | "//third_party/abseil-cpp/absl/memory", | |
66 | "//third_party/abseil-cpp/absl/strings", | |
67 | + "//third_party/abseil-cpp/absl/types:optional", | |
68 | ] | |
69 | ||
70 | if (rtc_use_x11_extensions) { | |
71 | @@ -526,20 +551,15 @@ rtc_library("desktop_capture_generic") { | |
72 | sources += [ | |
73 | "linux/base_capturer_pipewire.cc", | |
74 | "linux/base_capturer_pipewire.h", | |
75 | - "linux/screen_capturer_pipewire.cc", | |
76 | - "linux/screen_capturer_pipewire.h", | |
77 | - "linux/window_capturer_pipewire.cc", | |
78 | - "linux/window_capturer_pipewire.h", | |
79 | ] | |
80 | ||
81 | configs += [ | |
82 | ":pipewire_config", | |
83 | ":gio", | |
84 | + ":pipewire", | |
85 | ] | |
86 | ||
87 | - if (rtc_link_pipewire) { | |
88 | - configs += [ ":pipewire" ] | |
89 | - } else { | |
90 | + if (!rtc_link_pipewire) { | |
91 | deps += [ ":pipewire_stubs" ] | |
92 | } | |
93 | } | |
94 | diff --git a/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc b/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc | |
95 | index 2640e93aa98..c302a086ead 100644 | |
96 | --- a/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc | |
97 | +++ b/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.cc | |
98 | @@ -14,8 +14,14 @@ | |
99 | #include <glib-object.h> | |
100 | #include <spa/param/format-utils.h> | |
101 | #include <spa/param/props.h> | |
102 | +#if !PW_CHECK_VERSION(0, 3, 0) | |
103 | #include <spa/param/video/raw-utils.h> | |
104 | #include <spa/support/type-map.h> | |
105 | +#endif | |
106 | + | |
107 | +#include <sys/ioctl.h> | |
108 | +#include <sys/mman.h> | |
109 | +#include <sys/syscall.h> | |
110 | ||
111 | #include <memory> | |
112 | #include <utility> | |
113 | @@ -30,7 +36,11 @@ | |
114 | #include "modules/desktop_capture/linux/pipewire_stubs.h" | |
115 | ||
116 | using modules_desktop_capture_linux::InitializeStubs; | |
117 | -using modules_desktop_capture_linux::kModulePipewire; | |
118 | +#if PW_CHECK_VERSION(0, 3, 0) | |
119 | +using modules_desktop_capture_linux::kModulePipewire03; | |
120 | +#else | |
121 | +using modules_desktop_capture_linux::kModulePipewire02; | |
122 | +#endif | |
123 | using modules_desktop_capture_linux::StubPathMap; | |
124 | #endif // defined(WEBRTC_DLOPEN_PIPEWIRE) | |
125 | ||
126 | @@ -47,9 +57,156 @@ const char kScreenCastInterfaceName[] = "org.freedesktop.portal.ScreenCast"; | |
127 | const int kBytesPerPixel = 4; | |
128 | ||
129 | #if defined(WEBRTC_DLOPEN_PIPEWIRE) | |
130 | +#if PW_CHECK_VERSION(0, 3, 0) | |
131 | +const char kPipeWireLib[] = "libpipewire-0.3.so.0"; | |
132 | +#else | |
133 | const char kPipeWireLib[] = "libpipewire-0.2.so.1"; | |
134 | #endif | |
135 | +#endif | |
136 | ||
137 | +// static | |
138 | +struct dma_buf_sync { | |
139 | + uint64_t flags; | |
140 | +}; | |
141 | +#define DMA_BUF_SYNC_READ (1 << 0) | |
142 | +#define DMA_BUF_SYNC_START (0 << 2) | |
143 | +#define DMA_BUF_SYNC_END (1 << 2) | |
144 | +#define DMA_BUF_BASE 'b' | |
145 | +#define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync) | |
146 | + | |
147 | +static void SyncDmaBuf(int fd, uint64_t start_or_end) { | |
148 | + struct dma_buf_sync sync = {0}; | |
149 | + | |
150 | + sync.flags = start_or_end | DMA_BUF_SYNC_READ; | |
151 | + | |
152 | + while (true) { | |
153 | + int ret; | |
154 | + ret = ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync); | |
155 | + if (ret == -1 && errno == EINTR) { | |
156 | + continue; | |
157 | + } else if (ret == -1) { | |
158 | + RTC_LOG(LS_ERROR) << "Failed to synchronize DMA buffer: " | |
159 | + << g_strerror(errno); | |
160 | + break; | |
161 | + } else { | |
162 | + break; | |
163 | + } | |
164 | + } | |
165 | +} | |
166 | + | |
167 | +class ScopedBuf { | |
168 | + public: | |
169 | + ScopedBuf() {} | |
170 | + ScopedBuf(unsigned char* map, int map_size, bool is_dma_buf, int fd) | |
171 | + : map_(map), map_size_(map_size), is_dma_buf_(is_dma_buf), fd_(fd) {} | |
172 | + ~ScopedBuf() { | |
173 | + if (map_ != MAP_FAILED) { | |
174 | + if (is_dma_buf_) { | |
175 | + SyncDmaBuf(fd_, DMA_BUF_SYNC_END); | |
176 | + } | |
177 | + munmap(map_, map_size_); | |
178 | + } | |
179 | + } | |
180 | + | |
181 | + operator bool() { return map_ != MAP_FAILED; } | |
182 | + | |
183 | + void initialize(unsigned char* map, int map_size, bool is_dma_buf, int fd) { | |
184 | + map_ = map; | |
185 | + map_size_ = map_size; | |
186 | + is_dma_buf_ = is_dma_buf; | |
187 | + fd_ = fd; | |
188 | + } | |
189 | + | |
190 | + unsigned char* get() { return map_; } | |
191 | + | |
192 | + protected: | |
193 | + unsigned char* map_ = nullptr; | |
194 | + int map_size_; | |
195 | + bool is_dma_buf_; | |
196 | + int fd_; | |
197 | +}; | |
198 | + | |
199 | +template <class T> | |
200 | +class Scoped { | |
201 | + public: | |
202 | + Scoped() {} | |
203 | + explicit Scoped(T* val) { ptr_ = val; } | |
204 | + ~Scoped() { RTC_NOTREACHED(); } | |
205 | + | |
206 | + T* operator->() { return ptr_; } | |
207 | + | |
208 | + bool operator!() { return ptr_ == nullptr; } | |
209 | + | |
210 | + T* get() { return ptr_; } | |
211 | + | |
212 | + T** receive() { | |
213 | + RTC_CHECK(!ptr_); | |
214 | + return &ptr_; | |
215 | + } | |
216 | + | |
217 | + Scoped& operator=(T* val) { | |
218 | + ptr_ = val; | |
219 | + return *this; | |
220 | + } | |
221 | + | |
222 | + protected: | |
223 | + T* ptr_ = nullptr; | |
224 | +}; | |
225 | + | |
226 | +template <> | |
227 | +Scoped<GError>::~Scoped() { | |
228 | + if (ptr_) { | |
229 | + g_error_free(ptr_); | |
230 | + } | |
231 | +} | |
232 | + | |
233 | +template <> | |
234 | +Scoped<gchar>::~Scoped() { | |
235 | + if (ptr_) { | |
236 | + g_free(ptr_); | |
237 | + } | |
238 | +} | |
239 | + | |
240 | +template <> | |
241 | +Scoped<GVariant>::~Scoped() { | |
242 | + if (ptr_) { | |
243 | + g_variant_unref(ptr_); | |
244 | + } | |
245 | +} | |
246 | + | |
247 | +template <> | |
248 | +Scoped<GVariantIter>::~Scoped() { | |
249 | + if (ptr_) { | |
250 | + g_variant_iter_free(ptr_); | |
251 | + } | |
252 | +} | |
253 | + | |
254 | +template <> | |
255 | +Scoped<GDBusMessage>::~Scoped() { | |
256 | + if (ptr_) { | |
257 | + g_object_unref(ptr_); | |
258 | + } | |
259 | +} | |
260 | + | |
261 | +template <> | |
262 | +Scoped<GUnixFDList>::~Scoped() { | |
263 | + if (ptr_) { | |
264 | + g_object_unref(ptr_); | |
265 | + } | |
266 | +} | |
267 | + | |
268 | +#if PW_CHECK_VERSION(0, 3, 0) | |
269 | +void BaseCapturerPipeWire::OnCoreError(void* data, | |
270 | + uint32_t id, | |
271 | + int seq, | |
272 | + int res, | |
273 | + const char* message) { | |
274 | + BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data); | |
275 | + RTC_DCHECK(that); | |
276 | + | |
277 | + RTC_LOG(LS_ERROR) << "PipeWire remote error: " << message; | |
278 | +} | |
279 | +#else | |
280 | // static | |
281 | void BaseCapturerPipeWire::OnStateChanged(void* data, | |
282 | pw_remote_state old_state, | |
283 | @@ -64,7 +221,7 @@ void BaseCapturerPipeWire::OnStateChanged(void* data, | |
284 | break; | |
285 | case PW_REMOTE_STATE_CONNECTED: | |
286 | RTC_LOG(LS_INFO) << "PipeWire remote state: connected."; | |
287 | - that->CreateReceivingStream(); | |
288 | + that->pw_stream_ = that->CreateReceivingStream(); | |
289 | break; | |
290 | case PW_REMOTE_STATE_CONNECTING: | |
291 | RTC_LOG(LS_INFO) << "PipeWire remote state: connecting."; | |
292 | @@ -74,6 +231,7 @@ void BaseCapturerPipeWire::OnStateChanged(void* data, | |
293 | break; | |
294 | } | |
295 | } | |
296 | +#endif | |
297 | ||
298 | // static | |
299 | void BaseCapturerPipeWire::OnStreamStateChanged(void* data, | |
300 | @@ -83,6 +241,18 @@ void BaseCapturerPipeWire::OnStreamStateChanged(void* data, | |
301 | BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data); | |
302 | RTC_DCHECK(that); | |
303 | ||
304 | +#if PW_CHECK_VERSION(0, 3, 0) | |
305 | + switch (state) { | |
306 | + case PW_STREAM_STATE_ERROR: | |
307 | + RTC_LOG(LS_ERROR) << "PipeWire stream state error: " << error_message; | |
308 | + break; | |
309 | + case PW_STREAM_STATE_PAUSED: | |
310 | + case PW_STREAM_STATE_STREAMING: | |
311 | + case PW_STREAM_STATE_UNCONNECTED: | |
312 | + case PW_STREAM_STATE_CONNECTING: | |
313 | + break; | |
314 | + } | |
315 | +#else | |
316 | switch (state) { | |
317 | case PW_STREAM_STATE_ERROR: | |
318 | RTC_LOG(LS_ERROR) << "PipeWire stream state error: " << error_message; | |
319 | @@ -97,36 +267,74 @@ void BaseCapturerPipeWire::OnStreamStateChanged(void* data, | |
320 | case PW_STREAM_STATE_STREAMING: | |
321 | break; | |
322 | } | |
323 | +#endif | |
324 | } | |
325 | ||
326 | // static | |
327 | +#if PW_CHECK_VERSION(0, 3, 0) | |
328 | +void BaseCapturerPipeWire::OnStreamParamChanged(void* data, | |
329 | + uint32_t id, | |
330 | + const struct spa_pod* format) { | |
331 | +#else | |
332 | void BaseCapturerPipeWire::OnStreamFormatChanged(void* data, | |
333 | const struct spa_pod* format) { | |
334 | +#endif | |
335 | BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data); | |
336 | RTC_DCHECK(that); | |
337 | ||
338 | RTC_LOG(LS_INFO) << "PipeWire stream format changed."; | |
339 | ||
340 | +#if PW_CHECK_VERSION(0, 3, 0) | |
341 | + if (!format || id != SPA_PARAM_Format) { | |
342 | +#else | |
343 | if (!format) { | |
344 | pw_stream_finish_format(that->pw_stream_, /*res=*/0, /*params=*/nullptr, | |
345 | /*n_params=*/0); | |
346 | +#endif | |
347 | return; | |
348 | } | |
349 | ||
350 | +#if PW_CHECK_VERSION(0, 3, 0) | |
351 | + spa_format_video_raw_parse(format, &that->spa_video_format_); | |
352 | +#else | |
353 | that->spa_video_format_ = new spa_video_info_raw(); | |
354 | spa_format_video_raw_parse(format, that->spa_video_format_, | |
355 | &that->pw_type_->format_video); | |
356 | +#endif | |
357 | ||
358 | +#if PW_CHECK_VERSION(0, 3, 0) | |
359 | + auto width = that->spa_video_format_.size.width; | |
360 | + auto height = that->spa_video_format_.size.height; | |
361 | +#else | |
362 | auto width = that->spa_video_format_->size.width; | |
363 | auto height = that->spa_video_format_->size.height; | |
364 | +#endif | |
365 | auto stride = SPA_ROUND_UP_N(width * kBytesPerPixel, 4); | |
366 | auto size = height * stride; | |
367 | ||
368 | + that->desktop_size_ = DesktopSize(width, height); | |
369 | + | |
370 | uint8_t buffer[1024] = {}; | |
371 | auto builder = spa_pod_builder{buffer, sizeof(buffer)}; | |
372 | ||
373 | // Setup buffers and meta header for new format. | |
374 | - const struct spa_pod* params[2]; | |
375 | + const struct spa_pod* params[3]; | |
376 | +#if PW_CHECK_VERSION(0, 3, 0) | |
377 | + params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_add_object( | |
378 | + &builder, SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers, | |
379 | + SPA_PARAM_BUFFERS_size, SPA_POD_Int(size), SPA_PARAM_BUFFERS_stride, | |
380 | + SPA_POD_Int(stride), SPA_PARAM_BUFFERS_buffers, | |
381 | + SPA_POD_CHOICE_RANGE_Int(8, 1, 32))); | |
382 | + params[1] = reinterpret_cast<spa_pod*>(spa_pod_builder_add_object( | |
383 | + &builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, SPA_PARAM_META_type, | |
384 | + SPA_POD_Id(SPA_META_Header), SPA_PARAM_META_size, | |
385 | + SPA_POD_Int(sizeof(struct spa_meta_header)))); | |
386 | + params[2] = reinterpret_cast<spa_pod*>(spa_pod_builder_add_object( | |
387 | + &builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta, SPA_PARAM_META_type, | |
388 | + SPA_POD_Id(SPA_META_VideoCrop), SPA_PARAM_META_size, | |
389 | + SPA_POD_Int(sizeof(struct spa_meta_region)))); | |
390 | + pw_stream_update_params(that->pw_stream_, params, 3); | |
391 | +#else | |
392 | params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_object( | |
393 | &builder, | |
394 | // id to enumerate buffer requirements | |
395 | @@ -155,8 +363,18 @@ void BaseCapturerPipeWire::OnStreamFormatChanged(void* data, | |
396 | // Size: size of the metadata, specified as integer (i) | |
397 | ":", that->pw_core_type_->param_meta.size, "i", | |
398 | sizeof(struct spa_meta_header))); | |
399 | - | |
400 | - pw_stream_finish_format(that->pw_stream_, /*res=*/0, params, /*n_params=*/2); | |
401 | + params[2] = reinterpret_cast<spa_pod*>(spa_pod_builder_object( | |
402 | + &builder, | |
403 | + // id to enumerate supported metadata | |
404 | + that->pw_core_type_->param.idMeta, that->pw_core_type_->param_meta.Meta, | |
405 | + // Type: specified as id or enum (I) | |
406 | + ":", that->pw_core_type_->param_meta.type, "I", | |
407 | + that->pw_core_type_->meta.VideoCrop, | |
408 | + // Size: size of the metadata, specified as integer (i) | |
409 | + ":", that->pw_core_type_->param_meta.size, "i", | |
410 | + sizeof(struct spa_meta_video_crop))); | |
411 | + pw_stream_finish_format(that->pw_stream_, /*res=*/0, params, /*n_params=*/3); | |
412 | +#endif | |
413 | } | |
414 | ||
415 | // static | |
416 | @@ -164,15 +382,26 @@ void BaseCapturerPipeWire::OnStreamProcess(void* data) { | |
417 | BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data); | |
418 | RTC_DCHECK(that); | |
419 | ||
420 | - pw_buffer* buf = nullptr; | |
421 | + struct pw_buffer* next_buffer; | |
422 | + struct pw_buffer* buffer = nullptr; | |
423 | + | |
424 | + next_buffer = pw_stream_dequeue_buffer(that->pw_stream_); | |
425 | + while (next_buffer) { | |
426 | + buffer = next_buffer; | |
427 | + next_buffer = pw_stream_dequeue_buffer(that->pw_stream_); | |
428 | ||
429 | - if (!(buf = pw_stream_dequeue_buffer(that->pw_stream_))) { | |
430 | + if (next_buffer) { | |
431 | + pw_stream_queue_buffer(that->pw_stream_, buffer); | |
432 | + } | |
433 | + } | |
434 | + | |
435 | + if (!buffer) { | |
436 | return; | |
437 | } | |
438 | ||
439 | - that->HandleBuffer(buf); | |
440 | + that->HandleBuffer(buffer); | |
441 | ||
442 | - pw_stream_queue_buffer(that->pw_stream_, buf); | |
443 | + pw_stream_queue_buffer(that->pw_stream_, buffer); | |
444 | } | |
445 | ||
446 | BaseCapturerPipeWire::BaseCapturerPipeWire(CaptureSourceType source_type) | |
447 | @@ -183,6 +412,7 @@ BaseCapturerPipeWire::~BaseCapturerPipeWire() { | |
448 | pw_thread_loop_stop(pw_main_loop_); | |
449 | } | |
450 | ||
451 | +#if !PW_CHECK_VERSION(0, 3, 0) | |
452 | if (pw_type_) { | |
453 | delete pw_type_; | |
454 | } | |
455 | @@ -190,30 +420,41 @@ BaseCapturerPipeWire::~BaseCapturerPipeWire() { | |
456 | if (spa_video_format_) { | |
457 | delete spa_video_format_; | |
458 | } | |
459 | +#endif | |
460 | ||
461 | if (pw_stream_) { | |
462 | pw_stream_destroy(pw_stream_); | |
463 | } | |
464 | ||
465 | +#if !PW_CHECK_VERSION(0, 3, 0) | |
466 | if (pw_remote_) { | |
467 | pw_remote_destroy(pw_remote_); | |
468 | } | |
469 | +#endif | |
470 | ||
471 | +#if PW_CHECK_VERSION(0, 3, 0) | |
472 | + if (pw_core_) { | |
473 | + pw_core_disconnect(pw_core_); | |
474 | + } | |
475 | + | |
476 | + if (pw_context_) { | |
477 | + pw_context_destroy(pw_context_); | |
478 | + } | |
479 | +#else | |
480 | if (pw_core_) { | |
481 | pw_core_destroy(pw_core_); | |
482 | } | |
483 | +#endif | |
484 | ||
485 | if (pw_main_loop_) { | |
486 | pw_thread_loop_destroy(pw_main_loop_); | |
487 | } | |
488 | ||
489 | +#if !PW_CHECK_VERSION(0, 3, 0) | |
490 | if (pw_loop_) { | |
491 | pw_loop_destroy(pw_loop_); | |
492 | } | |
493 | - | |
494 | - if (current_frame_) { | |
495 | - free(current_frame_); | |
496 | - } | |
497 | +#endif | |
498 | ||
499 | if (start_request_signal_id_) { | |
500 | g_dbus_connection_signal_unsubscribe(connection_, start_request_signal_id_); | |
501 | @@ -228,18 +469,16 @@ BaseCapturerPipeWire::~BaseCapturerPipeWire() { | |
502 | } | |
503 | ||
504 | if (session_handle_) { | |
505 | - GDBusMessage* message = g_dbus_message_new_method_call( | |
506 | - kDesktopBusName, session_handle_, kSessionInterfaceName, "Close"); | |
507 | - if (message) { | |
508 | - GError* error = nullptr; | |
509 | - g_dbus_connection_send_message(connection_, message, | |
510 | + Scoped<GDBusMessage> message(g_dbus_message_new_method_call( | |
511 | + kDesktopBusName, session_handle_, kSessionInterfaceName, "Close")); | |
512 | + if (message.get()) { | |
513 | + Scoped<GError> error; | |
514 | + g_dbus_connection_send_message(connection_, message.get(), | |
515 | G_DBUS_SEND_MESSAGE_FLAGS_NONE, | |
516 | - /*out_serial=*/nullptr, &error); | |
517 | - if (error) { | |
518 | + /*out_serial=*/nullptr, error.receive()); | |
519 | + if (error.get()) { | |
520 | RTC_LOG(LS_ERROR) << "Failed to close the session: " << error->message; | |
521 | - g_error_free(error); | |
522 | } | |
523 | - g_object_unref(message); | |
524 | } | |
525 | } | |
526 | ||
527 | @@ -274,7 +513,11 @@ void BaseCapturerPipeWire::InitPipeWire() { | |
528 | StubPathMap paths; | |
529 | ||
530 | // Check if the PipeWire library is available. | |
531 | - paths[kModulePipewire].push_back(kPipeWireLib); | |
532 | +#if PW_CHECK_VERSION(0, 3, 0) | |
533 | + paths[kModulePipewire03].push_back(kPipeWireLib); | |
534 | +#else | |
535 | + paths[kModulePipewire02].push_back(kPipeWireLib); | |
536 | +#endif | |
537 | if (!InitializeStubs(paths)) { | |
538 | RTC_LOG(LS_ERROR) << "Failed to load the PipeWire library and symbols."; | |
539 | portal_init_failed_ = true; | |
540 | @@ -284,16 +527,46 @@ void BaseCapturerPipeWire::InitPipeWire() { | |
541 | ||
542 | pw_init(/*argc=*/nullptr, /*argc=*/nullptr); | |
543 | ||
544 | +#if PW_CHECK_VERSION(0, 3, 0) | |
545 | + pw_main_loop_ = pw_thread_loop_new("pipewire-main-loop", nullptr); | |
546 | + | |
547 | + pw_thread_loop_lock(pw_main_loop_); | |
548 | + | |
549 | + pw_context_ = | |
550 | + pw_context_new(pw_thread_loop_get_loop(pw_main_loop_), nullptr, 0); | |
551 | + if (!pw_context_) { | |
552 | + RTC_LOG(LS_ERROR) << "Failed to create PipeWire context"; | |
553 | + return; | |
554 | + } | |
555 | + | |
556 | + pw_core_ = pw_context_connect(pw_context_, nullptr, 0); | |
557 | + if (!pw_core_) { | |
558 | + RTC_LOG(LS_ERROR) << "Failed to connect PipeWire context"; | |
559 | + return; | |
560 | + } | |
561 | +#else | |
562 | pw_loop_ = pw_loop_new(/*properties=*/nullptr); | |
563 | pw_main_loop_ = pw_thread_loop_new(pw_loop_, "pipewire-main-loop"); | |
564 | ||
565 | + pw_thread_loop_lock(pw_main_loop_); | |
566 | + | |
567 | pw_core_ = pw_core_new(pw_loop_, /*properties=*/nullptr); | |
568 | pw_core_type_ = pw_core_get_type(pw_core_); | |
569 | pw_remote_ = pw_remote_new(pw_core_, nullptr, /*user_data_size=*/0); | |
570 | ||
571 | InitPipeWireTypes(); | |
572 | +#endif | |
573 | ||
574 | // Initialize event handlers, remote end and stream-related. | |
575 | +#if PW_CHECK_VERSION(0, 3, 0) | |
576 | + pw_core_events_.version = PW_VERSION_CORE_EVENTS; | |
577 | + pw_core_events_.error = &OnCoreError; | |
578 | + | |
579 | + pw_stream_events_.version = PW_VERSION_STREAM_EVENTS; | |
580 | + pw_stream_events_.state_changed = &OnStreamStateChanged; | |
581 | + pw_stream_events_.param_changed = &OnStreamParamChanged; | |
582 | + pw_stream_events_.process = &OnStreamProcess; | |
583 | +#else | |
584 | pw_remote_events_.version = PW_VERSION_REMOTE_EVENTS; | |
585 | pw_remote_events_.state_changed = &OnStateChanged; | |
586 | ||
587 | @@ -301,19 +574,33 @@ void BaseCapturerPipeWire::InitPipeWire() { | |
588 | pw_stream_events_.state_changed = &OnStreamStateChanged; | |
589 | pw_stream_events_.format_changed = &OnStreamFormatChanged; | |
590 | pw_stream_events_.process = &OnStreamProcess; | |
591 | +#endif | |
592 | ||
593 | +#if PW_CHECK_VERSION(0, 3, 0) | |
594 | + pw_core_add_listener(pw_core_, &spa_core_listener_, &pw_core_events_, this); | |
595 | + | |
596 | + pw_stream_ = CreateReceivingStream(); | |
597 | + if (!pw_stream_) { | |
598 | + RTC_LOG(LS_ERROR) << "Failed to create PipeWire stream"; | |
599 | + return; | |
600 | + } | |
601 | +#else | |
602 | pw_remote_add_listener(pw_remote_, &spa_remote_listener_, &pw_remote_events_, | |
603 | this); | |
604 | pw_remote_connect_fd(pw_remote_, pw_fd_); | |
605 | +#endif | |
606 | ||
607 | if (pw_thread_loop_start(pw_main_loop_) < 0) { | |
608 | RTC_LOG(LS_ERROR) << "Failed to start main PipeWire loop"; | |
609 | portal_init_failed_ = true; | |
610 | } | |
611 | ||
612 | + pw_thread_loop_unlock(pw_main_loop_); | |
613 | + | |
614 | RTC_LOG(LS_INFO) << "PipeWire remote opened."; | |
615 | } | |
616 | ||
617 | +#if !PW_CHECK_VERSION(0, 3, 0) | |
618 | void BaseCapturerPipeWire::InitPipeWireTypes() { | |
619 | spa_type_map* map = pw_core_type_->map; | |
620 | pw_type_ = new PipeWireType(); | |
621 | @@ -323,23 +610,44 @@ void BaseCapturerPipeWire::InitPipeWireTypes() { | |
622 | spa_type_format_video_map(map, &pw_type_->format_video); | |
623 | spa_type_video_format_map(map, &pw_type_->video_format); | |
624 | } | |
625 | +#endif | |
626 | ||
627 | -void BaseCapturerPipeWire::CreateReceivingStream() { | |
628 | +pw_stream* BaseCapturerPipeWire::CreateReceivingStream() { | |
629 | +#if !PW_CHECK_VERSION(0, 3, 0) | |
630 | + if (pw_remote_get_state(pw_remote_, nullptr) != PW_REMOTE_STATE_CONNECTED) { | |
631 | + RTC_LOG(LS_ERROR) << "Cannot create pipewire stream"; | |
632 | + return nullptr; | |
633 | + } | |
634 | +#endif | |
635 | spa_rectangle pwMinScreenBounds = spa_rectangle{1, 1}; | |
636 | - spa_rectangle pwScreenBounds = | |
637 | - spa_rectangle{static_cast<uint32_t>(desktop_size_.width()), | |
638 | - static_cast<uint32_t>(desktop_size_.height())}; | |
639 | - | |
640 | - spa_fraction pwFrameRateMin = spa_fraction{0, 1}; | |
641 | - spa_fraction pwFrameRateMax = spa_fraction{60, 1}; | |
642 | + spa_rectangle pwMaxScreenBounds = spa_rectangle{UINT32_MAX, UINT32_MAX}; | |
643 | ||
644 | pw_properties* reuseProps = | |
645 | pw_properties_new_string("pipewire.client.reuse=1"); | |
646 | - pw_stream_ = pw_stream_new(pw_remote_, "webrtc-consume-stream", reuseProps); | |
647 | +#if PW_CHECK_VERSION(0, 3, 0) | |
648 | + auto stream = pw_stream_new(pw_core_, "webrtc-consume-stream", reuseProps); | |
649 | +#else | |
650 | + auto stream = pw_stream_new(pw_remote_, "webrtc-consume-stream", reuseProps); | |
651 | +#endif | |
652 | ||
653 | uint8_t buffer[1024] = {}; | |
654 | const spa_pod* params[1]; | |
655 | spa_pod_builder builder = spa_pod_builder{buffer, sizeof(buffer)}; | |
656 | + | |
657 | +#if PW_CHECK_VERSION(0, 3, 0) | |
658 | + params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_add_object( | |
659 | + &builder, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, | |
660 | + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), | |
661 | + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), | |
662 | + SPA_FORMAT_VIDEO_format, | |
663 | + SPA_POD_CHOICE_ENUM_Id(5, SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_RGBx, | |
664 | + SPA_VIDEO_FORMAT_RGBA, SPA_VIDEO_FORMAT_BGRx, | |
665 | + SPA_VIDEO_FORMAT_BGRA), | |
666 | + SPA_FORMAT_VIDEO_size, | |
667 | + SPA_POD_CHOICE_RANGE_Rectangle(&pwMinScreenBounds, &pwMinScreenBounds, | |
668 | + &pwMaxScreenBounds), | |
669 | + 0)); | |
670 | +#else | |
671 | params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_object( | |
672 | &builder, | |
673 | // id to enumerate formats | |
674 | @@ -349,69 +657,218 @@ void BaseCapturerPipeWire::CreateReceivingStream() { | |
675 | // then allowed formats are enumerated (e) and the format is undecided (u) | |
676 | // to allow negotiation | |
677 | ":", pw_type_->format_video.format, "Ieu", pw_type_->video_format.BGRx, | |
678 | - SPA_POD_PROP_ENUM(2, pw_type_->video_format.RGBx, | |
679 | - pw_type_->video_format.BGRx), | |
680 | + SPA_POD_PROP_ENUM( | |
681 | + 4, pw_type_->video_format.RGBx, pw_type_->video_format.BGRx, | |
682 | + pw_type_->video_format.RGBA, pw_type_->video_format.BGRA), | |
683 | // Video size: specified as rectangle (R), preferred size is specified as | |
684 | // first parameter, then allowed size is defined as range (r) from min and | |
685 | // max values and the format is undecided (u) to allow negotiation | |
686 | - ":", pw_type_->format_video.size, "Rru", &pwScreenBounds, 2, | |
687 | - &pwMinScreenBounds, &pwScreenBounds, | |
688 | - // Frame rate: specified as fraction (F) and set to minimum frame rate | |
689 | - // value | |
690 | - ":", pw_type_->format_video.framerate, "F", &pwFrameRateMin, | |
691 | - // Max frame rate: specified as fraction (F), preferred frame rate is set | |
692 | - // to maximum value, then allowed frame rate is defined as range (r) from | |
693 | - // min and max values and it is undecided (u) to allow negotiation | |
694 | - ":", pw_type_->format_video.max_framerate, "Fru", &pwFrameRateMax, 2, | |
695 | - &pwFrameRateMin, &pwFrameRateMax)); | |
696 | - | |
697 | - pw_stream_add_listener(pw_stream_, &spa_stream_listener_, &pw_stream_events_, | |
698 | + ":", pw_type_->format_video.size, "Rru", &pwMinScreenBounds, | |
699 | + SPA_POD_PROP_MIN_MAX(&pwMinScreenBounds, &pwMaxScreenBounds))); | |
700 | +#endif | |
701 | + | |
702 | + pw_stream_add_listener(stream, &spa_stream_listener_, &pw_stream_events_, | |
703 | this); | |
704 | +#if PW_CHECK_VERSION(0, 3, 0) | |
705 | + if (pw_stream_connect(stream, PW_DIRECTION_INPUT, pw_stream_node_id_, | |
706 | + PW_STREAM_FLAG_AUTOCONNECT, params, 1) != 0) { | |
707 | +#else | |
708 | pw_stream_flags flags = static_cast<pw_stream_flags>( | |
709 | - PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE | | |
710 | - PW_STREAM_FLAG_MAP_BUFFERS); | |
711 | - if (pw_stream_connect(pw_stream_, PW_DIRECTION_INPUT, /*port_path=*/nullptr, | |
712 | + PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE); | |
713 | + if (pw_stream_connect(stream, PW_DIRECTION_INPUT, /*port_path=*/nullptr, | |
714 | flags, params, | |
715 | /*n_params=*/1) != 0) { | |
716 | +#endif | |
717 | RTC_LOG(LS_ERROR) << "Could not connect receiving stream."; | |
718 | portal_init_failed_ = true; | |
719 | - return; | |
720 | + return nullptr; | |
721 | } | |
722 | + | |
723 | + return stream; | |
724 | } | |
725 | ||
726 | void BaseCapturerPipeWire::HandleBuffer(pw_buffer* buffer) { | |
727 | spa_buffer* spaBuffer = buffer->buffer; | |
728 | - void* src = nullptr; | |
729 | + ScopedBuf map; | |
730 | + uint8_t* src = nullptr; | |
731 | + | |
732 | + if (spaBuffer->datas[0].chunk->size == 0) { | |
733 | + RTC_LOG(LS_ERROR) << "Failed to get video stream: Zero size."; | |
734 | + return; | |
735 | + } | |
736 | + | |
737 | +#if PW_CHECK_VERSION(0, 3, 0) | |
738 | + if (spaBuffer->datas[0].type == SPA_DATA_MemFd || | |
739 | + spaBuffer->datas[0].type == SPA_DATA_DmaBuf) { | |
740 | +#else | |
741 | + if (spaBuffer->datas[0].type == pw_core_type_->data.MemFd || | |
742 | + spaBuffer->datas[0].type == pw_core_type_->data.DmaBuf) { | |
743 | +#endif | |
744 | + map.initialize( | |
745 | + static_cast<uint8_t*>( | |
746 | + mmap(nullptr, | |
747 | + spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset, | |
748 | + PROT_READ, MAP_PRIVATE, spaBuffer->datas[0].fd, 0)), | |
749 | + spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset, | |
750 | +#if PW_CHECK_VERSION(0, 3, 0) | |
751 | + spaBuffer->datas[0].type == SPA_DATA_DmaBuf, | |
752 | +#else | |
753 | + spaBuffer->datas[0].type == pw_core_type_->data.DmaBuf, | |
754 | +#endif | |
755 | + spaBuffer->datas[0].fd); | |
756 | + | |
757 | + if (!map) { | |
758 | + RTC_LOG(LS_ERROR) << "Failed to mmap the memory: " | |
759 | + << std::strerror(errno); | |
760 | + return; | |
761 | + } | |
762 | + | |
763 | +#if PW_CHECK_VERSION(0, 3, 0) | |
764 | + if (spaBuffer->datas[0].type == SPA_DATA_DmaBuf) { | |
765 | +#else | |
766 | + if (spaBuffer->datas[0].type == pw_core_type_->data.DmaBuf) { | |
767 | +#endif | |
768 | + SyncDmaBuf(spaBuffer->datas[0].fd, DMA_BUF_SYNC_START); | |
769 | + } | |
770 | + | |
771 | + src = SPA_MEMBER(map.get(), spaBuffer->datas[0].mapoffset, uint8_t); | |
772 | +#if PW_CHECK_VERSION(0, 3, 0) | |
773 | + } else if (spaBuffer->datas[0].type == SPA_DATA_MemPtr) { | |
774 | +#else | |
775 | + } else if (spaBuffer->datas[0].type == pw_core_type_->data.MemPtr) { | |
776 | +#endif | |
777 | + src = static_cast<uint8_t*>(spaBuffer->datas[0].data); | |
778 | + } | |
779 | ||
780 | - if (!(src = spaBuffer->datas[0].data)) { | |
781 | + if (!src) { | |
782 | + return; | |
783 | + } | |
784 | + | |
785 | +#if PW_CHECK_VERSION(0, 3, 0) | |
786 | + struct spa_meta_region* video_metadata = | |
787 | + static_cast<struct spa_meta_region*>(spa_buffer_find_meta_data( | |
788 | + spaBuffer, SPA_META_VideoCrop, sizeof(*video_metadata))); | |
789 | +#else | |
790 | + struct spa_meta_video_crop* video_metadata = | |
791 | + static_cast<struct spa_meta_video_crop*>( | |
792 | + spa_buffer_find_meta(spaBuffer, pw_core_type_->meta.VideoCrop)); | |
793 | +#endif | |
794 | + | |
795 | + // Video size from metadata is bigger than an actual video stream size. | |
796 | + // The metadata are wrong or we should up-scale the video...in both cases | |
797 | + // just quit now. | |
798 | +#if PW_CHECK_VERSION(0, 3, 0) | |
799 | + if (video_metadata && (video_metadata->region.size.width > | |
800 | + static_cast<uint32_t>(desktop_size_.width()) || | |
801 | + video_metadata->region.size.height > | |
802 | + static_cast<uint32_t>(desktop_size_.height()))) { | |
803 | +#else | |
804 | + if (video_metadata && (video_metadata->width > desktop_size_.width() || | |
805 | + video_metadata->height > desktop_size_.height())) { | |
806 | +#endif | |
807 | + RTC_LOG(LS_ERROR) << "Stream metadata sizes are wrong!"; | |
808 | return; | |
809 | } | |
810 | ||
811 | - uint32_t maxSize = spaBuffer->datas[0].maxsize; | |
812 | - int32_t srcStride = spaBuffer->datas[0].chunk->stride; | |
813 | - if (srcStride != (desktop_size_.width() * kBytesPerPixel)) { | |
814 | + // Use video metadata when video size from metadata is set and smaller than | |
815 | + // video stream size, so we need to adjust it. | |
816 | + bool video_is_full_width = true; | |
817 | + bool video_is_full_height = true; | |
818 | +#if PW_CHECK_VERSION(0, 3, 0) | |
819 | + if (video_metadata && video_metadata->region.size.width != 0 && | |
820 | + video_metadata->region.size.height != 0) { | |
821 | + if (video_metadata->region.size.width < | |
822 | + static_cast<uint32_t>(desktop_size_.width())) { | |
823 | + video_is_full_width = false; | |
824 | + } else if (video_metadata->region.size.height < | |
825 | + static_cast<uint32_t>(desktop_size_.height())) { | |
826 | + video_is_full_height = false; | |
827 | + } | |
828 | + } | |
829 | +#else | |
830 | + if (video_metadata && video_metadata->width != 0 && | |
831 | + video_metadata->height != 0) { | |
832 | + if (video_metadata->width < desktop_size_.width()) { | |
833 | + } else if (video_metadata->height < desktop_size_.height()) { | |
834 | + video_is_full_height = false; | |
835 | + } | |
836 | + } | |
837 | +#endif | |
838 | + | |
839 | + DesktopSize video_size_prev = video_size_; | |
840 | + if (!video_is_full_height || !video_is_full_width) { | |
841 | +#if PW_CHECK_VERSION(0, 3, 0) | |
842 | + video_size_ = DesktopSize(video_metadata->region.size.width, | |
843 | + video_metadata->region.size.height); | |
844 | +#else | |
845 | + video_size_ = DesktopSize(video_metadata->width, video_metadata->height); | |
846 | +#endif | |
847 | + } else { | |
848 | + video_size_ = desktop_size_; | |
849 | + } | |
850 | + | |
851 | + webrtc::MutexLock lock(¤t_frame_lock_); | |
852 | + if (!current_frame_ || !video_size_.equals(video_size_prev)) { | |
853 | + current_frame_ = std::make_unique<uint8_t[]>( | |
854 | + video_size_.width() * video_size_.height() * kBytesPerPixel); | |
855 | + } | |
856 | + | |
857 | + const int32_t dst_stride = video_size_.width() * kBytesPerPixel; | |
858 | + const int32_t src_stride = spaBuffer->datas[0].chunk->stride; | |
859 | + | |
860 | + if (src_stride != (desktop_size_.width() * kBytesPerPixel)) { | |
861 | RTC_LOG(LS_ERROR) << "Got buffer with stride different from screen stride: " | |
862 | - << srcStride | |
863 | + << src_stride | |
864 | << " != " << (desktop_size_.width() * kBytesPerPixel); | |
865 | portal_init_failed_ = true; | |
866 | + | |
867 | return; | |
868 | } | |
869 | ||
870 | - if (!current_frame_) { | |
871 | - current_frame_ = static_cast<uint8_t*>(malloc(maxSize)); | |
872 | - } | |
873 | - RTC_DCHECK(current_frame_ != nullptr); | |
874 | - | |
875 | - // If both sides decided to go with the RGBx format we need to convert it to | |
876 | - // BGRx to match color format expected by WebRTC. | |
877 | - if (spa_video_format_->format == pw_type_->video_format.RGBx) { | |
878 | - uint8_t* tempFrame = static_cast<uint8_t*>(malloc(maxSize)); | |
879 | - std::memcpy(tempFrame, src, maxSize); | |
880 | - ConvertRGBxToBGRx(tempFrame, maxSize); | |
881 | - std::memcpy(current_frame_, tempFrame, maxSize); | |
882 | - free(tempFrame); | |
883 | - } else { | |
884 | - std::memcpy(current_frame_, src, maxSize); | |
885 | + // Adjust source content based on metadata video position | |
886 | +#if PW_CHECK_VERSION(0, 3, 0) | |
887 | + if (!video_is_full_height && | |
888 | + (video_metadata->region.position.y + video_size_.height() <= | |
889 | + desktop_size_.height())) { | |
890 | + src += src_stride * video_metadata->region.position.y; | |
891 | + } | |
892 | + const int x_offset = | |
893 | + !video_is_full_width && | |
894 | + (video_metadata->region.position.x + video_size_.width() <= | |
895 | + desktop_size_.width()) | |
896 | + ? video_metadata->region.position.x * kBytesPerPixel | |
897 | + : 0; | |
898 | +#else | |
899 | + if (!video_is_full_height && | |
900 | + (video_metadata->y + video_size_.height() <= desktop_size_.height())) { | |
901 | + src += src_stride * video_metadata->y; | |
902 | + } | |
903 | + | |
904 | + const int x_offset = | |
905 | + !video_is_full_width && | |
906 | + (video_metadata->x + video_size_.width() <= desktop_size_.width()) | |
907 | + ? video_metadata->x * kBytesPerPixel | |
908 | + : 0; | |
909 | +#endif | |
910 | + | |
911 | + uint8_t* dst = current_frame_.get(); | |
912 | + for (int i = 0; i < video_size_.height(); ++i) { | |
913 | + // Adjust source content based on crop video position if needed | |
914 | + src += x_offset; | |
915 | + std::memcpy(dst, src, dst_stride); | |
916 | + // If both sides decided to go with the RGBx format we need to convert it to | |
917 | + // BGRx to match color format expected by WebRTC. | |
918 | +#if PW_CHECK_VERSION(0, 3, 0) | |
919 | + if (spa_video_format_.format == SPA_VIDEO_FORMAT_RGBx || | |
920 | + spa_video_format_.format == SPA_VIDEO_FORMAT_RGBA) { | |
921 | +#else | |
922 | + if (spa_video_format_->format == pw_type_->video_format.RGBx || | |
923 | + spa_video_format_->format == pw_type_->video_format.RGBA) { | |
924 | +#endif | |
925 | + ConvertRGBxToBGRx(dst, dst_stride); | |
926 | + } | |
927 | + src += src_stride - x_offset; | |
928 | + dst += dst_stride; | |
929 | } | |
930 | } | |
931 | ||
932 | @@ -441,14 +898,13 @@ void BaseCapturerPipeWire::OnProxyRequested(GObject* /*object*/, | |
933 | BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(user_data); | |
934 | RTC_DCHECK(that); | |
935 | ||
936 | - GError* error = nullptr; | |
937 | - GDBusProxy *proxy = g_dbus_proxy_new_finish(result, &error); | |
938 | + Scoped<GError> error; | |
939 | + GDBusProxy* proxy = g_dbus_proxy_new_finish(result, error.receive()); | |
940 | if (!proxy) { | |
941 | - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) | |
942 | + if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED)) | |
943 | return; | |
944 | RTC_LOG(LS_ERROR) << "Failed to create a proxy for the screen cast portal: " | |
945 | << error->message; | |
946 | - g_error_free(error); | |
947 | that->portal_init_failed_ = true; | |
948 | return; | |
949 | } | |
950 | @@ -462,38 +918,36 @@ void BaseCapturerPipeWire::OnProxyRequested(GObject* /*object*/, | |
951 | // static | |
952 | gchar* BaseCapturerPipeWire::PrepareSignalHandle(GDBusConnection* connection, | |
953 | const gchar* token) { | |
954 | - gchar* sender = g_strdup(g_dbus_connection_get_unique_name(connection) + 1); | |
955 | - for (int i = 0; sender[i]; i++) { | |
956 | - if (sender[i] == '.') { | |
957 | - sender[i] = '_'; | |
958 | + Scoped<gchar> sender( | |
959 | + g_strdup(g_dbus_connection_get_unique_name(connection) + 1)); | |
960 | + for (int i = 0; sender.get()[i]; i++) { | |
961 | + if (sender.get()[i] == '.') { | |
962 | + sender.get()[i] = '_'; | |
963 | } | |
964 | } | |
965 | ||
966 | - gchar* handle = g_strconcat(kDesktopRequestObjectPath, "/", sender, "/", | |
967 | + gchar* handle = g_strconcat(kDesktopRequestObjectPath, "/", sender.get(), "/", | |
968 | token, /*end of varargs*/ nullptr); | |
969 | - g_free(sender); | |
970 | ||
971 | return handle; | |
972 | } | |
973 | ||
974 | void BaseCapturerPipeWire::SessionRequest() { | |
975 | GVariantBuilder builder; | |
976 | - gchar* variant_string; | |
977 | + Scoped<gchar> variant_string; | |
978 | ||
979 | g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); | |
980 | variant_string = | |
981 | g_strdup_printf("webrtc_session%d", g_random_int_range(0, G_MAXINT)); | |
982 | g_variant_builder_add(&builder, "{sv}", "session_handle_token", | |
983 | - g_variant_new_string(variant_string)); | |
984 | - g_free(variant_string); | |
985 | + g_variant_new_string(variant_string.get())); | |
986 | variant_string = g_strdup_printf("webrtc%d", g_random_int_range(0, G_MAXINT)); | |
987 | g_variant_builder_add(&builder, "{sv}", "handle_token", | |
988 | - g_variant_new_string(variant_string)); | |
989 | + g_variant_new_string(variant_string.get())); | |
990 | ||
991 | - portal_handle_ = PrepareSignalHandle(connection_, variant_string); | |
992 | + portal_handle_ = PrepareSignalHandle(connection_, variant_string.get()); | |
993 | session_request_signal_id_ = SetupRequestResponseSignal( | |
994 | portal_handle_, OnSessionRequestResponseSignal); | |
995 | - g_free(variant_string); | |
996 | ||
997 | RTC_LOG(LS_INFO) << "Screen cast session requested."; | |
998 | g_dbus_proxy_call( | |
999 | @@ -509,22 +963,21 @@ void BaseCapturerPipeWire::OnSessionRequested(GDBusProxy *proxy, | |
1000 | BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(user_data); | |
1001 | RTC_DCHECK(that); | |
1002 | ||
1003 | - GError* error = nullptr; | |
1004 | - GVariant* variant = g_dbus_proxy_call_finish(proxy, result, &error); | |
1005 | + Scoped<GError> error; | |
1006 | + Scoped<GVariant> variant( | |
1007 | + g_dbus_proxy_call_finish(proxy, result, error.receive())); | |
1008 | if (!variant) { | |
1009 | - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) | |
1010 | + if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED)) | |
1011 | return; | |
1012 | RTC_LOG(LS_ERROR) << "Failed to create a screen cast session: " | |
1013 | << error->message; | |
1014 | - g_error_free(error); | |
1015 | that->portal_init_failed_ = true; | |
1016 | return; | |
1017 | } | |
1018 | RTC_LOG(LS_INFO) << "Initializing the screen cast session."; | |
1019 | ||
1020 | - gchar* handle = nullptr; | |
1021 | - g_variant_get_child(variant, 0, "o", &handle); | |
1022 | - g_variant_unref(variant); | |
1023 | + Scoped<gchar> handle; | |
1024 | + g_variant_get_child(variant.get(), 0, "o", &handle); | |
1025 | if (!handle) { | |
1026 | RTC_LOG(LS_ERROR) << "Failed to initialize the screen cast session."; | |
1027 | if (that->session_request_signal_id_) { | |
1028 | @@ -536,8 +989,6 @@ void BaseCapturerPipeWire::OnSessionRequested(GDBusProxy *proxy, | |
1029 | return; | |
1030 | } | |
1031 | ||
1032 | - g_free(handle); | |
1033 | - | |
1034 | RTC_LOG(LS_INFO) << "Subscribing to the screen cast session."; | |
1035 | } | |
1036 | ||
1037 | @@ -557,11 +1008,11 @@ void BaseCapturerPipeWire::OnSessionRequestResponseSignal( | |
1038 | << "Received response for the screen cast session subscription."; | |
1039 | ||
1040 | guint32 portal_response; | |
1041 | - GVariant* response_data; | |
1042 | - g_variant_get(parameters, "(u@a{sv})", &portal_response, &response_data); | |
1043 | - g_variant_lookup(response_data, "session_handle", "s", | |
1044 | + Scoped<GVariant> response_data; | |
1045 | + g_variant_get(parameters, "(u@a{sv})", &portal_response, | |
1046 | + response_data.receive()); | |
1047 | + g_variant_lookup(response_data.get(), "session_handle", "s", | |
1048 | &that->session_handle_); | |
1049 | - g_variant_unref(response_data); | |
1050 | ||
1051 | if (!that->session_handle_ || portal_response) { | |
1052 | RTC_LOG(LS_ERROR) | |
1053 | @@ -575,23 +1026,23 @@ void BaseCapturerPipeWire::OnSessionRequestResponseSignal( | |
1054 | ||
1055 | void BaseCapturerPipeWire::SourcesRequest() { | |
1056 | GVariantBuilder builder; | |
1057 | - gchar* variant_string; | |
1058 | + Scoped<gchar> variant_string; | |
1059 | ||
1060 | g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); | |
1061 | // We want to record monitor content. | |
1062 | - g_variant_builder_add(&builder, "{sv}", "types", | |
1063 | - g_variant_new_uint32(capture_source_type_)); | |
1064 | + g_variant_builder_add( | |
1065 | + &builder, "{sv}", "types", | |
1066 | + g_variant_new_uint32(static_cast<uint32_t>(capture_source_type_))); | |
1067 | // We don't want to allow selection of multiple sources. | |
1068 | g_variant_builder_add(&builder, "{sv}", "multiple", | |
1069 | g_variant_new_boolean(false)); | |
1070 | variant_string = g_strdup_printf("webrtc%d", g_random_int_range(0, G_MAXINT)); | |
1071 | g_variant_builder_add(&builder, "{sv}", "handle_token", | |
1072 | - g_variant_new_string(variant_string)); | |
1073 | + g_variant_new_string(variant_string.get())); | |
1074 | ||
1075 | - sources_handle_ = PrepareSignalHandle(connection_, variant_string); | |
1076 | + sources_handle_ = PrepareSignalHandle(connection_, variant_string.get()); | |
1077 | sources_request_signal_id_ = SetupRequestResponseSignal( | |
1078 | sources_handle_, OnSourcesRequestResponseSignal); | |
1079 | - g_free(variant_string); | |
1080 | ||
1081 | RTC_LOG(LS_INFO) << "Requesting sources from the screen cast session."; | |
1082 | g_dbus_proxy_call( | |
1083 | @@ -608,22 +1059,21 @@ void BaseCapturerPipeWire::OnSourcesRequested(GDBusProxy *proxy, | |
1084 | BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(user_data); | |
1085 | RTC_DCHECK(that); | |
1086 | ||
1087 | - GError* error = nullptr; | |
1088 | - GVariant* variant = g_dbus_proxy_call_finish(proxy, result, &error); | |
1089 | + Scoped<GError> error; | |
1090 | + Scoped<GVariant> variant( | |
1091 | + g_dbus_proxy_call_finish(proxy, result, error.receive())); | |
1092 | if (!variant) { | |
1093 | - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) | |
1094 | + if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED)) | |
1095 | return; | |
1096 | RTC_LOG(LS_ERROR) << "Failed to request the sources: " << error->message; | |
1097 | - g_error_free(error); | |
1098 | that->portal_init_failed_ = true; | |
1099 | return; | |
1100 | } | |
1101 | ||
1102 | RTC_LOG(LS_INFO) << "Sources requested from the screen cast session."; | |
1103 | ||
1104 | - gchar* handle = nullptr; | |
1105 | - g_variant_get_child(variant, 0, "o", &handle); | |
1106 | - g_variant_unref(variant); | |
1107 | + Scoped<gchar> handle; | |
1108 | + g_variant_get_child(variant.get(), 0, "o", handle.receive()); | |
1109 | if (!handle) { | |
1110 | RTC_LOG(LS_ERROR) << "Failed to initialize the screen cast session."; | |
1111 | if (that->sources_request_signal_id_) { | |
1112 | @@ -635,8 +1085,6 @@ void BaseCapturerPipeWire::OnSourcesRequested(GDBusProxy *proxy, | |
1113 | return; | |
1114 | } | |
1115 | ||
1116 | - g_free(handle); | |
1117 | - | |
1118 | RTC_LOG(LS_INFO) << "Subscribed to sources signal."; | |
1119 | } | |
1120 | ||
1121 | @@ -668,17 +1116,16 @@ void BaseCapturerPipeWire::OnSourcesRequestResponseSignal( | |
1122 | ||
1123 | void BaseCapturerPipeWire::StartRequest() { | |
1124 | GVariantBuilder builder; | |
1125 | - gchar* variant_string; | |
1126 | + Scoped<gchar> variant_string; | |
1127 | ||
1128 | g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); | |
1129 | variant_string = g_strdup_printf("webrtc%d", g_random_int_range(0, G_MAXINT)); | |
1130 | g_variant_builder_add(&builder, "{sv}", "handle_token", | |
1131 | - g_variant_new_string(variant_string)); | |
1132 | + g_variant_new_string(variant_string.get())); | |
1133 | ||
1134 | - start_handle_ = PrepareSignalHandle(connection_, variant_string); | |
1135 | + start_handle_ = PrepareSignalHandle(connection_, variant_string.get()); | |
1136 | start_request_signal_id_ = | |
1137 | SetupRequestResponseSignal(start_handle_, OnStartRequestResponseSignal); | |
1138 | - g_free(variant_string); | |
1139 | ||
1140 | // "Identifier for the application window", this is Wayland, so not "x11:...". | |
1141 | const gchar parent_window[] = ""; | |
1142 | @@ -698,23 +1145,22 @@ void BaseCapturerPipeWire::OnStartRequested(GDBusProxy *proxy, | |
1143 | BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(user_data); | |
1144 | RTC_DCHECK(that); | |
1145 | ||
1146 | - GError* error = nullptr; | |
1147 | - GVariant* variant = g_dbus_proxy_call_finish(proxy, result, &error); | |
1148 | + Scoped<GError> error; | |
1149 | + Scoped<GVariant> variant( | |
1150 | + g_dbus_proxy_call_finish(proxy, result, error.receive())); | |
1151 | if (!variant) { | |
1152 | - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) | |
1153 | + if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED)) | |
1154 | return; | |
1155 | RTC_LOG(LS_ERROR) << "Failed to start the screen cast session: " | |
1156 | << error->message; | |
1157 | - g_error_free(error); | |
1158 | that->portal_init_failed_ = true; | |
1159 | return; | |
1160 | } | |
1161 | ||
1162 | RTC_LOG(LS_INFO) << "Initializing the start of the screen cast session."; | |
1163 | ||
1164 | - gchar* handle = nullptr; | |
1165 | - g_variant_get_child(variant, 0, "o", &handle); | |
1166 | - g_variant_unref(variant); | |
1167 | + Scoped<gchar> handle; | |
1168 | + g_variant_get_child(variant.get(), 0, "o", handle.receive()); | |
1169 | if (!handle) { | |
1170 | RTC_LOG(LS_ERROR) | |
1171 | << "Failed to initialize the start of the screen cast session."; | |
1172 | @@ -727,8 +1173,6 @@ void BaseCapturerPipeWire::OnStartRequested(GDBusProxy *proxy, | |
1173 | return; | |
1174 | } | |
1175 | ||
1176 | - g_free(handle); | |
1177 | - | |
1178 | RTC_LOG(LS_INFO) << "Subscribed to the start signal."; | |
1179 | } | |
1180 | ||
1181 | @@ -746,9 +1190,10 @@ void BaseCapturerPipeWire::OnStartRequestResponseSignal( | |
1182 | ||
1183 | RTC_LOG(LS_INFO) << "Start signal received."; | |
1184 | guint32 portal_response; | |
1185 | - GVariant* response_data; | |
1186 | - GVariantIter* iter = nullptr; | |
1187 | - g_variant_get(parameters, "(u@a{sv})", &portal_response, &response_data); | |
1188 | + Scoped<GVariant> response_data; | |
1189 | + Scoped<GVariantIter> iter; | |
1190 | + g_variant_get(parameters, "(u@a{sv})", &portal_response, | |
1191 | + response_data.receive()); | |
1192 | if (portal_response || !response_data) { | |
1193 | RTC_LOG(LS_ERROR) << "Failed to start the screen cast session."; | |
1194 | that->portal_init_failed_ = true; | |
1195 | @@ -758,28 +1203,28 @@ void BaseCapturerPipeWire::OnStartRequestResponseSignal( | |
1196 | // Array of PipeWire streams. See | |
1197 | // https://github.com/flatpak/xdg-desktop-portal/blob/master/data/org.freedesktop.portal.ScreenCast.xml | |
1198 | // documentation for <method name="Start">. | |
1199 | - if (g_variant_lookup(response_data, "streams", "a(ua{sv})", &iter)) { | |
1200 | - GVariant* variant; | |
1201 | + if (g_variant_lookup(response_data.get(), "streams", "a(ua{sv})", | |
1202 | + iter.receive())) { | |
1203 | + Scoped<GVariant> variant; | |
1204 | ||
1205 | - while (g_variant_iter_next(iter, "@(ua{sv})", &variant)) { | |
1206 | + while (g_variant_iter_next(iter.get(), "@(ua{sv})", variant.receive())) { | |
1207 | guint32 stream_id; | |
1208 | - gint32 width; | |
1209 | - gint32 height; | |
1210 | - GVariant* options; | |
1211 | + guint32 type; | |
1212 | + Scoped<GVariant> options; | |
1213 | ||
1214 | - g_variant_get(variant, "(u@a{sv})", &stream_id, &options); | |
1215 | - RTC_DCHECK(options != nullptr); | |
1216 | + g_variant_get(variant.get(), "(u@a{sv})", &stream_id, options.receive()); | |
1217 | + RTC_DCHECK(options.get()); | |
1218 | ||
1219 | - g_variant_lookup(options, "size", "(ii)", &width, &height); | |
1220 | + if (g_variant_lookup(options.get(), "source_type", "u", &type)) { | |
1221 | + that->capture_source_type_ = | |
1222 | + static_cast<BaseCapturerPipeWire::CaptureSourceType>(type); | |
1223 | + } | |
1224 | ||
1225 | - that->desktop_size_.set(width, height); | |
1226 | + that->pw_stream_node_id_ = stream_id; | |
1227 | ||
1228 | - g_variant_unref(options); | |
1229 | - g_variant_unref(variant); | |
1230 | + break; | |
1231 | } | |
1232 | } | |
1233 | - g_variant_iter_free(iter); | |
1234 | - g_variant_unref(response_data); | |
1235 | ||
1236 | that->OpenPipeWireRemote(); | |
1237 | } | |
1238 | @@ -807,35 +1252,30 @@ void BaseCapturerPipeWire::OnOpenPipeWireRemoteRequested( | |
1239 | BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(user_data); | |
1240 | RTC_DCHECK(that); | |
1241 | ||
1242 | - GError* error = nullptr; | |
1243 | - GUnixFDList* outlist = nullptr; | |
1244 | - GVariant* variant = g_dbus_proxy_call_with_unix_fd_list_finish( | |
1245 | - proxy, &outlist, result, &error); | |
1246 | + Scoped<GError> error; | |
1247 | + Scoped<GUnixFDList> outlist; | |
1248 | + Scoped<GVariant> variant(g_dbus_proxy_call_with_unix_fd_list_finish( | |
1249 | + proxy, outlist.receive(), result, error.receive())); | |
1250 | if (!variant) { | |
1251 | - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) | |
1252 | + if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED)) | |
1253 | return; | |
1254 | RTC_LOG(LS_ERROR) << "Failed to open the PipeWire remote: " | |
1255 | << error->message; | |
1256 | - g_error_free(error); | |
1257 | that->portal_init_failed_ = true; | |
1258 | return; | |
1259 | } | |
1260 | ||
1261 | gint32 index; | |
1262 | - g_variant_get(variant, "(h)", &index); | |
1263 | + g_variant_get(variant.get(), "(h)", &index); | |
1264 | ||
1265 | - if ((that->pw_fd_ = g_unix_fd_list_get(outlist, index, &error)) == -1) { | |
1266 | + if ((that->pw_fd_ = | |
1267 | + g_unix_fd_list_get(outlist.get(), index, error.receive())) == -1) { | |
1268 | RTC_LOG(LS_ERROR) << "Failed to get file descriptor from the list: " | |
1269 | << error->message; | |
1270 | - g_error_free(error); | |
1271 | - g_variant_unref(variant); | |
1272 | that->portal_init_failed_ = true; | |
1273 | return; | |
1274 | } | |
1275 | ||
1276 | - g_variant_unref(variant); | |
1277 | - g_object_unref(outlist); | |
1278 | - | |
1279 | that->InitPipeWire(); | |
1280 | } | |
1281 | ||
1282 | @@ -854,15 +1294,18 @@ void BaseCapturerPipeWire::CaptureFrame() { | |
1283 | return; | |
1284 | } | |
1285 | ||
1286 | + webrtc::MutexLock lock(¤t_frame_lock_); | |
1287 | if (!current_frame_) { | |
1288 | callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr); | |
1289 | return; | |
1290 | } | |
1291 | ||
1292 | - std::unique_ptr<DesktopFrame> result(new BasicDesktopFrame(desktop_size_)); | |
1293 | + DesktopSize frame_size = video_size_; | |
1294 | + | |
1295 | + std::unique_ptr<DesktopFrame> result(new BasicDesktopFrame(frame_size)); | |
1296 | result->CopyPixelsFrom( | |
1297 | - current_frame_, (desktop_size_.width() * kBytesPerPixel), | |
1298 | - DesktopRect::MakeWH(desktop_size_.width(), desktop_size_.height())); | |
1299 | + current_frame_.get(), (frame_size.width() * kBytesPerPixel), | |
1300 | + DesktopRect::MakeWH(frame_size.width(), frame_size.height())); | |
1301 | if (!result) { | |
1302 | callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr); | |
1303 | return; | |
1304 | @@ -887,4 +1330,11 @@ bool BaseCapturerPipeWire::SelectSource(SourceId id) { | |
1305 | return true; | |
1306 | } | |
1307 | ||
1308 | +// static | |
1309 | +std::unique_ptr<DesktopCapturer> BaseCapturerPipeWire::CreateRawCapturer( | |
1310 | + const DesktopCaptureOptions& options) { | |
1311 | + return std::make_unique<BaseCapturerPipeWire>( | |
1312 | + BaseCapturerPipeWire::CaptureSourceType::kAny); | |
1313 | +} | |
1314 | + | |
1315 | } // namespace webrtc | |
1316 | diff --git a/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h b/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h | |
1317 | index f28d7a558bc..75d20dbf1db 100644 | |
1318 | --- a/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h | |
1319 | +++ b/chromium/third_party/webrtc/modules/desktop_capture/linux/base_capturer_pipewire.h | |
1320 | @@ -10,18 +10,23 @@ | |
1321 | ||
1322 | #ifndef MODULES_DESKTOP_CAPTURE_LINUX_BASE_CAPTURER_PIPEWIRE_H_ | |
1323 | #define MODULES_DESKTOP_CAPTURE_LINUX_BASE_CAPTURER_PIPEWIRE_H_ | |
1324 | - | |
1325 | #include <gio/gio.h> | |
1326 | #define typeof __typeof__ | |
1327 | #include <pipewire/pipewire.h> | |
1328 | #include <spa/param/video/format-utils.h> | |
1329 | +#if PW_CHECK_VERSION(0, 3, 0) | |
1330 | +#include <spa/utils/result.h> | |
1331 | +#endif | |
1332 | ||
1333 | +#include "absl/types/optional.h" | |
1334 | #include "modules/desktop_capture/desktop_capture_options.h" | |
1335 | #include "modules/desktop_capture/desktop_capturer.h" | |
1336 | #include "rtc_base/constructor_magic.h" | |
1337 | +#include "rtc_base/synchronization/mutex.h" | |
1338 | ||
1339 | namespace webrtc { | |
1340 | ||
1341 | +#if !PW_CHECK_VERSION(0, 3, 0) | |
1342 | class PipeWireType { | |
1343 | public: | |
1344 | spa_type_media_type media_type; | |
1345 | @@ -29,14 +34,25 @@ class PipeWireType { | |
1346 | spa_type_format_video format_video; | |
1347 | spa_type_video_format video_format; | |
1348 | }; | |
1349 | +#endif | |
1350 | ||
1351 | class BaseCapturerPipeWire : public DesktopCapturer { | |
1352 | public: | |
1353 | - enum CaptureSourceType { Screen = 1, Window }; | |
1354 | + // Values are set based on source type property in | |
1355 | + // xdg-desktop-portal/screencast | |
1356 | + // https://github.com/flatpak/xdg-desktop-portal/blob/master/data/org.freedesktop.portal.ScreenCast.xml | |
1357 | + enum class CaptureSourceType : uint32_t { | |
1358 | + kScreen = 0b01, | |
1359 | + kWindow = 0b10, | |
1360 | + kAny = 0b11 | |
1361 | + }; | |
1362 | ||
1363 | explicit BaseCapturerPipeWire(CaptureSourceType source_type); | |
1364 | ~BaseCapturerPipeWire() override; | |
1365 | ||
1366 | + static std::unique_ptr<DesktopCapturer> CreateRawCapturer( | |
1367 | + const DesktopCaptureOptions& options); | |
1368 | + | |
1369 | // DesktopCapturer interface. | |
1370 | void Start(Callback* delegate) override; | |
1371 | void CaptureFrame() override; | |
1372 | @@ -45,6 +61,21 @@ class BaseCapturerPipeWire : public DesktopCapturer { | |
1373 | ||
1374 | private: | |
1375 | // PipeWire types --> | |
1376 | +#if PW_CHECK_VERSION(0, 3, 0) | |
1377 | + struct pw_context* pw_context_ = nullptr; | |
1378 | + struct pw_core* pw_core_ = nullptr; | |
1379 | + struct pw_stream* pw_stream_ = nullptr; | |
1380 | + struct pw_thread_loop* pw_main_loop_ = nullptr; | |
1381 | + | |
1382 | + spa_hook spa_core_listener_; | |
1383 | + spa_hook spa_stream_listener_; | |
1384 | + | |
1385 | + // event handlers | |
1386 | + pw_core_events pw_core_events_ = {}; | |
1387 | + pw_stream_events pw_stream_events_ = {}; | |
1388 | + | |
1389 | + struct spa_video_info_raw spa_video_format_; | |
1390 | +#else | |
1391 | pw_core* pw_core_ = nullptr; | |
1392 | pw_type* pw_core_type_ = nullptr; | |
1393 | pw_stream* pw_stream_ = nullptr; | |
1394 | @@ -60,11 +91,13 @@ class BaseCapturerPipeWire : public DesktopCapturer { | |
1395 | pw_remote_events pw_remote_events_ = {}; | |
1396 | ||
1397 | spa_video_info_raw* spa_video_format_ = nullptr; | |
1398 | +#endif | |
1399 | ||
1400 | + guint32 pw_stream_node_id_ = 0; | |
1401 | gint32 pw_fd_ = -1; | |
1402 | ||
1403 | CaptureSourceType capture_source_type_ = | |
1404 | - BaseCapturerPipeWire::CaptureSourceType::Screen; | |
1405 | + BaseCapturerPipeWire::CaptureSourceType::kScreen; | |
1406 | ||
1407 | // <-- end of PipeWire types | |
1408 | ||
1409 | @@ -79,10 +112,12 @@ class BaseCapturerPipeWire : public DesktopCapturer { | |
1410 | guint sources_request_signal_id_ = 0; | |
1411 | guint start_request_signal_id_ = 0; | |
1412 | ||
1413 | + DesktopSize video_size_; | |
1414 | DesktopSize desktop_size_ = {}; | |
1415 | DesktopCaptureOptions options_ = {}; | |
1416 | ||
1417 | - uint8_t* current_frame_ = nullptr; | |
1418 | + webrtc::Mutex current_frame_lock_; | |
1419 | + std::unique_ptr<uint8_t[]> current_frame_; | |
1420 | Callback* callback_ = nullptr; | |
1421 | ||
1422 | bool portal_init_failed_ = false; | |
1423 | @@ -91,21 +126,32 @@ class BaseCapturerPipeWire : public DesktopCapturer { | |
1424 | void InitPipeWire(); | |
1425 | void InitPipeWireTypes(); | |
1426 | ||
1427 | - void CreateReceivingStream(); | |
1428 | + pw_stream* CreateReceivingStream(); | |
1429 | void HandleBuffer(pw_buffer* buffer); | |
1430 | ||
1431 | void ConvertRGBxToBGRx(uint8_t* frame, uint32_t size); | |
1432 | ||
1433 | +#if PW_CHECK_VERSION(0, 3, 0) | |
1434 | + static void OnCoreError(void* data, | |
1435 | + uint32_t id, | |
1436 | + int seq, | |
1437 | + int res, | |
1438 | + const char* message); | |
1439 | + static void OnStreamParamChanged(void* data, | |
1440 | + uint32_t id, | |
1441 | + const struct spa_pod* format); | |
1442 | +#else | |
1443 | static void OnStateChanged(void* data, | |
1444 | pw_remote_state old_state, | |
1445 | pw_remote_state state, | |
1446 | const char* error); | |
1447 | + static void OnStreamFormatChanged(void* data, const struct spa_pod* format); | |
1448 | +#endif | |
1449 | static void OnStreamStateChanged(void* data, | |
1450 | pw_stream_state old_state, | |
1451 | pw_stream_state state, | |
1452 | const char* error_message); | |
1453 | ||
1454 | - static void OnStreamFormatChanged(void* data, const struct spa_pod* format); | |
1455 | static void OnStreamProcess(void* data); | |
1456 | static void OnNewBuffer(void* data, uint32_t id); | |
1457 | ||
1458 | diff --git a/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire.sigs b/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire.sigs | |
1459 | deleted file mode 100644 | |
1460 | index 3e21e9dc07c..00000000000 | |
1461 | --- a/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire.sigs | |
1462 | +++ /dev/null | |
1463 | @@ -1,44 +0,0 @@ | |
1464 | -// Copyright 2018 The WebRTC project authors. All rights reserved. | |
1465 | -// Use of this source code is governed by a BSD-style license that can be | |
1466 | -// found in the LICENSE file. | |
1467 | - | |
1468 | -//------------------------------------------------ | |
1469 | -// Functions from PipeWire used in capturer code. | |
1470 | -//------------------------------------------------ | |
1471 | - | |
1472 | -// core.h | |
1473 | -void pw_core_destroy(pw_core *core); | |
1474 | -pw_type *pw_core_get_type(pw_core *core); | |
1475 | -pw_core * pw_core_new(pw_loop *main_loop, pw_properties *props); | |
1476 | - | |
1477 | -// loop.h | |
1478 | -void pw_loop_destroy(pw_loop *loop); | |
1479 | -pw_loop * pw_loop_new(pw_properties *properties); | |
1480 | - | |
1481 | -// pipewire.h | |
1482 | -void pw_init(int *argc, char **argv[]); | |
1483 | - | |
1484 | -// properties.h | |
1485 | -pw_properties * pw_properties_new_string(const char *args); | |
1486 | - | |
1487 | -// remote.h | |
1488 | -void pw_remote_add_listener(pw_remote *remote, spa_hook *listener, const pw_remote_events *events, void *data); | |
1489 | -int pw_remote_connect_fd(pw_remote *remote, int fd); | |
1490 | -void pw_remote_destroy(pw_remote *remote); | |
1491 | -pw_remote * pw_remote_new(pw_core *core, pw_properties *properties, size_t user_data_size); | |
1492 | - | |
1493 | -// stream.h | |
1494 | -void pw_stream_add_listener(pw_stream *stream, spa_hook *listener, const pw_stream_events *events, void *data); | |
1495 | -int pw_stream_connect(pw_stream *stream, enum pw_direction direction, const char *port_path, enum pw_stream_flags flags, const spa_pod **params, uint32_t n_params); | |
1496 | -pw_buffer *pw_stream_dequeue_buffer(pw_stream *stream); | |
1497 | -void pw_stream_destroy(pw_stream *stream); | |
1498 | -void pw_stream_finish_format(pw_stream *stream, int res, const spa_pod **params, uint32_t n_params); | |
1499 | -pw_stream * pw_stream_new(pw_remote *remote, const char *name, pw_properties *props); | |
1500 | -int pw_stream_queue_buffer(pw_stream *stream, pw_buffer *buffer); | |
1501 | -int pw_stream_set_active(pw_stream *stream, bool active); | |
1502 | - | |
1503 | -// thread-loop.h | |
1504 | -void pw_thread_loop_destroy(pw_thread_loop *loop); | |
1505 | -pw_thread_loop * pw_thread_loop_new(pw_loop *loop, const char *name); | |
1506 | -int pw_thread_loop_start(pw_thread_loop *loop); | |
1507 | -void pw_thread_loop_stop(pw_thread_loop *loop); | |
1508 | diff --git a/chromium/third_party/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.cc b/chromium/third_party/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.cc | |
1509 | deleted file mode 100644 | |
1510 | index fe672140cca..00000000000 | |
1511 | --- a/chromium/third_party/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.cc | |
1512 | +++ /dev/null | |
1513 | @@ -1,29 +0,0 @@ | |
1514 | -/* | |
1515 | - * Copyright 2018 The WebRTC project authors. All Rights Reserved. | |
1516 | - * | |
1517 | - * Use of this source code is governed by a BSD-style license | |
1518 | - * that can be found in the LICENSE file in the root of the source | |
1519 | - * tree. An additional intellectual property rights grant can be found | |
1520 | - * in the file PATENTS. All contributing project authors may | |
1521 | - * be found in the AUTHORS file in the root of the source tree. | |
1522 | - */ | |
1523 | - | |
1524 | -#include "modules/desktop_capture/linux/screen_capturer_pipewire.h" | |
1525 | - | |
1526 | -#include <memory> | |
1527 | - | |
1528 | - | |
1529 | -namespace webrtc { | |
1530 | - | |
1531 | -ScreenCapturerPipeWire::ScreenCapturerPipeWire() | |
1532 | - : BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::Screen) {} | |
1533 | -ScreenCapturerPipeWire::~ScreenCapturerPipeWire() {} | |
1534 | - | |
1535 | -// static | |
1536 | -std::unique_ptr<DesktopCapturer> | |
1537 | -ScreenCapturerPipeWire::CreateRawScreenCapturer( | |
1538 | - const DesktopCaptureOptions& options) { | |
1539 | - return std::make_unique<ScreenCapturerPipeWire>(); | |
1540 | -} | |
1541 | - | |
1542 | -} // namespace webrtc | |
1543 | diff --git a/chromium/third_party/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.h b/chromium/third_party/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.h | |
1544 | deleted file mode 100644 | |
1545 | index 66dcd680e06..00000000000 | |
1546 | --- a/chromium/third_party/webrtc/modules/desktop_capture/linux/screen_capturer_pipewire.h | |
1547 | +++ /dev/null | |
1548 | @@ -1,33 +0,0 @@ | |
1549 | -/* | |
1550 | - * Copyright 2018 The WebRTC project authors. All Rights Reserved. | |
1551 | - * | |
1552 | - * Use of this source code is governed by a BSD-style license | |
1553 | - * that can be found in the LICENSE file in the root of the source | |
1554 | - * tree. An additional intellectual property rights grant can be found | |
1555 | - * in the file PATENTS. All contributing project authors may | |
1556 | - * be found in the AUTHORS file in the root of the source tree. | |
1557 | - */ | |
1558 | - | |
1559 | -#ifndef MODULES_DESKTOP_CAPTURE_LINUX_SCREEN_CAPTURER_PIPEWIRE_H_ | |
1560 | -#define MODULES_DESKTOP_CAPTURE_LINUX_SCREEN_CAPTURER_PIPEWIRE_H_ | |
1561 | - | |
1562 | -#include <memory> | |
1563 | - | |
1564 | -#include "modules/desktop_capture/linux/base_capturer_pipewire.h" | |
1565 | - | |
1566 | -namespace webrtc { | |
1567 | - | |
1568 | -class ScreenCapturerPipeWire : public BaseCapturerPipeWire { | |
1569 | - public: | |
1570 | - ScreenCapturerPipeWire(); | |
1571 | - ~ScreenCapturerPipeWire() override; | |
1572 | - | |
1573 | - static std::unique_ptr<DesktopCapturer> CreateRawScreenCapturer( | |
1574 | - const DesktopCaptureOptions& options); | |
1575 | - | |
1576 | - RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerPipeWire); | |
1577 | -}; | |
1578 | - | |
1579 | -} // namespace webrtc | |
1580 | - | |
1581 | -#endif // MODULES_DESKTOP_CAPTURE_LINUX_SCREEN_CAPTURER_PIPEWIRE_H_ | |
1582 | diff --git a/chromium/third_party/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.cc b/chromium/third_party/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.cc | |
1583 | deleted file mode 100644 | |
1584 | index b4559156dce..00000000000 | |
1585 | --- a/chromium/third_party/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.cc | |
1586 | +++ /dev/null | |
1587 | @@ -1,29 +0,0 @@ | |
1588 | -/* | |
1589 | - * Copyright 2018 The WebRTC project authors. All Rights Reserved. | |
1590 | - * | |
1591 | - * Use of this source code is governed by a BSD-style license | |
1592 | - * that can be found in the LICENSE file in the root of the source | |
1593 | - * tree. An additional intellectual property rights grant can be found | |
1594 | - * in the file PATENTS. All contributing project authors may | |
1595 | - * be found in the AUTHORS file in the root of the source tree. | |
1596 | - */ | |
1597 | - | |
1598 | -#include "modules/desktop_capture/linux/window_capturer_pipewire.h" | |
1599 | - | |
1600 | -#include <memory> | |
1601 | - | |
1602 | - | |
1603 | -namespace webrtc { | |
1604 | - | |
1605 | -WindowCapturerPipeWire::WindowCapturerPipeWire() | |
1606 | - : BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::Window) {} | |
1607 | -WindowCapturerPipeWire::~WindowCapturerPipeWire() {} | |
1608 | - | |
1609 | -// static | |
1610 | -std::unique_ptr<DesktopCapturer> | |
1611 | -WindowCapturerPipeWire::CreateRawWindowCapturer( | |
1612 | - const DesktopCaptureOptions& options) { | |
1613 | - return std::make_unique<WindowCapturerPipeWire>(); | |
1614 | -} | |
1615 | - | |
1616 | -} // namespace webrtc | |
1617 | diff --git a/chromium/third_party/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.h b/chromium/third_party/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.h | |
1618 | deleted file mode 100644 | |
1619 | index 7f184ef2999..00000000000 | |
1620 | --- a/chromium/third_party/webrtc/modules/desktop_capture/linux/window_capturer_pipewire.h | |
1621 | +++ /dev/null | |
1622 | @@ -1,33 +0,0 @@ | |
1623 | -/* | |
1624 | - * Copyright 2018 The WebRTC project authors. All Rights Reserved. | |
1625 | - * | |
1626 | - * Use of this source code is governed by a BSD-style license | |
1627 | - * that can be found in the LICENSE file in the root of the source | |
1628 | - * tree. An additional intellectual property rights grant can be found | |
1629 | - * in the file PATENTS. All contributing project authors may | |
1630 | - * be found in the AUTHORS file in the root of the source tree. | |
1631 | - */ | |
1632 | - | |
1633 | -#ifndef MODULES_DESKTOP_CAPTURE_LINUX_WINDOW_CAPTURER_PIPEWIRE_H_ | |
1634 | -#define MODULES_DESKTOP_CAPTURE_LINUX_WINDOW_CAPTURER_PIPEWIRE_H_ | |
1635 | - | |
1636 | -#include <memory> | |
1637 | - | |
1638 | -#include "modules/desktop_capture/linux/base_capturer_pipewire.h" | |
1639 | - | |
1640 | -namespace webrtc { | |
1641 | - | |
1642 | -class WindowCapturerPipeWire : public BaseCapturerPipeWire { | |
1643 | - public: | |
1644 | - WindowCapturerPipeWire(); | |
1645 | - ~WindowCapturerPipeWire() override; | |
1646 | - | |
1647 | - static std::unique_ptr<DesktopCapturer> CreateRawWindowCapturer( | |
1648 | - const DesktopCaptureOptions& options); | |
1649 | - | |
1650 | - RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerPipeWire); | |
1651 | -}; | |
1652 | - | |
1653 | -} // namespace webrtc | |
1654 | - | |
1655 | -#endif // MODULES_DESKTOP_CAPTURE_LINUX_WINDOW_CAPTURER_PIPEWIRE_H_ | |
1656 | diff --git a/chromium/third_party/webrtc/modules/desktop_capture/screen_capturer_linux.cc b/chromium/third_party/webrtc/modules/desktop_capture/screen_capturer_linux.cc | |
1657 | index 82dbae48137..ed48b7d6d59 100644 | |
1658 | --- a/chromium/third_party/webrtc/modules/desktop_capture/screen_capturer_linux.cc | |
1659 | +++ b/chromium/third_party/webrtc/modules/desktop_capture/screen_capturer_linux.cc | |
1660 | @@ -14,7 +14,7 @@ | |
1661 | #include "modules/desktop_capture/desktop_capturer.h" | |
1662 | ||
1663 | #if defined(WEBRTC_USE_PIPEWIRE) | |
1664 | -#include "modules/desktop_capture/linux/screen_capturer_pipewire.h" | |
1665 | +#include "modules/desktop_capture/linux/base_capturer_pipewire.h" | |
1666 | #endif // defined(WEBRTC_USE_PIPEWIRE) | |
1667 | ||
1668 | #if defined(WEBRTC_USE_X11) | |
1669 | @@ -28,7 +28,7 @@ std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawScreenCapturer( | |
1670 | const DesktopCaptureOptions& options) { | |
1671 | #if defined(WEBRTC_USE_PIPEWIRE) | |
1672 | if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) { | |
1673 | - return ScreenCapturerPipeWire::CreateRawScreenCapturer(options); | |
1674 | + return BaseCapturerPipeWire::CreateRawCapturer(options); | |
1675 | } | |
1676 | #endif // defined(WEBRTC_USE_PIPEWIRE) | |
1677 | ||
1678 | diff --git a/chromium/third_party/webrtc/modules/desktop_capture/window_capturer_linux.cc b/chromium/third_party/webrtc/modules/desktop_capture/window_capturer_linux.cc | |
1679 | index 41dbf836b03..2b142ae3b92 100644 | |
1680 | --- a/chromium/third_party/webrtc/modules/desktop_capture/window_capturer_linux.cc | |
1681 | +++ b/chromium/third_party/webrtc/modules/desktop_capture/window_capturer_linux.cc | |
1682 | @@ -14,7 +14,7 @@ | |
1683 | #include "modules/desktop_capture/desktop_capturer.h" | |
1684 | ||
1685 | #if defined(WEBRTC_USE_PIPEWIRE) | |
1686 | -#include "modules/desktop_capture/linux/window_capturer_pipewire.h" | |
1687 | +#include "modules/desktop_capture/linux/base_capturer_pipewire.h" | |
1688 | #endif // defined(WEBRTC_USE_PIPEWIRE) | |
1689 | ||
1690 | #if defined(WEBRTC_USE_X11) | |
1691 | @@ -28,7 +28,7 @@ std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawWindowCapturer( | |
1692 | const DesktopCaptureOptions& options) { | |
1693 | #if defined(WEBRTC_USE_PIPEWIRE) | |
1694 | if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) { | |
1695 | - return WindowCapturerPipeWire::CreateRawWindowCapturer(options); | |
1696 | + return BaseCapturerPipeWire::CreateRawCapturer(options); | |
1697 | } | |
1698 | #endif // defined(WEBRTC_USE_PIPEWIRE) | |
1699 | ||
1700 | diff --git a/chromium/third_party/webrtc/webrtc.gni b/chromium/third_party/webrtc/webrtc.gni | |
1701 | index ca8acdbf259..505c975cece 100644 | |
1702 | --- a/chromium/third_party/webrtc/webrtc.gni | |
1703 | +++ b/chromium/third_party/webrtc/webrtc.gni | |
1704 | @@ -117,6 +117,10 @@ declare_args() { | |
1705 | # Set this to link PipeWire directly instead of using the dlopen. | |
1706 | rtc_link_pipewire = false | |
1707 | ||
1708 | + # Set this to use certain PipeWire version | |
1709 | + # Currently we support PipeWire 0.2 (default) and PipeWire 0.3 | |
1710 | + rtc_pipewire_version = "0.3" | |
1711 | + | |
1712 | # Enable to use the Mozilla internal settings. | |
1713 | build_with_mozilla = false | |
1714 | ||
1715 | diff --git a/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire02.sigs b/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire02.sigs | |
1716 | new file mode 100644 | |
1717 | index 00000000000..5ac3d1d22b8 | |
1718 | --- /dev/null | |
1719 | +++ b/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire02.sigs | |
1720 | @@ -0,0 +1,47 @@ | |
1721 | +// Copyright 2018 The WebRTC project authors. All rights reserved. | |
1722 | +// Use of this source code is governed by a BSD-style license that can be | |
1723 | +// found in the LICENSE file. | |
1724 | + | |
1725 | +//------------------------------------------------ | |
1726 | +// Functions from PipeWire used in capturer code. | |
1727 | +//------------------------------------------------ | |
1728 | + | |
1729 | +// core.h | |
1730 | +void pw_core_destroy(pw_core *core); | |
1731 | +pw_type *pw_core_get_type(pw_core *core); | |
1732 | +pw_core * pw_core_new(pw_loop *main_loop, pw_properties *props); | |
1733 | + | |
1734 | +// loop.h | |
1735 | +void pw_loop_destroy(pw_loop *loop); | |
1736 | +pw_loop * pw_loop_new(pw_properties *properties); | |
1737 | + | |
1738 | +// pipewire.h | |
1739 | +void pw_init(int *argc, char **argv[]); | |
1740 | + | |
1741 | +// properties.h | |
1742 | +pw_properties * pw_properties_new_string(const char *args); | |
1743 | + | |
1744 | +// remote.h | |
1745 | +void pw_remote_add_listener(pw_remote *remote, spa_hook *listener, const pw_remote_events *events, void *data); | |
1746 | +int pw_remote_connect_fd(pw_remote *remote, int fd); | |
1747 | +void pw_remote_destroy(pw_remote *remote); | |
1748 | +pw_remote * pw_remote_new(pw_core *core, pw_properties *properties, size_t user_data_size); | |
1749 | +enum pw_remote_state pw_remote_get_state(pw_remote *remote, const char **error); | |
1750 | + | |
1751 | +// stream.h | |
1752 | +void pw_stream_add_listener(pw_stream *stream, spa_hook *listener, const pw_stream_events *events, void *data); | |
1753 | +int pw_stream_connect(pw_stream *stream, enum pw_direction direction, const char *port_path, enum pw_stream_flags flags, const spa_pod **params, uint32_t n_params); | |
1754 | +pw_buffer *pw_stream_dequeue_buffer(pw_stream *stream); | |
1755 | +void pw_stream_destroy(pw_stream *stream); | |
1756 | +void pw_stream_finish_format(pw_stream *stream, int res, const spa_pod **params, uint32_t n_params); | |
1757 | +pw_stream * pw_stream_new(pw_remote *remote, const char *name, pw_properties *props); | |
1758 | +int pw_stream_queue_buffer(pw_stream *stream, pw_buffer *buffer); | |
1759 | +int pw_stream_set_active(pw_stream *stream, bool active); | |
1760 | + | |
1761 | +// thread-loop.h | |
1762 | +void pw_thread_loop_destroy(pw_thread_loop *loop); | |
1763 | +pw_thread_loop * pw_thread_loop_new(pw_loop *loop, const char *name); | |
1764 | +int pw_thread_loop_start(pw_thread_loop *loop); | |
1765 | +void pw_thread_loop_stop(pw_thread_loop *loop); | |
1766 | +void pw_thread_loop_lock(struct pw_thread_loop *loop); | |
1767 | +void pw_thread_loop_unlock(struct pw_thread_loop *loop); | |
1768 | diff --git a/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire03.sigs b/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire03.sigs | |
1769 | new file mode 100644 | |
1770 | index 00000000000..78d241f40c6 | |
1771 | --- /dev/null | |
1772 | +++ b/chromium/third_party/webrtc/modules/desktop_capture/linux/pipewire03.sigs | |
1773 | @@ -0,0 +1,46 @@ | |
1774 | +// Copyright 2018 The WebRTC project authors. All rights reserved. | |
1775 | +// Use of this source code is governed by a BSD-style license that can be | |
1776 | +// found in the LICENSE file. | |
1777 | + | |
1778 | +//------------------------------------------------ | |
1779 | +// Functions from PipeWire used in capturer code. | |
1780 | +//------------------------------------------------ | |
1781 | + | |
1782 | +// core.h | |
1783 | +int pw_core_disconnect(pw_core *core); | |
1784 | + | |
1785 | +// loop.h | |
1786 | +void pw_loop_destroy(pw_loop *loop); | |
1787 | +pw_loop * pw_loop_new(const spa_dict *props); | |
1788 | + | |
1789 | + | |
1790 | +// pipewire.h | |
1791 | +void pw_init(int *argc, char **argv[]); | |
1792 | + | |
1793 | +// properties.h | |
1794 | +pw_properties * pw_properties_new_string(const char *args); | |
1795 | + | |
1796 | +// stream.h | |
1797 | +void pw_stream_add_listener(pw_stream *stream, spa_hook *listener, const pw_stream_events *events, void *data); | |
1798 | +int pw_stream_connect(pw_stream *stream, enum pw_direction direction, uint32_t target_id, enum pw_stream_flags flags, const spa_pod **params, uint32_t n_params); | |
1799 | +pw_buffer *pw_stream_dequeue_buffer(pw_stream *stream); | |
1800 | +void pw_stream_destroy(pw_stream *stream); | |
1801 | +pw_stream * pw_stream_new(pw_core *core, const char *name, pw_properties *props); | |
1802 | +int pw_stream_queue_buffer(pw_stream *stream, pw_buffer *buffer); | |
1803 | +int pw_stream_set_active(pw_stream *stream, bool active); | |
1804 | +int pw_stream_update_params(pw_stream *stream, const spa_pod **params, uint32_t n_params); | |
1805 | + | |
1806 | +// thread-loop.h | |
1807 | +void pw_thread_loop_destroy(pw_thread_loop *loop); | |
1808 | +pw_thread_loop * pw_thread_loop_new(const char *name, const spa_dict *props); | |
1809 | +int pw_thread_loop_start(pw_thread_loop *loop); | |
1810 | +void pw_thread_loop_stop(pw_thread_loop *loop); | |
1811 | +void pw_thread_loop_lock(pw_thread_loop *loop); | |
1812 | +void pw_thread_loop_unlock(pw_thread_loop *loop); | |
1813 | +pw_loop * pw_thread_loop_get_loop(pw_thread_loop *loop); | |
1814 | + | |
1815 | + | |
1816 | +// context.h | |
1817 | +void pw_context_destroy(pw_context *context); | |
1818 | +pw_context *pw_context_new(pw_loop *main_loop, pw_properties *props, size_t user_data_size); | |
1819 | +pw_core * pw_context_connect(pw_context *context, pw_properties *properties, size_t user_data_size); |