From 4d2cdd6da34f90bdd31fb5b026d4ea51476b9c27 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 6 Sep 2024 17:30:58 +0200 Subject: [PATCH] audioadapter: dynamically load the audio converter So that we can plug in other implementations. Also handle the cases where we can't load a converter. --- spa/plugins/audioconvert/audioadapter.c | 108 ++++++++++++++++++------ spa/plugins/videoconvert/videoadapter.c | 4 +- 2 files changed, 86 insertions(+), 26 deletions(-) diff --git a/spa/plugins/audioconvert/audioadapter.c b/spa/plugins/audioconvert/audioadapter.c index 045769c7a..eab5cc949 100644 --- a/spa/plugins/audioconvert/audioadapter.c +++ b/spa/plugins/audioconvert/audioadapter.c @@ -3,6 +3,7 @@ /* SPDX-License-Identifier: MIT */ #include +#include #include #include @@ -42,6 +43,7 @@ struct impl { struct spa_log *log; struct spa_cpu *cpu; + struct spa_plugin_loader *ploader; uint32_t max_align; enum spa_direction direction; @@ -59,6 +61,7 @@ struct impl { struct spa_node *convert; struct spa_hook convert_listener; uint64_t convert_port_flags; + char *convertname; uint32_t n_buffers; struct spa_buffer **buffers; @@ -137,6 +140,9 @@ static int convert_enum_port_config(struct impl *this, struct spa_pod *f1, *f2 = NULL; int res; + if (this->convert == NULL) + return 0; + f1 = spa_pod_builder_add_object(builder, SPA_TYPE_OBJECT_ParamPortConfig, id, SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(this->direction)); @@ -570,6 +576,9 @@ static int configure_convert(struct impl *this, uint32_t mode) uint8_t buffer[1024]; struct spa_pod *param; + if (this->convert == NULL) + return 0; + spa_pod_builder_init(&b, buffer, sizeof(buffer)); spa_log_debug(this->log, "%p: configure convert %p", this, this->target); @@ -669,6 +678,9 @@ static int reconfigure_mode(struct impl *this, enum spa_param_port_config_mode m spa_log_debug(this->log, "%p: passthrough mode %d", this, passthrough); + if (!passthrough && this->convert == NULL) + return -ENOTSUP; + if (this->passthrough != passthrough) { if (passthrough) { /* remove converter split/merge ports */ @@ -1753,6 +1765,48 @@ static const struct spa_node_methods impl_node = { .process = impl_node_process, }; +static int load_plugin_from(struct impl *this, const struct spa_dict *info, + const char *convertname, struct spa_handle **handle, struct spa_node **iface) +{ + struct spa_handle *hnd_convert = NULL; + void *iface_conv = NULL; + hnd_convert = spa_plugin_loader_load(this->ploader, convertname, info); + if (!hnd_convert) + return -EINVAL; + + spa_handle_get_interface(hnd_convert, SPA_TYPE_INTERFACE_Node, &iface_conv); + if (iface_conv == NULL) { + spa_plugin_loader_unload(this->ploader, hnd_convert); + return -EINVAL; + } + + *handle = hnd_convert; + *iface = iface_conv; + + return 0; +} + +static int load_converter(struct impl *this, const struct spa_dict *info) +{ + int ret; + if (!this->ploader || !info) + return -EINVAL; + + const char* factory_name = spa_dict_lookup(info, "audio.adapt.converter"); + if (factory_name == NULL) + factory_name = SPA_NAME_AUDIO_CONVERT; + + if (factory_name) { + ret = load_plugin_from(this, info, factory_name, &this->hnd_convert, &this->convert); + if (ret >= 0) { + this->convertname = strdup(factory_name); + return ret; + } + } + return 0; +} + + static int do_auto_port_config(struct impl *this, const char *str) { uint32_t state = 0, i; @@ -1873,7 +1927,10 @@ static int impl_clear(struct spa_handle *handle) spa_hook_remove(&this->follower_listener); spa_node_set_callbacks(this->follower, NULL, NULL); - spa_handle_clear(this->hnd_convert); + if (this->hnd_convert) { + spa_plugin_loader_unload(this->ploader, this->hnd_convert); + free(this->convertname); + } clear_buffers(this); return 0; @@ -1884,10 +1941,7 @@ static size_t impl_get_size(const struct spa_handle_factory *factory, const struct spa_dict *params) { - size_t size; - - size = spa_handle_factory_get_size(&spa_audioconvert_factory, params); - size += sizeof(struct impl); + size_t size = sizeof(struct impl); return size; } @@ -1900,8 +1954,8 @@ impl_init(const struct spa_handle_factory *factory, uint32_t n_support) { struct impl *this; - void *iface; const char *str; + int ret; spa_return_val_if_fail(factory != NULL, -EINVAL); spa_return_val_if_fail(handle != NULL, -EINVAL); @@ -1916,6 +1970,8 @@ impl_init(const struct spa_handle_factory *factory, this->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU); + this->ploader = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_PluginLoader); + if (info == NULL || (str = spa_dict_lookup(info, "audio.adapt.follower")) == NULL) return -EINVAL; @@ -1934,17 +1990,19 @@ impl_init(const struct spa_handle_factory *factory, SPA_VERSION_NODE, &impl_node, this); - this->hnd_convert = SPA_PTROFF(this, sizeof(struct impl), struct spa_handle); - spa_handle_factory_init(&spa_audioconvert_factory, - this->hnd_convert, - info, support, n_support); + ret = load_converter(this, info); + spa_log_info(this->log, "%p: loaded converter %s, hnd %p, convert %p", this, + this->convertname, this->hnd_convert, this->convert); + if (ret < 0) + return ret; - spa_handle_get_interface(this->hnd_convert, SPA_TYPE_INTERFACE_Node, &iface); - if (iface == NULL) - return -EINVAL; - - this->convert = iface; - this->target = this->convert; + if (this->convert == NULL) { + this->target = this->follower; + this->passthrough = true; + } else { + this->target = this->convert; + this->passthrough = false; + } this->info_all = SPA_NODE_CHANGE_MASK_FLAGS | SPA_NODE_CHANGE_MASK_PROPS | @@ -1968,14 +2026,16 @@ impl_init(const struct spa_handle_factory *factory, &this->follower_listener, &follower_node_events, this); spa_node_set_callbacks(this->follower, &follower_node_callbacks, this); - spa_node_add_listener(this->convert, - &this->convert_listener, &convert_node_events, this); - - if (info && (str = spa_dict_lookup(info, "adapter.auto-port-config")) != NULL) - do_auto_port_config(this, str); - else - configure_convert(this, SPA_PARAM_PORT_CONFIG_MODE_dsp); - + if (this->convert) { + spa_node_add_listener(this->convert, + &this->convert_listener, &convert_node_events, this); + if (info && (str = spa_dict_lookup(info, "adapter.auto-port-config")) != NULL) + do_auto_port_config(this, str); + else + configure_convert(this, SPA_PARAM_PORT_CONFIG_MODE_dsp); + } else { + reconfigure_mode(this, SPA_PARAM_PORT_CONFIG_MODE_passthrough, this->direction, NULL); + } link_io(this); return 0; diff --git a/spa/plugins/videoconvert/videoadapter.c b/spa/plugins/videoconvert/videoadapter.c index c163f631e..91e3b21fb 100644 --- a/spa/plugins/videoconvert/videoadapter.c +++ b/spa/plugins/videoconvert/videoadapter.c @@ -1994,12 +1994,12 @@ impl_init(const struct spa_handle_factory *factory, if (strcmp(this->convertname, "video.convert.dummy") == 0) { configure_convert(this, SPA_PARAM_PORT_CONFIG_MODE_none); - reconfigure_mode(this, true, this->direction, NULL); + reconfigure_mode(this, SPA_PARAM_PORT_CONFIG_MODE_passthrough, this->direction, NULL); } else { configure_convert(this, SPA_PARAM_PORT_CONFIG_MODE_convert); } } else { - reconfigure_mode(this, true, this->direction, NULL); + reconfigure_mode(this, SPA_PARAM_PORT_CONFIG_MODE_passthrough, this->direction, NULL); } link_io(this);