From cc08737e3fd174ec3c4c208ea4f2a3a6a9e8af3e Mon Sep 17 00:00:00 2001
From: James Hilliard <james.hilliard1@gmail.com>
Date: Mon, 6 Jul 2020 00:58:02 -0600
Subject: [PATCH] pipewire: add support for 0.3 API

Fixes: #369

Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
[james.hilliard1@gmail.com: backport from upstream commit
80b585f8d2a31e780b4de41fbd187a742bea7e1a]
---
 .gitlab-ci.yml               |   2 +-
 .gitlab-ci/debian-install.sh |  16 ++++-
 pipewire/meson.build         |  28 ++++++---
 pipewire/pipewire-plugin.c   | 118 ++++++++++++++++++++++++++++++++++-
 4 files changed, 151 insertions(+), 13 deletions(-)

diff --git a/pipewire/meson.build b/pipewire/meson.build
index 3d3374b8..e30a0b62 100644
--- a/pipewire/meson.build
+++ b/pipewire/meson.build
@@ -5,17 +5,25 @@ if get_option('pipewire')
 		error('Attempting to build the pipewire plugin without the required DRM backend. ' + user_hint)
 	endif
 
-	depnames = [
-		'libpipewire-0.2', 'libspa-0.1'
-	]
 	deps_pipewire = [ dep_libweston_private ]
-	foreach depname : depnames
-		dep = dependency(depname, required: false)
-		if not dep.found()
-			error('Pipewire plugin requires @0@ which was not found. '.format(depname) + user_hint)
-		endif
-		deps_pipewire += dep
-	endforeach
+
+	dep_libpipewire = dependency('libpipewire-0.3', required: false)
+	if not dep_libpipewire.found()
+		dep_libpipewire = dependency('libpipewire-0.2', required: false)
+	endif
+	if not dep_libpipewire.found()
+		error('Pipewire plugin requires libpipewire which was not found. ' + user_hint)
+	endif
+	deps_pipewire += dep_libpipewire
+
+	dep_libspa = dependency('libspa-0.2', required: false)
+	if not dep_libspa.found()
+		dep_libspa = dependency('libspa-0.1', required: false)
+	endif
+	if not dep_libspa.found()
+		error('Pipewire plugin requires libspa which was not found. ' + user_hint)
+	endif
+	deps_pipewire += dep_libspa
 
 	plugin_pipewire = shared_library(
 		'pipewire-plugin',
diff --git a/pipewire/pipewire-plugin.c b/pipewire/pipewire-plugin.c
index 6f892574..ce70ea63 100644
--- a/pipewire/pipewire-plugin.c
+++ b/pipewire/pipewire-plugin.c
@@ -34,20 +34,27 @@
 #include <errno.h>
 #include <unistd.h>
 
+#include <pipewire/pipewire.h>
+
 #include <spa/param/format-utils.h>
 #include <spa/param/video/format-utils.h>
 #include <spa/utils/defs.h>
 
-#include <pipewire/pipewire.h>
+#if PW_CHECK_VERSION(0, 2, 90)
+#include <spa/buffer/meta.h>
+#include <spa/utils/result.h>
+#endif
 
 #define PROP_RANGE(min, max) 2, (min), (max)
 
+#if !PW_CHECK_VERSION(0, 2, 90)
 struct type {
 	struct spa_type_media_type media_type;
 	struct spa_type_media_subtype media_subtype;
 	struct spa_type_format_video format_video;
 	struct spa_type_video_format video_format;
 };
+#endif
 
 struct weston_pipewire {
 	struct weston_compositor *compositor;
@@ -60,12 +67,19 @@ struct weston_pipewire {
 	struct pw_loop *loop;
 	struct wl_event_source *loop_source;
 
+#if PW_CHECK_VERSION(0, 2, 90)
+	struct pw_context *context;
+#endif
 	struct pw_core *core;
 	struct pw_type *t;
+#if PW_CHECK_VERSION(0, 2, 90)
+	struct spa_hook core_listener;
+#else
 	struct type type;
 
 	struct pw_remote *remote;
 	struct spa_hook remote_listener;
+#endif
 };
 
 struct pipewire_output {
@@ -100,6 +114,7 @@ struct pipewire_frame_data {
 	struct wl_event_source *fence_sync_event_source;
 };
 
+#if !PW_CHECK_VERSION(0, 2, 90)
 static inline void init_type(struct type *type, struct spa_type_map *map)
 {
 	spa_type_media_type_map(map, &type->media_type);
@@ -107,6 +122,7 @@ static inline void init_type(struct type *type, struct spa_type_map *map)
 	spa_type_format_video_map(map, &type->format_video);
 	spa_type_video_format_map(map, &type->video_format);
 }
+#endif
 
 static void
 pipewire_debug_impl(struct weston_pipewire *pipewire,
@@ -141,6 +157,7 @@ pipewire_debug_impl(struct weston_pipewire *pipewire,
 	free(logstr);
 }
 
+#if !PW_CHECK_VERSION(0, 2, 90)
 static void
 pipewire_debug(struct weston_pipewire *pipewire, const char *fmt, ...)
 {
@@ -150,6 +167,7 @@ pipewire_debug(struct weston_pipewire *pipewire, const char *fmt, ...)
 	pipewire_debug_impl(pipewire, NULL, fmt, ap);
 	va_end(ap);
 }
+#endif
 
 static void
 pipewire_output_debug(struct pipewire_output *output, const char *fmt, ...)
@@ -185,7 +203,9 @@ pipewire_output_handle_frame(struct pipewire_output *output, int fd,
 	const struct weston_drm_virtual_output_api *api =
 		output->pipewire->virtual_output_api;
 	size_t size = output->output->height * stride;
+#if !PW_CHECK_VERSION(0, 2, 90)
 	struct pw_type *t = output->pipewire->t;
+#endif
 	struct pw_buffer *buffer;
 	struct spa_buffer *spa_buffer;
 	struct spa_meta_header *h;
@@ -203,7 +223,12 @@ pipewire_output_handle_frame(struct pipewire_output *output, int fd,
 
 	spa_buffer = buffer->buffer;
 
+#if PW_CHECK_VERSION(0, 2, 90)
+	if ((h = spa_buffer_find_meta_data(spa_buffer, SPA_META_Header,
+				     sizeof(struct spa_meta_header)))) {
+#else
 	if ((h = spa_buffer_find_meta(spa_buffer, t->meta.Header))) {
+#endif
 		h->pts = -1;
 		h->flags = 0;
 		h->seq = output->seq++;
@@ -375,18 +400,40 @@ pipewire_set_dpms(struct weston_output *base_output, enum dpms_enum level)
 static int
 pipewire_output_connect(struct pipewire_output *output)
 {
+#if !PW_CHECK_VERSION(0, 2, 90)
 	struct weston_pipewire *pipewire = output->pipewire;
 	struct type *type = &pipewire->type;
+#endif
 	uint8_t buffer[1024];
 	struct spa_pod_builder builder =
 		SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
 	const struct spa_pod *params[1];
+#if !PW_CHECK_VERSION(0, 2, 90)
 	struct pw_type *t = pipewire->t;
+#endif
 	int frame_rate = output->output->current_mode->refresh / 1000;
 	int width = output->output->width;
 	int height = output->output->height;
 	int ret;
 
+#if PW_CHECK_VERSION(0, 2, 90)
+	params[0] = spa_pod_builder_add_object(&builder,
+		SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
+		SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
+		SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
+		SPA_FORMAT_VIDEO_format, SPA_POD_Id(SPA_VIDEO_FORMAT_BGRx),
+		SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&SPA_RECTANGLE(width, height)),
+		SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&SPA_FRACTION (0, 1)),
+		SPA_FORMAT_VIDEO_maxFramerate,
+		SPA_POD_CHOICE_RANGE_Fraction(&SPA_FRACTION(frame_rate, 1),
+			&SPA_FRACTION(1, 1),
+			&SPA_FRACTION(frame_rate, 1)));
+
+	ret = pw_stream_connect(output->stream, PW_DIRECTION_OUTPUT, SPA_ID_INVALID,
+				(PW_STREAM_FLAG_DRIVER |
+				 PW_STREAM_FLAG_MAP_BUFFERS),
+				params, 1);
+#else
 	params[0] = spa_pod_builder_object(&builder,
 		t->param.idEnumFormat, t->spa_format,
 		"I", type->media_type.video,
@@ -406,6 +453,7 @@ pipewire_output_connect(struct pipewire_output *output)
 				(PW_STREAM_FLAG_DRIVER |
 				 PW_STREAM_FLAG_MAP_BUFFERS),
 				params, 1);
+#endif
 	if (ret != 0) {
 		weston_log("Failed to connect pipewire stream: %s",
 			   spa_strerror(ret));
@@ -482,26 +530,42 @@ pipewire_output_stream_state_changed(void *data, enum pw_stream_state old,
 }
 
 static void
+#if PW_CHECK_VERSION(0, 2, 90)
+pipewire_output_stream_param_changed(void *data, uint32_t id, const struct spa_pod *format)
+#else
 pipewire_output_stream_format_changed(void *data, const struct spa_pod *format)
+#endif
 {
 	struct pipewire_output *output = data;
+#if !PW_CHECK_VERSION(0, 2, 90)
 	struct weston_pipewire *pipewire = output->pipewire;
+#endif
 	uint8_t buffer[1024];
 	struct spa_pod_builder builder =
 		SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
 	const struct spa_pod *params[2];
+#if !PW_CHECK_VERSION(0, 2, 90)
 	struct pw_type *t = pipewire->t;
+#endif
 	int32_t width, height, stride, size;
 	const int bpp = 4;
 
 	if (!format) {
 		pipewire_output_debug(output, "format = None");
+#if PW_CHECK_VERSION(0, 2, 90)
+		pw_stream_update_params(output->stream, NULL, 0);
+#else
 		pw_stream_finish_format(output->stream, 0, NULL, 0);
+#endif
 		return;
 	}
 
+#if PW_CHECK_VERSION(0, 2, 90)
+	spa_format_video_raw_parse(format, &output->video_format);
+#else
 	spa_format_video_raw_parse(format, &output->video_format,
 				   &pipewire->type.format_video);
+#endif
 
 	width = output->video_format.size.width;
 	height = output->video_format.size.height;
@@ -510,6 +574,21 @@ pipewire_output_stream_format_changed(void *data, const struct spa_pod *format)
 
 	pipewire_output_debug(output, "format = %dx%d", width, height);
 
+#if PW_CHECK_VERSION(0, 2, 90)
+	params[0] = spa_pod_builder_add_object(&builder,
+		SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
+		SPA_PARAM_BUFFERS_size, SPA_POD_Int(size),
+		SPA_PARAM_BUFFERS_stride, SPA_POD_Int(stride),
+		SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(4, 2, 8),
+		SPA_PARAM_BUFFERS_align, SPA_POD_Int(16));
+
+	params[1] = spa_pod_builder_add_object(&builder,
+		SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
+		SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Header),
+		SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_header)));
+
+	pw_stream_update_params(output->stream, params, 2);
+#else
 	params[0] = spa_pod_builder_object(&builder,
 		t->param.idBuffers, t->param_buffers.Buffers,
 		":", t->param_buffers.size,
@@ -527,12 +606,17 @@ pipewire_output_stream_format_changed(void *data, const struct spa_pod *format)
 		":", t->param_meta.size, "i", sizeof(struct spa_meta_header));
 
 	pw_stream_finish_format(output->stream, 0, params, 2);
+#endif
 }
 
 static const struct pw_stream_events stream_events = {
 	PW_VERSION_STREAM_EVENTS,
 	.state_changed = pipewire_output_stream_state_changed,
+#if PW_CHECK_VERSION(0, 2, 90)
+	.param_changed = pipewire_output_stream_param_changed,
+#else
 	.format_changed = pipewire_output_stream_format_changed,
+#endif
 };
 
 static struct weston_output *
@@ -560,7 +644,11 @@ pipewire_output_create(struct weston_compositor *c, char *name)
 	if (!head)
 		goto err;
 
+#if PW_CHECK_VERSION(0, 2, 90)
+	output->stream = pw_stream_new(pipewire->core, name, NULL);
+#else
 	output->stream = pw_stream_new(pipewire->remote, name, NULL);
+#endif
 	if (!output->stream) {
 		weston_log("Cannot initialize pipewire stream\n");
 		goto err;
@@ -704,6 +792,14 @@ weston_pipewire_loop_handler(int fd, uint32_t mask, void *data)
 	return 0;
 }
 
+#if PW_CHECK_VERSION(0, 2, 90)
+static void
+weston_pipewire_error(void *data, uint32_t id, int seq, int res,
+			      const char *error)
+{
+	weston_log("pipewire remote error: %s\n", error);
+}
+#else
 static void
 weston_pipewire_state_changed(void *data, enum pw_remote_state old,
 			      enum pw_remote_state state, const char *error)
@@ -725,12 +821,20 @@ weston_pipewire_state_changed(void *data, enum pw_remote_state old,
 		break;
 	}
 }
+#endif
 
 
+#if PW_CHECK_VERSION(0, 2, 90)
+static const struct pw_core_events core_events = {
+	PW_VERSION_CORE_EVENTS,
+	.error = weston_pipewire_error,
+};
+#else
 static const struct pw_remote_events remote_events = {
 	PW_VERSION_REMOTE_EVENTS,
 	.state_changed = weston_pipewire_state_changed,
 };
+#endif
 
 static int
 weston_pipewire_init(struct weston_pipewire *pipewire)
@@ -745,10 +849,19 @@ weston_pipewire_init(struct weston_pipewire *pipewire)
 
 	pw_loop_enter(pipewire->loop);
 
+#if PW_CHECK_VERSION(0, 2, 90)
+	pipewire->context = pw_context_new(pipewire->loop, NULL, 0);
+#else
 	pipewire->core = pw_core_new(pipewire->loop, NULL);
 	pipewire->t = pw_core_get_type(pipewire->core);
 	init_type(&pipewire->type, pipewire->t->map);
+#endif
 
+#if PW_CHECK_VERSION(0, 2, 90)
+	pw_core_add_listener(pipewire->core,
+			       &pipewire->core_listener,
+			       &core_events, pipewire);
+#else
 	pipewire->remote = pw_remote_new(pipewire->core, NULL, 0);
 	pw_remote_add_listener(pipewire->remote,
 			       &pipewire->remote_listener,
@@ -777,6 +890,7 @@ weston_pipewire_init(struct weston_pipewire *pipewire)
 			goto err;
 		}
 	}
+#endif
 
 	loop = wl_display_get_event_loop(pipewire->compositor->wl_display);
 	pipewire->loop_source =
@@ -786,12 +900,14 @@ weston_pipewire_init(struct weston_pipewire *pipewire)
 				     pipewire);
 
 	return 0;
+#if !PW_CHECK_VERSION(0, 2, 90)
 err:
 	if (pipewire->remote)
 		pw_remote_destroy(pipewire->remote);
 	pw_loop_leave(pipewire->loop);
 	pw_loop_destroy(pipewire->loop);
 	return -1;
+#endif
 }
 
 static const struct weston_pipewire_api pipewire_api = {
-- 
2.25.1

