From b9ad90f68cbfd6a3ef3c40e786fec08db540cc49 Mon Sep 17 00:00:00 2001 From: Julian Bouzas <julian.bouzas@collabora.com> Date: Wed, 25 Sep 2019 11:58:02 +0200 Subject: [PATCH] softdsp-endpoint: use the same number of channels in the converters as the sink/source node --- .../module-pipewire/audio-softdsp-endpoint.c | 13 +++- .../audio-softdsp-endpoint/adapter.c | 77 +++++++++++++++---- .../audio-softdsp-endpoint/adapter.h | 4 + .../audio-softdsp-endpoint/convert.c | 32 +++++--- .../audio-softdsp-endpoint/convert.h | 6 +- 5 files changed, 98 insertions(+), 34 deletions(-) diff --git a/modules/module-pipewire/audio-softdsp-endpoint.c b/modules/module-pipewire/audio-softdsp-endpoint.c index c7d2bde1..a35fea2a 100644 --- a/modules/module-pipewire/audio-softdsp-endpoint.c +++ b/modules/module-pipewire/audio-softdsp-endpoint.c @@ -162,6 +162,7 @@ on_audio_adapter_created(GObject *initable, GAsyncResult *res, enum pw_direction direction = wp_endpoint_get_direction(WP_ENDPOINT(self)); g_autoptr (WpCore) core = wp_endpoint_get_core(WP_ENDPOINT(self)); g_autoptr (WpProperties) props = NULL; + const struct spa_audio_info_raw *format; g_autofree gchar *name = NULL; GVariantDict d; GVariantIter iter; @@ -190,14 +191,20 @@ on_audio_adapter_created(GObject *initable, GAsyncResult *res, self->role = g_strdup (wp_properties_get (props, PW_KEY_MEDIA_ROLE)); /* Just finish if no streams need to be created */ - if (!self->streams) - return finish_endpoint_creation (self); + if (!self->streams) { + finish_endpoint_creation (self); + return; + } + + /* Get the adapter format */ + format = wp_audio_adapter_get_format (WP_AUDIO_ADAPTER (self->adapter)); + g_return_if_fail (format); /* Create the audio converters */ g_variant_iter_init (&iter, self->streams); for (i = 0; g_variant_iter_next (&iter, "&s", &stream); i++) { wp_audio_convert_new (WP_ENDPOINT(self), i, stream, direction, - self->proxy_node, on_audio_convert_created, self); + self->proxy_node, format, on_audio_convert_created, self); /* Register the stream */ g_variant_dict_init (&d, NULL); diff --git a/modules/module-pipewire/audio-softdsp-endpoint/adapter.c b/modules/module-pipewire/audio-softdsp-endpoint/adapter.c index 84cfc512..abae8c3c 100644 --- a/modules/module-pipewire/audio-softdsp-endpoint/adapter.c +++ b/modules/module-pipewire/audio-softdsp-endpoint/adapter.c @@ -24,6 +24,9 @@ struct _WpAudioAdapter /* Props */ gboolean convert; + + /* THe raw format this adapter is configured */ + struct spa_audio_info_raw format; }; static GAsyncInitableIface *wp_audio_adapter_parent_interface = NULL; @@ -35,46 +38,79 @@ G_DEFINE_TYPE_WITH_CODE (WpAudioAdapter, wp_audio_adapter, WP_TYPE_AUDIO_STREAM, wp_audio_adapter_async_initable_init)) static void -wp_audio_adapter_init_async (GAsyncInitable *initable, int io_priority, - GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data) +on_proxy_enum_format_done (WpProxyNode *proxy, GAsyncResult *res, + WpAudioAdapter *self) { - WpAudioAdapter *self = WP_AUDIO_ADAPTER(initable); + g_autoptr (GPtrArray) formats = NULL; + g_autoptr (GError) error = NULL; enum pw_direction direction = wp_audio_stream_get_direction (WP_AUDIO_STREAM (self)); uint8_t buf[1024]; struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(buf, sizeof(buf)); struct spa_pod *param; - struct spa_audio_info_raw fmt_raw; + uint32_t media_type, media_subtype; + + formats = wp_proxy_node_enum_params_collect_finish (proxy, res, &error); + if (error) { + g_message("WpAudioAdapter:%p enum format error: %s", self, error->message); + wp_audio_stream_init_task_finish (WP_AUDIO_STREAM (self), + g_steal_pointer (&error)); + return; + } - /* Call the parent interface */ - /* This will also augment the proxy and therefore bind it */ - wp_audio_adapter_parent_interface->init_async (initable, io_priority, - cancellable, callback, data); + if (formats->len == 0 || + !(param = g_ptr_array_index (formats, 0)) || + spa_format_parse (param, &media_type, &media_subtype) < 0 || + media_type != SPA_MEDIA_TYPE_audio || + media_subtype != SPA_MEDIA_SUBTYPE_raw) { + g_message("WpAudioAdapter:%p node does not support audio/raw format", self); + wp_audio_stream_init_task_finish (WP_AUDIO_STREAM (self), + g_error_new (WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED, + "node does not support audio/raw format")); + return; + } + + /* Parse the raw audio format */ + spa_pod_fixate (param); + spa_format_audio_raw_parse (param, &self->format); + + /* Keep the chanels but use the default format */ + self->format.format = SPA_AUDIO_FORMAT_F32P; + self->format.rate = 48000; - /* Emit the ports */ if (self->convert) { param = spa_pod_builder_add_object(&pod_builder, SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig, SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(direction), SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_convert)); } else { - /* Use the default format */ - fmt_raw.format = SPA_AUDIO_FORMAT_F32P; - fmt_raw.flags = 1; - fmt_raw.rate = 48000; - fmt_raw.channels = 2; - fmt_raw.position[0] = SPA_AUDIO_CHANNEL_FL; - fmt_raw.position[1] = SPA_AUDIO_CHANNEL_FR; - param = spa_format_audio_raw_build(&pod_builder, SPA_PARAM_Format, &fmt_raw); + param = spa_format_audio_raw_build(&pod_builder, SPA_PARAM_Format, &self->format); param = spa_pod_builder_add_object(&pod_builder, SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig, SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(direction), SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_dsp), SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(param)); } + wp_audio_stream_set_port_config (WP_AUDIO_STREAM (self), param); } +static void +wp_audio_adapter_init_async (GAsyncInitable *initable, int io_priority, + GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data) +{ + WpAudioAdapter *self = WP_AUDIO_ADAPTER(initable); + WpProxyNode *proxy = wp_audio_stream_get_proxy_node (WP_AUDIO_STREAM (self)); + + /* Call the parent interface */ + /* This will also augment the proxy and therefore bind it */ + wp_audio_adapter_parent_interface->init_async (initable, io_priority, + cancellable, callback, data); + + wp_proxy_node_enum_params_collect (proxy, SPA_PARAM_EnumFormat, NULL, NULL, + (GAsyncReadyCallback) on_proxy_enum_format_done, self); +} + static void wp_audio_adapter_async_initable_init (gpointer iface, gpointer iface_data) { @@ -153,3 +189,10 @@ wp_audio_adapter_new (WpEndpoint *endpoint, guint stream_id, "convert", convert, NULL); } + +struct spa_audio_info_raw * +wp_audio_adapter_get_format (WpAudioAdapter *self) +{ + g_return_val_if_fail (self, NULL); + return &self->format; +} diff --git a/modules/module-pipewire/audio-softdsp-endpoint/adapter.h b/modules/module-pipewire/audio-softdsp-endpoint/adapter.h index 25012261..9dc145ea 100644 --- a/modules/module-pipewire/audio-softdsp-endpoint/adapter.h +++ b/modules/module-pipewire/audio-softdsp-endpoint/adapter.h @@ -16,6 +16,8 @@ G_BEGIN_DECLS +struct spa_audio_info_raw format; + #define WP_TYPE_AUDIO_ADAPTER (wp_audio_adapter_get_type ()) G_DECLARE_FINAL_TYPE (WpAudioAdapter, wp_audio_adapter, WP, AUDIO_ADAPTER, WpAudioStream) @@ -24,6 +26,8 @@ void wp_audio_adapter_new (WpEndpoint *endpoint, guint stream_id, const char *stream_name, enum pw_direction direction, WpProxyNode *node, gboolean convert, GAsyncReadyCallback callback, gpointer user_data); +struct spa_audio_info_raw *wp_audio_adapter_get_format (WpAudioAdapter *self); + G_END_DECLS #endif diff --git a/modules/module-pipewire/audio-softdsp-endpoint/convert.c b/modules/module-pipewire/audio-softdsp-endpoint/convert.c index 5c41d235..afb7228c 100644 --- a/modules/module-pipewire/audio-softdsp-endpoint/convert.c +++ b/modules/module-pipewire/audio-softdsp-endpoint/convert.c @@ -17,6 +17,7 @@ enum { PROP_0, PROP_TARGET, + PROP_FORMAT, }; struct _WpAudioConvert @@ -25,6 +26,7 @@ struct _WpAudioConvert /* Props */ WpProxyNode *target; + struct spa_audio_info_raw format; /* Proxies */ WpProxy *link_proxy; @@ -109,7 +111,6 @@ on_audio_convert_proxy_done (WpProxy *proxy, GAsyncResult *res, g_autoptr (GError) error = NULL; enum pw_direction direction = wp_audio_stream_get_direction (WP_AUDIO_STREAM (self)); - struct spa_audio_info_raw format; uint8_t buf[1024]; struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(buf, sizeof(buf)); struct spa_pod *param; @@ -124,16 +125,8 @@ on_audio_convert_proxy_done (WpProxy *proxy, GAsyncResult *res, g_debug ("%s:%p setting format", G_OBJECT_TYPE_NAME (self), self); - /* Use the default format */ - format.format = SPA_AUDIO_FORMAT_F32P; - format.flags = 1; - format.rate = 48000; - format.channels = 2; - format.position[0] = SPA_AUDIO_CHANNEL_FL; - format.position[1] = SPA_AUDIO_CHANNEL_FR; - /* Emit the ports */ - param = spa_format_audio_raw_build(&pod_builder, SPA_PARAM_Format, &format); + param = spa_format_audio_raw_build(&pod_builder, SPA_PARAM_Format, &self->format); param = spa_pod_builder_add_object(&pod_builder, SPA_TYPE_OBJECT_ParamPortConfig, SPA_PARAM_PortConfig, SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(direction), @@ -198,6 +191,14 @@ wp_audio_convert_set_property (GObject * object, guint property_id, case PROP_TARGET: self->target = g_value_dup_object (value); break; + case PROP_FORMAT: { + const struct spa_audio_info_raw *f = g_value_get_pointer (value); + if (f) + self->format = *f; + else + g_warning ("WpAudioConvert:%p Format needs to be valid", self); + break; + } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -214,6 +215,9 @@ wp_audio_convert_get_property (GObject * object, guint property_id, case PROP_TARGET: g_value_set_object (value, self->target); break; + case PROP_FORMAT: + g_value_set_pointer (value, &self->format); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -250,13 +254,16 @@ wp_audio_convert_class_init (WpAudioConvertClass * klass) g_param_spec_object ("target", "target", "The target device node", WP_TYPE_PROXY_NODE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, PROP_FORMAT, + g_param_spec_pointer ("format", "format", "The accepted format", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); } void wp_audio_convert_new (WpEndpoint *endpoint, guint stream_id, const char *stream_name, enum pw_direction direction, - WpProxyNode *target, GAsyncReadyCallback callback, - gpointer user_data) + WpProxyNode *target, const struct spa_audio_info_raw *format, + GAsyncReadyCallback callback, gpointer user_data) { g_async_initable_new_async ( WP_TYPE_AUDIO_CONVERT, G_PRIORITY_DEFAULT, NULL, callback, user_data, @@ -265,5 +272,6 @@ wp_audio_convert_new (WpEndpoint *endpoint, guint stream_id, "name", stream_name, "direction", direction, "target", target, + "format", format, NULL); } diff --git a/modules/module-pipewire/audio-softdsp-endpoint/convert.h b/modules/module-pipewire/audio-softdsp-endpoint/convert.h index 75737e42..84e8f404 100644 --- a/modules/module-pipewire/audio-softdsp-endpoint/convert.h +++ b/modules/module-pipewire/audio-softdsp-endpoint/convert.h @@ -16,14 +16,16 @@ G_BEGIN_DECLS +struct spa_audio_info_raw format; + #define WP_TYPE_AUDIO_CONVERT (wp_audio_convert_get_type ()) G_DECLARE_FINAL_TYPE (WpAudioConvert, wp_audio_convert, WP, AUDIO_CONVERT, WpAudioStream) void wp_audio_convert_new (WpEndpoint *endpoint, guint stream_id, const char *stream_name, enum pw_direction direction, - WpProxyNode *target, GAsyncReadyCallback callback, - gpointer user_data); + WpProxyNode *target, const struct spa_audio_info_raw *format, + GAsyncReadyCallback callback, gpointer user_data); G_END_DECLS -- GitLab