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