Support creating links for all ports from a node to another

This commit allows to specify the port-ids as "*" in
create-link in order to connect all output ports from the
first node to all input ports from the second node (in
port-id order). For example, executing something like:

`create-link my-virtual-device * alsa_output.usb-headset *`
This commit is contained in:
Antonio Larrosa 2022-04-21 18:22:24 +02:00
parent da6ab064d2
commit 36060e375d

View file

@ -133,6 +133,11 @@ struct command {
bool (*func) (struct data *data, const char *cmd, char *args, char **error);
};
static struct spa_dict * global_props(struct global *global);
static struct global * obj_global(struct remote_data *rd, uint32_t id);
static int children_of(struct remote_data *rd, uint32_t parent_id,
const char *child_type, uint32_t **children);
static int pw_split_ip(char *str, const char *delimiter, int max_tokens, char *tokens[])
{
const char *state = NULL;
@ -1498,15 +1503,68 @@ static bool do_destroy(struct data *data, const char *cmd, char *args, char **er
return true;
}
static struct global *
obj_global_port(struct remote_data *rd, struct global *global, const char *port_direction, const char *port_id)
{
struct global *global_port_found = NULL;
uint32_t *ports = NULL;
int port_count;
port_count = children_of(rd, global->id, PW_TYPE_INTERFACE_Port, &ports);
if (port_count <= 0)
return NULL;
for (int i = 0; i < port_count; i++) {
struct global *global_port = obj_global(rd, ports[i]);
if (!global_port)
continue;
struct spa_dict *props_port = global_props(global_port);
if (spa_streq(spa_dict_lookup(props_port, "port.direction"), port_direction)
&& spa_streq(spa_dict_lookup(props_port, "port.id"), port_id)) {
global_port_found = global_port;
break;
}
}
free(ports);
return global_port_found;
}
static void create_link_with_properties(struct data *data, struct pw_properties *props)
{
struct remote_data *rd = data->current;
uint32_t id;
struct pw_proxy *proxy;
struct proxy_data *pd;
proxy = (struct pw_proxy*)pw_core_create_object(rd->core,
"link-factory",
PW_TYPE_INTERFACE_Link,
PW_VERSION_LINK,
props ? &props->dict : NULL,
sizeof(struct proxy_data));
pd = pw_proxy_get_user_data(proxy);
pd->rd = rd;
pd->proxy = proxy;
pd->class = &link_class;
pw_proxy_add_object_listener(proxy, &pd->object_listener, &link_events, pd);
pw_proxy_add_listener(proxy, &pd->proxy_listener, &proxy_events, pd);
id = pw_map_insert_new(&data->vars, proxy);
printf("%d = @proxy:%d\n", id, pw_proxy_get_id((struct pw_proxy*)proxy));
}
static bool do_create_link(struct data *data, const char *cmd, char *args, char **error)
{
struct remote_data *rd = data->current;
char *a[5];
int n;
uint32_t id;
struct pw_proxy *proxy;
int n;
struct pw_properties *props = NULL;
struct proxy_data *pd;
n = pw_split_ip(args, WHITESPACE, 5, a);
if (n < 4) {
@ -1527,25 +1585,55 @@ static bool do_create_link(struct data *data, const char *cmd, char *args, char
if (!spa_streq(a[3], "-"))
pw_properties_set(props, PW_KEY_LINK_INPUT_PORT, a[3]);
proxy = (struct pw_proxy*)pw_core_create_object(rd->core,
"link-factory",
PW_TYPE_INTERFACE_Link,
PW_VERSION_LINK,
props ? &props->dict : NULL,
sizeof(struct proxy_data));
if (spa_streq(a[1], "*") && spa_streq(a[3], "*")) {
struct global *global_out, *global_in;
struct proxy_data *pd_out, *pd_in;
uint32_t n_output_ports, n_input_ports;
global_out = find_global(rd, a[0]);
if (global_out == NULL) {
*error = spa_aprintf("%s: unknown global '%s'", cmd, a[0]);
return false;
}
global_in = find_global(rd, a[2]);
if (global_in == NULL) {
*error = spa_aprintf("%s: unknown global '%s'", cmd, a[2]);
return false;
}
pd_out = pw_proxy_get_user_data(global_out->proxy);
pd_in = pw_proxy_get_user_data(global_in->proxy);
n_output_ports = ((struct pw_node_info *)pd_out->info)->n_output_ports;
n_input_ports = ((struct pw_node_info *)pd_in->info)->n_input_ports;
if (n_output_ports != n_input_ports) {
*error = spa_aprintf("%s: Number of ports don't match (%u != %u)", cmd, n_output_ports, n_input_ports);
return false;
}
for (uint32_t i = 0; i < n_output_ports; i++) {
char port_id[4];
struct global *global_port_out, *global_port_in;
snprintf(port_id, 4, "%d", i);
global_port_out = obj_global_port(rd, global_out, "out", port_id);
global_port_in = obj_global_port(rd, global_in, "in", port_id);
if (!global_port_out || !global_port_in)
continue;
pw_properties_setf(props, PW_KEY_LINK_OUTPUT_PORT, "%d", global_port_out->id);
pw_properties_setf(props, PW_KEY_LINK_INPUT_PORT, "%d", global_port_in->id);
create_link_with_properties(data, props);
}
} else
create_link_with_properties(data, props);
pw_properties_free(props);
pd = pw_proxy_get_user_data(proxy);
pd->rd = rd;
pd->proxy = proxy;
pd->class = &link_class;
pw_proxy_add_object_listener(proxy, &pd->object_listener, &link_events, pd);
pw_proxy_add_listener(proxy, &pd->proxy_listener, &proxy_events, pd);
id = pw_map_insert_new(&data->vars, proxy);
printf("%d = @proxy:%d\n", id, pw_proxy_get_id((struct pw_proxy*)proxy));
return true;
}