diff --git a/src/tools/pw-link.c b/src/tools/pw-link.c index 155f48fe5..a435bc27c 100644 --- a/src/tools/pw-link.c +++ b/src/tools/pw-link.c @@ -109,6 +109,8 @@ static int create_link(struct data *data) struct pw_proxy *proxy; struct spa_hook listener; + data->link_res = 0; + proxy = pw_core_create_object(data->core, "link-factory", PW_TYPE_INTERFACE_Link, @@ -139,6 +141,47 @@ static struct object *find_object(struct data *data, uint32_t type, uint32_t id) return NULL; } +static struct object *find_node_port(struct data *data, struct object *node, enum pw_direction direction, const char *port_id) +{ + struct object *o; + + spa_list_for_each(o, &data->objects, link) { + const char *o_port_id; + if (o->type != OBJECT_PORT) + continue; + if (o->extra[1] != node->id) + continue; + if (o->extra[0] != direction) + continue; + if ((o_port_id = pw_properties_get(o->props, PW_KEY_PORT_ID)) == NULL) + continue; + if (spa_streq(o_port_id, port_id)) + return o; + } + + return NULL; +} + +static char *node_name(char *buffer, int size, struct object *n) +{ + const char *name; + buffer[0] = '\0'; + if ((name = pw_properties_get(n->props, PW_KEY_NODE_NAME)) == NULL) + return buffer; + snprintf(buffer, size, "%s", name); + return buffer; +} + +static char *node_path(char *buffer, int size, struct object *n) +{ + const char *name; + buffer[0] = '\0'; + if ((name = pw_properties_get(n->props, PW_KEY_OBJECT_PATH)) == NULL) + return buffer; + snprintf(buffer, size, "%s", name); + return buffer; +} + static char *port_name(char *buffer, int size, struct object *n, struct object *p) { const char *name1, *name2; @@ -241,6 +284,19 @@ static void do_list_port_links(struct data *data, struct object *node, struct ob } } +static int node_matches(struct data *data, struct object *n, const char *name) +{ + char buffer[1024]; + uint32_t id = atoi(name); + if (n->id == id) + return 1; + if (spa_streq(node_name(buffer, sizeof(buffer), n), name)) + return 1; + if (spa_streq(node_path(buffer, sizeof(buffer), n), name)) + return 1; + return 0; +} + static int port_matches(struct data *data, struct object *n, struct object *p, const char *name) { char buffer[1024]; @@ -304,11 +360,20 @@ static int do_link_ports(struct data *data) { uint32_t in_port = 0, out_port = 0; struct object *n, *p; + struct object *in_node = NULL, *out_node = NULL; spa_list_for_each(n, &data->objects, link) { if (n->type != OBJECT_NODE) continue; + if (out_node == NULL && node_matches(data, n, data->opt_output)) { + out_node = n; + continue; + } else if (in_node == NULL && node_matches(data, n, data->opt_input)) { + in_node = n; + continue; + } + spa_list_for_each(p, &data->objects, link) { if (p->type != OBJECT_PORT) continue; @@ -323,6 +388,33 @@ static int do_link_ports(struct data *data) in_port = p->id; } } + + if (in_node && out_node) { + int i, ret; + char port_id[5]; + bool all_links_exist = true; + + for (i=0;; i++) { + snprintf(port_id, sizeof(port_id), "%d", i); + + struct object *port_out = find_node_port(data, out_node, PW_DIRECTION_OUTPUT, port_id); + struct object *port_in = find_node_port(data, in_node, PW_DIRECTION_INPUT, port_id); + + if (!port_out || !port_in) + break; + + pw_properties_setf(data->props, PW_KEY_LINK_OUTPUT_PORT, "%u", port_out->id); + pw_properties_setf(data->props, PW_KEY_LINK_INPUT_PORT, "%u", port_in->id); + + if ((ret = create_link(data)) < 0 && ret != -EEXIST) + return ret; + + if (ret >= 0) + all_links_exist = false; + } + return (all_links_exist ? -EEXIST : 0); + } + if (in_port == 0 || out_port == 0) return -ENOENT;