diff --git a/configure.ac b/configure.ac index c8e5384..54eb2a3 100644 --- a/configure.ac +++ b/configure.ac @@ -16,7 +16,7 @@ dnl micro version = incremented when implementation-only dnl changes are made dnl --- JACK_MAJOR_VERSION=0 -JACK_MINOR_VERSION=103 +JACK_MINOR_VERSION=104 JACK_MICRO_VERSION=0 dnl --- @@ -27,7 +27,7 @@ dnl made to the way libjack communicates with jackd dnl that would break applications linked with an older dnl version of libjack. dnl --- -JACK_PROTOCOL_VERSION=19 +JACK_PROTOCOL_VERSION=20 dnl --- dnl HOWTO: updating the libjack interface version @@ -44,7 +44,7 @@ dnl slacker than this, and closer to those for the JACK version dnl number. dnl --- JACK_API_CURRENT=0 -JACK_API_REVISION=25 +JACK_API_REVISION=26 JACK_API_AGE=0 AC_SUBST(JACK_MAJOR_VERSION) diff --git a/drivers/alsa/alsa_driver.c b/drivers/alsa/alsa_driver.c index b2a14e6..0affea8 100644 --- a/drivers/alsa/alsa_driver.c +++ b/drivers/alsa/alsa_driver.c @@ -1751,7 +1751,7 @@ alsa_driver_attach (alsa_driver_t *driver) for (chn = 0; chn < driver->capture_nchannels; chn++) { - snprintf (buf, sizeof(buf) - 1, "capture_%lu", chn+1); + snprintf (buf, sizeof(buf), "capture_%lu", chn+1); if ((port = jack_port_register (driver->client, buf, JACK_DEFAULT_AUDIO_TYPE, diff --git a/example-clients/Makefile.am b/example-clients/Makefile.am index f4adffe..e218719 100644 --- a/example-clients/Makefile.am +++ b/example-clients/Makefile.am @@ -37,6 +37,7 @@ bin_PROGRAMS = jack_load \ jack_lsp \ jack_freewheel \ jack_evmon \ + jack_alias \ $(JACKREC) \ $(JACK_TRANSPORT) \ jack_midisine \ @@ -80,6 +81,10 @@ jack_evmon_SOURCES = evmon.c jack_evmon_LDFLAGS = @OS_LDFLAGS@ jack_evmon_LDADD = ../libjack/libjack.la +jack_alias_SOURCES = alias.c +jack_alias_LDFLAGS = @OS_LDFLAGS@ +jack_alias_LDADD = ../libjack/libjack.la + jack_lsp_SOURCES = lsp.c jack_lsp_LDFLAGS = @OS_LDFLAGS@ jack_lsp_LDADD = ../libjack/libjack.la diff --git a/example-clients/alias.c b/example-clients/alias.c new file mode 100644 index 0000000..5a5d523 --- /dev/null +++ b/example-clients/alias.c @@ -0,0 +1,121 @@ +#include +#include +#include +#include +#include + +#include + +#include + +char * my_name; + +void +show_version (void) +{ + fprintf (stderr, "%s: JACK Audio Connection Kit version " VERSION "\n", + my_name); +} + +void +show_usage (void) +{ + show_version (); + fprintf (stderr, "\nUsage: %s [options] portname alias\n", my_name); + fprintf (stderr, "List active Jack ports, and optionally display extra information.\n\n"); + fprintf (stderr, "Display options:\n"); + fprintf (stderr, " -u, --unalias remove `alias' as an alias for `port'\n"); + fprintf (stderr, " -h, --help Display this help message\n"); + fprintf (stderr, " --version Output version information and exit\n\n"); + fprintf (stderr, "For more information see http://jackaudio.org/\n"); +} + +int +main (int argc, char *argv[]) +{ + jack_client_t *client; + jack_status_t status; + char* portname; + char* alias; + int unset = 0; + int ret; + int c; + int option_index; + extern int optind; + jack_port_t* port; + + struct option long_options[] = { + { "unalias", 0, 0, 'u' }, + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'v' }, + { 0, 0, 0, 0 } + }; + + if (argc < 3) { + show_usage (); + return 1; + } + + my_name = strrchr(argv[0], '/'); + if (my_name == 0) { + my_name = argv[0]; + } else { + my_name ++; + } + + while ((c = getopt_long (argc, argv, "uhv", long_options, &option_index)) >= 0) { + switch (c) { + case 'u': + unset = 1; + break; + case 'h': + show_usage (); + return 1; + break; + case 'v': + show_version (); + return 1; + break; + default: + show_usage (); + return 1; + break; + } + } + + portname = argv[optind++]; + alias = argv[optind]; + + /* Open a client connection to the JACK server. Starting a + * new server only to list its ports seems pointless, so we + * specify JackNoStartServer. */ + //JOQ: need a new server name option + + client = jack_client_open ("lsp", JackNoStartServer, &status); + + if (client == NULL) { + if (status & JackServerFailed) { + fprintf (stderr, "JACK server not running\n"); + } else { + fprintf (stderr, "jack_client_open() failed, " + "status = 0x%2.0x\n", status); + } + return 1; + } + + if ((port = jack_port_by_name (client, portname)) == 0) { + fprintf (stderr, "No port named \"%s\"\n", portname); + return 1; + } + + if (!unset) { + ret = jack_port_set_alias (port, alias); + } else { + ret = jack_port_unset_alias (port, alias); + } + + jack_client_close (client); + + return ret; + +} diff --git a/example-clients/lsp.c b/example-clients/lsp.c index 2e167eb..d7e7804 100644 --- a/example-clients/lsp.c +++ b/example-clients/lsp.c @@ -24,6 +24,7 @@ show_usage (void) fprintf (stderr, "\nUsage: %s [options]\n", my_name); fprintf (stderr, "List active Jack ports, and optionally display extra information.\n\n"); fprintf (stderr, "Display options:\n"); + fprintf (stderr, " -A, --aliases List aliases for each port\n"); fprintf (stderr, " -c, --connections List connections to/from each port\n"); fprintf (stderr, " -l, --latency Display per-port latency in frames at each port\n"); fprintf (stderr, " -L, --latency Display total latency in frames at each port\n"); @@ -32,7 +33,7 @@ show_usage (void) fprintf (stderr, " -t, --type Display port type\n"); fprintf (stderr, " -h, --help Display this help message\n"); fprintf (stderr, " --version Output version information and exit\n\n"); - fprintf (stderr, "For more information see http://jackit.sourceforge.net/\n"); + fprintf (stderr, "For more information see http://jackaudio.org/\n"); } int @@ -42,6 +43,7 @@ main (int argc, char *argv[]) jack_status_t status; const char **ports, **connections; unsigned int i, j; + int show_aliases = 0; int show_con = 0; int show_port_latency = 0; int show_total_latency = 0; @@ -49,8 +51,10 @@ main (int argc, char *argv[]) int show_type = 0; int c; int option_index; - + char* aliases[2]; + struct option long_options[] = { + { "aliases", 0, 0, 'A' }, { "connections", 0, 0, 'c' }, { "port-latency", 0, 0, 'l' }, { "total-latency", 0, 0, 'L' }, @@ -68,8 +72,13 @@ main (int argc, char *argv[]) my_name ++; } - while ((c = getopt_long (argc, argv, "clLphvt", long_options, &option_index)) >= 0) { + while ((c = getopt_long (argc, argv, "AclLphvt", long_options, &option_index)) >= 0) { switch (c) { + case 'A': + aliases[0] = (char *) malloc (jack_port_name_size()); + aliases[1] = (char *) malloc (jack_port_name_size()); + show_aliases = 1; + break; case 'c': show_con = 1; break; @@ -123,6 +132,16 @@ main (int argc, char *argv[]) jack_port_t *port = jack_port_by_name (client, ports[i]); + if (show_aliases) { + int cnt; + int i; + + cnt = jack_port_get_aliases (port, aliases); + for (i = 0; i < cnt; ++i) { + printf (" %s\n", aliases[i]); + } + } + if (show_con) { if ((connections = jack_port_get_all_connections (client, jack_port_by_name(client, ports[i]))) != 0) { for (j = 0; connections[j]; j++) { diff --git a/jack/engine.h b/jack/engine.h index f97e8cf..3e0455e 100644 --- a/jack/engine.h +++ b/jack/engine.h @@ -203,5 +203,6 @@ void jack_port_clear_connections (jack_engine_t *engine, void jack_port_registration_notify (jack_engine_t *, jack_port_id_t, int); void jack_port_release (jack_engine_t *engine, jack_port_internal_t *); void jack_sort_graph (jack_engine_t *engine); +void jack_engine_munge_backend_port_names (jack_engine_t* engine); #endif /* __jack_engine_h__ */ diff --git a/jack/internal.h b/jack/internal.h index 6685782..8a0af2e 100644 --- a/jack/internal.h +++ b/jack/internal.h @@ -460,6 +460,7 @@ jack_port_t *jack_port_by_id_int (const jack_client_t *client, jack_port_t *jack_port_by_name_int (jack_client_t *client, const char *port_name); +int jack_port_name_equals (jack_port_shared_t* port, const char* target); #ifdef __GNUC__ # define likely(x) __builtin_expect((x),1) diff --git a/jack/jack.h b/jack/jack.h index 47e30d8..bd580b6 100644 --- a/jack/jack.h +++ b/jack/jack.h @@ -569,6 +569,38 @@ int jack_recompute_total_latencies (jack_client_t*); */ int jack_port_set_name (jack_port_t *port, const char *port_name); +/** + * Set @a alias as an alias for @a port. May be called at any time. + * If the alias is longer than jack_port_name_size(), it will be truncated. + * + * After a successful call, and until JACK exits or + * @function jack_port_unset_alias() is called, @alias may be + * used as a alternate name for the port. + * + * Ports can have up to two aliases - if both are already + * set, this function will return an error. + * + * @return 0 on success, otherwise a non-zero error code. + */ +int jack_port_set_alias (jack_port_t *port, const char *alias); + +/** + * Remove @a alias as an alias for @a port. May be called at any time. + * + * After a successful call, @a alias can no longer be + * used as a alternate name for the port. + * + * @return 0 on success, otherwise a non-zero error code. + */ +int jack_port_unset_alias (jack_port_t *port, const char *alias); + +/* + * Get any aliases known for @port. + * + * @return the number of aliases discovered for the port + */ +int jack_port_get_aliases (const jack_port_t *port, char* const aliases[2]); + /** * If @ref JackPortCanMonitor is set for this @a port, turn input * monitoring on or off. Otherwise, do nothing. diff --git a/jack/port.h b/jack/port.h index 782e36b..e73d1c1 100644 --- a/jack/port.h +++ b/jack/port.h @@ -98,6 +98,8 @@ typedef struct _jack_port_shared { jack_port_id_t id; /* index into engine port array */ enum JackPortFlags flags; char name[JACK_CLIENT_NAME_SIZE+JACK_PORT_NAME_SIZE]; + char alias1[JACK_CLIENT_NAME_SIZE+JACK_PORT_NAME_SIZE]; + char alias2[JACK_CLIENT_NAME_SIZE+JACK_PORT_NAME_SIZE]; jack_client_id_t client_id; /* who owns me */ volatile jack_nframes_t latency; diff --git a/jackd/engine.c b/jackd/engine.c index 640403d..e1c47a4 100644 --- a/jackd/engine.c +++ b/jackd/engine.c @@ -944,6 +944,44 @@ jack_start_watchdog (jack_engine_t *engine) } #endif /* !JACK_USE_MACH_THREADS */ +void +jack_engine_munge_backend_port_names (jack_engine_t* engine) +{ + int out_cnt = 1; + int in_cnt = 1; + int i; + char* backend_client_name = (char*) engine->driver->internal_client->control->name; + size_t len = strlen (backend_client_name); + + for (i = 0; i < engine->port_max; i++) { + jack_port_shared_t* port = &engine->control->ports[i]; + + if (strncmp (port->name, backend_client_name, len) == 0) { + + /* save the backend's own name */ + + char name[JACK_CLIENT_NAME_SIZE+JACK_PORT_NAME_SIZE]; + snprintf (name, sizeof (name), "%s", engine->control->ports[i].name); + + /* replace input port names, and use backend's original as an alias */ + + if ((port->flags & (JackPortIsPhysical|JackPortIsInput)) == (JackPortIsPhysical|JackPortIsInput)) { + snprintf (port->name, sizeof (port->name), "system:playback_%d", out_cnt++); + strcpy (port->alias1, name); + continue; + } + + /* replace output port names, and use backend's original as an alias */ + + if ((port->flags & (JackPortIsPhysical|JackPortIsOutput)) == (JackPortIsPhysical|JackPortIsOutput)) { + snprintf (port->name, sizeof (port->name), "system:capture_%d", in_cnt++); + strcpy (port->alias1, name); + continue; + } + } + } +} + static jack_driver_info_t * jack_load_driver (jack_engine_t *engine, jack_driver_desc_t * driver_desc) { @@ -1678,6 +1716,8 @@ jack_engine_new (int realtime, int rtpriority, int do_mlock, int do_unlock, for (i = 0; i < engine->port_max; i++) { engine->control->ports[i].in_use = 0; engine->control->ports[i].id = i; + engine->control->ports[i].alias1[0] = '\0'; + engine->control->ports[i].alias2[0] = '\0'; } /* allocate internal port structures so that we can keep track @@ -3369,6 +3409,8 @@ jack_port_release (jack_engine_t *engine, jack_port_internal_t *port) { pthread_mutex_lock (&engine->port_lock); port->shared->in_use = 0; + port->shared->alias1[0] = '\0'; + port->shared->alias2[0] = '\0'; if (port->buffer_info) { jack_port_buffer_list_t *blist = @@ -3391,7 +3433,7 @@ jack_get_port_internal_by_name (jack_engine_t *engine, const char *name) pthread_mutex_lock (&engine->port_lock); for (id = 0; id < engine->port_max; id++) { - if (strcmp (engine->control->ports[id].name, name) == 0) { + if (jack_port_name_equals (&engine->control->ports[id], name)) { break; } } @@ -3725,7 +3767,7 @@ jack_get_port_by_name (jack_engine_t *engine, const char *name) for (id = 0; id < engine->port_max; id++) { if (engine->control->ports[id].in_use && - strcmp (engine->control->ports[id].name, name) == 0) { + jack_port_name_equals (&engine->control->ports[id], name)) { return &engine->internal_ports[id]; } } diff --git a/jackd/jackd.c b/jackd/jackd.c index 70a7664..d1de77d 100644 --- a/jackd/jackd.c +++ b/jackd/jackd.c @@ -158,6 +158,8 @@ jack_main (jack_driver_desc_t * driver_desc, JSList * driver_params) goto error; } + jack_engine_munge_backend_port_names (engine); + if (engine->driver->start (engine->driver) != 0) { jack_error ("cannot start driver"); goto error; diff --git a/libjack/port.c b/libjack/port.c index 2c3f3b8..db43f39 100644 --- a/libjack/port.c +++ b/libjack/port.c @@ -333,6 +333,14 @@ void jack_port_set_funcs () #endif /* USE_DYNSIMD */ +int +jack_port_name_equals (jack_port_shared_t* port, const char* target) +{ + return (strcmp (port->name, target) == 0 || + strcmp (port->alias1, target) == 0 || + strcmp (port->alias2, target) == 0); +} + jack_port_functions_t * jack_get_port_functions(jack_port_type_id_t ptid) { @@ -372,7 +380,7 @@ jack_port_new (const jack_client_t *client, jack_port_id_t port_id, pthread_mutex_init (&port->connection_lock, NULL); port->connections = 0; port->tied = NULL; - + if (client->control->id == port->shared->client_id) { /* It's our port, so initialize the pointers to port @@ -488,7 +496,7 @@ jack_port_connected_to (const jack_port_t *port, const char *portname) for (node = port->connections; node; node = jack_slist_next (node)) { jack_port_t *other_port = (jack_port_t *) node->data; - if (strcmp (other_port->shared->name, portname) == 0) { + if (jack_port_name_equals (other_port->shared, portname)) { ret = TRUE; break; } @@ -521,7 +529,8 @@ jack_port_get_connections (const jack_port_t *port) * (jack_slist_length (port->connections) + 1)); for (n = 0, node = port->connections; node; node = jack_slist_next (node), ++n) { - ret[n] = ((jack_port_t *) node->data)->shared->name; + jack_port_t* other =(jack_port_t *) node->data; + ret[n] = other->shared->name; } ret[n] = NULL; } @@ -644,7 +653,7 @@ jack_port_by_name_int (jack_client_t *client, const char *port_name) port = &client->engine->ports[0]; for (i = 0; i < limit; i++) { - if (port[i].in_use && strcmp (port[i].name, port_name) == 0) { + if (port[i].in_use && jack_port_name_equals (&port[i], port_name)) { return jack_port_new (client, port[i].id, client->engine); } @@ -660,7 +669,7 @@ jack_port_by_name (jack_client_t *client, const char *port_name) jack_port_t* port; for (node = client->ports_ext; node; node = jack_slist_next (node)) { port = node->data; - if (strcmp (port->shared->name, port_name) == 0) { + if (jack_port_name_equals (port->shared, port_name)) { /* Found port, return the cached structure. */ return port; } @@ -766,7 +775,6 @@ jack_port_tie (jack_port_t *src, jack_port_t *dst) int jack_port_untie (jack_port_t *port) - { if (port->tied == NULL) { jack_error ("port \"%s\" is not tied", port->shared->name); @@ -868,6 +876,24 @@ jack_port_name (const jack_port_t *port) return port->shared->name; } +int +jack_port_get_aliases (const jack_port_t *port, char* const aliases[2]) +{ + int cnt = 0; + + if (port->shared->alias1[0] != '\0') { + snprintf (aliases[0], JACK_CLIENT_NAME_SIZE+JACK_PORT_NAME_SIZE, "%s", port->shared->alias1); + cnt++; + } + + if (port->shared->alias2[0] != '\0') { + snprintf (aliases[1], JACK_CLIENT_NAME_SIZE+JACK_PORT_NAME_SIZE, "%s", port->shared->alias2); + cnt++; + } + + return cnt; +} + const char * jack_port_short_name (const jack_port_t *port) { @@ -910,6 +936,35 @@ jack_port_set_name (jack_port_t *port, const char *new_name) return 0; } +int +jack_port_set_alias (jack_port_t *port, const char *alias) +{ + if (port->shared->alias1[0] == '\0') { + snprintf (port->shared->alias1, sizeof (port->shared->alias1), "%s", alias); + } else if (port->shared->alias2[0] == '\0') { + snprintf (port->shared->alias2, sizeof (port->shared->alias2), "%s", alias); + } else { + return -1; + } + + return 0; +} + +int +jack_port_unset_alias (jack_port_t *port, const char *alias) +{ + if (strcmp (port->shared->alias1, alias) == 0) { + port->shared->alias1[0] = '\0'; + } else if (strcmp (port->shared->alias2, alias) == 0) { + port->shared->alias2[0] = '\0'; + } else { + return -1; + } + + return 0; +} + + /* AUDIO PORT SUPPORT */ static inline float f_max(float x, float a)