From f261b2f96fcf3cfe9ff7aad6362f8fbdb8abc404 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 15 Nov 2024 10:53:45 +0100 Subject: [PATCH] filter-chain: update channels from filter-graph Add a filter-graph info structure with the number of inputs and outputs in the graph definition. Use the input/outputs to update the number of channels on the capture and playback streams when not explicitly given. Also copy over the positions when they match the other stream and were not explicitly specified. Fixes #4404 --- spa/include/spa/filter-graph/filter-graph.h | 14 +++++++ spa/plugins/filter-graph/filter-graph.c | 45 ++++++++++++++------- src/modules/module-filter-chain.c | 25 ++++++++++++ 3 files changed, 69 insertions(+), 15 deletions(-) diff --git a/spa/include/spa/filter-graph/filter-graph.h b/spa/include/spa/filter-graph/filter-graph.h index e1a5b0430..966f46942 100644 --- a/spa/include/spa/filter-graph/filter-graph.h +++ b/spa/include/spa/filter-graph/filter-graph.h @@ -32,10 +32,24 @@ extern "C" { #define SPA_VERSION_FILTER_GRAPH 0 struct spa_filter_graph { struct spa_interface iface; }; +struct spa_filter_graph_info { + uint32_t n_inputs; + uint32_t n_outputs; + +#define SPA_FILTER_GRAPH_CHANGE_MASK_FLAGS (1u<<0) +#define SPA_FILTER_GRAPH_CHANGE_MASK_PROPS (1u<<1) + uint64_t change_mask; + + uint64_t flags; + struct spa_dict *props; +}; + struct spa_filter_graph_events { #define SPA_VERSION_FILTER_GRAPH_EVENTS 0 uint32_t version; + void (*info) (void *object, const struct spa_filter_graph_info *info); + void (*apply_props) (void *object, enum spa_direction direction, const struct spa_pod *props); void (*props_changed) (void *object, enum spa_direction direction); diff --git a/spa/plugins/filter-graph/filter-graph.c b/spa/plugins/filter-graph/filter-graph.c index 6ae50109b..00a261af1 100644 --- a/spa/plugins/filter-graph/filter-graph.c +++ b/spa/plugins/filter-graph/filter-graph.c @@ -46,6 +46,7 @@ SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.filter-graph"); spa_hook_list_call_simple(hooks, struct spa_filter_graph_events, \ method, version, ##__VA_ARGS__) +#define spa_filter_graph_emit_info(hooks,...) spa_filter_graph_emit(hooks,info, 0, __VA_ARGS__) #define spa_filter_graph_emit_apply_props(hooks,...) spa_filter_graph_emit(hooks,apply_props, 0, __VA_ARGS__) #define spa_filter_graph_emit_props_changed(hooks,...) spa_filter_graph_emit(hooks,props_changed, 0, __VA_ARGS__) @@ -190,21 +191,32 @@ struct impl { struct spa_fga_dsp *dsp; struct spa_plugin_loader *loader; + uint64_t info_all; + struct spa_filter_graph_info info; + struct graph graph; uint32_t quantum_limit; uint32_t max_align; long unsigned rate; - uint32_t in_ports; - uint32_t out_ports; - struct spa_list plugin_list; float *silence_data; float *discard_data; }; +static void emit_filter_graph_info(struct impl *impl, bool full) +{ + uint64_t old = full ? impl->info.change_mask : 0; + + if (full) + impl->info.change_mask = impl->info_all; + if (impl->info.change_mask || full) { + spa_filter_graph_emit_info(&impl->hooks, &impl->info); + impl->info.change_mask = old; + } +} static int impl_add_listener(void *object, struct spa_hook *listener, @@ -216,6 +228,9 @@ impl_add_listener(void *object, spa_log_trace(impl->log, "%p: add listener %p", impl, listener); spa_hook_list_isolate(&impl->hooks, &save, listener, events, data); + + emit_filter_graph_info(impl, true); + spa_hook_list_join(&impl->hooks, &save); return 0; @@ -1591,21 +1606,21 @@ static int setup_graph(struct graph *graph, struct spa_json *inputs, struct spa_ goto error; } - if (impl->in_ports == 0) - impl->in_ports = n_input; - if (impl->out_ports == 0) - impl->out_ports = n_output; + if (impl->info.n_inputs == 0) + impl->info.n_inputs = n_input; + if (impl->info.n_outputs == 0) + impl->info.n_outputs = n_output; /* compare to the requested number of inputs and duplicate the * graph n_hndl times when needed. */ - n_hndl = impl->in_ports / n_input; - if (n_hndl != impl->out_ports / n_output) { + n_hndl = impl->info.n_inputs / n_input; + if (n_hndl != impl->info.n_outputs / n_output) { spa_log_error(impl->log, "invalid ports. The input stream has %1$d ports and " "the filter has %2$d inputs. The output stream has %3$d ports " "and the filter has %4$d outputs. input:%1$d / input:%2$d != " "output:%3$d / output:%4$d. Check inputs and outputs objects.", - impl->in_ports, n_input, - impl->out_ports, n_output); + impl->info.n_inputs, n_input, + impl->info.n_outputs, n_output); res = -EINVAL; goto error; } @@ -1621,8 +1636,8 @@ static int setup_graph(struct graph *graph, struct spa_json *inputs, struct spa_ "the filter has %2$d inputs. The output stream has %3$d ports " "and the filter has %4$d outputs. Some filter ports will be " "unconnected..", - impl->in_ports, n_input, - impl->out_ports, n_output); + impl->info.n_inputs, n_input, + impl->info.n_outputs, n_output); } spa_log_info(impl->log, "using %d instances %d %d", n_hndl, n_input, n_output); @@ -2027,9 +2042,9 @@ impl_init(const struct spa_handle_factory *factory, if (spa_streq(k, "clock.quantum-limit")) spa_atou32(s, &impl->quantum_limit, 0); if (spa_streq(k, "filter-graph.n_inputs")) - spa_atou32(s, &impl->in_ports, 0); + spa_atou32(s, &impl->info.n_inputs, 0); if (spa_streq(k, "filter-graph.n_outputs")) - spa_atou32(s, &impl->out_ports, 0); + spa_atou32(s, &impl->info.n_outputs, 0); } if (impl->quantum_limit == 0) return -EINVAL; diff --git a/src/modules/module-filter-chain.c b/src/modules/module-filter-chain.c index b09b94895..39fd14d96 100644 --- a/src/modules/module-filter-chain.c +++ b/src/modules/module-filter-chain.c @@ -1088,6 +1088,30 @@ done: return res < 0 ? res : 0; } +static void copy_position(struct spa_audio_info_raw *dst, const struct spa_audio_info_raw *src) +{ + if (SPA_FLAG_IS_SET(dst->flags, SPA_AUDIO_FLAG_UNPOSITIONED) && + !SPA_FLAG_IS_SET(src->flags, SPA_AUDIO_FLAG_UNPOSITIONED)) { + for (uint32_t i = 0; i < src->channels; i++) + dst->position[i] = src->position[i]; + SPA_FLAG_CLEAR(dst->flags, SPA_AUDIO_FLAG_UNPOSITIONED); + } +} + +static void graph_info(void *object, const struct spa_filter_graph_info *info) +{ + struct impl *impl = object; + if (impl->capture_info.channels == 0) + impl->capture_info.channels = info->n_inputs; + if (impl->playback_info.channels == 0) + impl->playback_info.channels = info->n_outputs; + + if (impl->capture_info.channels == impl->playback_info.channels) { + copy_position(&impl->capture_info, &impl->playback_info); + copy_position(&impl->playback_info, &impl->capture_info); + } +} + static void graph_apply_props(void *object, enum spa_direction direction, const struct spa_pod *props) { struct impl *impl = object; @@ -1113,6 +1137,7 @@ static void graph_props_changed(void *object, enum spa_direction direction) struct spa_filter_graph_events graph_events = { SPA_VERSION_FILTER_GRAPH_EVENTS, + .info = graph_info, .apply_props = graph_apply_props, .props_changed = graph_props_changed, };