1 /*
2  * Copyright © 2019 Pengutronix, Michael Olbrich <m.olbrich@pengutronix.de>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 
26 #include "pipewire-plugin.h"
27 #include "backend.h"
28 #include "libweston-internal.h"
29 #include "shared/timespec-util.h"
30 #include <libweston/backend-drm.h>
31 #include <libweston/weston-log.h>
32 
33 #include <sys/mman.h>
34 #include <errno.h>
35 #include <unistd.h>
36 
37 #include <spa/param/format-utils.h>
38 #include <spa/param/video/format-utils.h>
39 #include <spa/utils/defs.h>
40 
41 #include <pipewire/pipewire.h>
42 
43 #define PROP_RANGE(min, max) 2, (min), (max)
44 
45 struct type {
46 	struct spa_type_media_type media_type;
47 	struct spa_type_media_subtype media_subtype;
48 	struct spa_type_format_video format_video;
49 	struct spa_type_video_format video_format;
50 };
51 
52 struct weston_pipewire {
53 	struct weston_compositor *compositor;
54 	struct wl_list output_list;
55 	struct wl_listener destroy_listener;
56 	const struct weston_drm_virtual_output_api *virtual_output_api;
57 
58 	struct weston_log_scope *debug;
59 
60 	struct pw_loop *loop;
61 	struct wl_event_source *loop_source;
62 
63 	struct pw_core *core;
64 	struct pw_type *t;
65 	struct type type;
66 
67 	struct pw_remote *remote;
68 	struct spa_hook remote_listener;
69 };
70 
71 struct pipewire_output {
72 	struct weston_output *output;
73 	void (*saved_destroy)(struct weston_output *output);
74 	int (*saved_enable)(struct weston_output *output);
75 	int (*saved_disable)(struct weston_output *output);
76 	int (*saved_start_repaint_loop)(struct weston_output *output);
77 
78 	struct weston_head *head;
79 
80 	struct weston_pipewire *pipewire;
81 
82 	uint32_t seq;
83 	struct pw_stream *stream;
84 	struct spa_hook stream_listener;
85 
86 	struct spa_video_info_raw video_format;
87 
88 	struct wl_event_source *finish_frame_timer;
89 	struct wl_list link;
90 	bool submitted_frame;
91 };
92 
93 struct pipewire_frame_data {
94 	struct pipewire_output *output;
95 	int fd;
96 	int stride;
97 	struct drm_fb *drm_buffer;
98 	int fence_sync_fd;
99 	struct wl_event_source *fence_sync_event_source;
100 };
101 
init_type(struct type * type,struct spa_type_map * map)102 static inline void init_type(struct type *type, struct spa_type_map *map)
103 {
104 	spa_type_media_type_map(map, &type->media_type);
105 	spa_type_media_subtype_map(map, &type->media_subtype);
106 	spa_type_format_video_map(map, &type->format_video);
107 	spa_type_video_format_map(map, &type->video_format);
108 }
109 
110 static void
pipewire_debug_impl(struct weston_pipewire * pipewire,struct pipewire_output * output,const char * fmt,va_list ap)111 pipewire_debug_impl(struct weston_pipewire *pipewire,
112 		    struct pipewire_output *output,
113 		    const char *fmt, va_list ap)
114 {
115 	FILE *fp;
116 	char *logstr;
117 	size_t logsize;
118 	char timestr[128];
119 
120 	if (!weston_log_scope_is_enabled(pipewire->debug))
121 		return;
122 
123 	fp = open_memstream(&logstr, &logsize);
124 	if (!fp)
125 		return;
126 
127 	weston_log_scope_timestamp(pipewire->debug, timestr, sizeof timestr);
128 	fprintf(fp, "%s", timestr);
129 
130 	if (output)
131 		fprintf(fp, "[%s]", output->output->name);
132 
133 	fprintf(fp, " ");
134 	vfprintf(fp, fmt, ap);
135 	fprintf(fp, "\n");
136 
137 	if (fclose(fp) == 0)
138 		weston_log_scope_write(pipewire->debug, logstr, logsize);
139 
140 	free(logstr);
141 }
142 
143 static void
pipewire_debug(struct weston_pipewire * pipewire,const char * fmt,...)144 pipewire_debug(struct weston_pipewire *pipewire, const char *fmt, ...)
145 {
146 	va_list ap;
147 
148 	va_start(ap, fmt);
149 	pipewire_debug_impl(pipewire, NULL, fmt, ap);
150 	va_end(ap);
151 }
152 
153 static void
pipewire_output_debug(struct pipewire_output * output,const char * fmt,...)154 pipewire_output_debug(struct pipewire_output *output, const char *fmt, ...)
155 {
156 	va_list ap;
157 
158 	va_start(ap, fmt);
159 	pipewire_debug_impl(output->pipewire, output, fmt, ap);
160 	va_end(ap);
161 }
162 
163 static struct weston_pipewire *
164 weston_pipewire_get(struct weston_compositor *compositor);
165 
166 static struct pipewire_output *
lookup_pipewire_output(struct weston_output * base_output)167 lookup_pipewire_output(struct weston_output *base_output)
168 {
169 	struct weston_compositor *c = base_output->compositor;
170 	struct weston_pipewire *pipewire = weston_pipewire_get(c);
171 	struct pipewire_output *output;
172 
173 	wl_list_for_each(output, &pipewire->output_list, link) {
174 		if (output->output == base_output)
175 			return output;
176 	}
177 	return NULL;
178 }
179 
180 static void
pipewire_output_handle_frame(struct pipewire_output * output,int fd,int stride,struct drm_fb * drm_buffer)181 pipewire_output_handle_frame(struct pipewire_output *output, int fd,
182 			     int stride, struct drm_fb *drm_buffer)
183 {
184 	const struct weston_drm_virtual_output_api *api =
185 		output->pipewire->virtual_output_api;
186 	size_t size = output->output->height * stride;
187 	struct pw_type *t = output->pipewire->t;
188 	struct pw_buffer *buffer;
189 	struct spa_buffer *spa_buffer;
190 	struct spa_meta_header *h;
191 	void *ptr;
192 
193 	if (pw_stream_get_state(output->stream, NULL) !=
194 	    PW_STREAM_STATE_STREAMING)
195 		goto out;
196 
197 	buffer = pw_stream_dequeue_buffer(output->stream);
198 	if (!buffer) {
199 		weston_log("Failed to dequeue a pipewire buffer\n");
200 		goto out;
201 	}
202 
203 	spa_buffer = buffer->buffer;
204 
205 	if ((h = spa_buffer_find_meta(spa_buffer, t->meta.Header))) {
206 		h->pts = -1;
207 		h->flags = 0;
208 		h->seq = output->seq++;
209 		h->dts_offset = 0;
210 	}
211 
212 	ptr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
213 	memcpy(spa_buffer->datas[0].data, ptr, size);
214 	munmap(ptr, size);
215 
216 	spa_buffer->datas[0].chunk->offset = 0;
217 	spa_buffer->datas[0].chunk->stride = stride;
218 	spa_buffer->datas[0].chunk->size = spa_buffer->datas[0].maxsize;
219 
220 	pipewire_output_debug(output, "push frame");
221 	pw_stream_queue_buffer(output->stream, buffer);
222 
223 out:
224 	close(fd);
225 	output->submitted_frame = true;
226 	api->buffer_released(drm_buffer);
227 }
228 
229 static int
pipewire_output_fence_sync_handler(int fd,uint32_t mask,void * data)230 pipewire_output_fence_sync_handler(int fd, uint32_t mask, void *data)
231 {
232 	struct pipewire_frame_data *frame_data = data;
233 	struct pipewire_output *output = frame_data->output;
234 
235 	pipewire_output_handle_frame(output, frame_data->fd, frame_data->stride,
236 				     frame_data->drm_buffer);
237 
238 	wl_event_source_remove(frame_data->fence_sync_event_source);
239 	close(frame_data->fence_sync_fd);
240 	free(frame_data);
241 
242 	return 0;
243 }
244 
245 static int
pipewire_output_submit_frame(struct weston_output * base_output,int fd,int stride,struct drm_fb * drm_buffer)246 pipewire_output_submit_frame(struct weston_output *base_output, int fd,
247 			     int stride, struct drm_fb *drm_buffer)
248 {
249 	struct pipewire_output *output = lookup_pipewire_output(base_output);
250 	struct weston_pipewire *pipewire = output->pipewire;
251 	const struct weston_drm_virtual_output_api *api =
252 		pipewire->virtual_output_api;
253 	struct wl_event_loop *loop;
254 	struct pipewire_frame_data *frame_data;
255 	int fence_sync_fd;
256 
257 	pipewire_output_debug(output, "submit frame: fd = %d drm_fb = %p",
258 			      fd, drm_buffer);
259 
260 	fence_sync_fd = api->get_fence_sync_fd(output->output);
261 	if (fence_sync_fd == -1) {
262 		pipewire_output_handle_frame(output, fd, stride, drm_buffer);
263 		return 0;
264 	}
265 
266 	frame_data = zalloc(sizeof *frame_data);
267 	if (!frame_data) {
268 		close(fence_sync_fd);
269 		pipewire_output_handle_frame(output, fd, stride, drm_buffer);
270 		return 0;
271 	}
272 
273 	loop = wl_display_get_event_loop(pipewire->compositor->wl_display);
274 
275 	frame_data->output = output;
276 	frame_data->fd = fd;
277 	frame_data->stride = stride;
278 	frame_data->drm_buffer = drm_buffer;
279 	frame_data->fence_sync_fd = fence_sync_fd;
280 	frame_data->fence_sync_event_source =
281 		wl_event_loop_add_fd(loop, frame_data->fence_sync_fd,
282 				     WL_EVENT_READABLE,
283 				     pipewire_output_fence_sync_handler,
284 				     frame_data);
285 
286 	return 0;
287 }
288 
289 static void
pipewire_output_timer_update(struct pipewire_output * output)290 pipewire_output_timer_update(struct pipewire_output *output)
291 {
292 	int64_t msec;
293 	int32_t refresh;
294 
295 	if (pw_stream_get_state(output->stream, NULL) ==
296 	    PW_STREAM_STATE_STREAMING)
297 		refresh = output->output->current_mode->refresh;
298 	else
299 		refresh = 1000;
300 
301 	msec = millihz_to_nsec(refresh) / 1000000;
302 	wl_event_source_timer_update(output->finish_frame_timer, msec);
303 }
304 
305 static int
pipewire_output_finish_frame_handler(void * data)306 pipewire_output_finish_frame_handler(void *data)
307 {
308 	struct pipewire_output *output = data;
309 	const struct weston_drm_virtual_output_api *api
310 		= output->pipewire->virtual_output_api;
311 	struct timespec now;
312 
313 	if (output->submitted_frame) {
314 		struct weston_compositor *c = output->pipewire->compositor;
315 		output->submitted_frame = false;
316 		weston_compositor_read_presentation_clock(c, &now);
317 		api->finish_frame(output->output, &now, 0);
318 	}
319 
320 	pipewire_output_timer_update(output);
321 	return 0;
322 }
323 
324 static void
pipewire_output_destroy(struct weston_output * base_output)325 pipewire_output_destroy(struct weston_output *base_output)
326 {
327 	struct pipewire_output *output = lookup_pipewire_output(base_output);
328 	struct weston_mode *mode, *next;
329 
330 	wl_list_for_each_safe(mode, next, &base_output->mode_list, link) {
331 		wl_list_remove(&mode->link);
332 		free(mode);
333 	}
334 
335 	output->saved_destroy(base_output);
336 
337 	pw_stream_destroy(output->stream);
338 
339 	wl_list_remove(&output->link);
340 	weston_head_release(output->head);
341 	free(output->head);
342 	free(output);
343 }
344 
345 static int
pipewire_output_start_repaint_loop(struct weston_output * base_output)346 pipewire_output_start_repaint_loop(struct weston_output *base_output)
347 {
348 	struct pipewire_output *output = lookup_pipewire_output(base_output);
349 
350 	pipewire_output_debug(output, "start repaint loop");
351 	output->saved_start_repaint_loop(base_output);
352 
353 	pipewire_output_timer_update(output);
354 
355 	return 0;
356 }
357 
358 static int
pipewire_output_connect(struct pipewire_output * output)359 pipewire_output_connect(struct pipewire_output *output)
360 {
361 	struct weston_pipewire *pipewire = output->pipewire;
362 	struct type *type = &pipewire->type;
363 	uint8_t buffer[1024];
364 	struct spa_pod_builder builder =
365 		SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
366 	const struct spa_pod *params[1];
367 	struct pw_type *t = pipewire->t;
368 	int frame_rate = output->output->current_mode->refresh / 1000;
369 	int width = output->output->width;
370 	int height = output->output->height;
371 	int ret;
372 
373 	params[0] = spa_pod_builder_object(&builder,
374 		t->param.idEnumFormat, t->spa_format,
375 		"I", type->media_type.video,
376 		"I", type->media_subtype.raw,
377 		":", type->format_video.format,
378 		"I", type->video_format.BGRx,
379 		":", type->format_video.size,
380 		"R", &SPA_RECTANGLE(width, height),
381 		":", type->format_video.framerate,
382 		"F", &SPA_FRACTION(0, 1),
383 		":", type->format_video.max_framerate,
384 		"Fru", &SPA_FRACTION(frame_rate, 1),
385 		       PROP_RANGE(&SPA_FRACTION(1, 1),
386 				  &SPA_FRACTION(frame_rate, 1)));
387 
388 	ret = pw_stream_connect(output->stream, PW_DIRECTION_OUTPUT, NULL,
389 				(PW_STREAM_FLAG_DRIVER |
390 				 PW_STREAM_FLAG_MAP_BUFFERS),
391 				params, 1);
392 	if (ret != 0) {
393 		weston_log("Failed to connect pipewire stream: %s",
394 			   spa_strerror(ret));
395 		return -1;
396 	}
397 
398 	return 0;
399 }
400 
401 static int
pipewire_output_enable(struct weston_output * base_output)402 pipewire_output_enable(struct weston_output *base_output)
403 {
404 	struct pipewire_output *output = lookup_pipewire_output(base_output);
405 	struct weston_compositor *c = base_output->compositor;
406 	const struct weston_drm_virtual_output_api *api
407 		= output->pipewire->virtual_output_api;
408 	struct wl_event_loop *loop;
409 	int ret;
410 
411 	api->set_submit_frame_cb(base_output, pipewire_output_submit_frame);
412 
413 	ret = pipewire_output_connect(output);
414 	if (ret < 0)
415 		return ret;
416 
417 	ret = output->saved_enable(base_output);
418 	if (ret < 0)
419 		return ret;
420 
421 	output->saved_start_repaint_loop = base_output->start_repaint_loop;
422 	base_output->start_repaint_loop = pipewire_output_start_repaint_loop;
423 
424 	loop = wl_display_get_event_loop(c->wl_display);
425 	output->finish_frame_timer =
426 		wl_event_loop_add_timer(loop,
427 					pipewire_output_finish_frame_handler,
428 					output);
429 
430 	return 0;
431 }
432 
433 static int
pipewire_output_disable(struct weston_output * base_output)434 pipewire_output_disable(struct weston_output *base_output)
435 {
436 	struct pipewire_output *output = lookup_pipewire_output(base_output);
437 
438 	wl_event_source_remove(output->finish_frame_timer);
439 
440 	pw_stream_disconnect(output->stream);
441 
442 	return output->saved_disable(base_output);
443 }
444 
445 static void
pipewire_output_stream_state_changed(void * data,enum pw_stream_state old,enum pw_stream_state state,const char * error_message)446 pipewire_output_stream_state_changed(void *data, enum pw_stream_state old,
447 				     enum pw_stream_state state,
448 				     const char *error_message)
449 {
450 	struct pipewire_output *output = data;
451 
452 	pipewire_output_debug(output, "state changed %s -> %s",
453 			      pw_stream_state_as_string(old),
454 			      pw_stream_state_as_string(state));
455 
456 	switch (state) {
457 	case PW_STREAM_STATE_STREAMING:
458 		weston_output_schedule_repaint(output->output);
459 		break;
460 	default:
461 		break;
462 	}
463 }
464 
465 static void
pipewire_output_stream_format_changed(void * data,const struct spa_pod * format)466 pipewire_output_stream_format_changed(void *data, const struct spa_pod *format)
467 {
468 	struct pipewire_output *output = data;
469 	struct weston_pipewire *pipewire = output->pipewire;
470 	uint8_t buffer[1024];
471 	struct spa_pod_builder builder =
472 		SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
473 	const struct spa_pod *params[2];
474 	struct pw_type *t = pipewire->t;
475 	int32_t width, height, stride, size;
476 	const int bpp = 4;
477 
478 	if (!format) {
479 		pipewire_output_debug(output, "format = None");
480 		pw_stream_finish_format(output->stream, 0, NULL, 0);
481 		return;
482 	}
483 
484 	spa_format_video_raw_parse(format, &output->video_format,
485 				   &pipewire->type.format_video);
486 
487 	width = output->video_format.size.width;
488 	height = output->video_format.size.height;
489 	stride = SPA_ROUND_UP_N(width * bpp, 4);
490 	size = height * stride;
491 
492 	pipewire_output_debug(output, "format = %dx%d", width, height);
493 
494 	params[0] = spa_pod_builder_object(&builder,
495 		t->param.idBuffers, t->param_buffers.Buffers,
496 		":", t->param_buffers.size,
497 		"i", size,
498 		":", t->param_buffers.stride,
499 		"i", stride,
500 		":", t->param_buffers.buffers,
501 		"iru", 4, PROP_RANGE(2, 8),
502 		":", t->param_buffers.align,
503 		"i", 16);
504 
505 	params[1] = spa_pod_builder_object(&builder,
506 		t->param.idMeta, t->param_meta.Meta,
507 		":", t->param_meta.type, "I", t->meta.Header,
508 		":", t->param_meta.size, "i", sizeof(struct spa_meta_header));
509 
510 	pw_stream_finish_format(output->stream, 0, params, 2);
511 }
512 
513 static const struct pw_stream_events stream_events = {
514 	PW_VERSION_STREAM_EVENTS,
515 	.state_changed = pipewire_output_stream_state_changed,
516 	.format_changed = pipewire_output_stream_format_changed,
517 };
518 
519 static struct weston_output *
pipewire_output_create(struct weston_compositor * c,char * name)520 pipewire_output_create(struct weston_compositor *c, char *name)
521 {
522 	struct weston_pipewire *pipewire = weston_pipewire_get(c);
523 	struct pipewire_output *output;
524 	struct weston_head *head;
525 	const struct weston_drm_virtual_output_api *api;
526 	const char *make = "Weston";
527 	const char *model = "Virtual Display";
528 	const char *serial_number = "unknown";
529 	const char *connector_name = "pipewire";
530 
531 	if (!name || !strlen(name))
532 		return NULL;
533 
534 	api = pipewire->virtual_output_api;
535 
536 	output = zalloc(sizeof *output);
537 	if (!output)
538 		return NULL;
539 
540 	head = zalloc(sizeof *head);
541 	if (!head)
542 		goto err;
543 
544 	output->stream = pw_stream_new(pipewire->remote, name, NULL);
545 	if (!output->stream) {
546 		weston_log("Cannot initialize pipewire stream\n");
547 		goto err;
548 	}
549 
550 	pw_stream_add_listener(output->stream, &output->stream_listener,
551 			       &stream_events, output);
552 
553 	output->output = api->create_output(c, name);
554 	if (!output->output) {
555 		weston_log("Cannot create virtual output\n");
556 		goto err;
557 	}
558 
559 	output->saved_destroy = output->output->destroy;
560 	output->output->destroy = pipewire_output_destroy;
561 	output->saved_enable = output->output->enable;
562 	output->output->enable = pipewire_output_enable;
563 	output->saved_disable = output->output->disable;
564 	output->output->disable = pipewire_output_disable;
565 	output->pipewire = pipewire;
566 	wl_list_insert(pipewire->output_list.prev, &output->link);
567 
568 	weston_head_init(head, connector_name);
569 	weston_head_set_subpixel(head, WL_OUTPUT_SUBPIXEL_NONE);
570 	weston_head_set_monitor_strings(head, make, model, serial_number);
571 	head->compositor = c;
572 	output->head = head;
573 
574 	weston_output_attach_head(output->output, head);
575 
576 	pipewire_output_debug(output, "created");
577 
578 	return output->output;
579 err:
580 	if (output->stream)
581 		pw_stream_destroy(output->stream);
582 	if (head)
583 		free(head);
584 	free(output);
585 	return NULL;
586 }
587 
588 static bool
pipewire_output_is_pipewire(struct weston_output * output)589 pipewire_output_is_pipewire(struct weston_output *output)
590 {
591 	return lookup_pipewire_output(output) != NULL;
592 }
593 
594 static int
pipewire_output_set_mode(struct weston_output * base_output,const char * modeline)595 pipewire_output_set_mode(struct weston_output *base_output, const char *modeline)
596 {
597 	struct pipewire_output *output = lookup_pipewire_output(base_output);
598 	const struct weston_drm_virtual_output_api *api =
599 		output->pipewire->virtual_output_api;
600 	struct weston_mode *mode;
601 	int n, width, height, refresh = 0;
602 
603 	if (output == NULL) {
604 		weston_log("Output is not pipewire.\n");
605 		return -1;
606 	}
607 
608 	if (!modeline)
609 		return -1;
610 
611 	n = sscanf(modeline, "%dx%d@%d", &width, &height, &refresh);
612 	if (n != 2 && n != 3)
613 		return -1;
614 
615 	if (pw_stream_get_state(output->stream, NULL) !=
616 	    PW_STREAM_STATE_UNCONNECTED) {
617 		return -1;
618 	}
619 
620 	mode = zalloc(sizeof *mode);
621 	if (!mode)
622 		return -1;
623 
624 	pipewire_output_debug(output, "mode = %dx%d@%d", width, height, refresh);
625 
626 	mode->flags = WL_OUTPUT_MODE_CURRENT;
627 	mode->width = width;
628 	mode->height = height;
629 	mode->refresh = (refresh ? refresh : 60) * 1000LL;
630 
631 	wl_list_insert(base_output->mode_list.prev, &mode->link);
632 
633 	base_output->current_mode = mode;
634 
635 	api->set_gbm_format(base_output, "XRGB8888");
636 
637 	return 0;
638 }
639 
640 static void
pipewire_output_set_seat(struct weston_output * output,const char * seat)641 pipewire_output_set_seat(struct weston_output *output, const char *seat)
642 {
643 }
644 
645 static void
weston_pipewire_destroy(struct wl_listener * l,void * data)646 weston_pipewire_destroy(struct wl_listener *l, void *data)
647 {
648 	struct weston_pipewire *pipewire =
649 		wl_container_of(l, pipewire, destroy_listener);
650 
651 	weston_compositor_log_scope_destroy(pipewire->debug);
652 	pipewire->debug = NULL;
653 
654 	wl_event_source_remove(pipewire->loop_source);
655 	pw_loop_leave(pipewire->loop);
656 	pw_loop_destroy(pipewire->loop);
657 }
658 
659 static struct weston_pipewire *
weston_pipewire_get(struct weston_compositor * compositor)660 weston_pipewire_get(struct weston_compositor *compositor)
661 {
662 	struct wl_listener *listener;
663 	struct weston_pipewire *pipewire;
664 
665 	listener = wl_signal_get(&compositor->destroy_signal,
666 				 weston_pipewire_destroy);
667 	if (!listener)
668 		return NULL;
669 
670 	pipewire = wl_container_of(listener, pipewire, destroy_listener);
671 	return pipewire;
672 }
673 
674 static int
weston_pipewire_loop_handler(int fd,uint32_t mask,void * data)675 weston_pipewire_loop_handler(int fd, uint32_t mask, void *data)
676 {
677 	struct weston_pipewire *pipewire = data;
678 	int ret;
679 
680 	ret = pw_loop_iterate(pipewire->loop, 0);
681 	if (ret < 0)
682 		weston_log("pipewire_loop_iterate failed: %s",
683 			   spa_strerror(ret));
684 
685 	return 0;
686 }
687 
688 static void
weston_pipewire_state_changed(void * data,enum pw_remote_state old,enum pw_remote_state state,const char * error)689 weston_pipewire_state_changed(void *data, enum pw_remote_state old,
690 			      enum pw_remote_state state, const char *error)
691 {
692 	struct weston_pipewire *pipewire = data;
693 
694 	pipewire_debug(pipewire, "[remote] state changed %s -> %s",
695 		       pw_remote_state_as_string(old),
696 		       pw_remote_state_as_string(state));
697 
698 	switch (state) {
699 	case PW_REMOTE_STATE_ERROR:
700 		weston_log("pipewire remote error: %s\n", error);
701 		break;
702 	case PW_REMOTE_STATE_CONNECTED:
703 		weston_log("connected to pipewire daemon\n");
704 		break;
705 	default:
706 		break;
707 	}
708 }
709 
710 
711 static const struct pw_remote_events remote_events = {
712 	PW_VERSION_REMOTE_EVENTS,
713 	.state_changed = weston_pipewire_state_changed,
714 };
715 
716 static int
weston_pipewire_init(struct weston_pipewire * pipewire)717 weston_pipewire_init(struct weston_pipewire *pipewire)
718 {
719 	struct wl_event_loop *loop;
720 
721 	pw_init(NULL, NULL);
722 
723 	pipewire->loop = pw_loop_new(NULL);
724 	if (!pipewire->loop)
725 		return -1;
726 
727 	pw_loop_enter(pipewire->loop);
728 
729 	pipewire->core = pw_core_new(pipewire->loop, NULL);
730 	pipewire->t = pw_core_get_type(pipewire->core);
731 	init_type(&pipewire->type, pipewire->t->map);
732 
733 	pipewire->remote = pw_remote_new(pipewire->core, NULL, 0);
734 	pw_remote_add_listener(pipewire->remote,
735 			       &pipewire->remote_listener,
736 			       &remote_events, pipewire);
737 
738 	pw_remote_connect(pipewire->remote);
739 
740 	while (true) {
741 		enum pw_remote_state state;
742 		const char *error = NULL;
743 		int ret;
744 
745 		state = pw_remote_get_state(pipewire->remote, &error);
746 		if (state == PW_REMOTE_STATE_CONNECTED)
747 			break;
748 
749 		if (state == PW_REMOTE_STATE_ERROR) {
750 			weston_log("pipewire error: %s\n", error);
751 			goto err;
752 		}
753 
754 		ret = pw_loop_iterate(pipewire->loop, -1);
755 		if (ret < 0) {
756 			weston_log("pipewire_loop_iterate failed: %s",
757 				   spa_strerror(ret));
758 			goto err;
759 		}
760 	}
761 
762 	loop = wl_display_get_event_loop(pipewire->compositor->wl_display);
763 	pipewire->loop_source =
764 		wl_event_loop_add_fd(loop, pw_loop_get_fd(pipewire->loop),
765 				     WL_EVENT_READABLE,
766 				     weston_pipewire_loop_handler,
767 				     pipewire);
768 
769 	return 0;
770 err:
771 	if (pipewire->remote)
772 		pw_remote_destroy(pipewire->remote);
773 	pw_loop_leave(pipewire->loop);
774 	pw_loop_destroy(pipewire->loop);
775 	return -1;
776 }
777 
778 static const struct weston_pipewire_api pipewire_api = {
779 	pipewire_output_create,
780 	pipewire_output_is_pipewire,
781 	pipewire_output_set_mode,
782 	pipewire_output_set_seat,
783 };
784 
785 WL_EXPORT int
weston_module_init(struct weston_compositor * compositor)786 weston_module_init(struct weston_compositor *compositor)
787 {
788 	int ret;
789 	struct weston_pipewire *pipewire;
790 	const struct weston_drm_virtual_output_api *api =
791 		weston_drm_virtual_output_get_api(compositor);
792 
793 	if (!api)
794 		return -1;
795 
796 	pipewire = zalloc(sizeof *pipewire);
797 	if (!pipewire)
798 		return -1;
799 
800 	pipewire->virtual_output_api = api;
801 	pipewire->compositor = compositor;
802 	wl_list_init(&pipewire->output_list);
803 
804 	ret = weston_plugin_api_register(compositor, WESTON_PIPEWIRE_API_NAME,
805 					 &pipewire_api, sizeof(pipewire_api));
806 
807 	if (ret < 0) {
808 		weston_log("Failed to register pipewire API.\n");
809 		goto failed;
810 	}
811 
812 	ret = weston_pipewire_init(pipewire);
813 	if (ret < 0) {
814 		weston_log("Failed to initialize pipewire.\n");
815 		goto failed;
816 	}
817 
818 	pipewire->debug = weston_compositor_add_log_scope(
819 			compositor->weston_log_ctx,
820 			"pipewire",
821 			"Debug messages from pipewire plugin\n",
822 			NULL, NULL);
823 
824 	pipewire->destroy_listener.notify = weston_pipewire_destroy;
825 	wl_signal_add(&compositor->destroy_signal, &pipewire->destroy_listener);
826 	return 0;
827 
828 failed:
829 	free(pipewire);
830 	return -1;
831 }
832