From 27f811d726c8b7fdf698bb9eb2ef3a1a3d464794 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 16 Aug 2017 12:43:06 +0200 Subject: [PATCH] jack: move more stuff to nodes and ports Improve cleanup and registration of jack clients --- src/modules/module-jack.c | 520 +++++++++++++++------------- src/modules/module-jack/jack-node.c | 439 ++++++++++++++++------- src/modules/module-jack/jack-node.h | 74 +++- src/modules/module-jack/server.h | 6 +- src/modules/module-jack/shared.h | 113 +++++- src/modules/module-jack/synchro.h | 17 +- 6 files changed, 784 insertions(+), 385 deletions(-) diff --git a/src/modules/module-jack.c b/src/modules/module-jack.c index 25d93eb56..1330f4bd0 100644 --- a/src/modules/module-jack.c +++ b/src/modules/module-jack.c @@ -95,11 +95,31 @@ struct impl { struct client { struct impl *impl; + struct spa_list link; + struct pw_client *client; struct spa_hook client_listener; + int fd; struct spa_source *source; + + struct spa_list jack_clients; +}; + +struct port { + struct impl *impl; + struct pw_jack_port *port; + struct spa_hook port_listener; + struct jack_client *jc; +}; + +struct link { + struct impl *impl; + struct pw_link *link; + struct pw_jack_port *out_port; + struct pw_jack_port *in_port; + struct spa_hook link_listener; }; static bool init_socket_name(struct sockaddr_un *addr, const char *name, bool promiscuous, int which) @@ -135,11 +155,11 @@ notify_client(struct jack_client *client, int ref_num, const char *name, int not char _name[JACK_CLIENT_NAME_SIZE+1]; char _message[JACK_MESSAGE_SIZE+1]; - if (client->fd == 0) + if (client->fd == -1) return 0; if (name == NULL) - name = client->control->name; + name = client->node->control->name; snprintf(_name, sizeof(_name), "%s", name); snprintf(_message, sizeof(_message), "%s", message); @@ -173,17 +193,33 @@ notify_add_client(struct impl *impl, struct jack_client *client, const char *nam if (c == NULL || c == client) continue; - n = c->control->name; - if (notify_client(c, ref_num, name, jack_notify_AddClient, false, "", 0, 0) < 0) { - pw_log_warn("module-jack %p: can't notify client", impl); - } + n = c->node->control->name; + if (notify_client(c, ref_num, name, jack_notify_AddClient, false, "", 0, 0) < 0) + pw_log_warn("module-jack %p: can't notify add client", impl); + if (notify_client(client, i, n, jack_notify_AddClient, true, "", 0, 0) < 0) { - pw_log_error("module-jack %p: can't notify client", impl); + pw_log_error("module-jack %p: can't notify add client", impl); return -1; } } return 0; } +static int +notify_remove_client(struct impl *impl, const char *name, int ref_num) +{ + struct jack_server *server = &impl->server; + int i; + + for (i = 0; i < CLIENT_NUM; i++) { + struct jack_client *c = server->client_table[i]; + + if (c == NULL) + continue; + if (notify_client(c, ref_num, name, jack_notify_RemoveClient, false, "", 0, 0) < 0) + pw_log_warn("module-jack %p: can't notify remove client", impl); + } + return 0; +} void notify_clients(struct impl *impl, int notify, @@ -201,34 +237,39 @@ notify_clients(struct impl *impl, int notify, } } -static int process_messages(struct client *client); - -static void client_destroy(void *data) +static void port_destroy(void *data) { - struct client *this = data; + struct pw_jack_port *port = data; + struct port *p = port->user_data; + struct impl *impl = p->impl; - pw_loop_destroy_source(pw_core_get_main_loop(this->impl->core), this->source); - spa_list_remove(&this->link); + pw_log_debug("port %p: destroy", port); - close(this->fd); + notify_clients(impl, jack_notify_PortRegistrationOffCallback, false, "", port->port_id, 0); } +static const struct pw_jack_port_events port_listener = { + PW_VERSION_JACK_PORT_EVENTS, + .destroy = port_destroy, +}; + +static int process_messages(struct client *client); + static int handle_register_port(struct client *client) { struct impl *impl = client->impl; struct jack_server *server = &impl->server; - struct jack_graph_manager *mgr = server->graph_manager; - struct jack_connection_manager *conn; - int result = 0; + int result = -1; int ref_num; char name[JACK_PORT_NAME_SIZE + 1]; char port_type[JACK_PORT_TYPE_SIZE + 1]; unsigned int flags; unsigned int buffer_size; static jack_port_id_t port_index = 0; - jack_port_type_id_t type_id; struct jack_client *jc; + struct pw_jack_port *port; + struct port *p; CheckSize(kRegisterPort_size); CheckRead(&ref_num, sizeof(int)); @@ -240,44 +281,25 @@ handle_register_port(struct client *client) pw_log_debug("protocol-jack %p: kRegisterPort %d %s %s %u %u", impl, ref_num, name, port_type, flags, buffer_size); - type_id = jack_port_get_type_id(port_type); - - if (jack_graph_manager_find_port(mgr, name) != NO_PORT) { - pw_log_error("protocol-jack %p: port_name %s exists", impl, name); - result = -1; - goto reply; - } - - port_index = jack_graph_manager_allocate_port(mgr, ref_num, name, type_id, flags); - if (port_index == NO_PORT) { - pw_log_error("protocol-jack %p: failed to create port name %s", impl, name); - result = -1; - goto reply; - } - jc = server->client_table[ref_num]; - pw_jack_node_add_port(jc->node, - flags & JackPortIsInput ? - PW_DIRECTION_INPUT : - PW_DIRECTION_OUTPUT, - port_index); - conn = jack_graph_manager_next_start(mgr); - - if (jack_connection_manager_add_port(conn, (flags & JackPortIsInput) ? true : false, - ref_num, port_index) < 0) { - pw_log_error("protocol-jack %p: failed to add port", impl); - jack_graph_manager_release_port(mgr, port_index); - result = -1; - goto reply_stop; + port = pw_jack_node_add_port(jc->node, name, port_type, flags, sizeof(struct port)); + if (port == NULL) { + pw_log_error("module-jack %p: can't add port", impl); + goto reply; } + p = port->user_data; + p->impl = impl; + p->jc = jc; + port_index = port->port_id; - reply_stop: - jack_graph_manager_next_stop(mgr); + pw_jack_port_add_listener(port, &p->port_listener, &port_listener, port); - if (jc->control->active) + if (jc->node->control->active) notify_clients(impl, jack_notify_PortRegistrationOnCallback, false, "", port_index, 0); + result = 0; + reply: CheckWrite(&result, sizeof(int)); CheckWrite(&port_index, sizeof(jack_port_id_t)); @@ -291,9 +313,11 @@ handle_activate_client(struct client *client) struct jack_server *server = &impl->server; struct jack_graph_manager *mgr = server->graph_manager; struct jack_connection_manager *conn; - int result = 0; - int ref_num; + struct jack_client *jc; + int result = 0, ref_num, i; int is_real_time; + jack_int_t input_ports[PORT_NUM_FOR_CLIENT]; + jack_int_t output_ports[PORT_NUM_FOR_CLIENT]; CheckSize(kActivateClient_size); CheckRead(&ref_num, sizeof(int)); @@ -307,34 +331,38 @@ handle_activate_client(struct client *client) jack_connection_manager_direct_connect(conn, server->freewheel_ref_num, ref_num); jack_connection_manager_direct_connect(conn, ref_num, server->freewheel_ref_num); + memcpy (input_ports, jack_connection_manager_get_inputs(conn, ref_num), sizeof(input_ports)); + memcpy (output_ports, jack_connection_manager_get_outputs(conn, ref_num), sizeof(input_ports)); + jack_graph_manager_next_stop(mgr); - notify_clients(impl, jack_notify_ActivateClient, true, "", 0, 0); + for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) + notify_clients(impl, jack_notify_PortRegistrationOnCallback, false, "", input_ports[i], 0); + for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) + notify_clients(impl, jack_notify_PortRegistrationOnCallback, false, "", output_ports[i], 0); + + jc = server->client_table[ref_num]; + if (jc) + notify_client(jc, ref_num, NULL, jack_notify_ActivateClient, true, "", 0, 0); CheckWrite(&result, sizeof(int)); return 0; } -static int -handle_deactivate_client(struct client *client) +static int client_deactivate(struct impl *impl, int ref_num) { - struct impl *impl = client->impl; struct jack_server *server = &impl->server; + int fw_ref = server->freewheel_ref_num, i; struct jack_graph_manager *mgr = server->graph_manager; struct jack_connection_manager *conn; - int result = 0; - int ref_num, fw_ref; - - CheckSize(kDeactivateClient_size); - CheckRead(&ref_num, sizeof(int)); - - pw_log_debug("protocol-jack %p: kDeactivateClient %d", client->impl, - ref_num); - - fw_ref = server->freewheel_ref_num; + jack_int_t input_ports[PORT_NUM_FOR_CLIENT]; + jack_int_t output_ports[PORT_NUM_FOR_CLIENT]; conn = jack_graph_manager_next_start(mgr); + memcpy (input_ports, jack_connection_manager_get_inputs(conn, ref_num), sizeof(input_ports)); + memcpy (output_ports, jack_connection_manager_get_outputs(conn, ref_num), sizeof(input_ports)); + if (jack_connection_manager_is_direct_connection(conn, fw_ref, ref_num)) jack_connection_manager_direct_disconnect(conn, fw_ref, ref_num); @@ -343,6 +371,29 @@ handle_deactivate_client(struct client *client) jack_graph_manager_next_stop(mgr); + for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) + notify_clients(impl, jack_notify_PortRegistrationOffCallback, false, "", input_ports[i], 0); + for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) + notify_clients(impl, jack_notify_PortRegistrationOffCallback, false, "", output_ports[i], 0); + + return 0; +} + +static int +handle_deactivate_client(struct client *client) +{ + struct impl *impl = client->impl; + int result = 0; + int ref_num; + + CheckSize(kDeactivateClient_size); + CheckRead(&ref_num, sizeof(int)); + + pw_log_debug("protocol-jack %p: kDeactivateClient %d", client->impl, + ref_num); + + result = client_deactivate(impl, ref_num); + CheckWrite(&result, sizeof(int)); return 0; } @@ -388,44 +439,84 @@ handle_client_check(struct client *client) return 0; } +static void node_destroy(void *data) +{ + struct jack_client *jc = data; + struct impl *impl = jc->data; + struct jack_server *server = &impl->server; + int ref_num = jc->node->control->ref_num; + + pw_log_debug("module-jack %p: jack_client %p destroy", impl, jc); + + client_deactivate(impl, ref_num); + + spa_list_remove(&jc->client_link); + spa_list_remove(&jc->node->graph_link); + + jack_server_free_ref_num(server, ref_num); +} + +static void node_free(void *data) +{ + struct jack_client *jc = data; + struct impl *impl = jc->data; + struct jack_server *server = &impl->server; + int ref_num = jc->node->control->ref_num; + + notify_remove_client(impl, jc->node->control->name, ref_num); + + jack_synchro_close(&server->synchro_table[ref_num]); + if (jc->fd != -1) + close(jc->fd); +} + +static const struct pw_jack_node_events node_events = { + PW_VERSION_JACK_NODE_EVENTS, + .destroy = node_destroy, + .free = node_free, +}; + static int handle_client_open(struct client *client) { struct impl *impl = client->impl; struct jack_server *server = &impl->server; - struct jack_graph_manager *mgr = server->graph_manager; - struct jack_connection_manager *conn; int PID, UUID; char name[JACK_CLIENT_NAME_SIZE+1]; int result = -1, ref_num, shared_engine, shared_client, shared_graph; struct jack_client *jc; const struct ucred *ucred; struct sockaddr_un addr; + struct pw_jack_node *node; CheckSize(kClientOpen_size); CheckRead(&PID, sizeof(int)); CheckRead(&UUID, sizeof(int)); CheckRead(name, sizeof(name)); - ref_num = jack_server_allocate_ref_num(server); - if (ref_num == -1) { - pw_log_error("module-jack %p: can't allocated ref_num", impl); + ucred = pw_client_get_ucred(client->client); + + node = pw_jack_node_new(impl->core, + pw_module_get_global(impl->module), + server, + name, + ucred ? ucred->pid : PID, + NULL, + sizeof(struct jack_client)); + if (node == NULL) { + pw_log_error("module-jack %p: can't create node", impl); goto reply; } - jc = calloc(1,sizeof(struct jack_client)); + ref_num = node->control->ref_num; + + jc = node->user_data; + jc->fd = -1; + jc->data = impl; jc->owner = client; - jc->ref_num = ref_num; + jc->node = node; - if (jack_synchro_init(&server->synchro_table[ref_num], - name, - server->engine_control->server_name, - 0, - false, - server->promiscuous) < 0) { - pw_log_error("module-jack %p: can't init synchro", impl); - goto reply; - } + pw_jack_node_add_listener(node, &jc->node_listener, &node_events, jc); if ((jc->fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { pw_log_error("module-jack %p: can't create socket %s", impl, strerror(errno)); @@ -440,33 +531,19 @@ handle_client_open(struct client *client) goto reply; } - ucred = pw_client_get_ucred(client->client); - - jc->control = jack_client_control_alloc(name, ucred ? ucred->pid : 0, ref_num, -1); - if (jc->control == NULL) { - pw_log_error("module-jack %p: can't create control", impl); - goto reply; - } - server->client_table[ref_num] = jc; pw_log_debug("module-jack %p: Added client %d \"%s\"", impl, ref_num, name); - conn = jack_graph_manager_next_start(mgr); - jack_connection_manager_init_ref_num(conn, ref_num); - jack_graph_manager_next_stop(mgr); - - jc->node = pw_jack_node_new(impl->core, pw_module_get_global(impl->module), - server, ref_num, NULL); + spa_list_append(&client->jack_clients, &jc->client_link); + spa_list_append(&impl->rt.nodes, &jc->node->graph_link); if (notify_add_client(impl, jc, name, ref_num) < 0) { pw_log_error("module-jack %p: can't notify add_client", impl); goto reply; } - spa_list_append(&impl->rt.nodes, &jc->node->graph_link); - shared_engine = impl->server.engine_control->info.index; - shared_client = jc->control->info.index; + shared_client = jc->node->control->info.index; shared_graph = impl->server.graph_manager->info.index; result = 0; @@ -488,10 +565,38 @@ handle_client_close(struct client *client) CheckRead(&ref_num, sizeof(int)); int result = 0; + + CheckWrite(&result, sizeof(int)); return 0; } +static void link_destroy(void *data) +{ + struct link *ld = data; + struct impl *impl = ld->impl; + struct pw_jack_port *out_port = ld->out_port, *in_port = ld->in_port; + struct jack_server *server = &impl->server; + struct jack_graph_manager *mgr = server->graph_manager; + struct jack_connection_manager *conn; + jack_port_id_t src_id = out_port->port_id, dst_id = in_port->port_id; + + pw_log_debug("module-jack %p: link %p destroy", impl, ld->link); + + conn = jack_graph_manager_next_start(mgr); + if (jack_connection_manager_disconnect_ports(conn, src_id, dst_id)) { + pw_log_warn("module-jack %p: ports can't disconnect", impl); + } + jack_graph_manager_next_stop(mgr); + + notify_clients(impl, jack_notify_PortDisconnectCallback, false, "", src_id, dst_id); +} + +static const struct pw_link_events link_events = { + PW_VERSION_LINK_EVENTS, + .destroy = link_destroy, +}; + static int handle_connect_name_ports(struct client *client) { @@ -506,8 +611,9 @@ handle_connect_name_ports(struct client *client) int result = -1, in_ref, out_ref; jack_port_id_t src_id, dst_id; struct jack_port *src_port, *dst_port; - struct pw_port *out_port, *in_port; + struct pw_jack_port *out_port, *in_port; struct pw_link *link; + struct link *ld; CheckSize(kConnectNamePorts_size); CheckRead(&ref_num, sizeof(int)); @@ -557,7 +663,7 @@ handle_connect_name_ports(struct client *client) pw_log_error("protocol-jack %p: unknown client %d", impl, out_ref); goto reply_stop; } - if (!jc->control->active) { + if (!jc->node->control->active) { pw_log_error("protocol-jack %p: can't connect ports of inactive client", impl); goto reply_stop; } @@ -572,39 +678,32 @@ handle_connect_name_ports(struct client *client) pw_log_error("protocol-jack %p: unknown client %d", impl, in_ref); goto reply_stop; } - if (!jc->control->active) { + if (!jc->node->control->active) { pw_log_error("protocol-jack %p: can't connect ports of inactive client", impl); goto reply_stop; } in_port = pw_jack_node_find_port(jc->node, PW_DIRECTION_INPUT, dst_id); - if (jack_connection_manager_is_connected(conn, src_id, dst_id)) { - pw_log_error("protocol-jack %p: ports are already connected", impl); + if (jack_connection_manager_connect_ports(conn, src_id, dst_id)) { + pw_log_error("protocol-jack %p: ports can't connect", impl); goto reply_stop; } - if (jack_connection_manager_connect(conn, src_id, dst_id) < 0) { - pw_log_error("protocol-jack %p: connection table is full", impl); - goto reply_stop; - } - if (jack_connection_manager_connect(conn, dst_id, src_id) < 0) { - pw_log_error("protocol-jack %p: connection table is full", impl); - goto reply_stop; - } - if (jack_connection_manager_is_loop_path(conn, src_id, dst_id) < 0) - jack_connection_manager_inc_feedback_connection(conn, src_id, dst_id); - else - jack_connection_manager_inc_direct_connection(conn, src_id, dst_id); - - pw_log_debug("%p %p", out_port, in_port); + pw_log_debug("protocol-jack %p: connected ports %p %p", impl, out_port, in_port); link = pw_link_new(impl->core, pw_module_get_global(impl->module), - out_port, - in_port, + out_port->port, + in_port->port, NULL, NULL, NULL, - 0); + sizeof(struct link)); + ld = pw_link_get_user_data(link); + ld->impl = impl; + ld->link = link; + ld->out_port = out_port; + ld->in_port = in_port; + pw_link_add_listener(link, &ld->link_listener, &link_events, ld); pw_link_activate(link); notify_clients(impl, jack_notify_PortConnectCallback, false, "", src_id, dst_id); @@ -736,6 +835,17 @@ client_busy_changed(void *data, bool busy) process_messages(c); } +static void client_killed(struct client *client) +{ + struct jack_client *jc; + + spa_list_for_each(jc, &client->jack_clients, client_link) { + close(jc->fd); + jc->fd = -1; + } + pw_client_destroy(client->client); +} + static void connection_data(void *data, int fd, enum spa_io mask) { @@ -743,7 +853,7 @@ connection_data(void *data, int fd, enum spa_io mask) if (mask & (SPA_IO_ERR | SPA_IO_HUP)) { pw_log_error("protocol-native %p: got connection error", client->impl); - pw_client_destroy(client->client); + client_killed(client); return; } @@ -751,6 +861,20 @@ connection_data(void *data, int fd, enum spa_io mask) process_messages(client); } +static void client_destroy(void *data) +{ + struct client *this = data; + struct jack_client *jc, *t; + + pw_loop_destroy_source(pw_core_get_main_loop(this->impl->core), this->source); + spa_list_remove(&this->link); + + spa_list_for_each_safe(jc, t, &this->jack_clients, client_link) + pw_jack_node_destroy(jc->node); + + close(this->fd); +} + static const struct pw_client_events client_events = { PW_VERSION_CLIENT_EVENTS, .destroy = client_destroy, @@ -778,6 +902,7 @@ static struct client *client_new(struct impl *impl, int fd) goto no_client; this = pw_client_get_user_data(client); + this->client = client; this->impl = impl; this->fd = fd; this->source = pw_loop_add_io(pw_core_get_main_loop(impl->core), @@ -786,8 +911,7 @@ static struct client *client_new(struct impl *impl, int fd) if (this->source == NULL) goto no_source; - this->client = client; - + spa_list_init(&this->jack_clients); spa_list_insert(impl->client_list.prev, &this->link); pw_client_add_listener(client, &this->client_listener, &client_events, this); @@ -894,63 +1018,35 @@ static int make_audio_client(struct impl *impl) { struct jack_server *server = &impl->server; - struct jack_graph_manager *mgr = server->graph_manager; - struct jack_connection_manager *conn; int ref_num; struct jack_client *jc; - jack_port_id_t port_id; + struct pw_jack_node *node; - ref_num = jack_server_allocate_ref_num(server); - if (ref_num == -1) - return -1; - - if (jack_synchro_init(&server->synchro_table[ref_num], - "system", - server->engine_control->server_name, - 0, - false, - server->promiscuous) < 0) { + node = pw_jack_driver_new(impl->core, + pw_module_get_global(impl->module), + server, + "system", + 0, 2, + NULL, + sizeof(struct jack_client)); + if (node == NULL) { + pw_log_error("module-jack %p: can't create driver node", impl); return -1; } - jc = calloc(1,sizeof(struct jack_client)); + ref_num = node->control->ref_num; + + jc = node->user_data; + jc->fd = -1; jc->data = impl; - jc->ref_num = ref_num; - jc->control = jack_client_control_alloc("system", -1, ref_num, -1); - jc->control->active = true; + jc->node = node; + pw_jack_node_add_listener(node, &jc->node_listener, &jack_node_events, jc); server->client_table[ref_num] = jc; - impl->server.engine_control->driver_num++; - - conn = jack_graph_manager_next_start(mgr); - - jack_connection_manager_init_ref_num(conn, ref_num); - jack_connection_manager_direct_connect(conn, ref_num, ref_num); - - port_id = jack_graph_manager_allocate_port(mgr, - ref_num, "system:playback_1", 0, - JackPortIsInput | - JackPortIsPhysical | - JackPortIsTerminal); - jack_connection_manager_add_port(conn, true, ref_num, port_id); - - port_id = jack_graph_manager_allocate_port(mgr, - ref_num, "system:playback_2", 0, - JackPortIsInput | - JackPortIsPhysical | - JackPortIsTerminal); - jack_connection_manager_add_port(conn, true, ref_num, port_id); - - jack_graph_manager_next_stop(mgr); - server->audio_ref_num = ref_num; - server->audio_node = pw_jack_node_new(impl->core, pw_module_get_global(impl->module), - server, ref_num, NULL); - server->audio_node_node = pw_jack_node_get_node(server->audio_node); - jc->node = server->audio_node; - - pw_jack_node_add_listener(server->audio_node, &jc->node_listener, &jack_node_events, jc); + server->audio_node = node; + server->audio_node_node = node->node; pw_log_debug("module-jack %p: Added audio driver %d", impl, ref_num); @@ -961,41 +1057,31 @@ static int make_freewheel_client(struct impl *impl) { struct jack_server *server = &impl->server; - struct jack_graph_manager *mgr = server->graph_manager; - struct jack_connection_manager *conn; int ref_num; struct jack_client *jc; + struct pw_jack_node *node; - ref_num = jack_server_allocate_ref_num(server); - if (ref_num == -1) - return -1; - - if (jack_synchro_init(&server->synchro_table[ref_num], - "freewheel", - server->engine_control->server_name, - 0, - false, - server->promiscuous) < 0) { + node = pw_jack_driver_new(impl->core, + pw_module_get_global(impl->module), + server, + "freewheel", + 0, 0, + NULL, + sizeof(struct jack_client)); + if (node == NULL) { + pw_log_error("module-jack %p: can't create driver node", impl); return -1; } - jc = calloc(1,sizeof(struct jack_client)); + ref_num = node->control->ref_num; + + jc = node->user_data; + jc->fd = -1; jc->data = impl; - jc->ref_num = ref_num; - jc->control = jack_client_control_alloc("freewheel", -1, ref_num, -1); - jc->control->active = true; + jc->node = node; server->client_table[ref_num] = jc; - impl->server.engine_control->driver_num++; - - conn = jack_graph_manager_next_start(mgr); - - jack_connection_manager_init_ref_num(conn, ref_num); - jack_connection_manager_direct_connect(conn, ref_num, ref_num); - - jack_graph_manager_next_stop(mgr); - server->freewheel_ref_num = ref_num; pw_log_debug("module-jack %p: Added freewheel driver %d", impl, ref_num); @@ -1009,6 +1095,7 @@ static bool on_global(void *data, struct pw_global *global) struct pw_node *node; const struct pw_properties *properties; const char *str; + struct pw_port *in_port, *out_port; if (pw_global_get_type(global) != impl->t->node) return true; @@ -1022,9 +1109,14 @@ static bool on_global(void *data, struct pw_global *global) if (strcmp(str, "Audio/Sink") != 0) return true; + out_port = pw_node_get_free_port(impl->server.audio_node_node, PW_DIRECTION_OUTPUT); + in_port = pw_node_get_free_port(node, PW_DIRECTION_INPUT); + if (out_port == NULL || in_port == NULL) + return true; + impl->sink_link = pw_link_new(impl->core, pw_module_get_global(impl->module), - pw_node_get_free_port(impl->server.audio_node_node, PW_DIRECTION_OUTPUT), - pw_node_get_free_port(node, PW_DIRECTION_INPUT), + out_port, + in_port, NULL, NULL, NULL, @@ -1034,42 +1126,6 @@ static bool on_global(void *data, struct pw_global *global) return false; } -#if 0 -static void on_timeout(void *data, uint64_t expirations) -{ - struct impl *impl = data; - struct jack_server *server = &impl->server; - struct jack_graph_manager *mgr = server->graph_manager; - struct jack_connection_manager *conn; - struct jack_client *client; - int activation; - - client = server->client_table[server->freewheel_ref_num]; - - conn = jack_graph_manager_try_switch(mgr); - - jack_connection_manager_reset(conn, mgr->client_timing); - - activation = jack_connection_manager_get_activation(conn, server->freewheel_ref_num); - if (activation == 0) - return; - - pw_log_trace("resume %d", activation); - jack_connection_manager_resume_ref_num(conn, - client->control, - server->synchro_table, - mgr->client_timing); - - if (server->engine_control->sync_mode) { - pw_log_trace("suspend"); - jack_connection_manager_suspend_ref_num(conn, - client->control, - server->synchro_table, - mgr->client_timing); - } -} -#endif - static bool init_nodes(struct impl *impl) { struct pw_core *core = impl->core; diff --git a/src/modules/module-jack/jack-node.c b/src/modules/module-jack/jack-node.c index 9e52714e1..2194ff828 100644 --- a/src/modules/module-jack/jack-node.c +++ b/src/modules/module-jack/jack-node.c @@ -54,14 +54,6 @@ struct type { struct spa_type_audio_format audio_format; }; -struct impl { - struct pw_jack_node node; - - struct type type; - - int status; -}; - static inline void init_type(struct type *type, struct spa_type_map *map) { type->format = spa_type_map_get_id(map, SPA_TYPE__Format); @@ -72,6 +64,22 @@ static inline void init_type(struct type *type, struct spa_type_map *map) spa_type_audio_format_map(map, &type->audio_format); } +struct node_data { + struct pw_jack_node node; + struct spa_hook node_listener; + + struct type type; + + int n_capture_channels; + int n_playback_channels; + + struct spa_hook_list listener_list; + + int port_count; + + int status; +}; + struct buffer { struct spa_list link; struct spa_buffer *outbuf; @@ -79,12 +87,14 @@ struct buffer { }; struct port_data { - struct impl *impl; - enum pw_direction direction; + struct pw_jack_port port; + struct spa_hook port_listener; - int jack_port_id; - struct jack_port *port; - float *ptr; + struct node_data *node; + + struct spa_hook_list listener_list; + + bool driver_port; struct spa_port_info info; @@ -148,7 +158,7 @@ static int driver_process_input(void *data) struct spa_graph_node *node = &this->node->rt.node; struct spa_graph_port *p; struct buffer *out; - struct port_data *opd = pw_port_get_user_data(this->otherport); + struct port_data *opd = SPA_CONTAINER_OF(this->driverport, struct port_data, port); struct spa_port_io *out_io = opd->io; pw_log_trace("process input"); @@ -197,10 +207,11 @@ static void fill_s16(int16_t *out, int n_samples, int stride) static int driver_process_output(void *data) { - struct pw_jack_node *this = data; + struct node_data *nd = data; + struct pw_jack_node *this = &nd->node; struct spa_graph_node *node = &this->node->rt.node; struct spa_graph_port *p; - struct port_data *opd = pw_port_get_user_data(this->otherport); + struct port_data *opd = SPA_CONTAINER_OF(this->driverport, struct port_data, port); struct spa_port_io *out_io = opd->io; struct jack_engine_control *ctrl = this->server->engine_control; struct buffer *out; @@ -225,7 +236,7 @@ static int driver_process_output(void *data) op = out->ptr; - spa_hook_list_call(&this->listener_list, struct pw_jack_node_events, pull); + spa_hook_list_call(&nd->listener_list, struct pw_jack_node_events, pull); spa_list_for_each(p, &node->ports[SPA_DIRECTION_INPUT], link) { struct pw_port *port = p->callbacks_data; @@ -246,7 +257,7 @@ static int driver_process_output(void *data) } out->outbuf->datas[0].chunk->size = ctrl->buffer_size * sizeof(int16_t) * 2; - spa_hook_list_call(&this->listener_list, struct pw_jack_node_events, push); + spa_hook_list_call(&nd->listener_list, struct pw_jack_node_events, push); node->ready_in = node->required_in; return SPA_RESULT_HAVE_BUFFER; @@ -264,18 +275,18 @@ static const struct pw_node_implementation driver_impl = { static int node_process_input(void *data) { - struct impl *impl = data; - struct pw_jack_node *this = &impl->node; + struct node_data *nd = data; + struct pw_jack_node *this = &nd->node; struct spa_graph_node *node = &this->node->rt.node; struct spa_graph_port *p; struct jack_server *server = this->server; struct jack_graph_manager *mgr = server->graph_manager; struct jack_connection_manager *conn; jack_time_t current_date = 0; - int ref_num = this->ref_num; + int ref_num = this->control->ref_num; - pw_log_trace(NAME " %p: process input", impl); - if (impl->status == SPA_RESULT_HAVE_BUFFER) + pw_log_trace(NAME " %p: process input", nd); + if (nd->status == SPA_RESULT_HAVE_BUFFER) return SPA_RESULT_HAVE_BUFFER; mgr->client_timing[ref_num].status = Triggered; @@ -292,28 +303,28 @@ static int node_process_input(void *data) struct spa_port_io *out_io = opd->io; out_io->buffer_id = 0; out_io->status = SPA_RESULT_HAVE_BUFFER; - pw_log_trace(NAME " %p: port %p: %d %d", impl, p, out_io->buffer_id, out_io->status); + pw_log_trace(NAME " %p: port %p: %d %d", nd, p, out_io->buffer_id, out_io->status); } - return impl->status = SPA_RESULT_HAVE_BUFFER; + return nd->status = SPA_RESULT_HAVE_BUFFER; } static int node_process_output(void *data) { - struct impl *impl = data; - struct pw_jack_node *this = &impl->node; + struct node_data *nd = data; + struct pw_jack_node *this = &nd->node; struct spa_graph_node *node = &this->node->rt.node; struct spa_graph_port *p; - pw_log_trace(NAME " %p: process output", impl); + pw_log_trace(NAME " %p: process output", nd); spa_list_for_each(p, &node->ports[SPA_DIRECTION_INPUT], link) { struct pw_port *port = p->callbacks_data; struct port_data *ipd = pw_port_get_user_data(port); struct spa_port_io *in_io = ipd->io; in_io->buffer_id = 0; in_io->status = SPA_RESULT_NEED_BUFFER; - pw_log_trace(NAME " %p: port %p: %d %d", impl, p, in_io->buffer_id, in_io->status); + pw_log_trace(NAME " %p: port %p: %d %d", nd, p, in_io->buffer_id, in_io->status); } - return impl->status = SPA_RESULT_NEED_BUFFER; + return nd->status = SPA_RESULT_NEED_BUFFER; } static const struct pw_node_implementation node_impl = { @@ -342,25 +353,25 @@ static int port_enum_formats(void *data, int32_t index) { struct port_data *pd = data; - struct type *t = &pd->impl->type; + struct type *t = &pd->node->type; struct spa_pod_builder b = { NULL, }; struct spa_pod_frame f[2]; - struct jack_engine_control *ctrl = pd->impl->node.server->engine_control; + struct jack_engine_control *ctrl = pd->node->node.server->engine_control; if (index > 0) return SPA_RESULT_ENUM_END; spa_pod_builder_init(&b, pd->buffer, sizeof(pd->buffer)); - if (pd->port) { - if (pd->port->type_id == 0) { + if (pd->port.jack_port) { + if (pd->port.jack_port->type_id == 0) { spa_pod_builder_format(&b, &f[0], t->format, t->media_type.audio, t->media_subtype.raw, PROP(&f[1], t->format_audio.format, SPA_POD_TYPE_ID, t->audio_format.F32), PROP(&f[1], t->format_audio.rate, SPA_POD_TYPE_INT, ctrl->sample_rate), PROP(&f[1], t->format_audio.channels, SPA_POD_TYPE_INT, 1)); } - else if (pd->port->type_id == 1) { + else if (pd->port.jack_port->type_id == 1) { return SPA_RESULT_ENUM_END; } else @@ -395,12 +406,13 @@ static int port_get_format(void *data, const struct spa_format **format) static int port_get_info(void *data, const struct spa_port_info **info) { struct port_data *pd = data; + struct pw_jack_port *port = &pd->port; pd->info.flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS | SPA_PORT_INFO_FLAG_LIVE; - if (pd->direction == PW_DIRECTION_OUTPUT && pd->impl->node.otherport == NULL) + if (port->direction == PW_DIRECTION_OUTPUT && port->jack_port != NULL) pd->info.flags |= SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS; - pd->info.rate = pd->impl->node.server->engine_control->sample_rate; + pd->info.rate = pd->node->node.server->engine_control->sample_rate; *info = &pd->info; return SPA_RESULT_OK; @@ -419,7 +431,7 @@ static int port_set_param(void *data, struct spa_param *param) static int port_use_buffers(void *data, struct spa_buffer **buffers, uint32_t n_buffers) { struct port_data *pd = data; - struct type *t = &pd->impl->type; + struct type *t = &pd->node->type; int i; for (i = 0; i < n_buffers; i++) { @@ -448,7 +460,7 @@ static int port_alloc_buffers(void *data, struct spa_buffer **buffers, uint32_t *n_buffers) { struct port_data *pd = data; - struct type *t = &pd->impl->type; + struct type *t = &pd->node->type; int i; for (i = 0; i < *n_buffers; i++) { @@ -458,7 +470,7 @@ static int port_alloc_buffers(void *data, b = &pd->buffers[i]; b->outbuf = buffers[i]; d[0].type = t->data.MemPtr; - b->ptr = d[0].data = pd->ptr; + b->ptr = d[0].data = pd->port.ptr; spa_list_append(&pd->empty, &b->link); } pd->n_buffers = *n_buffers; @@ -491,97 +503,294 @@ static const struct pw_port_implementation port_impl = { .send_command = port_send_command, }; -static struct pw_port *make_port(struct pw_jack_node *node, enum pw_direction direction, - int port_id, int jack_port_id, struct jack_port *jp, bool autoconnect) +static void port_destroy(void *data) { - struct impl *impl = SPA_CONTAINER_OF(node, struct impl, node); - struct pw_port *port; + struct port_data *pd = data; + struct pw_jack_port *port = &pd->port; + struct pw_jack_node *node = &pd->node->node; + struct jack_server *server = node->server; + struct jack_graph_manager *mgr = server->graph_manager; + struct jack_connection_manager *conn; + int ref_num = node->control->ref_num; + jack_port_id_t port_id = port->port_id; + + if (port->jack_port == NULL) + return; + + spa_hook_list_call(&pd->listener_list, struct pw_jack_port_events, destroy); + + conn = jack_graph_manager_next_start(mgr); + + if (port->direction == PW_DIRECTION_INPUT) + jack_connection_manager_remove_inport(conn, ref_num, port_id); + else + jack_connection_manager_remove_outport(conn, ref_num, port_id); + jack_graph_manager_next_stop(mgr); + + jack_graph_manager_release_port(mgr, port->port_id); +} + +static const struct pw_port_events port_events = { + PW_VERSION_PORT_EVENTS, + .destroy = port_destroy, +}; + +struct pw_jack_port * +alloc_port(struct pw_jack_node *node, enum pw_direction direction, uint32_t port_id, size_t user_data_size) +{ + struct node_data *nd = SPA_CONTAINER_OF(node, struct node_data, node); + struct pw_port *p; struct port_data *pd; - struct pw_properties *properties = NULL; + struct pw_jack_port *port; - if (autoconnect) - properties = pw_properties_new("pipewire.autoconnect", "1", NULL); + p = pw_port_new(direction, port_id, NULL, sizeof(struct port_data) + user_data_size); + if (p == NULL) + return NULL; - port = pw_port_new(direction, port_id, properties, sizeof(struct port_data)); - pd = pw_port_get_user_data(port); - pd->direction = direction; - pd->impl = impl; - pd->jack_port_id = jack_port_id; - pd->port = jp; - pd->ptr = (float *)((uintptr_t)jp->buffer & ~31L) + 8; + pd = pw_port_get_user_data(p); + pd->node = nd; + spa_hook_list_init(&pd->listener_list); spa_list_init(&pd->empty); - pw_port_set_implementation(port, &port_impl, pd); - pw_port_add(port, node->node); + port = &pd->port; + + port->node = node; + port->direction = direction; + port->port = p; + + if (user_data_size > 0) + port->user_data = SPA_MEMBER(pd, sizeof(struct port_data), void); + + pw_port_add_listener(p, &pd->port_listener, &port_events, pd); + + pw_port_set_implementation(p, &port_impl, pd); + pw_port_add(p, node->node); return port; } +struct pw_jack_port * +pw_jack_node_add_port(struct pw_jack_node *node, + const char *name, + const char *type, + unsigned int flags, + size_t user_data_size) +{ + struct node_data *nd = SPA_CONTAINER_OF(node, struct node_data, node); + struct jack_server *server = node->server; + struct jack_graph_manager *mgr = server->graph_manager; + struct jack_connection_manager *conn; + struct pw_jack_port *port; + jack_port_type_id_t type_id; + jack_port_id_t port_id; + enum pw_direction direction; + int ref_num; + + type_id = jack_port_get_type_id(type); + + if (jack_graph_manager_find_port(mgr, name) != NO_PORT) { + pw_log_error(NAME " %p: port_name %s exists", node, name); + return NULL; + } + + direction = flags & JackPortIsInput ? PW_DIRECTION_INPUT : PW_DIRECTION_OUTPUT; + ref_num = node->control->ref_num; + + port_id = jack_graph_manager_allocate_port(mgr, ref_num, name, type_id, flags); + if (port_id == NO_PORT) { + pw_log_error(NAME " %p: failed to create port name %s", node, name); + return NULL; + } + + port = alloc_port(node, direction, nd->port_count++, user_data_size); + if (port == NULL) + return NULL; + + port->port_id = port_id; + port->jack_port = jack_graph_manager_get_port(mgr, port_id); + port->ptr = (float *)((uintptr_t)port->jack_port->buffer & ~31L) + 8; + + conn = jack_graph_manager_next_start(mgr); + if (direction == PW_DIRECTION_INPUT) + jack_connection_manager_add_inport(conn, ref_num, port_id); + else + jack_connection_manager_add_outport(conn, ref_num, port_id); + jack_graph_manager_next_stop(mgr); + + return port; +} + +void pw_jack_port_add_listener(struct pw_jack_port *port, + struct spa_hook *listener, + const struct pw_jack_port_events *events, + void *data) +{ + struct port_data *pd = SPA_CONTAINER_OF(port, struct port_data, port); + spa_hook_list_append(&pd->listener_list, listener, events, data); +} + +static void node_destroy(void *data) +{ + struct node_data *nd = data; + spa_hook_list_call(&nd->listener_list, struct pw_jack_node_events, destroy); +} + +static void node_free(void *data) +{ + struct node_data *nd = data; + spa_hook_list_call(&nd->listener_list, struct pw_jack_node_events, free); +} + +static const struct pw_node_events node_events = { + PW_VERSION_NODE_EVENTS, + .destroy = node_destroy, + .free = node_free, +}; + struct pw_jack_node *pw_jack_node_new(struct pw_core *core, struct pw_global *parent, struct jack_server *server, - int ref_num, - struct pw_properties *properties) + const char *name, + int pid, + struct pw_properties *properties, + size_t user_data_size) { - struct impl *impl; - struct pw_jack_node *this; + struct node_data *nd; + int ref_num; struct pw_node *node; - struct jack_client *client = server->client_table[ref_num]; + struct pw_jack_node *this; struct jack_graph_manager *mgr = server->graph_manager; - struct jack_connection_manager *conn; - int i; - jack_int_t *p; - bool make_input = false, make_output = false; + struct jack_connection_manager *conn; - node = pw_node_new(core, NULL, parent, client->control->name, - properties, sizeof(struct impl)); + ref_num = jack_server_allocate_ref_num(server); + if (ref_num == -1) { + pw_log_error(NAME " %p: can't allocated ref_num", core); + return NULL; + } + + if (jack_synchro_init(&server->synchro_table[ref_num], + name, + server->engine_control->server_name, + 0, + server->promiscuous) < 0) { + pw_log_error(NAME " %p: can't init synchro", core); + return NULL; + } + + node = pw_node_new(core, NULL, parent, name, properties, sizeof(struct node_data) + user_data_size); if (node == NULL) return NULL; - impl = pw_node_get_user_data(node); - this = &impl->node; + nd = pw_node_get_user_data(node); + spa_hook_list_init(&nd->listener_list); + init_type(&nd->type, pw_core_get_type(core)->map); + + pw_node_add_listener(node, &nd->node_listener, &node_events, nd); + pw_node_set_implementation(node, &node_impl, nd); + + this = &nd->node; pw_log_debug("jack-node %p: new", this); + if (user_data_size > 0) + this->user_data = SPA_MEMBER(nd, sizeof(struct node_data), void); + this->node = node; this->core = core; - spa_hook_list_init(&this->listener_list); this->server = server; - this->client = client; - this->ref_num = ref_num; - init_type(&impl->type, pw_core_get_type(core)->map); - - conn = jack_graph_manager_next_start(mgr); - - p = GET_ITEMS_FIXED_ARRAY1(conn->input_port[ref_num]); - for (i = 0; i < PORT_NUM_FOR_CLIENT && p[i] != EMPTY; i++) { - struct jack_port *jp = jack_graph_manager_get_port(mgr, p[i]); - - if (jp->flags & JackPortIsPhysical) - make_output = true; - - make_port(this, PW_DIRECTION_INPUT, i, p[i], jp, false); + this->control = jack_client_control_alloc(name, pid, ref_num, -1); + if (this->control == NULL) { + pw_log_error(NAME " %p: can't create control", nd); + return NULL; } - p = GET_ITEMS_FIXED_ARRAY(conn->output_port[ref_num]); - for (i = 0; i < PORT_NUM_FOR_CLIENT && p[i] != EMPTY; i++) { - struct jack_port *jp = jack_graph_manager_get_port(mgr, p[i]); + conn = jack_graph_manager_next_start(mgr); + jack_connection_manager_init_ref_num(conn, ref_num); + jack_graph_manager_next_stop(mgr); - if (jp->flags & JackPortIsPhysical) - make_input = true; + pw_node_register(node); - make_port(this, PW_DIRECTION_OUTPUT, i, p[i], jp, false); + return this; +} + +struct pw_jack_node * +pw_jack_driver_new(struct pw_core *core, + struct pw_global *parent, + struct jack_server *server, + const char *name, + int n_capture_channels, + int n_playback_channels, + struct pw_properties *properties, + size_t user_data_size) +{ + struct node_data *nd; + int ref_num, i; + struct pw_node *node; + struct pw_jack_node *this; + struct jack_graph_manager *mgr = server->graph_manager; + struct jack_connection_manager *conn; + char n[REAL_JACK_PORT_NAME_SIZE]; + + ref_num = jack_server_allocate_ref_num(server); + if (ref_num == -1) { + pw_log_error(NAME " %p: can't allocated ref_num", core); + return NULL; } - jack_graph_manager_next_stop(mgr); - if (make_output) - this->otherport = make_port(this, PW_DIRECTION_OUTPUT, 0, -1, NULL, true); - if (make_input) - this->otherport = make_port(this, PW_DIRECTION_INPUT, 0, -1, NULL, true); + if (jack_synchro_init(&server->synchro_table[ref_num], + name, + server->engine_control->server_name, + 0, + server->promiscuous) < 0) { + pw_log_error(NAME " %p: can't init synchro", core); + return NULL; + } - if (make_output || make_input) - pw_node_set_implementation(node, &driver_impl, this); - else - pw_node_set_implementation(node, &node_impl, this); + node = pw_node_new(core, NULL, parent, name, properties, sizeof(struct node_data) + user_data_size); + if (node == NULL) + return NULL; + nd = pw_node_get_user_data(node); + spa_hook_list_init(&nd->listener_list); + init_type(&nd->type, pw_core_get_type(core)->map); + + pw_node_set_implementation(node, &driver_impl, nd); + + this = &nd->node; + this->node = node; + this->core = core; + this->server = server; + this->control = jack_client_control_alloc(name, -1, ref_num, -1); + this->control->active = true; + + if (user_data_size > 0) + this->user_data = SPA_MEMBER(nd, sizeof(struct node_data), void); + + server->engine_control->driver_num++; + + conn = jack_graph_manager_next_start(mgr); + jack_connection_manager_init_ref_num(conn, ref_num); + jack_connection_manager_direct_connect(conn, ref_num, ref_num); + + for (i = 0; i < n_capture_channels; i++) { + snprintf(n, sizeof(n), "%s:capture_%d", name, i); + pw_jack_node_add_port(this, n, JACK_DEFAULT_AUDIO_TYPE, + JackPortIsOutput | + JackPortIsPhysical | + JackPortIsTerminal, 0); + } + + for (i = 0; i < n_playback_channels; i++) { + snprintf(n, sizeof(n), "%s:playback_%d", name, i); + pw_jack_node_add_port(this, n, JACK_DEFAULT_AUDIO_TYPE, + JackPortIsInput | + JackPortIsPhysical | + JackPortIsTerminal, 0); + } + jack_graph_manager_next_stop(mgr); + + if (n_capture_channels > 0) + this->driverport = alloc_port(this, PW_DIRECTION_INPUT, 0, 0); + if (n_playback_channels > 0) + this->driverport = alloc_port(this, PW_DIRECTION_OUTPUT, 0, 0); pw_node_register(node); @@ -592,12 +801,6 @@ void pw_jack_node_destroy(struct pw_jack_node *node) { pw_log_debug("jack-node %p: destroy", node); pw_node_destroy(node->node); - free(node); -} - -struct pw_node *pw_jack_node_get_node(struct pw_jack_node *node) -{ - return node->node; } void pw_jack_node_add_listener(struct pw_jack_node *node, @@ -605,12 +808,13 @@ void pw_jack_node_add_listener(struct pw_jack_node *node, const struct pw_jack_node_events *events, void *data) { - spa_hook_list_append(&node->listener_list, listener, events, data); + struct node_data *nd = SPA_CONTAINER_OF(node, struct node_data, node); + spa_hook_list_append(&nd->listener_list, listener, events, data); } struct find_data { jack_port_id_t port_id; - struct pw_port *result; + struct pw_jack_port *result; }; static bool find_port(void *data, struct pw_port *port) @@ -618,26 +822,17 @@ static bool find_port(void *data, struct pw_port *port) struct find_data *d = data; struct port_data *pd = pw_port_get_user_data(port); - if (pd->jack_port_id == d->port_id) { - d->result = port; + if (pd->port.port_id == d->port_id) { + d->result = &pd->port; return false; } return true; } -struct pw_port *pw_jack_node_add_port(struct pw_jack_node *node, - enum pw_direction direction, - jack_port_id_t port_id) -{ - struct jack_server *server = node->server; - struct jack_graph_manager *mgr = server->graph_manager; - struct jack_port *jp = jack_graph_manager_get_port(mgr, port_id); - return make_port(node, direction, port_id, port_id, jp, false); -} - -struct pw_port *pw_jack_node_find_port(struct pw_jack_node *node, - enum pw_direction direction, - jack_port_id_t port_id) +struct pw_jack_port * +pw_jack_node_find_port(struct pw_jack_node *node, + enum pw_direction direction, + jack_port_id_t port_id) { struct find_data data = { port_id, }; if (!pw_node_for_each_port(node->node, direction, find_port, &data)) diff --git a/src/modules/module-jack/jack-node.h b/src/modules/module-jack/jack-node.h index fa2b57419..1443004b2 100644 --- a/src/modules/module-jack/jack-node.h +++ b/src/modules/module-jack/jack-node.h @@ -20,25 +20,29 @@ #ifndef __PIPEWIRE_JACK_NODE_H__ #define __PIPEWIRE_JACK_NODE_H__ +#include + #include #ifdef __cplusplus extern "C" { #endif +struct pw_jack_port; + struct pw_jack_node { - struct pw_core *core; struct pw_node *node; - struct spa_hook_list listener_list; - + struct pw_core *core; struct jack_server *server; - struct jack_client *client; - int ref_num; - struct pw_port *otherport; + struct jack_client_control *control; + + struct pw_jack_port *driverport; struct spa_list graph_link; + + void *user_data; }; struct pw_jack_node_events { @@ -46,36 +50,76 @@ struct pw_jack_node_events { uint32_t version; void (*destroy) (void *data); + void (*free) (void *data); void (*pull) (void *data); void (*push) (void *data); }; +struct pw_jack_port { + struct pw_jack_node *node; + + enum pw_direction direction; + struct pw_port *port; + + jack_port_id_t port_id; + struct jack_port *jack_port; + float *ptr; + + void *user_data; +}; + +struct pw_jack_port_events { +#define PW_VERSION_JACK_PORT_EVENTS 0 + uint32_t version; + + void (*destroy) (void *data); +}; struct pw_jack_node * pw_jack_node_new(struct pw_core *core, struct pw_global *parent, struct jack_server *server, - int ref_num, - struct pw_properties *properties); + const char *name, + int pid, + struct pw_properties *properties, + size_t user_data_size); + +struct pw_jack_node * +pw_jack_driver_new(struct pw_core *core, + struct pw_global *parent, + struct jack_server *server, + const char *name, + int n_capture_channels, + int n_playback_channels, + struct pw_properties *properties, + size_t user_data_size); void pw_jack_node_destroy(struct pw_jack_node *node); -struct pw_node *pw_jack_node_get_node(struct pw_jack_node *node); - void pw_jack_node_add_listener(struct pw_jack_node *node, struct spa_hook *listener, const struct pw_jack_node_events *events, void *data); -struct pw_port *pw_jack_node_add_port(struct pw_jack_node *node, - enum pw_direction direction, - jack_port_id_t port_id); +struct pw_jack_port * +pw_jack_node_add_port(struct pw_jack_node *node, + const char *name, + const char *type, + unsigned int flags, + size_t user_data_size); -struct pw_port *pw_jack_node_find_port(struct pw_jack_node *node, - enum pw_direction direction, jack_port_id_t port_id); +void pw_jack_port_add_listener(struct pw_jack_port *port, + struct spa_hook *listener, + const struct pw_jack_port_events *events, + void *data); + +struct pw_jack_port * +pw_jack_node_find_port(struct pw_jack_node *node, + enum pw_direction direction, + jack_port_id_t port_id); #ifdef __cplusplus } diff --git a/src/modules/module-jack/server.h b/src/modules/module-jack/server.h index 9be2d74d4..598dc7602 100644 --- a/src/modules/module-jack/server.h +++ b/src/modules/module-jack/server.h @@ -17,15 +17,15 @@ * Boston, MA 02110-1301, USA. */ +struct jack_server; + struct jack_client { - int ref_num; void *data; struct client *owner; - struct jack_client_control *control; struct pw_jack_node *node; int fd; /* notify fd */ struct spa_hook node_listener; - struct spa_list graph_link; + struct spa_list client_link; }; struct jack_server { diff --git a/src/modules/module-jack/shared.h b/src/modules/module-jack/shared.h index a94d8dafa..943525fe9 100644 --- a/src/modules/module-jack/shared.h +++ b/src/modules/module-jack/shared.h @@ -211,9 +211,10 @@ struct { \ INIT_FIXED_ARRAY(arr.array); \ arr.used = false; \ }) +#define GET_ITEMS_FIXED_ARRAY1(arr) GET_ITEMS_FIXED_ARRAY(arr.array) #define ADD_FIXED_ARRAY1(arr,item) ADD_FIXED_ARRAY(arr.array,item) #define GET_FIXED_ARRAY1(arr,item) GET_FIXED_ARRAY(arr.array,item) -#define GET_ITEMS_FIXED_ARRAY1(arr) GET_ITEMS_FIXED_ARRAY(arr.array) +#define REMOVE_FIXED_ARRAY1(arr,item) REMOVE_FIXED_ARRAY(arr.array,item) #define MAKE_FIXED_MATRIX(size) \ PRE_PACKED_STRUCTURE \ @@ -341,7 +342,7 @@ struct { \ res = ADD_LOOP_FEEDBACK(arr,ref1,ref2); \ res; \ }) -#define DEC_LOOP_FEEDBACK(arr,idx) ({ \ +#define DEC_LOOP_FEEDBACK(arr,ref1,ref2) ({ \ int res = true, idx = GET_LOOP_FEEDBACK(arr,ref1,ref2); \ if (idx >= 0) { \ if (--arr.table[idx][2] == 0) \ @@ -397,15 +398,43 @@ jack_connection_manager_reset(struct jack_connection_manager *conn, } static inline int -jack_connection_manager_add_port(struct jack_connection_manager *conn, bool input, - int ref_num, jack_port_id_t port_id) +jack_connection_manager_add_inport(struct jack_connection_manager *conn, + int ref_num, jack_port_id_t port_id) { - if (input) { - return ADD_FIXED_ARRAY1(conn->input_port[ref_num], port_id); - } - else { - return ADD_FIXED_ARRAY(conn->output_port[ref_num], port_id); - } + return ADD_FIXED_ARRAY1(conn->input_port[ref_num], port_id); +} + +static inline int +jack_connection_manager_remove_inport(struct jack_connection_manager *conn, + int ref_num, jack_port_id_t port_id) +{ + return REMOVE_FIXED_ARRAY1(conn->input_port[ref_num], port_id); +} + +static inline int +jack_connection_manager_add_outport(struct jack_connection_manager *conn, + int ref_num, jack_port_id_t port_id) +{ + return ADD_FIXED_ARRAY(conn->output_port[ref_num], port_id); +} + +static inline int +jack_connection_manager_remove_outport(struct jack_connection_manager *conn, + int ref_num, jack_port_id_t port_id) +{ + return REMOVE_FIXED_ARRAY(conn->output_port[ref_num], port_id); +} + +static inline const jack_int_t * +jack_connection_manager_get_inputs(struct jack_connection_manager *conn, int ref_num) +{ + return GET_ITEMS_FIXED_ARRAY1(conn->input_port[ref_num]); +} + +static inline const jack_int_t * +jack_connection_manager_get_outputs(struct jack_connection_manager *conn, int ref_num) +{ + return GET_ITEMS_FIXED_ARRAY(conn->output_port[ref_num]); } static inline int @@ -497,6 +526,19 @@ jack_connection_manager_inc_feedback_connection(struct jack_connection_manager * return INC_LOOP_FEEDBACK(conn->loop_feedback, ref1, ref2); } +static inline bool +jack_connection_manager_dec_feedback_connection(struct jack_connection_manager *conn, + jack_port_id_t src_id, jack_port_id_t dst_id) +{ + int ref1 = jack_connection_manager_get_output_refnum(conn, src_id); + int ref2 = jack_connection_manager_get_input_refnum(conn, dst_id); + + if (ref1 != ref2) + jack_connection_manager_direct_disconnect(conn, ref2, ref1); + + return DEC_LOOP_FEEDBACK(conn->loop_feedback, ref1, ref2); +} + static inline void jack_connection_manager_inc_direct_connection(struct jack_connection_manager *conn, jack_port_id_t src_id, jack_port_id_t dst_id) @@ -517,6 +559,55 @@ jack_connection_manager_dec_direct_connection(struct jack_connection_manager *co jack_connection_manager_direct_disconnect(conn, ref1, ref2); } +static inline int +jack_connection_manager_connect_ports(struct jack_connection_manager *conn, + jack_port_id_t src_id, jack_port_id_t dst_id) +{ + if (jack_connection_manager_is_connected(conn, src_id, dst_id)) { + pw_log_error("connection %p: ports are already connected", conn); + return -1; + } + if (jack_connection_manager_connect(conn, src_id, dst_id) < 0) { + pw_log_error("connection %p: connection table is full", conn); + return -1; + } + if (jack_connection_manager_connect(conn, dst_id, src_id) < 0) { + pw_log_error("connection %p: connection table is full", conn); + return -1; + } + if (jack_connection_manager_is_loop_path(conn, src_id, dst_id) < 0) + jack_connection_manager_inc_feedback_connection(conn, src_id, dst_id); + else + jack_connection_manager_inc_direct_connection(conn, src_id, dst_id); + + return 0; +} + +static inline int +jack_connection_manager_disconnect_ports(struct jack_connection_manager *conn, + jack_port_id_t src_id, jack_port_id_t dst_id) +{ + if (!jack_connection_manager_is_connected(conn, src_id, dst_id)) { + pw_log_error("connection %p: ports are not connected", conn); + return -1; + } + if (jack_connection_manager_disconnect(conn, src_id, dst_id) < 0) { + pw_log_error("connection %p: connection table is full", conn); + return -1; + } + if (jack_connection_manager_disconnect(conn, dst_id, src_id) < 0) { + pw_log_error("connection %p: connection table is full", conn); + return -1; + } + if (jack_connection_manager_is_loop_path(conn, src_id, dst_id) < 0) + jack_connection_manager_dec_feedback_connection(conn, src_id, dst_id); + else + jack_connection_manager_dec_direct_connection(conn, src_id, dst_id); + + return 0; +} + + static inline int jack_connection_manager_get_activation(struct jack_connection_manager *conn, int ref_num) { @@ -918,7 +1009,7 @@ jack_engine_control_alloc(const char* name) ctrl = (struct jack_engine_control *)jack_shm_addr(&info); ctrl->info = info; - ctrl->buffer_size = 128; + ctrl->buffer_size = 64; ctrl->sample_rate = 48000; ctrl->sync_mode = false; ctrl->temporary = false; diff --git a/src/modules/module-jack/synchro.h b/src/modules/module-jack/synchro.h index 35dd75d55..7f8f4a4db 100644 --- a/src/modules/module-jack/synchro.h +++ b/src/modules/module-jack/synchro.h @@ -31,7 +31,7 @@ static inline int jack_synchro_init(struct jack_synchro *synchro, const char *client_name, const char *server_name, - int value, bool internal, + int value, bool promiscuous) { if (promiscuous) @@ -43,12 +43,25 @@ jack_synchro_init(struct jack_synchro *synchro, synchro->flush = false; if ((synchro->semaphore = sem_open(synchro->name, O_CREAT | O_RDWR, 0777, value)) == (sem_t*)SEM_FAILED) { - pw_log_error("can't check in named semaphore name = %s err = %s", synchro->name, strerror(errno)); + pw_log_error("can't check semaphore %s: %s", synchro->name, strerror(errno)); return -1; } return 0; } +static inline bool +jack_synchro_close(struct jack_synchro *synchro) +{ + if (synchro->semaphore == NULL) + return true; + + if (sem_close(synchro->semaphore) < 0) { + pw_log_warn("can't close semaphore %s: %s", synchro->name, strerror(errno)); + } + synchro->semaphore = NULL; + return true; +} + static inline bool jack_synchro_signal(struct jack_synchro *synchro) {