From 80b585f8d2a31e780b4de41fbd187a742bea7e1a Mon Sep 17 00:00:00 2001 From: James Hilliard 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 --- .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/.gitlab-ci.yml b/.gitlab-ci.yml index 9c24dd80..9d64695f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -20,7 +20,7 @@ stages: variables: FDO_DISTRIBUTION_VERSION: buster FDO_DISTRIBUTION_EXEC: 'bash .gitlab-ci/debian-install.sh' - FDO_DISTRIBUTION_TAG: '2020-06-24.0' + FDO_DISTRIBUTION_TAG: '2020-08-17.0' container_prep: diff --git a/.gitlab-ci/debian-install.sh b/.gitlab-ci/debian-install.sh index 12fb4e3f..017126b8 100644 --- a/.gitlab-ci/debian-install.sh +++ b/.gitlab-ci/debian-install.sh @@ -38,6 +38,8 @@ apt-get -y --no-install-recommends install \ doxygen \ freerdp2-dev \ git \ + libasound2-dev \ + libbluetooth-dev \ libcairo2-dev \ libcolord-dev \ libdbus-1-dev \ @@ -52,20 +54,23 @@ apt-get -y --no-install-recommends install \ libgstreamer1.0-dev \ libgstreamer-plugins-base1.0-dev \ libinput-dev \ + libjack-jackd2-dev \ libjpeg-dev \ libjpeg-dev \ liblcms2-dev \ libmtdev-dev \ libpam0g-dev \ libpango1.0-dev \ - libpipewire-0.2-dev \ libpixman-1-dev \ libpng-dev \ + libpulse-dev \ + libsbc-dev \ libsystemd-dev \ libtool \ libudev-dev \ libva-dev \ libvpx-dev \ + libvulkan-dev \ libwayland-dev \ libwebp-dev \ libx11-dev \ @@ -146,5 +151,14 @@ ninja -C build install cd .. rm -rf mesa +rm -rf pipewire +git clone --single-branch --branch master https://gitlab.freedesktop.org/pipewire/pipewire.git pipewire +cd pipewire +git checkout -b snapshot db12f47505ddccb257acdc0fa2bb884aceb1b593 +meson build +ninja -C build install +cd .. +rm -rf pipewire + apt-get -y --autoremove purge $LINUX_DEV_PKGS apt-get -y --autoremove purge $MESA_DEV_PKGS \ No newline at end of file diff --git a/pipewire/meson.build b/pipewire/meson.build index 67db61f0..944b2259 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 fe7eb1d6..2c65f502 100644 --- a/pipewire/pipewire-plugin.c +++ b/pipewire/pipewire-plugin.c @@ -34,20 +34,27 @@ #include #include +#include + #include #include #include -#include +#if PW_CHECK_VERSION(0, 2, 90) +#include +#include +#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 = {