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
This commit is contained in:
Wim Taymans 2024-11-15 10:53:45 +01:00
parent 8c59fae42d
commit f261b2f96f
3 changed files with 69 additions and 15 deletions

View file

@ -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);

View file

@ -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;

View file

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