|
View:
New views
1 Messages
—
Rating Filter:
Alert me
|
|
|
[PATCH] connection veto....maybe its possible, that the feedback to this patch can be constructive. a) i layed out usecases for multiple veto clients. b) its more complex, to implement a single vetoer. patch is against jack1. -- torben Hohn http://galan.sourceforge.net -- The graphical Audio language diff --git a/example-clients/Makefile.am b/example-clients/Makefile.am index 8eddc4c..f16978f 100644 --- a/example-clients/Makefile.am +++ b/example-clients/Makefile.am @@ -6,7 +6,8 @@ bin_PROGRAMS = jack_simple_client \ jack_metro \ jack_showtime \ jack_midisine \ - jack_midiseq + jack_midiseq \ + jack_veto_test if HAVE_SNDFILE # note! jackrec_CFLAGS syntax not supported by automake-1.4 @@ -44,6 +45,10 @@ jack_midisine_SOURCES = midisine.c jack_midisine_LDFLAGS = @OS_LDFLAGS@ jack_midisine_LDADD = $(top_builddir)/libjack/libjack.la +jack_veto_test_SOURCES = veto_test.c +jack_veto_test_LDFLAGS = @OS_LDFLAGS@ +jack_veto_test_LDADD = $(top_builddir)/libjack/libjack.la + # # sample in-process client(s) # diff --git a/example-clients/veto_test.c b/example-clients/veto_test.c new file mode 100644 index 0000000..ad9e094 --- /dev/null +++ b/example-clients/veto_test.c @@ -0,0 +1,106 @@ +/** @file simple_client.c + * + * @brief This simple client demonstrates the most basic features of JACK + * as they would be used by many applications. + */ + +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> + +#include <jack/jack.h> + +jack_client_t *client; + + +int veto_cb( const char *req_client, jack_port_id_t a, jack_port_id_t b, int connect, void *arg ) +{ + const char *name_a = jack_port_name( jack_port_by_id( client, a ) ); + const char *name_b = jack_port_name( jack_port_by_id( client, b ) ); + + if( connect ) + printf( "connection attempt... requestor: %s ( %s -> %s )\n", req_client, name_a, name_b ); + else + printf( "disconnection attempt... requestor: %s ( %s -> %s )\n", req_client, name_a, name_b ); + + if( strcmp( req_client, "ardour" ) && strcmp( req_client, "qjackctl" ) ) { + // its not ardour, and its not qjack... lets veto :) + return 1; + } else { + // ok... ardour of qjack. + return 0; + } +} + +/** + * JACK calls this shutdown_callback if the server ever shuts down or + * decides to disconnect the client. + */ +void +jack_shutdown (void *arg) +{ + exit (1); +} + +int +main (int argc, char *argv[]) +{ + const char *client_name = "veto"; + const char *server_name = NULL; + jack_options_t options = JackNullOption; + jack_status_t status; + + /* open a client connection to the JACK server */ + + client = jack_client_open (client_name, options, &status, server_name); + if (client == NULL) { + fprintf (stderr, "jack_client_open() failed, " + "status = 0x%2.0x\n", status); + if (status & JackServerFailed) { + fprintf (stderr, "Unable to connect to JACK server\n"); + } + exit (1); + } + if (status & JackServerStarted) { + fprintf (stderr, "JACK server started\n"); + } + if (status & JackNameNotUnique) { + client_name = jack_get_client_name(client); + fprintf (stderr, "unique name `%s' assigned\n", client_name); + } + + /* tell the JACK server to call `process()' whenever + there is work to be done. + */ + + jack_set_connection_veto_callback (client, veto_cb, 0); + + /* tell the JACK server to call `jack_shutdown()' if + it ever shuts down, either entirely, or if it + just decides to stop calling us. + */ + + jack_on_shutdown (client, jack_shutdown, 0); + + /* display the current sample rate. + */ + + if (jack_activate (client)) { + fprintf (stderr, "cannot activate client"); + exit (1); + } + + /* keep running until stopped by the user */ + + sleep (-1); + + /* this is never reached but if the program + had some other way to exit besides being killed, + they would be important to call. + */ + + jack_client_close (client); + exit (0); +} diff --git a/jack/internal.h b/jack/internal.h index b51ef44..a5fc559 100644 --- a/jack/internal.h +++ b/jack/internal.h @@ -217,7 +217,9 @@ typedef enum { StartFreewheel, StopFreewheel, ClientRegistered, - ClientUnregistered + ClientUnregistered, + PortConnectVeto, + PortDisconnectVeto } JackEventType; typedef struct { @@ -233,6 +235,9 @@ typedef struct { jack_port_type_id_t ptid; jack_port_id_t other_id; } y; + union { + jack_port_id_t port_id; + } z; } POST_PACKED_STRUCTURE jack_event_t; typedef enum { @@ -291,6 +296,7 @@ typedef volatile struct { volatile uint8_t timebase_cb_cbset; volatile uint8_t freewheel_cb_cbset; volatile uint8_t client_register_cbset; + volatile uint8_t connect_veto_cbset; volatile uint8_t thread_cb_cbset; } POST_PACKED_STRUCTURE jack_client_control_t; @@ -389,6 +395,7 @@ struct _jack_request { struct { char source_port[JACK_PORT_NAME_SIZE]; char destination_port[JACK_PORT_NAME_SIZE]; + jack_client_id_t client_id; } POST_PACKED_STRUCTURE connect; struct { int32_t nports; diff --git a/jack/jack.h b/jack/jack.h index 64ba8a7..2cd66bf 100644 --- a/jack/jack.h +++ b/jack/jack.h @@ -365,6 +365,16 @@ int jack_set_graph_order_callback (jack_client_t *, int jack_set_xrun_callback (jack_client_t *, JackXRunCallback xrun_callback, void *arg); +/** + * Tell the JACK server to call @a veto_callback whenever there is an + * attempt to connect or disconnect a port. + * + * @return 0 on success, otherwise a non-zero error code + */ + +int jack_set_connection_veto_callback(jack_client_t *client, + JackConnectVetoCallback veto_callback, + void *arg); /*@}*/ /** diff --git a/jack/types.h b/jack/types.h index 020a51b..9e90a0b 100644 --- a/jack/types.h +++ b/jack/types.h @@ -186,6 +186,20 @@ typedef void (*JackPortConnectCallback)(jack_port_id_t a, jack_port_id_t b, int /** * Prototype for the client supplied function that is called + * whenever a Connection or Disconnection is made. + * if it returns non-zero, it means a veto against the process, + * and the connection/disconnection, will not be made. + * + * @param a one of two ports connected or disconnected + * @param b one of two ports connected or disconnected + * @param connect non-zero if ports were connected + * zero if ports were disconnected + * @param arg pointer to a client supplied data + */ +typedef int (*JackConnectVetoCallback)(const char *req_client, jack_port_id_t a, jack_port_id_t b, int connect, void* arg); + +/** + * Prototype for the client supplied function that is called * whenever jackd starts or stops freewheeling. * * @param starting non-zero if we start starting to freewheel, zero otherwise diff --git a/jackd/clientengine.c b/jackd/clientengine.c index 5de971f..b5db3b5 100644 --- a/jackd/clientengine.c +++ b/jackd/clientengine.c @@ -538,6 +538,7 @@ jack_setup_client_control (jack_engine_t *engine, int fd, client->control->graph_order_cbset = FALSE; client->control->client_register_cbset = FALSE; client->control->thread_cb_cbset = FALSE; + client->control->connect_veto_cbset = FALSE; #if 0 if (type != ClientExternal) { diff --git a/jackd/engine.c b/jackd/engine.c index d3f7263..b38a6c7 100644 --- a/jackd/engine.c +++ b/jackd/engine.c @@ -89,10 +89,10 @@ static int jack_rechain_graph (jack_engine_t *engine); static void jack_clear_fifos (jack_engine_t *engine); static int jack_port_do_connect (jack_engine_t *engine, const char *source_port, - const char *destination_port); + const char *destination_port, jack_client_id_t req_id); static int jack_port_do_disconnect (jack_engine_t *engine, const char *source_port, - const char *destination_port); + const char *destination_port, jack_client_id_t req_id); static int jack_port_do_disconnect_all (jack_engine_t *engine, jack_port_id_t); static int jack_port_do_unregister (jack_engine_t *engine, jack_request_t *); @@ -1229,7 +1229,7 @@ do_request (jack_engine_t *engine, jack_request_t *req, int *reply_fd) case ConnectPorts: req->status = jack_port_do_connect (engine, req->x.connect.source_port, - req->x.connect.destination_port); + req->x.connect.destination_port, req->x.connect.client_id); break; case DisconnectPort: @@ -1240,7 +1240,7 @@ do_request (jack_engine_t *engine, jack_request_t *req, int *reply_fd) case DisconnectPorts: req->status = jack_port_do_disconnect (engine, req->x.connect.source_port, - req->x.connect.destination_port); + req->x.connect.destination_port, req->x.connect.client_id); break; case ActivateClient: @@ -2423,6 +2423,37 @@ jack_deliver_event_to_all (jack_engine_t *engine, jack_event_t *event) jack_unlock_graph (engine); } +static int +jack_query_veto_clients (jack_engine_t *engine, jack_client_id_t requestor, jack_port_id_t a, jack_port_id_t b, int connected) +{ + JSList *node; + jack_event_t event; + + int retval = 0; + int reply; + + jack_client_internal_t* req_client = jack_client_internal_by_id (engine, requestor); + + event.type = (connected ? PortConnectVeto : PortDisconnectVeto); + snprintf (event.x.name, sizeof (event.x.name), "%s", req_client->control->name); + event.y.other_id = a; + event.z.port_id = b; + + /* GRAPH MUST BE LOCKED : see callers of jack_send_connection_notification() + */ + + for (node = engine->clients; node; node = jack_slist_next (node)) { + jack_client_internal_t* client = (jack_client_internal_t*) node->data; + if (client->control->connect_veto_cbset) { + + reply = jack_deliver_event (engine, client, &event); + if( reply >= 0 ) + retval |= reply; + } + } + return retval; +} + static void jack_notify_all_port_interested_clients (jack_engine_t *engine, jack_client_id_t src, jack_client_id_t dst, jack_port_id_t a, jack_port_id_t b, int connected) { @@ -2453,7 +2484,7 @@ static int jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, jack_event_t *event) { - char status; + char status = -1; /* caller must hold the graph lock */ @@ -2603,7 +2634,7 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, client->event_fd, pfd[0].revents, poll_timeout); - status = 1; + status = -2; #ifdef __linux } #endif @@ -2628,7 +2659,7 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, event->type); } - if (status) { + if (status < 0) { client->error += JACK_ERROR_WITH_SOCKETS; jack_engine_signal_problems (engine); } @@ -2636,7 +2667,7 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, } DEBUG ("event delivered"); - return 0; + return status; } int @@ -3202,7 +3233,8 @@ void jack_dump_configuration(jack_engine_t *engine, int take_lock) static int jack_port_do_connect (jack_engine_t *engine, const char *source_port, - const char *destination_port) + const char *destination_port, + jack_client_id_t req_id ) { jack_connection_internal_t *connection; jack_port_internal_t *srcport, *dstport; @@ -3291,6 +3323,15 @@ jack_port_do_connect (jack_engine_t *engine, jack_lock_graph (engine); + // XXX: do i really need to have the graph locked, las ? + if( jack_query_veto_clients( engine, req_id, src_id, dst_id, 1 ) ) { + // Connection vetoed... go to the UN if you dont like it. + free (connection); + jack_unlock_graph (engine); + + // we return success here, because most dumb clients exit, when the connection fails + return 0; + } if (dstport->connections && !dstport->shared->has_mixdown) { jack_port_type_info_t *port_type = jack_port_type_info (engine, dstport); @@ -3532,7 +3573,7 @@ jack_port_do_disconnect_all (jack_engine_t *engine, static int jack_port_do_disconnect (jack_engine_t *engine, const char *source_port, - const char *destination_port) + const char *destination_port, jack_client_id_t req_id) { jack_port_internal_t *srcport, *dstport; int ret = -1; @@ -3550,8 +3591,18 @@ jack_port_do_disconnect (jack_engine_t *engine, return -1; } + jack_port_id_t src_id = srcport->shared->id; + jack_port_id_t dst_id = dstport->shared->id; + jack_lock_graph (engine); + // XXX: do i really need to have the graph locked, las ? + if( jack_query_veto_clients( engine, req_id, src_id, dst_id, 0 ) ) { + // Connection vetoed... go to the UN if you dont like it. + jack_unlock_graph (engine); + return -1; + } + ret = jack_port_disconnect_internal (engine, srcport, dstport); jack_unlock_graph (engine); diff --git a/libjack/client.c b/libjack/client.c index ed0bee8..4b0f6db 100644 --- a/libjack/client.c +++ b/libjack/client.c @@ -468,6 +468,19 @@ jack_client_handle_port_connection (jack_client_t *client, jack_event_t *event) return 0; } +int +jack_client_handle_connect_veto (jack_client_t *client, jack_event_t *event) +{ + int retval = 0; + + if (client->control->connect_veto_cbset) { + retval = client->connect_veto (event->x.name, event->y.other_id, event->z.port_id, + (event->type == PortConnectVeto ? 1 : 0), + client->connect_veto_arg); + } + + return retval; +} #if JACK_USE_MACH_THREADS static int @@ -1412,6 +1425,12 @@ jack_client_process_events (jack_client_t* client) case StopFreewheel: jack_stop_freewheel (client); break; + + case PortConnectVeto: + case PortDisconnectVeto: + status = jack_client_handle_connect_veto + (client, &event); + break; } DEBUG ("client has dealt with the event, writing " @@ -2173,6 +2192,7 @@ jack_connect (jack_client_t *client, const char *source_port, snprintf (req.x.connect.destination_port, sizeof (req.x.connect.destination_port), "%s", destination_port); + req.x.connect.client_id = client->control->id; return jack_client_deliver_request (client, &req); } @@ -2210,6 +2230,7 @@ jack_disconnect (jack_client_t *client, const char *source_port, snprintf (req.x.connect.destination_port, sizeof (req.x.connect.destination_port), "%s", destination_port); + req.x.connect.client_id = client->control->id; return jack_client_deliver_request (client, &req); } @@ -2360,6 +2381,22 @@ jack_set_client_registration_callback(jack_client_t *client, } int +jack_set_connection_veto_callback(jack_client_t *client, + JackConnectVetoCallback callback, + void *arg) +{ + if (client->control->active) { + jack_error ("You cannot set callbacks on an active client."); + return -1; + } + client->connect_veto_arg = arg; + client->connect_veto = callback; + client->control->connect_veto_cbset = (callback != NULL); + return 0; +} + + +int jack_set_process_thread(jack_client_t* client, JackThreadCallback callback, void *arg) { if (client->control->active) { diff --git a/libjack/local.h b/libjack/local.h index 7ee4bbb..95f714b 100644 --- a/libjack/local.h +++ b/libjack/local.h @@ -68,7 +68,9 @@ struct _jack_client { void *freewheel_arg; JackClientRegistrationCallback client_register; void *client_register_arg; - JackThreadCallback thread_cb; + JackConnectVetoCallback connect_veto; + void *connect_veto_arg; + JackThreadCallback thread_cb; void *thread_cb_arg; /* external clients: set by libjack _______________________________________________ Jack-Devel mailing list Jack-Devel@... http://lists.jackaudio.org/listinfo.cgi/jack-devel-jackaudio.org |
| Free embeddable forum powered by Nabble | Forum Help |