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