mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	filter-graph: add support for channel positions
Make it possible to define a channel position in filter-graph. Use the channel positions to perform the final channelmix.
This commit is contained in:
		
							parent
							
								
									9b2b420cf5
								
							
						
					
					
						commit
						de2ab7cac9
					
				
					 3 changed files with 139 additions and 39 deletions
				
			
		| 
						 | 
					@ -46,7 +46,6 @@ struct spa_filter_graph_info {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SPA_FILTER_GRAPH_CHANGE_MASK_FLAGS		(1u<<0)
 | 
					#define SPA_FILTER_GRAPH_CHANGE_MASK_FLAGS		(1u<<0)
 | 
				
			||||||
#define SPA_FILTER_GRAPH_CHANGE_MASK_PROPS		(1u<<1)
 | 
					#define SPA_FILTER_GRAPH_CHANGE_MASK_PROPS		(1u<<1)
 | 
				
			||||||
#define SPA_FILTER_GRAPH_CHANGE_MASK_PORTS		(1u<<2)
 | 
					 | 
				
			||||||
	uint64_t change_mask;
 | 
						uint64_t change_mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint64_t flags;
 | 
						uint64_t flags;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -229,7 +229,9 @@ struct filter_graph {
 | 
				
			||||||
	struct spa_filter_graph *graph;
 | 
						struct spa_filter_graph *graph;
 | 
				
			||||||
	struct spa_hook listener;
 | 
						struct spa_hook listener;
 | 
				
			||||||
	uint32_t n_inputs;
 | 
						uint32_t n_inputs;
 | 
				
			||||||
 | 
						uint32_t inputs_position[SPA_AUDIO_MAX_CHANNELS];
 | 
				
			||||||
	uint32_t n_outputs;
 | 
						uint32_t n_outputs;
 | 
				
			||||||
 | 
						uint32_t outputs_position[SPA_AUDIO_MAX_CHANNELS];
 | 
				
			||||||
	bool active;
 | 
						bool active;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -961,10 +963,28 @@ static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size)
 | 
				
			||||||
static void graph_info(void *object, const struct spa_filter_graph_info *info)
 | 
					static void graph_info(void *object, const struct spa_filter_graph_info *info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct filter_graph *g = object;
 | 
						struct filter_graph *g = object;
 | 
				
			||||||
 | 
						struct spa_dict *props = info->props;
 | 
				
			||||||
 | 
						uint32_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!g->active)
 | 
						if (!g->active)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	g->n_inputs = info->n_inputs;
 | 
						g->n_inputs = info->n_inputs;
 | 
				
			||||||
	g->n_outputs = info->n_outputs;
 | 
						g->n_outputs = info->n_outputs;
 | 
				
			||||||
 | 
						for (i = 0; props && i < props->n_items; i++) {
 | 
				
			||||||
 | 
							const char *k = props->items[i].key;
 | 
				
			||||||
 | 
							const char *s = props->items[i].value;
 | 
				
			||||||
 | 
							if (spa_streq(k, "n_inputs"))
 | 
				
			||||||
 | 
								spa_atou32(s, &g->n_inputs, 0);
 | 
				
			||||||
 | 
							else if (spa_streq(k, "n_outputs"))
 | 
				
			||||||
 | 
								spa_atou32(s, &g->n_outputs, 0);
 | 
				
			||||||
 | 
							else if (spa_streq(k, "inputs.audio.position"))
 | 
				
			||||||
 | 
								spa_audio_parse_position(s, strlen(s),
 | 
				
			||||||
 | 
										g->inputs_position, &g->n_inputs);
 | 
				
			||||||
 | 
							else if (spa_streq(k, "outputs.audio.position"))
 | 
				
			||||||
 | 
								spa_audio_parse_position(s, strlen(s),
 | 
				
			||||||
 | 
										g->outputs_position, &g->n_outputs);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int apply_props(struct impl *impl, const struct spa_pod *props);
 | 
					static int apply_props(struct impl *impl, const struct spa_pod *props);
 | 
				
			||||||
| 
						 | 
					@ -996,22 +1016,29 @@ struct spa_filter_graph_events graph_events = {
 | 
				
			||||||
	.props_changed = graph_props_changed,
 | 
						.props_changed = graph_props_changed,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int setup_filter_graph(struct impl *this, struct spa_filter_graph *graph, uint32_t channels)
 | 
					static int setup_filter_graph(struct impl *this, struct filter_graph *g,
 | 
				
			||||||
 | 
							uint32_t channels, uint32_t *position)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
	char rate_str[64], in_ports[64];
 | 
						char rate_str[64], in_ports[64];
 | 
				
			||||||
	struct dir *dir;
 | 
						struct dir *dir;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (graph == NULL)
 | 
						if (g == NULL || g->graph == NULL)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dir = &this->dir[SPA_DIRECTION_REVERSE(this->direction)];
 | 
						dir = &this->dir[SPA_DIRECTION_REVERSE(this->direction)];
 | 
				
			||||||
	snprintf(rate_str, sizeof(rate_str), "%d", dir->format.info.raw.rate);
 | 
						snprintf(rate_str, sizeof(rate_str), "%d", dir->format.info.raw.rate);
 | 
				
			||||||
	if (channels)
 | 
						if (channels) {
 | 
				
			||||||
		snprintf(in_ports, sizeof(in_ports), "%d", channels);
 | 
							snprintf(in_ports, sizeof(in_ports), "%d", channels);
 | 
				
			||||||
 | 
							g->n_inputs = channels;
 | 
				
			||||||
 | 
							if (position) {
 | 
				
			||||||
 | 
								memcpy(g->inputs_position, position, sizeof(uint32_t) * channels);
 | 
				
			||||||
 | 
								memcpy(g->outputs_position, position, sizeof(uint32_t) * channels);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_filter_graph_deactivate(graph);
 | 
						spa_filter_graph_deactivate(g->graph);
 | 
				
			||||||
	res = spa_filter_graph_activate(graph,
 | 
						res = spa_filter_graph_activate(g->graph,
 | 
				
			||||||
				     &SPA_DICT_ITEMS(
 | 
									     &SPA_DICT_ITEMS(
 | 
				
			||||||
					     SPA_DICT_ITEM(SPA_KEY_AUDIO_RATE, rate_str),
 | 
										     SPA_DICT_ITEM(SPA_KEY_AUDIO_RATE, rate_str),
 | 
				
			||||||
					     SPA_DICT_ITEM("filter-graph.n_inputs", channels ? in_ports : NULL)));
 | 
										     SPA_DICT_ITEM("filter-graph.n_inputs", channels ? in_ports : NULL)));
 | 
				
			||||||
| 
						 | 
					@ -1109,10 +1136,12 @@ static int load_filter_graph(struct impl *impl, const char *graph, int order)
 | 
				
			||||||
			goto error;
 | 
								goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* prepare new filter and swap it */
 | 
							/* prepare new filter and swap it */
 | 
				
			||||||
		res = setup_filter_graph(impl, iface, 0);
 | 
					 | 
				
			||||||
		if (res < 0)
 | 
					 | 
				
			||||||
			goto error;
 | 
					 | 
				
			||||||
		pending->graph = iface;
 | 
							pending->graph = iface;
 | 
				
			||||||
 | 
							res = setup_filter_graph(impl, pending, 0, NULL);
 | 
				
			||||||
 | 
							if (res < 0) {
 | 
				
			||||||
 | 
								pending->graph = NULL;
 | 
				
			||||||
 | 
								goto error;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		pending->active = true;
 | 
							pending->active = true;
 | 
				
			||||||
		spa_log_info(impl->log, "loading filter-graph order:%d in %d active:%d",
 | 
							spa_log_info(impl->log, "loading filter-graph order:%d in %d active:%d",
 | 
				
			||||||
				order, idx, n_graph + 1);
 | 
									order, idx, n_graph + 1);
 | 
				
			||||||
| 
						 | 
					@ -1908,7 +1937,7 @@ static char *format_position(char *str, size_t len, uint32_t channels, uint32_t
 | 
				
			||||||
	return str;
 | 
						return str;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int setup_channelmix(struct impl *this, uint32_t channels)
 | 
					static int setup_channelmix(struct impl *this, uint32_t channels, uint32_t *position)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dir *in = &this->dir[SPA_DIRECTION_INPUT];
 | 
						struct dir *in = &this->dir[SPA_DIRECTION_INPUT];
 | 
				
			||||||
	struct dir *out = &this->dir[SPA_DIRECTION_OUTPUT];
 | 
						struct dir *out = &this->dir[SPA_DIRECTION_OUTPUT];
 | 
				
			||||||
| 
						 | 
					@ -1921,7 +1950,7 @@ static int setup_channelmix(struct impl *this, uint32_t channels)
 | 
				
			||||||
	dst_chan = out->format.info.raw.channels;
 | 
						dst_chan = out->format.info.raw.channels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0, src_mask = 0; i < src_chan; i++) {
 | 
						for (i = 0, src_mask = 0; i < src_chan; i++) {
 | 
				
			||||||
		p = in->format.info.raw.position[i];
 | 
							p = position[i];
 | 
				
			||||||
		src_mask |= 1ULL << (p < 64 ? p : 0);
 | 
							src_mask |= 1ULL << (p < 64 ? p : 0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (i = 0, dst_mask = 0; i < dst_chan; i++) {
 | 
						for (i = 0, dst_mask = 0; i < dst_chan; i++) {
 | 
				
			||||||
| 
						 | 
					@ -1936,7 +1965,7 @@ static int setup_channelmix(struct impl *this, uint32_t channels)
 | 
				
			||||||
		src_mask = dst_mask;
 | 
							src_mask = dst_mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_log_info(this->log, "in  %s (%016"PRIx64")", format_position(str, sizeof(str),
 | 
						spa_log_info(this->log, "in  %s (%016"PRIx64")", format_position(str, sizeof(str),
 | 
				
			||||||
				src_chan, in->format.info.raw.position), src_mask);
 | 
									src_chan, position), src_mask);
 | 
				
			||||||
	spa_log_info(this->log, "out %s (%016"PRIx64")", format_position(str, sizeof(str),
 | 
						spa_log_info(this->log, "out %s (%016"PRIx64")", format_position(str, sizeof(str),
 | 
				
			||||||
				dst_chan, out->format.info.raw.position), dst_mask);
 | 
									dst_chan, out->format.info.raw.position), dst_mask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2228,7 +2257,7 @@ static inline bool resample_is_passthrough(struct impl *this)
 | 
				
			||||||
static int setup_convert(struct impl *this)
 | 
					static int setup_convert(struct impl *this)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dir *in, *out;
 | 
						struct dir *in, *out;
 | 
				
			||||||
	uint32_t i, rate, maxsize, maxports, duration, channels;
 | 
						uint32_t i, rate, maxsize, maxports, duration, channels, *position;
 | 
				
			||||||
	struct port *p;
 | 
						struct port *p;
 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2276,6 +2305,8 @@ static int setup_convert(struct impl *this)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	channels = in->format.info.raw.channels;
 | 
						channels = in->format.info.raw.channels;
 | 
				
			||||||
 | 
						position = in->format.info.raw.position;
 | 
				
			||||||
 | 
						maxports = SPA_MAX(in->format.info.raw.channels, out->format.info.raw.channels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((res = setup_in_convert(this)) < 0)
 | 
						if ((res = setup_in_convert(this)) < 0)
 | 
				
			||||||
		return res;
 | 
							return res;
 | 
				
			||||||
| 
						 | 
					@ -2283,11 +2314,13 @@ static int setup_convert(struct impl *this)
 | 
				
			||||||
		struct filter_graph *g = &this->filter_graph[this->graph_index[i]];
 | 
							struct filter_graph *g = &this->filter_graph[this->graph_index[i]];
 | 
				
			||||||
		if (!g->active)
 | 
							if (!g->active)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		if ((res = setup_filter_graph(this, g->graph, channels)) < 0)
 | 
							if ((res = setup_filter_graph(this, g, channels, position)) < 0)
 | 
				
			||||||
			return res;
 | 
								return res;
 | 
				
			||||||
		channels = g->n_outputs;
 | 
							channels = g->n_outputs;
 | 
				
			||||||
 | 
							position = g->outputs_position;
 | 
				
			||||||
 | 
							maxports = SPA_MAX(maxports, channels);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if ((res = setup_channelmix(this, channels)) < 0)
 | 
						if ((res = setup_channelmix(this, channels, position)) < 0)
 | 
				
			||||||
		return res;
 | 
							return res;
 | 
				
			||||||
	if ((res = setup_resample(this)) < 0)
 | 
						if ((res = setup_resample(this)) < 0)
 | 
				
			||||||
		return res;
 | 
							return res;
 | 
				
			||||||
| 
						 | 
					@ -2303,7 +2336,6 @@ static int setup_convert(struct impl *this)
 | 
				
			||||||
		p = GET_OUT_PORT(this, i);
 | 
							p = GET_OUT_PORT(this, i);
 | 
				
			||||||
		maxsize = SPA_MAX(maxsize, p->maxsize);
 | 
							maxsize = SPA_MAX(maxsize, p->maxsize);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	maxports = SPA_MAX(in->format.info.raw.channels, out->format.info.raw.channels);
 | 
					 | 
				
			||||||
	if ((res = ensure_tmp(this, maxsize, maxports)) < 0)
 | 
						if ((res = ensure_tmp(this, maxsize, maxports)) < 0)
 | 
				
			||||||
		return res;
 | 
							return res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -183,6 +183,13 @@ struct graph {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct volume volume[2];
 | 
						struct volume volume[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t n_inputs;
 | 
				
			||||||
 | 
						uint32_t n_outputs;
 | 
				
			||||||
 | 
						uint32_t inputs_position[SPA_AUDIO_MAX_CHANNELS];
 | 
				
			||||||
 | 
						uint32_t n_inputs_position;
 | 
				
			||||||
 | 
						uint32_t outputs_position[SPA_AUDIO_MAX_CHANNELS];
 | 
				
			||||||
 | 
						uint32_t n_outputs_position;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned activated:1;
 | 
						unsigned activated:1;
 | 
				
			||||||
	unsigned setup:1;
 | 
						unsigned setup:1;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -212,14 +219,52 @@ struct impl {
 | 
				
			||||||
	float *discard_data;
 | 
						float *discard_data;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void print_channels(char *buffer, size_t max_size, uint32_t n_channels, uint32_t *positions)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint32_t i;
 | 
				
			||||||
 | 
						struct spa_strbuf buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_strbuf_init(&buf, buffer, max_size);
 | 
				
			||||||
 | 
						spa_strbuf_append(&buf, "[");
 | 
				
			||||||
 | 
						for (i = 0; i < n_channels; i++) {
 | 
				
			||||||
 | 
							spa_strbuf_append(&buf, "%s%s", i ? "," : "",
 | 
				
			||||||
 | 
								spa_type_audio_channel_to_short_name(positions[i]));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						spa_strbuf_append(&buf, "]");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void emit_filter_graph_info(struct impl *impl, bool full)
 | 
					static void emit_filter_graph_info(struct impl *impl, bool full)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint64_t old = full ? impl->info.change_mask : 0;
 | 
						uint64_t old = full ? impl->info.change_mask : 0;
 | 
				
			||||||
 | 
						struct graph *graph = &impl->graph;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (full)
 | 
						if (full)
 | 
				
			||||||
		impl->info.change_mask = impl->info_all;
 | 
							impl->info.change_mask = impl->info_all;
 | 
				
			||||||
	if (impl->info.change_mask || full) {
 | 
						if (impl->info.change_mask || full) {
 | 
				
			||||||
 | 
							char n_inputs[64], n_outputs[64];
 | 
				
			||||||
 | 
							struct spa_dict_item items[6];
 | 
				
			||||||
 | 
							struct spa_dict dict = SPA_DICT(items, 0);
 | 
				
			||||||
 | 
							char in_pos[SPA_AUDIO_MAX_CHANNELS * 8];
 | 
				
			||||||
 | 
							char out_pos[SPA_AUDIO_MAX_CHANNELS * 8];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							snprintf(n_inputs, sizeof(n_inputs), "%d", impl->graph.n_inputs);
 | 
				
			||||||
 | 
							snprintf(n_outputs, sizeof(n_outputs), "%d", impl->graph.n_outputs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							items[dict.n_items++] = SPA_DICT_ITEM("n_inputs", n_inputs);
 | 
				
			||||||
 | 
							items[dict.n_items++] = SPA_DICT_ITEM("n_outputs", n_outputs);
 | 
				
			||||||
 | 
							if (graph->n_inputs_position) {
 | 
				
			||||||
 | 
								print_channels(in_pos, sizeof(in_pos),
 | 
				
			||||||
 | 
										graph->n_inputs_position, graph->inputs_position);
 | 
				
			||||||
 | 
								items[dict.n_items++] = SPA_DICT_ITEM("inputs.audio.position", in_pos);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (graph->n_outputs_position) {
 | 
				
			||||||
 | 
								print_channels(out_pos, sizeof(out_pos),
 | 
				
			||||||
 | 
										graph->n_outputs_position, graph->outputs_position);
 | 
				
			||||||
 | 
								items[dict.n_items++] = SPA_DICT_ITEM("outputs.audio.position", out_pos);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							impl->info.props = &dict;
 | 
				
			||||||
		spa_filter_graph_emit_info(&impl->hooks, &impl->info);
 | 
							spa_filter_graph_emit_info(&impl->hooks, &impl->info);
 | 
				
			||||||
 | 
							impl->info.props = NULL;
 | 
				
			||||||
		impl->info.change_mask = old;
 | 
							impl->info.change_mask = old;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -250,7 +295,7 @@ static int impl_process(void *object,
 | 
				
			||||||
	uint32_t i, j, n_hndl = graph->n_hndl;
 | 
						uint32_t i, j, n_hndl = graph->n_hndl;
 | 
				
			||||||
	struct graph_port *port;
 | 
						struct graph_port *port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0, j = 0; i < impl->info.n_inputs; i++) {
 | 
						for (i = 0, j = 0; i < graph->n_inputs; i++) {
 | 
				
			||||||
		while (j < graph->n_input) {
 | 
							while (j < graph->n_input) {
 | 
				
			||||||
			port = &graph->input[j++];
 | 
								port = &graph->input[j++];
 | 
				
			||||||
			if (port->desc && in[i])
 | 
								if (port->desc && in[i])
 | 
				
			||||||
| 
						 | 
					@ -259,7 +304,7 @@ static int impl_process(void *object,
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (i = 0; i < impl->info.n_outputs; i++) {
 | 
						for (i = 0; i < graph->n_outputs; i++) {
 | 
				
			||||||
		if (out[i] == NULL)
 | 
							if (out[i] == NULL)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1457,19 +1502,19 @@ static int impl_activate(void *object, const struct spa_dict *props)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((str = spa_dict_lookup(props, "filter-graph.n_inputs")) != NULL) {
 | 
						if ((str = spa_dict_lookup(props, "filter-graph.n_inputs")) != NULL) {
 | 
				
			||||||
		if (spa_atou32(str, &n_ports, 0) &&
 | 
							if (spa_atou32(str, &n_ports, 0) &&
 | 
				
			||||||
		    n_ports != impl->info.n_inputs) {
 | 
							    n_ports != graph->n_inputs) {
 | 
				
			||||||
			impl->info.n_inputs = n_ports;
 | 
								graph->n_inputs = n_ports;
 | 
				
			||||||
			impl->info.n_outputs = 0;
 | 
								graph->n_outputs = 0;
 | 
				
			||||||
			impl->info.change_mask |= SPA_FILTER_GRAPH_CHANGE_MASK_PORTS;
 | 
								impl->info.change_mask |= SPA_FILTER_GRAPH_CHANGE_MASK_PROPS;
 | 
				
			||||||
			graph->setup = false;
 | 
								graph->setup = false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if ((str = spa_dict_lookup(props, "filter-graph.n_outputs")) != NULL) {
 | 
						if ((str = spa_dict_lookup(props, "filter-graph.n_outputs")) != NULL) {
 | 
				
			||||||
		if (spa_atou32(str, &n_ports, 0) &&
 | 
							if (spa_atou32(str, &n_ports, 0) &&
 | 
				
			||||||
		    n_ports != impl->info.n_outputs) {
 | 
							    n_ports != graph->n_outputs) {
 | 
				
			||||||
			impl->info.n_outputs = n_ports;
 | 
								graph->n_outputs = n_ports;
 | 
				
			||||||
			impl->info.n_inputs = 0;
 | 
								graph->n_inputs = 0;
 | 
				
			||||||
			impl->info.change_mask |= SPA_FILTER_GRAPH_CHANGE_MASK_PORTS;
 | 
								impl->info.change_mask |= SPA_FILTER_GRAPH_CHANGE_MASK_PROPS;
 | 
				
			||||||
			graph->setup = false;
 | 
								graph->setup = false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1477,7 +1522,7 @@ static int impl_activate(void *object, const struct spa_dict *props)
 | 
				
			||||||
		if ((res = setup_graph(graph)) < 0)
 | 
							if ((res = setup_graph(graph)) < 0)
 | 
				
			||||||
			return res;
 | 
								return res;
 | 
				
			||||||
		graph->setup = true;
 | 
							graph->setup = true;
 | 
				
			||||||
		spa_filter_graph_emit_info(&impl->hooks, &impl->info);
 | 
							emit_filter_graph_info(impl, false);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* first make instances */
 | 
						/* first make instances */
 | 
				
			||||||
| 
						 | 
					@ -1666,24 +1711,28 @@ static int setup_graph(struct graph *graph)
 | 
				
			||||||
		res = -EINVAL;
 | 
							res = -EINVAL;
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (graph->n_inputs == 0)
 | 
				
			||||||
 | 
							graph->n_inputs = impl->info.n_inputs;
 | 
				
			||||||
 | 
						if (graph->n_inputs == 0)
 | 
				
			||||||
 | 
							graph->n_inputs = n_input;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (impl->info.n_inputs == 0)
 | 
						if (graph->n_outputs == 0)
 | 
				
			||||||
		impl->info.n_inputs = n_input;
 | 
							graph->n_outputs = impl->info.n_outputs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* compare to the requested number of inputs and duplicate the
 | 
						/* compare to the requested number of inputs and duplicate the
 | 
				
			||||||
	 * graph n_hndl times when needed. */
 | 
						 * graph n_hndl times when needed. */
 | 
				
			||||||
	n_hndl = impl->info.n_inputs / n_input;
 | 
						n_hndl = graph->n_inputs / n_input;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (impl->info.n_outputs == 0)
 | 
						if (graph->n_outputs == 0)
 | 
				
			||||||
		impl->info.n_outputs = n_output * n_hndl;
 | 
							graph->n_outputs = n_output * n_hndl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (n_hndl != impl->info.n_outputs / n_output) {
 | 
						if (n_hndl != graph->n_outputs / n_output) {
 | 
				
			||||||
		spa_log_error(impl->log, "invalid ports. The input stream has %1$d ports and "
 | 
							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 "
 | 
									"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 != "
 | 
									"and the filter has %4$d outputs. input:%1$d / input:%2$d != "
 | 
				
			||||||
				"output:%3$d / output:%4$d. Check inputs and outputs objects.",
 | 
									"output:%3$d / output:%4$d. Check inputs and outputs objects.",
 | 
				
			||||||
				impl->info.n_inputs, n_input,
 | 
									graph->n_inputs, n_input,
 | 
				
			||||||
				impl->info.n_outputs, n_output);
 | 
									graph->n_outputs, n_output);
 | 
				
			||||||
		res = -EINVAL;
 | 
							res = -EINVAL;
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1699,11 +1748,11 @@ static int setup_graph(struct graph *graph)
 | 
				
			||||||
				"the filter has %2$d inputs. The output stream has %3$d ports "
 | 
									"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 "
 | 
									"and the filter has %4$d outputs. Some filter ports will be "
 | 
				
			||||||
				"unconnected..",
 | 
									"unconnected..",
 | 
				
			||||||
				impl->info.n_inputs, n_input,
 | 
									graph->n_inputs, n_input,
 | 
				
			||||||
				impl->info.n_outputs, n_output);
 | 
									graph->n_outputs, n_output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (impl->info.n_outputs == 0)
 | 
							if (graph->n_outputs == 0)
 | 
				
			||||||
			impl->info.n_outputs = n_output * n_hndl;
 | 
								graph->n_outputs = n_output * n_hndl;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	spa_log_info(impl->log, "using %d instances %d %d", n_hndl, n_input, n_output);
 | 
						spa_log_info(impl->log, "using %d instances %d %d", n_hndl, n_input, n_output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1949,6 +1998,26 @@ static int load_graph(struct graph *graph, const struct spa_dict *props)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			impl->info.n_outputs = res;
 | 
								impl->info.n_outputs = res;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							else if (spa_streq("inputs.audio.position", key)) {
 | 
				
			||||||
 | 
								if (!spa_json_is_array(val, len) ||
 | 
				
			||||||
 | 
								    (len = spa_json_container_len(&it[0], val, len)) < 0) {
 | 
				
			||||||
 | 
									spa_log_error(impl->log, "%s expects an array", key);
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								spa_audio_parse_position(val, len, graph->inputs_position,
 | 
				
			||||||
 | 
											&graph->n_inputs_position);
 | 
				
			||||||
 | 
								impl->info.n_inputs = graph->n_inputs_position;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else if (spa_streq("outputs.audio.position", key)) {
 | 
				
			||||||
 | 
								if (!spa_json_is_array(val, len) ||
 | 
				
			||||||
 | 
								    (len = spa_json_container_len(&it[0], val, len)) < 0) {
 | 
				
			||||||
 | 
									spa_log_error(impl->log, "%s expects an array", key);
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								spa_audio_parse_position(val, len, graph->outputs_position,
 | 
				
			||||||
 | 
											&graph->n_outputs_position);
 | 
				
			||||||
 | 
								impl->info.n_outputs = graph->n_outputs_position;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		else if (spa_streq("nodes", key)) {
 | 
							else if (spa_streq("nodes", key)) {
 | 
				
			||||||
			if (!spa_json_is_array(val, len)) {
 | 
								if (!spa_json_is_array(val, len)) {
 | 
				
			||||||
				spa_log_error(impl->log, "%s expects an array", key);
 | 
									spa_log_error(impl->log, "%s expects an array", key);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue