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, };