mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
filter-chain: implement inputs and outputs
When inputs/outputs are specified, find the node:port and link them. Fall back to the first/last node for input/output if no node is given. Fall back to all input/output ports when no ports are given.
This commit is contained in:
parent
aa0fdaf454
commit
5df221cf9a
1 changed files with 146 additions and 60 deletions
|
|
@ -577,44 +577,38 @@ static const LADSPA_Descriptor *find_descriptor(LADSPA_Descriptor_Function desc_
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
static struct node *find_node(struct graph *graph, const char *name)
|
||||||
static uint32_t find_port(struct impl *impl, const char *name, int mask)
|
{
|
||||||
|
struct node *node;
|
||||||
|
spa_list_for_each(node, &graph->node_list, link) {
|
||||||
|
if (strcmp(node->name, name) == 0)
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t find_port(struct node *node, const char *name, int mask)
|
||||||
{
|
{
|
||||||
uint32_t p;
|
uint32_t p;
|
||||||
const LADSPA_Descriptor *d = impl->desc;
|
const LADSPA_Descriptor *d = node->desc->desc;
|
||||||
for (p = 0; p < d->PortCount; p++) {
|
for (p = 0; p < d->PortCount; p++) {
|
||||||
if ((d->PortDescriptors[p] & mask) != mask)
|
if ((d->PortDescriptors[p] & mask) != mask)
|
||||||
continue;
|
continue;
|
||||||
if (strcmp(impl->desc->PortNames[p], name) == 0)
|
if (strcmp(d->PortNames[p], name) == 0)
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
return SPA_ID_INVALID;
|
return SPA_ID_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t collect_ports(struct impl *impl, const char *str, unsigned long ports[], int mask)
|
static uint32_t count_array(struct spa_json *json)
|
||||||
{
|
{
|
||||||
struct spa_json it[2];
|
struct spa_json it = *json;
|
||||||
char v[256];
|
char v[256];
|
||||||
uint32_t p, n_ports;
|
uint32_t count = 0;
|
||||||
const char *dir = mask & LADSPA_PORT_INPUT ? "input" : "output";
|
while (spa_json_get_string(&it, v, sizeof(v)) > 0)
|
||||||
|
count++;
|
||||||
spa_json_init(&it[0], str, strlen(str));
|
return count;
|
||||||
if (spa_json_enter_array(&it[0], &it[1]) <= 0)
|
|
||||||
spa_json_init(&it[1], str, strlen(str));
|
|
||||||
|
|
||||||
n_ports = 0;
|
|
||||||
while (spa_json_get_string(&it[1], v, sizeof(v)) > 0 &&
|
|
||||||
n_ports < MAX_PORTS) {
|
|
||||||
if ((p = find_port(impl, v, mask)) == SPA_ID_INVALID) {
|
|
||||||
pw_log_error("unknown %s port '%s'", dir, v);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
pw_log_info("using port %d ('%s') as %s %d", p, v, dir, n_ports);
|
|
||||||
ports[n_ports++] = p;
|
|
||||||
}
|
|
||||||
return n_ports;
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static void ladspa_handle_unref(struct ladspa_handle *hndl)
|
static void ladspa_handle_unref(struct ladspa_handle *hndl)
|
||||||
{
|
{
|
||||||
|
|
@ -859,22 +853,33 @@ static int load_node(struct graph *graph, struct spa_json *json)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int setup_graph(struct graph *graph)
|
static int setup_graph(struct graph *graph, struct spa_json *inputs, struct spa_json *outputs)
|
||||||
{
|
{
|
||||||
struct impl *impl = graph->impl;
|
struct impl *impl = graph->impl;
|
||||||
struct node *node;
|
struct node *node, *first, *last;
|
||||||
uint32_t i, j, n_input, n_output, n_hndl;
|
uint32_t i, j, n_input, n_output, n_hndl;
|
||||||
int res;
|
int res;
|
||||||
unsigned long p;
|
unsigned long p;
|
||||||
|
struct ladspa_descriptor *desc;
|
||||||
|
const LADSPA_Descriptor *d;
|
||||||
|
char v[256], *col, *node_name, *port_name;
|
||||||
|
|
||||||
graph->n_input = n_input = 0;
|
graph->n_input = 0;
|
||||||
graph->n_output = n_output = 0;
|
graph->n_output = 0;
|
||||||
graph->n_control = 0;
|
graph->n_control = 0;
|
||||||
|
|
||||||
spa_list_for_each(node, &graph->node_list, link) {
|
first = spa_list_first(&graph->node_list, struct node, link);
|
||||||
struct ladspa_descriptor *desc = node->desc;
|
last = spa_list_last(&graph->node_list, struct node, link);
|
||||||
n_input += desc->n_input;
|
|
||||||
n_output += desc->n_output;
|
if (inputs != NULL) {
|
||||||
|
n_input = count_array(inputs);
|
||||||
|
} else {
|
||||||
|
n_input = first->desc->n_input;
|
||||||
|
}
|
||||||
|
if (outputs != NULL) {
|
||||||
|
n_output = count_array(outputs);
|
||||||
|
} else {
|
||||||
|
n_output = last->desc->n_output;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (impl->capture_info.channels == 0)
|
if (impl->capture_info.channels == 0)
|
||||||
|
|
@ -886,36 +891,21 @@ static int setup_graph(struct graph *graph)
|
||||||
if (n_hndl != impl->playback_info.channels / n_output) {
|
if (n_hndl != impl->playback_info.channels / n_output) {
|
||||||
pw_log_error("invalid channels");
|
pw_log_error("invalid channels");
|
||||||
res = -EINVAL;
|
res = -EINVAL;
|
||||||
goto exit;
|
goto error;
|
||||||
}
|
}
|
||||||
pw_log_info("using %d instances", n_hndl);
|
pw_log_info("using %d instances %d %d", n_hndl, n_input, n_output);
|
||||||
|
|
||||||
spa_list_for_each(node, &graph->node_list, link) {
|
spa_list_for_each(node, &graph->node_list, link) {
|
||||||
struct ladspa_descriptor *desc = node->desc;
|
desc = node->desc;
|
||||||
const LADSPA_Descriptor *d = desc->desc;
|
d = desc->desc;
|
||||||
for (i = 0; i < n_hndl; i++) {
|
for (i = 0; i < n_hndl; i++) {
|
||||||
if ((node->hndl[i] = d->instantiate(d, impl->rate)) == NULL) {
|
if ((node->hndl[i] = d->instantiate(d, impl->rate)) == NULL) {
|
||||||
pw_log_error("cannot create plugin instance");
|
pw_log_error("cannot create plugin instance");
|
||||||
res = -ENOMEM;
|
res = -ENOMEM;
|
||||||
goto exit;
|
goto error;
|
||||||
}
|
}
|
||||||
node->n_hndl = i;
|
node->n_hndl = i;
|
||||||
|
|
||||||
for (j = 0; j < desc->n_input; j++) {
|
|
||||||
p = desc->input[j];
|
|
||||||
graph->in_desc[graph->n_input] = d;
|
|
||||||
graph->in_hndl[graph->n_input] = node->hndl[i];
|
|
||||||
graph->in_port[graph->n_input] = p;
|
|
||||||
graph->n_input++;
|
|
||||||
}
|
|
||||||
for (j = 0; j < desc->n_output; j++) {
|
|
||||||
p = desc->output[j];
|
|
||||||
graph->out_desc[graph->n_output] = d;
|
|
||||||
graph->out_hndl[graph->n_output] = node->hndl[i];
|
|
||||||
graph->out_port[graph->n_output] = p;
|
|
||||||
graph->n_output++;
|
|
||||||
}
|
|
||||||
|
|
||||||
graph->hndl[graph->n_hndl] = node->hndl[i];
|
graph->hndl[graph->n_hndl] = node->hndl[i];
|
||||||
graph->desc[graph->n_hndl] = d;
|
graph->desc[graph->n_hndl] = d;
|
||||||
graph->n_hndl++;
|
graph->n_hndl++;
|
||||||
|
|
@ -937,12 +927,106 @@ static int setup_graph(struct graph *graph)
|
||||||
graph->n_control++;
|
graph->n_control++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
exit:
|
|
||||||
for (i = 0; i < n_hndl; i++) {
|
for (i = 0; i < n_hndl; i++) {
|
||||||
if (node->hndl[i] != NULL)
|
if (inputs == NULL) {
|
||||||
node->desc->desc->cleanup(node->hndl[i]);
|
desc = first->desc;
|
||||||
node->hndl[i] = NULL;
|
d = desc->desc;
|
||||||
|
for (j = 0; j < desc->n_input; j++) {
|
||||||
|
p = desc->input[j];
|
||||||
|
graph->in_desc[graph->n_input] = d;
|
||||||
|
graph->in_hndl[graph->n_input] = first->hndl[i];
|
||||||
|
graph->in_port[graph->n_input] = p;
|
||||||
|
graph->n_input++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
struct spa_json it = *inputs;
|
||||||
|
while (spa_json_get_string(&it, v, sizeof(v)) > 0) {
|
||||||
|
col = strchr(v, ':');
|
||||||
|
if (col != NULL) {
|
||||||
|
node_name = v;
|
||||||
|
port_name = col + 1;
|
||||||
|
*col = '\0';
|
||||||
|
node = find_node(graph, node_name);
|
||||||
|
} else {
|
||||||
|
node = first;
|
||||||
|
node_name = first->name;
|
||||||
|
port_name = v;
|
||||||
|
}
|
||||||
|
if (node == NULL) {
|
||||||
|
pw_log_error("input node %s not found", node_name);
|
||||||
|
res = -EINVAL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
p = find_port(node, port_name, LADSPA_PORT_INPUT);
|
||||||
|
if (p == SPA_ID_INVALID) {
|
||||||
|
pw_log_error("input port %s:%s not found", node_name, port_name);
|
||||||
|
res = -EINVAL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
desc = node->desc;
|
||||||
|
d = desc->desc;
|
||||||
|
|
||||||
|
graph->in_desc[graph->n_input] = d;
|
||||||
|
graph->in_hndl[graph->n_input] = node->hndl[i];
|
||||||
|
graph->in_port[graph->n_input] = p;
|
||||||
|
graph->n_input++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (outputs == NULL) {
|
||||||
|
desc = first->desc;
|
||||||
|
d = desc->desc;
|
||||||
|
for (j = 0; j < desc->n_output; j++) {
|
||||||
|
p = desc->output[j];
|
||||||
|
graph->out_desc[graph->n_output] = d;
|
||||||
|
graph->out_hndl[graph->n_output] = last->hndl[i];
|
||||||
|
graph->out_port[graph->n_output] = p;
|
||||||
|
graph->n_output++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
struct spa_json it = *outputs;
|
||||||
|
while (spa_json_get_string(&it, v, sizeof(v)) > 0) {
|
||||||
|
col = strchr(v, ':');
|
||||||
|
if (col != NULL) {
|
||||||
|
node_name = v;
|
||||||
|
port_name = col + 1;
|
||||||
|
*col = '\0';
|
||||||
|
node = find_node(graph, node_name);
|
||||||
|
} else {
|
||||||
|
node = first;
|
||||||
|
node_name = first->name;
|
||||||
|
port_name = v;
|
||||||
|
}
|
||||||
|
if (node == NULL) {
|
||||||
|
pw_log_error("output node %s not found", node_name);
|
||||||
|
res = -EINVAL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
p = find_port(node, port_name, LADSPA_PORT_OUTPUT);
|
||||||
|
if (p == SPA_ID_INVALID) {
|
||||||
|
pw_log_error("output port %s:%s not found", node_name, port_name);
|
||||||
|
res = -EINVAL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
desc = node->desc;
|
||||||
|
d = desc->desc;
|
||||||
|
|
||||||
|
graph->out_desc[graph->n_output] = d;
|
||||||
|
graph->out_hndl[graph->n_output] = node->hndl[i];
|
||||||
|
graph->out_port[graph->n_output] = p;
|
||||||
|
graph->n_output++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
spa_list_for_each(node, &graph->node_list, link) {
|
||||||
|
for (i = 0; i < n_hndl; i++) {
|
||||||
|
if (node->hndl[i] != NULL)
|
||||||
|
node->desc->desc->cleanup(node->hndl[i]);
|
||||||
|
node->hndl[i] = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
@ -962,7 +1046,7 @@ exit:
|
||||||
static int load_graph(struct graph *graph, struct pw_properties *props)
|
static int load_graph(struct graph *graph, struct pw_properties *props)
|
||||||
{
|
{
|
||||||
struct spa_json it[4];
|
struct spa_json it[4];
|
||||||
struct spa_json inputs, outputs;
|
struct spa_json inputs, outputs, *pinputs = NULL, *poutputs = NULL;
|
||||||
const char *json, *val;
|
const char *json, *val;
|
||||||
char key[256];
|
char key[256];
|
||||||
int res;
|
int res;
|
||||||
|
|
@ -998,14 +1082,16 @@ static int load_graph(struct graph *graph, struct pw_properties *props)
|
||||||
else if (strcmp("inputs", key) == 0) {
|
else if (strcmp("inputs", key) == 0) {
|
||||||
if (spa_json_enter_array(&it[1], &inputs) <= 0)
|
if (spa_json_enter_array(&it[1], &inputs) <= 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
pinputs = &inputs;
|
||||||
}
|
}
|
||||||
else if (strcmp("outputs", key) == 0) {
|
else if (strcmp("outputs", key) == 0) {
|
||||||
if (spa_json_enter_array(&it[1], &outputs) <= 0)
|
if (spa_json_enter_array(&it[1], &outputs) <= 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
poutputs = &outputs;
|
||||||
} else if (spa_json_next(&it[1], &val) < 0)
|
} else if (spa_json_next(&it[1], &val) < 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return setup_graph(graph);;
|
return setup_graph(graph, pinputs, poutputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void core_error(void *data, uint32_t id, int seq, int res, const char *message)
|
static void core_error(void *data, uint32_t id, int seq, int res, const char *message)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue