From daf53b94ed692d14d88bd526ed1a73254c2811a6 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 11 May 2022 12:28:26 +0200 Subject: [PATCH] adapter: pass spa_node to adapter Make it possible to pass a spa_node as the follower of the adapter. This avoids us having to wrap it in a pw_impl_node in order to unwrap it again for the adapter spa_node. --- src/modules/module-adapter.c | 54 ++++++++++++++----- src/modules/module-adapter/adapter.c | 77 ++++++++++++++++++++-------- src/modules/module-adapter/adapter.h | 2 +- src/pipewire/stream.c | 20 +++----- 4 files changed, 108 insertions(+), 45 deletions(-) diff --git a/src/modules/module-adapter.c b/src/modules/module-adapter.c index 0435b7fbf..edc183b0c 100644 --- a/src/modules/module-adapter.c +++ b/src/modules/module-adapter.c @@ -71,6 +71,7 @@ struct node_data { struct spa_list link; struct pw_impl_node *adapter; struct pw_impl_node *follower; + struct spa_handle *handle; struct spa_hook adapter_listener; struct pw_resource *resource; struct pw_resource *bound_resource; @@ -114,7 +115,10 @@ static void node_free(void *data) spa_hook_remove(&nd->adapter_listener); - pw_impl_node_destroy(nd->follower); + if (nd->follower) + pw_impl_node_destroy(nd->follower); + if (nd->handle) + pw_unload_spa_handle(nd->handle); } static void node_initialized(void *data) @@ -169,10 +173,13 @@ static void *create_object(void *_data, struct factory_data *d = _data; struct pw_impl_client *client; struct pw_impl_node *adapter, *follower; - const char *str, *factory_name; + struct spa_node *spa_follower; + const char *str; int res; struct node_data *nd; bool linger, do_register; + struct spa_handle *handle = NULL; + const struct pw_properties *p; if (properties == NULL) goto error_properties; @@ -183,6 +190,10 @@ static void *create_object(void *_data, linger = pw_properties_get_bool(properties, PW_KEY_OBJECT_LINGER, false); do_register = pw_properties_get_bool(properties, PW_KEY_OBJECT_REGISTER, true); + p = pw_context_get_properties(d->context); + pw_properties_set(properties, "clock.quantum-limit", + pw_properties_get(p, "default.clock.quantum-limit")); + client = resource ? pw_resource_get_client(resource): NULL; if (client && !linger) { pw_properties_setf(properties, PW_KEY_CLIENT_ID, "%d", @@ -190,29 +201,44 @@ static void *create_object(void *_data, } follower = NULL; + spa_follower = NULL; str = pw_properties_get(properties, "adapt.follower.node"); if (str != NULL) { if (sscanf(str, "pointer:%p", &follower) != 1) goto error_properties; - - pw_properties_setf(properties, "audio.adapt.follower", "pointer:%p", follower); + spa_follower = pw_impl_node_get_implementation(follower); } - if (follower == NULL) { + str = pw_properties_get(properties, "adapt.follower.spa-node"); + if (str != NULL) { + if (sscanf(str, "pointer:%p", &spa_follower) != 1) + goto error_properties; + } + if (spa_follower == NULL) { + void *iface; + const char *factory_name; + factory_name = pw_properties_get(properties, SPA_KEY_FACTORY_NAME); if (factory_name == NULL) goto error_properties; - follower = pw_spa_node_load(d->context, - factory_name, - PW_SPA_NODE_FLAG_ACTIVATE | - PW_SPA_NODE_FLAG_NO_REGISTER, - pw_properties_copy(properties), 0); - if (follower == NULL) + handle = pw_context_load_spa_handle(d->context, + factory_name, + properties ? &properties->dict : NULL); + if (handle == NULL) goto error_errno; + + if ((res = spa_handle_get_interface(handle, SPA_TYPE_INTERFACE_Node, &iface)) < 0) + goto error_res; + + spa_follower = iface; + } + if (spa_follower == NULL) { + res = -EINVAL; + goto error_res; } adapter = pw_adapter_new(pw_impl_module_get_context(d->module), - follower, + spa_follower, properties, sizeof(struct node_data)); properties = NULL; @@ -228,6 +254,7 @@ static void *create_object(void *_data, nd->data = d; nd->adapter = adapter; nd->follower = follower; + nd->handle = handle; nd->resource = resource; nd->new_id = new_id; nd->linger = linger; @@ -248,6 +275,7 @@ error_properties: goto error_cleanup; error_errno: res = -errno; +error_res: pw_resource_errorf_id(resource, new_id, res, "can't create node: %s", spa_strerror(res)); goto error_cleanup; error_usage: @@ -257,6 +285,8 @@ error_usage: goto error_cleanup; error_cleanup: pw_properties_free(properties); + if (handle) + pw_unload_spa_handle(handle); errno = -res; return NULL; } diff --git a/src/modules/module-adapter/adapter.c b/src/modules/module-adapter/adapter.c index 88519feeb..aab785527 100644 --- a/src/modules/module-adapter/adapter.c +++ b/src/modules/module-adapter/adapter.c @@ -67,7 +67,7 @@ struct node { struct pw_impl_node *node; struct spa_hook node_listener; - struct pw_impl_node *follower; + struct spa_node *follower; void *user_data; enum pw_direction direction; @@ -199,7 +199,7 @@ static int handle_node_param(struct pw_impl_node *node, const char *key, const c return 0; } -static int find_format(struct pw_impl_node *node, enum pw_direction direction, +static int find_format(struct spa_node *node, enum pw_direction direction, uint32_t *media_type, uint32_t *media_subtype) { uint32_t state = 0; @@ -209,7 +209,7 @@ static int find_format(struct pw_impl_node *node, enum pw_direction direction, struct spa_pod *format; spa_pod_builder_init(&b, buffer, sizeof(buffer)); - if ((res = spa_node_port_enum_params_sync(pw_impl_node_get_implementation(node), + if ((res = spa_node_port_enum_params_sync(node, direction == PW_DIRECTION_INPUT ? SPA_DIRECTION_INPUT : SPA_DIRECTION_OUTPUT, 0, @@ -276,7 +276,7 @@ static int do_auto_port_config(struct node *n, const char *str) uint32_t n_position = 0; spa_pod_builder_init(&b, buffer, sizeof(buffer)); - if ((res = spa_node_port_enum_params_sync(pw_impl_node_get_implementation(n->follower), + if ((res = spa_node_port_enum_params_sync(n->follower, n->direction == PW_DIRECTION_INPUT ? SPA_DIRECTION_INPUT : SPA_DIRECTION_OUTPUT, 0, @@ -337,36 +337,75 @@ static int do_auto_port_config(struct node *n, const char *str) return 0; } +struct info_data { + struct spa_hook listener; + struct spa_node *node; + struct pw_properties *props; + uint32_t n_input_ports; + uint32_t max_input_ports; + uint32_t n_output_ports; + uint32_t max_output_ports; +}; + +static void info_event(void *data, const struct spa_node_info *info) +{ + struct info_data *d = data; + + pw_properties_update(d->props, info->props); + + d->max_input_ports = info->max_input_ports; + d->max_output_ports = info->max_output_ports; +} + +static void port_info_event(void *data, enum spa_direction direction, uint32_t port, + const struct spa_port_info *info) +{ + struct info_data *d = data; + + if (direction == SPA_DIRECTION_OUTPUT) + d->n_output_ports++; + else if (direction == SPA_DIRECTION_INPUT) + d->n_input_ports++; +} + +static const struct spa_node_events node_info_events = { + .version = SPA_VERSION_NODE_EVENTS, + .info = info_event, + .port_info = port_info_event, +}; + struct pw_impl_node *pw_adapter_new(struct pw_context *context, - struct pw_impl_node *follower, + struct spa_node *follower, struct pw_properties *props, size_t user_data_size) { struct pw_impl_node *node; struct node *n; const char *str, *factory_name; - const struct pw_node_info *info; enum pw_direction direction; int res; uint32_t media_type, media_subtype; const struct spa_dict_item *it; struct pw_properties *copy; + struct info_data info; - info = pw_impl_node_get_info(follower); - if (info == NULL) { - res = -EINVAL; + spa_zero(info); + info.node = follower; + info.props = props; + + res = spa_node_add_listener(info.node, &info.listener, &node_info_events, &info); + if (res < 0) goto error; - } - pw_log_debug("%p: in %d/%d out %d/%d", follower, - info->n_input_ports, info->max_input_ports, - info->n_output_ports, info->max_output_ports); + spa_hook_remove(&info.listener); - pw_properties_update(props, info->props); + pw_log_debug("%p: in %d/%d out %d/%d", info.node, + info.n_input_ports, info.max_input_ports, + info.n_output_ports, info.max_output_ports); - if (info->n_output_ports > 0) { + if (info.n_output_ports > 0) { direction = PW_DIRECTION_OUTPUT; - } else if (info->n_input_ports > 0) { + } else if (info.n_input_ports > 0) { direction = PW_DIRECTION_INPUT; } else { res = -EINVAL; @@ -388,8 +427,7 @@ struct pw_impl_node *pw_adapter_new(struct pw_context *context, goto error; if (media_type == SPA_MEDIA_TYPE_audio) { - pw_properties_setf(props, "audio.adapt.follower", "pointer:%p", - pw_impl_node_get_implementation(follower)); + pw_properties_setf(props, "audio.adapt.follower", "pointer:%p", follower); pw_properties_set(props, SPA_KEY_LIBRARY_NAME, "audioconvert/libspa-audioconvert"); if (pw_properties_get(props, PW_KEY_MEDIA_CLASS) == NULL) pw_properties_setf(props, PW_KEY_MEDIA_CLASS, "Audio/%s", @@ -397,8 +435,7 @@ struct pw_impl_node *pw_adapter_new(struct pw_context *context, factory_name = SPA_NAME_AUDIO_ADAPT; } else if (media_type == SPA_MEDIA_TYPE_video) { - pw_properties_setf(props, "video.adapt.follower", "pointer:%p", - pw_impl_node_get_implementation(follower)); + pw_properties_setf(props, "video.adapt.follower", "pointer:%p", follower); pw_properties_set(props, SPA_KEY_LIBRARY_NAME, "videoconvert/libspa-videoconvert"); if (pw_properties_get(props, PW_KEY_MEDIA_CLASS) == NULL) pw_properties_setf(props, PW_KEY_MEDIA_CLASS, "Video/%s", diff --git a/src/modules/module-adapter/adapter.h b/src/modules/module-adapter/adapter.h index 110ed12f1..80fa9c799 100644 --- a/src/modules/module-adapter/adapter.h +++ b/src/modules/module-adapter/adapter.h @@ -35,7 +35,7 @@ extern "C" { struct pw_impl_node * pw_adapter_new(struct pw_context *context, - struct pw_impl_node *follower, + struct spa_node *follower, struct pw_properties *properties, size_t user_data_size); diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index 193f7a1cf..58dc80ab7 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -1774,7 +1774,6 @@ pw_stream_connect(struct pw_stream *stream, struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); struct pw_impl_factory *factory; struct pw_properties *props = NULL; - struct pw_impl_node *follower; const char *str; uint32_t i; int res; @@ -1923,14 +1922,6 @@ pw_stream_connect(struct pw_stream *stream, pw_properties_set(props, "channelmix.normalize", "true"); } - follower = pw_context_create_node(impl->context, pw_properties_copy(props), 0); - if (follower == NULL) { - res = -errno; - goto error_node; - } - - pw_impl_node_set_implementation(follower, &impl->impl_node); - if (impl->media_type == SPA_MEDIA_TYPE_audio) { factory = pw_context_find_factory(impl->context, "adapter"); if (factory == NULL) { @@ -1938,7 +1929,8 @@ pw_stream_connect(struct pw_stream *stream, res = -ENOENT; goto error_node; } - pw_properties_setf(props, "adapt.follower.node", "pointer:%p", follower); + pw_properties_setf(props, "adapt.follower.spa-node", "pointer:%p", + &impl->impl_node); pw_properties_set(props, "object.register", "false"); impl->node = pw_impl_factory_create_object(factory, NULL, @@ -1952,9 +1944,13 @@ pw_stream_connect(struct pw_stream *stream, goto error_node; } } else { - impl->node = follower; - pw_properties_free(props); + impl->node = pw_context_create_node(impl->context, props, 0); props = NULL; + if (impl->node == NULL) { + res = -errno; + goto error_node; + } + pw_impl_node_set_implementation(impl->node, &impl->impl_node); } pw_impl_node_set_active(impl->node, !SPA_FLAG_IS_SET(impl->flags, PW_STREAM_FLAG_INACTIVE));