diff --git a/configure.in b/configure.in index 74a7029..687805b 100644 --- a/configure.in +++ b/configure.in @@ -13,7 +13,7 @@ dnl micro version = incremented when implementation-only dnl changes are made dnl --- JACK_MAJOR_VERSION=0 -JACK_MINOR_VERSION=51 +JACK_MINOR_VERSION=60 JACK_MICRO_VERSION=0 dnl --- @@ -24,7 +24,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=1 +JACK_PROTOCOL_VERSION=2 dnl --- dnl HOWTO: updating the libjack interface version @@ -41,7 +41,7 @@ dnl slacker than this, and closer to those for the JACK version dnl number. dnl --- JACK_API_CURRENT=0 -JACK_API_REVISION=8 +JACK_API_REVISION=9 JACK_API_AGE=0 AC_SUBST(JACK_MAJOR_VERSION) @@ -87,7 +87,7 @@ AC_CHECK_FUNCS(on_exit atexit) JACK_CORE_CFLAGS='-I$(top_srcdir) -D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS -Wall' JACK_CFLAGS="$JACK_CORE_CFLAGS -g" -JACK_OPT_CFLAGS="$JACK_CORE_CFLAGS -O6 -fomit-frame-pointer -ffast-math -fstrength-reduce -funroll-loops -fmove-all-movables" +JACK_OPT_CFLAGS="$JACK_CORE_CFLAGS -O3 -fomit-frame-pointer -ffast-math -fstrength-reduce -funroll-loops -fmove-all-movables" AC_ARG_ENABLE(optimize, [ --enable-optimize ask the compiler for its best optimizations], diff --git a/drivers/alsa/Makefile.am b/drivers/alsa/Makefile.am index 6478581..8364afb 100644 --- a/drivers/alsa/Makefile.am +++ b/drivers/alsa/Makefile.am @@ -4,9 +4,9 @@ AM_CFLAGS = $(JACK_CFLAGS) plugindir = $(ADDON_DIR) -plugin_LTLIBRARIES = jack_alsa.la +plugin_LTLIBRARIES = jack_alsa_pcm.la -jack_alsa_la_LDFLAGS = -module -avoid-version -jack_alsa_la_SOURCES = alsa_driver.c generic_hw.c memops.c \ +jack_alsa_pcm_la_LDFLAGS = -module -avoid-version +jack_alsa_pcm_la_SOURCES = alsa_driver.c generic_hw.c memops.c \ hammerfall.c hdsp.c ice1712.c -jack_alsa_la_LIBADD = $(ALSA_LIBS) +jack_alsa_pcm_la_LIBADD = $(ALSA_LIBS) diff --git a/drivers/alsa/alsa_driver.c b/drivers/alsa/alsa_driver.c index e6e913b..e423baf 100644 --- a/drivers/alsa/alsa_driver.c +++ b/drivers/alsa/alsa_driver.c @@ -1197,9 +1197,8 @@ alsa_driver_process (alsa_driver_t *driver, jack_nframes_t nframes) return 0; } -static void +static int alsa_driver_attach (alsa_driver_t *driver, jack_engine_t *engine) - { char buf[32]; channel_t chn; @@ -1211,13 +1210,6 @@ alsa_driver_attach (alsa_driver_t *driver, jack_engine_t *engine) driver->engine->set_buffer_size (engine, driver->frames_per_cycle); driver->engine->set_sample_rate (engine, driver->frame_rate); - /* Now become a client of the engine */ - - if ((driver->client = jack_driver_become_client ("alsa_pcm")) == NULL) { - jack_error ("ALSA: cannot become client"); - return; - } - port_flags = JackPortIsOutput|JackPortIsPhysical|JackPortIsTerminal; if (driver->has_hw_monitoring) { @@ -1260,6 +1252,7 @@ alsa_driver_attach (alsa_driver_t *driver, jack_engine_t *engine) } jack_activate (driver->client); + return 0; } static void @@ -1394,6 +1387,7 @@ alsa_driver_delete (alsa_driver_t *driver) static jack_driver_t * alsa_driver_new (char *name, char *alsa_device, + jack_client_t *client, jack_nframes_t frames_per_cycle, jack_nframes_t user_nperiods, jack_nframes_t rate, @@ -1532,6 +1526,8 @@ alsa_driver_new (char *name, char *alsa_device, alsa_driver_hw_specific (driver, hw_monitoring); + driver->client = client; + return (jack_driver_t *) driver; } @@ -1587,8 +1583,6 @@ alsa_driver_clock_sync_notify (alsa_driver_t *driver, channel_t chn, ClockSyncSt } -/* DRIVER "PLUGIN" INTERFACE */ - static void alsa_usage () { @@ -1608,8 +1602,10 @@ alsa_usage () ); } +/* DRIVER "PLUGIN" INTERFACE */ + jack_driver_t * -driver_initialize (int argc, char **argv) +driver_initialize (jack_client_t *client, int argc, char **argv) { jack_nframes_t srate = 48000; jack_nframes_t frames_per_interrupt = 1024; @@ -1710,7 +1706,7 @@ driver_initialize (int argc, char **argv) playback = TRUE; } - return alsa_driver_new ("alsa_pcm", pcm_name, frames_per_interrupt, + return alsa_driver_new ("alsa_pcm", pcm_name, client, frames_per_interrupt, user_nperiods, srate, hw_monitoring, capture, playback, dither, soft_mode); } diff --git a/example-clients/Makefile.am b/example-clients/Makefile.am index 4ffa7c8..03c86d8 100644 --- a/example-clients/Makefile.am +++ b/example-clients/Makefile.am @@ -24,7 +24,9 @@ dist-check-sndfile: @false endif -bin_PROGRAMS = jack_simple_client \ +bin_PROGRAMS = jack_load \ + jack_unload \ + jack_simple_client \ jack_monitor_client \ jack_impulse_grabber \ jack_connect \ @@ -87,4 +89,27 @@ jack_impulse_grabber_SOURCES = impulse_grabber.c jack_impulse_grabber_LDFLAGS = -ldl -lpthread -lm jack_impulse_grabber_LDADD = ../libjack/libjack.la +# +# general purpose in-process loader +# + +jack_load_SOURCES = ipload.c +jack_load_LDFLAGS = -ldl -lpthread -lm +jack_load_LDADD = ../libjack/libjack.la + +jack_unload_SOURCES = ipunload.c +jack_unload_LDFLAGS = -ldl -lpthread -lm +jack_unload_LDADD = ../libjack/libjack.la + +# +# sample in-process client(s) +# + +ip_clientdir = $(ADDON_DIR) + +ip_client_LTLIBRARIES = inprocess.la + +inprocess_la_LDFLAGS = -module -avoid-version +inprocess_la_SOURCES = inprocess.c + dist-hook: dist-check-fltk dist-check-sndfile diff --git a/example-clients/inprocess.c b/example-clients/inprocess.c new file mode 100644 index 0000000..4835d20 --- /dev/null +++ b/example-clients/inprocess.c @@ -0,0 +1,52 @@ +#include +#include +#include + +jack_port_t *input_port; +jack_port_t *output_port; + +static int +process (jack_nframes_t nframes, void *arg) +{ + jack_default_audio_sample_t *out = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port, nframes); + jack_default_audio_sample_t *in = (jack_default_audio_sample_t *) jack_port_get_buffer (input_port, nframes); + + memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes); + + return 0; +} + +int +jack_initialize (jack_client_t *client, const char *data) +{ + jack_set_process_callback (client, process, 0); + + /* create two ports */ + + input_port = jack_port_register (client, "input", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); + output_port = jack_port_register (client, "output", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + + /* start the client */ + + jack_activate (client); + + /* connect the ports */ + + if (jack_connect (client, "alsa_pcm:capture_1", jack_port_name (input_port))) { + fprintf (stderr, "cannot connect input port\n"); + } + + if (jack_connect (client, jack_port_name (output_port), "alsa_pcm:playback_1")) { + fprintf (stderr, "cannot connect output port\n"); + } + + /* our client is running. we're happy */ + + return 0; +} + +void +jack_finish (void) +{ + /* relax */ +} diff --git a/example-clients/ipload.c b/example-clients/ipload.c new file mode 100644 index 0000000..72484ad --- /dev/null +++ b/example-clients/ipload.c @@ -0,0 +1,34 @@ +#include +#include + +int +main (int argc, char *argv[]) +{ + char *name; + char *so_name; + char *so_data; + + if (argc < 3) { + fprintf (stderr, "usage: %s client-name so-name [ so-data ]\n", argv[0]); + return -1; + } + + name = argv[1]; + so_name = argv[2]; + + if (argc < 4) { + so_data = ""; + } else { + so_data = argv[3]; + } + + if (jack_inprocess_client_new (name, so_name, so_data) != 0) { + fprintf (stderr, "could not load %s\n", so_name); + return -1; + } else { + fprintf (stdout, "%s is running.\n", name); + return 0; + } +} + + diff --git a/example-clients/ipunload.c b/example-clients/ipunload.c new file mode 100644 index 0000000..c3a2e8a --- /dev/null +++ b/example-clients/ipunload.c @@ -0,0 +1,10 @@ +#include + +int +main (int argc, char *argv[]) +{ + jack_inprocess_client_close (argv[1]); + return 0; +} + + diff --git a/jack/engine.h b/jack/engine.h index 1263a17..2df4b72 100644 --- a/jack/engine.h +++ b/jack/engine.h @@ -43,10 +43,10 @@ struct _jack_engine { /* "private" sections starts here */ - pthread_mutex_t client_lock; pthread_mutex_t buffer_lock; pthread_mutex_t port_lock; + pthread_mutex_t request_lock; int process_errors; int period_msecs; unsigned int port_max; @@ -109,7 +109,7 @@ jack_engine_t *jack_engine_new (int real_time, int real_time_priority, int verb int jack_engine_delete (jack_engine_t *); int jack_run (jack_engine_t *engine); int jack_wait (jack_engine_t *engine); -int jack_use_driver (jack_engine_t *, struct _jack_driver *); +int jack_engine_load_driver (jack_engine_t *, int, char **); void jack_set_asio_mode (jack_engine_t *, int yn); void jack_dump_configuration(jack_engine_t *engine, int take_lock); diff --git a/jack/internal.h b/jack/internal.h index bc44782..efbc2c7 100644 --- a/jack/internal.h +++ b/jack/internal.h @@ -51,6 +51,7 @@ #endif typedef struct _jack_engine jack_engine_t; +typedef struct _jack_request jack_request_t; typedef void * dlhandle; @@ -112,6 +113,7 @@ typedef struct { float cpu_load; unsigned long port_max; int engine_ok; + jack_engine_t *engine; jack_port_shared_t ports[0]; } jack_control_t; @@ -134,15 +136,17 @@ typedef struct { unsigned long n; jack_port_id_t port_id; jack_port_id_t self_id; + int key; } x; union { unsigned long n; jack_port_id_t other_id; + void* addr; } y; } jack_event_t; typedef enum { - ClientDynamic, /* connect request just names .so */ + ClientInProcess, /* connect request just names .so */ ClientDriver, /* code is loaded along with driver */ ClientOutOfProcess /* client is in another process */ } ClientType; @@ -184,6 +188,13 @@ typedef volatile struct { JackXRunCallback xrun; void *xrun_arg; + /* OOP clients: set by libjack + IP clients: set by engine + */ + + int (*deliver_request)(void*, jack_request_t*); + void *deliver_arg; + /* for engine use only */ void *private_internal_client; @@ -192,10 +203,12 @@ typedef volatile struct { typedef struct { + int load; ClientType type; char name[JACK_CLIENT_NAME_SIZE+1]; char object_path[PATH_MAX+1]; + char object_data[1024]; } jack_client_connect_request_t; @@ -247,10 +260,10 @@ typedef enum { GetPortConnections = 10, GetPortNConnections = 11, AddAlias = 12, - RemoveAlias = 13 + RemoveAlias = 13, } RequestType; -typedef struct { +struct _jack_request { RequestType type; union { @@ -275,7 +288,7 @@ typedef struct { unsigned int nports; } x; int status; -} jack_request_t; +}; typedef struct _jack_port_alias { char port[JACK_PORT_NAME_SIZE+1]; @@ -285,9 +298,15 @@ typedef struct _jack_port_alias { extern void jack_cleanup_shm (); extern void jack_cleanup_files (); -extern int jack_client_handle_port_connection (jack_client_t *client, jack_event_t *event); +extern int jack_client_handle_port_connection (jack_client_t *client, jack_event_t *event); +extern void jack_client_handle_new_port_segment (jack_client_t *client, int key, void* addr); + +extern jack_client_t *jack_driver_client_new (jack_engine_t *, const char *client_name); +jack_client_t *jack_client_alloc_inprocess(jack_client_control_t*, jack_control_t*); + +/* in process clients call this. its defined in jack/engine.c */ -jack_client_t *jack_driver_become_client (const char *client_name); +void handle_in_process_client_request (jack_control_t*, jack_request_t*); extern char *jack_server_dir; diff --git a/jack/jack.h b/jack/jack.h index 105da68..bf06e6e 100644 --- a/jack/jack.h +++ b/jack/jack.h @@ -40,22 +40,28 @@ extern "C" { */ jack_client_t *jack_client_new (const char *client_name); +/** + * Disconnects an out-of-process client from a JACK server. + * + * @return 0 on success, otherwise a non-zero error code + */ +int jack_client_close (jack_client_t *client); /** * @param client_name The name for the new client * @param so_name A path to a shared object file containing the code for the new client * @param so_data An arbitary string containing information to be passed to the init() routine of the new client * - * Attemps to create an in-process client of the Jack server. + * Attemps to load an in-process client into the Jack server. */ -jack_client_t *jack_client_new_inprocess (const char *client_name, const char *so_name, const char *so_data); +int jack_inprocess_client_new (const char *client_name, const char *so_name, const char *so_data); /** - * Disconnects from Jack server. + * Removes an in-process client from a JACK server. * * @return 0 on success, otherwise a non-zero error code */ -int jack_client_close (jack_client_t *client); +void jack_inprocess_client_close (const char *client_name); /** * @param client The Jack client structure. diff --git a/jackd/ChangeLog b/jackd/ChangeLog index ec61a2c..92c104d 100644 --- a/jackd/ChangeLog +++ b/jackd/ChangeLog @@ -1,3 +1,9 @@ +2003-02-21 Paul Davis + + * jackd.c: modified signal catching design to actually follow + sigwait() specifications (ie. install handlers for all blocked + signals). also removed some dead code from benchmarking/debugging. + 2003-2-10 Taybin Rutkin * Initial Changelog * engine.c (handle_new_client): Returns protocol version for checking. diff --git a/jackd/engine.c b/jackd/engine.c index 17c0e5d..6f886c1 100644 --- a/jackd/engine.c +++ b/jackd/engine.c @@ -82,8 +82,10 @@ typedef struct _jack_client_internal { int shm_id; int shm_key; unsigned long execution_order; - struct _jack_client_internal *next_client; /* not a linked list! */ + struct _jack_client_internal *next_client; /* not a linked list! */ dlhandle handle; + int (*initialize)(jack_client_t*, const char*); /* for in-process clients only */ + void (*finish)(void); /* for in-process clients only */ int error; } jack_client_internal_t; @@ -120,13 +122,18 @@ static int jack_port_disconnect_internal (jack_engine_t *engine, jack_port_inte static void jack_port_registration_notify (jack_engine_t *, jack_port_id_t, int); static int jack_send_connection_notification (jack_engine_t *, jack_client_id_t, jack_port_id_t, jack_port_id_t, int); static int jack_deliver_event (jack_engine_t *, jack_client_internal_t *, jack_event_t *); +static void jack_deliver_event_to_all (jack_engine_t *engine, jack_event_t *event); static int jack_engine_process_lock (jack_engine_t *); static void jack_engine_process_unlock (jack_engine_t *); static int jack_engine_post_process (jack_engine_t *); +static int in_process_client_request (void*, jack_request_t *); + static const char *jack_lookup_alias (jack_engine_t *engine, const char *alias); +static int jack_use_driver (jack_engine_t *engine, jack_driver_t *driver); + static int *jack_shm_registry; static int jack_shm_id_cnt; @@ -140,7 +147,7 @@ static char *client_state_names[] = { static inline int jack_client_is_inprocess (jack_client_internal_t *client) { - return (client->control->type == ClientDynamic) || (client->control->type == ClientDriver); + return (client->control->type == ClientInProcess) || (client->control->type == ClientDriver); } #define jack_lock_graph(engine) do { \ @@ -331,8 +338,8 @@ jack_cleanup_files () static int jack_add_port_segment (jack_engine_t *engine, unsigned long nports) - { + jack_event_t event; jack_port_segment_info_t *si; key_t key; int id; @@ -398,7 +405,13 @@ jack_add_port_segment (jack_engine_t *engine, unsigned long nports) pthread_mutex_unlock (&engine->buffer_lock); - /* XXX notify all clients of new segment */ + /* tell everybody about it */ + + event.type = NewPortBufferSegment; + event.x.key = key; + event.y.addr = addr; + + jack_deliver_event_to_all (engine, &event); return 0; } @@ -621,9 +634,15 @@ jack_engine_post_process (jack_engine_t *engine) client = (jack_client_internal_t *) node->data; ctl = client->control; - - if (ctl->awake_at != 0 && ctl->state > NotTriggered && ctl->state != Finished && ctl->timed_out++) { - client->error = TRUE; + + /* this check is invalid for in-process clients and out-of-process + clients with no process callback. + */ + + if (!jack_client_is_inprocess (client) && ctl->process) { + if (ctl->awake_at != 0 && ctl->state > NotTriggered && ctl->state != Finished && ctl->timed_out++) { + client->error = TRUE; + } } if (client->error) { @@ -671,149 +690,307 @@ jack_engine_post_process (jack_engine_t *engine) } static int -jack_load_client (jack_engine_t *engine, jack_client_internal_t *client, const char *path_to_so) +jack_load_client (jack_engine_t *engine, jack_client_internal_t *client, const char *so_name) { const char *errstr; - dlhandle handle; + char path_to_so[PATH_MAX+1]; - handle = dlopen (path_to_so, RTLD_NOW|RTLD_GLOBAL); + snprintf (path_to_so, sizeof (path_to_so), ADDON_DIR "/%s.so", so_name); + client->handle = dlopen (path_to_so, RTLD_NOW|RTLD_GLOBAL); - if (handle == NULL) { + if (client->handle == 0) { if ((errstr = dlerror ()) != 0) { jack_error ("can't load \"%s\": %s", path_to_so, errstr); } else { - jack_error ("bizarre error loading driver shared object %s", path_to_so); + jack_error ("bizarre error loading shared object %s", so_name); } return -1; } - client->handle = handle; - -#if 0 - initialize = dlsym (handle, "client_initialize"); + client->initialize = dlsym (client->handle, "jack_initialize"); if ((errstr = dlerror ()) != 0) { - jack_error ("no initialize function in shared object %s\n", path_to_so); - dlclose (handle); + jack_error ("no initialize function in shared object %s\n", so_name); + dlclose (client->handle); + client->handle = 0; return -1; } - finish = dlsym (handle, "client_finish"); - + client->finish = (void (*)(void)) dlsym (client->handle, "jack_finish"); + if ((errstr = dlerror ()) != 0) { - jack_error ("no finish function in in shared driver object %s", path_to_so); - dlclose (handle); + jack_error ("no finish function in in shared object %s", so_name); + dlclose (client->handle); + client->handle = 0; return -1; } -#endif return 0; - } static void jack_client_unload (jack_client_internal_t *client) { if (client->handle) { -// client->finish (client); + if (client->finish) { + client->finish (); + } dlclose (client->handle); } } -static int -handle_new_client (jack_engine_t *engine, int client_fd) - +static jack_client_internal_t * +setup_client (jack_engine_t *engine, int client_fd, jack_client_connect_request_t *req, jack_client_connect_result_t *res) { JSList *node; jack_client_internal_t *client = NULL; - jack_client_connect_request_t req; - jack_client_connect_result_t res; - - if (read (client_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot read connection request from client"); - return -1; - } - - res.status = 0; for (node = engine->clients; node; node = jack_slist_next (node)) { client = (jack_client_internal_t *) node->data; - if (strncmp(req.name, (char*)client->control->name, sizeof(req.name)) == 0) { + if (strncmp(req->name, (char*)client->control->name, sizeof(req->name)) == 0) { jack_error ("cannot create new client; %s already exists", client->control->name); - - res.status = -1; + return NULL; } } - /* we do this to avoid sending replies to some random client if - * creation of a new client fails */ - client = NULL; + if ((client = jack_client_internal_new (engine, client_fd, req)) == NULL) { + jack_error ("cannot create new client object"); + return 0; + } + + if (engine->verbose) { + fprintf (stderr, "new client: %s, id = %ld type %d @ %p fd = %d\n", + client->control->name, client->control->id, + req->type, client->control, client_fd); + } + + res->protocol_v = jack_protocol_version; + res->client_key = client->shm_key; + res->control_key = engine->control_key; + res->port_segment_key = engine->port_segment_key; + res->realtime = engine->control->real_time; + res->realtime_priority = engine->rtpriority - 1; + + if (jack_client_is_inprocess (client)) { + + /* set up the pointers necessary for the request system + to work. + */ + + client->control->deliver_request = in_process_client_request; + client->control->deliver_arg = engine; + + /* the client is in the same address space */ + + res->client_control = client->control; + res->engine_control = engine->control; + + } else { + strcpy (res->fifo_prefix, engine->fifo_prefix); + } - if (res.status == 0) { + jack_lock_graph (engine); - if ((client = jack_client_internal_new (engine, client_fd, &req)) == NULL) { - jack_error ("cannot create new client object"); - return -1; - } + engine->clients = jack_slist_prepend (engine->clients, client); - if (engine->verbose) { - fprintf (stderr, "new client: %s, id = %ld type %d @ %p fd = %d\n", - client->control->name, client->control->id, - req.type, client->control, client_fd); + jack_engine_reset_rolling_usecs (engine); + + switch (client->control->type) { + case ClientDriver: + case ClientInProcess: + + /* an in-process client still needs to be able to make + regular JACK API calls, which need a jack_client_t + structure. create one here for it. + */ + + client->control->private_internal_client = jack_client_alloc_inprocess (client->control, engine->control); + + jack_unlock_graph (engine); + + /* call its initialization function */ + + if (client->control->type == ClientInProcess) { + + /* tell it about the port segment. XXX fix to work with multiples */ + + jack_client_handle_new_port_segment (client->control->private_internal_client, + engine->port_segment_key, + engine->port_segment_address); + + if (client->initialize (client->control->private_internal_client, req->object_data)) { + jack_client_delete (engine, client); + return 0; + } } - res.protocol_v = jack_protocol_version; - res.client_key = client->shm_key; - res.control_key = engine->control_key; - res.port_segment_key = engine->port_segment_key; - res.realtime = engine->control->real_time; - res.realtime_priority = engine->rtpriority - 1; + /* its good to go */ + break; + + default: - if (jack_client_is_inprocess (client)) { - res.client_control = client->control; - res.engine_control = engine->control; + if (engine->pfd_max >= engine->pfd_size) { + engine->pfd = (struct pollfd *) realloc (engine->pfd, sizeof (struct pollfd) * engine->pfd_size + 16); + engine->pfd_size += 16; + } + + engine->pfd[engine->pfd_max].fd = client->request_fd; + engine->pfd[engine->pfd_max].events = POLLIN|POLLPRI|POLLERR|POLLHUP|POLLNVAL; + engine->pfd_max++; + + jack_unlock_graph (engine); + break; + } + + return client; +} + +static jack_driver_t * +jack_load_driver (jack_engine_t *engine, jack_client_internal_t *client, int argc, char **argv) +{ + const char *errstr; + dlhandle handle; + jack_driver_t *driver; + jack_driver_t *(*initialize)(jack_client_t*, int, char **); + void (*finish)(jack_driver_t *); + char path_to_so[PATH_MAX+1]; + + snprintf (path_to_so, sizeof (path_to_so), ADDON_DIR "/jack_%s.so", argv[0]); + + handle = dlopen (path_to_so, RTLD_NOW|RTLD_GLOBAL); + + if (handle == NULL) { + if ((errstr = dlerror ()) != 0) { + jack_error ("can't load \"%s\": %s", path_to_so, errstr); } else { - strcpy (res.fifo_prefix, engine->fifo_prefix); + jack_error ("bizarre error loading driver shared object %s", path_to_so); } + return NULL; } - if (client == NULL) { + initialize = dlsym (handle, "driver_initialize"); + + if ((errstr = dlerror ()) != 0) { + jack_error ("no initialize function in shared object %s\n", path_to_so); + dlclose (handle); + return 0; + } + + finish = dlsym (handle, "driver_finish"); + + if ((errstr = dlerror ()) != 0) { + jack_error ("no finish function in in shared driver object %s", path_to_so); + dlclose (handle); + return 0; + } + + if ((driver = initialize (client->control->private_internal_client, argc, argv)) != 0) { + driver->handle = handle; + driver->finish = finish; + } + + return driver; +} + +void +jack_driver_unload (jack_driver_t *driver) +{ + driver->finish (driver); + dlclose (driver->handle); +} + +int +jack_engine_load_driver (jack_engine_t *engine, int argc, char *argv[]) +{ + jack_client_connect_request_t req; + jack_client_connect_result_t res; + jack_client_internal_t *client; + jack_driver_t *driver; + + req.type = ClientDriver; + snprintf (req.name, sizeof (req.name), "%s", argv[0]); + + if ((client = setup_client (engine, -1, &req, &res)) == NULL) { return -1; } - if (write (client->request_fd, &res, sizeof (res)) != sizeof (res)) { - jack_error ("cannot write connection response to client"); + if ((driver = jack_load_driver (engine, client, argc, argv)) == NULL) { jack_client_delete (engine, client); return -1; } - if (res.status) { - return res.status; + if (jack_use_driver (engine, driver)) { + jack_driver_unload (driver); + jack_client_delete (engine, client); + return -1; } - jack_lock_graph (engine); + return 0; +} - engine->clients = jack_slist_prepend (engine->clients, client); +static int +handle_unload_client (jack_engine_t *engine, int client_fd, jack_client_connect_request_t *req) +{ + JSList *node; + jack_client_connect_result_t res; - jack_engine_reset_rolling_usecs (engine); + res.status = -1; - if (client->control->type != ClientDynamic) { - if (engine->pfd_max >= engine->pfd_size) { - engine->pfd = (struct pollfd *) realloc (engine->pfd, sizeof (struct pollfd) * engine->pfd_size + 16); - engine->pfd_size += 16; + fprintf (stderr, "unloading client \"%s\"\n", req->name); + + jack_lock_graph (engine); + for (node = engine->clients; node; node = jack_slist_next (node)) { + if (strcmp ((char *) ((jack_client_internal_t *) node->data)->control->name, req->name) == 0) { + jack_remove_client (engine, (jack_client_internal_t *) node->data); + fprintf (stderr, "found it\n"); + res.status = 0; + break; } - - engine->pfd[engine->pfd_max].fd = client->request_fd; - engine->pfd[engine->pfd_max].events = POLLIN|POLLPRI|POLLERR|POLLHUP|POLLNVAL; - engine->pfd_max++; } - jack_unlock_graph (engine); return 0; } +static int +handle_new_client (jack_engine_t *engine, int client_fd) +{ + jack_client_internal_t *client; + jack_client_connect_request_t req; + jack_client_connect_result_t res; + + if (read (client_fd, &req, sizeof (req)) != sizeof (req)) { + jack_error ("cannot read connection request from client"); + return -1; + } + + if (!req.load) { + return handle_unload_client (engine, client_fd, &req); + } + + if ((client = setup_client (engine, client_fd, &req, &res)) == NULL) { + return -1; + } + + if (write (client->request_fd, &res, sizeof (res)) != sizeof (res)) { + jack_error ("cannot write connection response to client"); + jack_client_delete (engine, client); + return -1; + } + + switch (client->control->type) { + case ClientDriver: + case ClientInProcess: + close (client_fd); + break; + default: + break; + } + + return 0; +} + static int handle_client_ack_connection (jack_engine_t *engine, int client_fd) @@ -1111,6 +1288,11 @@ handle_client_jack_error (jack_engine_t *engine, int fd) jack_lock_graph (engine); for (node = engine->clients; node; node = jack_slist_next (node)) { + + if (jack_client_is_inprocess((jack_client_internal_t *) node->data)) { + continue; + } + if (((jack_client_internal_t *) node->data)->request_fd == fd) { client = (jack_client_internal_t *) node->data; client->error++; @@ -1123,103 +1305,70 @@ handle_client_jack_error (jack_engine_t *engine, int fd) return 0; } -static int -handle_client_request (jack_engine_t *engine, int fd) +static void +do_request (jack_engine_t *engine, jack_request_t *req, int *reply_fd) { - jack_request_t req; - jack_client_internal_t *client = 0; - int reply_fd; - JSList *node; - int might_reorder = FALSE; + pthread_mutex_lock (&engine->request_lock); - DEBUG ("HIT: before lock"); - - jack_lock_graph (engine); + DEBUG ("got a request of type %d", req->type); - DEBUG ("HIT: before for"); - - for (node = engine->clients; node; node = jack_slist_next (node)) { - if (((jack_client_internal_t *) node->data)->request_fd == fd) { - DEBUG ("HIT: in for"); - client = (jack_client_internal_t *) node->data; - break; - } - } - DEBUG ("HIT: after for"); - - jack_unlock_graph (engine); - - if (client == NULL) { - jack_error ("client input on unknown fd %d!", fd); - return -1; - } - - if (read (client->request_fd, &req, sizeof (req)) < (ssize_t) sizeof (req)) { - jack_error ("cannot read request from client"); - client->error++; - return -1; - } - - reply_fd = client->request_fd; - - DEBUG ("got a request of type %d", req.type); - - switch (req.type) { + switch (req->type) { case RegisterPort: - req.status = jack_port_do_register (engine, &req); + req->status = jack_port_do_register (engine, req); break; case UnRegisterPort: - req.status = jack_port_do_unregister (engine, &req); + req->status = jack_port_do_unregister (engine, req); break; case ConnectPorts: - might_reorder = TRUE; - req.status = jack_port_do_connect (engine, req.x.connect.source_port, req.x.connect.destination_port); + req->status = jack_port_do_connect (engine, req->x.connect.source_port, req->x.connect.destination_port); break; case DisconnectPort: - might_reorder = TRUE; - req.status = jack_port_do_disconnect_all (engine, req.x.port_info.port_id); + req->status = jack_port_do_disconnect_all (engine, req->x.port_info.port_id); break; case DisconnectPorts: - might_reorder = TRUE; - req.status = jack_port_do_disconnect (engine, req.x.connect.source_port, req.x.connect.destination_port); + req->status = jack_port_do_disconnect (engine, req->x.connect.source_port, req->x.connect.destination_port); break; case ActivateClient: - req.status = jack_client_activate (engine, req.x.client_id); + req->status = jack_client_activate (engine, req->x.client_id); break; case DeactivateClient: - might_reorder = TRUE; - req.status = jack_client_deactivate (engine, req.x.client_id); + req->status = jack_client_deactivate (engine, req->x.client_id); break; case SetTimeBaseClient: - req.status = jack_set_timebase (engine, req.x.client_id); + req->status = jack_set_timebase (engine, req->x.client_id); break; #ifdef USE_CAPABILITIES case SetClientCapabilities: - req.status = jack_set_client_capabilities (engine, req.x.client_id); + req->status = jack_set_client_capabilities (engine, req->x.client_id); break; #endif case GetPortConnections: case GetPortNConnections: - req.status = jack_do_get_port_connections (engine, &req, reply_fd); - if( req.status >= 0 ) - reply_fd = -1; + if (reply_fd) { + req->status = jack_do_get_port_connections (engine, req, *reply_fd); + if (req->status != 0) { + *reply_fd = -1; + } + } else { + req->status = -1; + } break; case AddAlias: - req.status = jack_do_add_alias (engine, &req); + req->status = jack_do_add_alias (engine, req); break; case RemoveAlias: - req.status = jack_do_remove_alias (engine, &req); + req->status = jack_do_remove_alias (engine, req); break; default: @@ -1229,8 +1378,59 @@ handle_client_request (jack_engine_t *engine, int fd) break; } - DEBUG ("status of request: %d", req.status); + pthread_mutex_unlock (&engine->request_lock); + + DEBUG ("status of request: %d", req->status); +} + +static int +in_process_client_request (void* ptr, jack_request_t *request) +{ + do_request ((jack_engine_t*) ptr, request, 0); + return request->status; +} + +static int +handle_out_of_process_client_request (jack_engine_t *engine, int fd) +{ + jack_request_t req; + jack_client_internal_t *client = 0; + int reply_fd; + JSList *node; + ssize_t r; + + DEBUG ("HIT: before lock"); + + jack_lock_graph (engine); + + DEBUG ("HIT: before for"); + + for (node = engine->clients; node; node = jack_slist_next (node)) { + if (((jack_client_internal_t *) node->data)->request_fd == fd) { + DEBUG ("HIT: in for"); + client = (jack_client_internal_t *) node->data; + break; + } + } + DEBUG ("HIT: after for"); + + jack_unlock_graph (engine); + + if (client == NULL) { + jack_error ("client input on unknown fd %d!", fd); + return -1; + } + + if ((r = read (client->request_fd, &req, sizeof (req))) < (ssize_t) sizeof (req)) { + jack_error ("cannot read request from client (%d/%d/%s)", r, sizeof(req), strerror (errno)); + client->error++; + return -1; + } + reply_fd = client->request_fd; + + do_request (engine, &req, &reply_fd); + if (reply_fd >= 0) { DEBUG ("replying to client"); if (write (reply_fd, &req, sizeof (req)) < (ssize_t) sizeof (req)) { @@ -1338,7 +1538,7 @@ jack_server_thread (void *arg) if (pfd[i].revents & ~POLLIN) { handle_client_jack_error (engine, pfd[i].fd); } else if (pfd[i].revents & POLLIN) { - if (handle_client_request (engine, pfd[i].fd)) { + if (handle_out_of_process_client_request (engine, pfd[i].fd)) { jack_error ("bad hci\n"); } } @@ -1348,14 +1548,6 @@ jack_server_thread (void *arg) return 0; } -static void -jack_start_server (jack_engine_t *engine) - -{ - pthread_create (&engine->server_thread, 0, &jack_server_thread, engine); - pthread_detach (engine->server_thread); -} - jack_engine_t * jack_engine_new (int realtime, int rtpriority, int verbose) { @@ -1392,6 +1584,7 @@ jack_engine_new (int realtime, int rtpriority, int verbose) pthread_mutex_init (&engine->client_lock, 0); pthread_mutex_init (&engine->buffer_lock, 0); pthread_mutex_init (&engine->port_lock, 0); + pthread_mutex_init (&engine->request_lock, 0); engine->clients = 0; engine->aliases = 0; @@ -1434,6 +1627,7 @@ jack_engine_new (int realtime, int rtpriority, int verbose) } engine->control = (jack_control_t *) addr; + engine->control->engine = engine; /* Mark all ports as available */ @@ -1496,7 +1690,9 @@ jack_engine_new (int realtime, int rtpriority, int verbose) snprintf (engine->fifo_prefix, sizeof (engine->fifo_prefix), "%s/jack-ack-fifo-%d", jack_server_dir, getpid()); (void) jack_get_fifo_fd (engine, 0); - jack_start_server (engine); + + pthread_create (&engine->server_thread, 0, &jack_server_thread, engine); + pthread_detach (engine->server_thread); return engine; } @@ -1833,7 +2029,7 @@ jack_client_internal_new (jack_engine_t *engine, int fd, jack_client_connect_req void *addr = 0; switch (req->type) { - case ClientDynamic: + case ClientInProcess: case ClientDriver: break; @@ -1866,6 +2062,7 @@ jack_client_internal_new (jack_engine_t *engine, int fd, jack_client_connect_req client->execution_order = UINT_MAX; client->next_client = NULL; client->handle = NULL; + client->finish = NULL; client->error = 0; if (req->type != ClientOutOfProcess) { @@ -1899,7 +2096,7 @@ jack_client_internal_new (jack_engine_t *engine, int fd, jack_client_connect_req client->control->graph_order = NULL; client->control->graph_order_arg = NULL; - if (req->type == ClientDynamic) { + if (req->type == ClientInProcess) { if (jack_load_client (engine, client, req->object_path)) { jack_error ("cannot dynamically load client from \"%s\"", req->object_path); jack_client_delete (engine, client); @@ -1981,16 +2178,19 @@ jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client) jack_client_do_deactivate (engine, client, FALSE); - /* rearrange the pollfd array so that things work right the - next time we go into poll(2). - */ - - for (i = 0; i < engine->pfd_max; i++) { - if (engine->pfd[i].fd == client->request_fd) { - if (i+1 < engine->pfd_max) { - memmove (&engine->pfd[i], &engine->pfd[i+1], sizeof (struct pollfd) * (engine->pfd_max - i)); + if (client->control->type == ClientOutOfProcess) { + + /* rearrange the pollfd array so that things work right the + next time we go into poll(2). + */ + + for (i = 0; i < engine->pfd_max; i++) { + if (engine->pfd[i].fd == client->request_fd) { + if (i+1 < engine->pfd_max) { + memmove (&engine->pfd[i], &engine->pfd[i+1], sizeof (struct pollfd) * (engine->pfd_max - i)); + } + engine->pfd_max--; } - engine->pfd_max--; } } @@ -1999,7 +2199,6 @@ jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client) static void jack_client_delete (jack_engine_t *engine, jack_client_internal_t *client) - { if (jack_client_is_inprocess (client)) { jack_client_unload (client); @@ -2038,7 +2237,7 @@ jack_client_internal_by_id (jack_engine_t *engine, jack_client_id_t id) jack_client_internal_t *client = NULL; JSList *node; - /* call tree ***MUST HOLD*** engine->client_lock */ + /* call tree ***MUST HOLD*** the graph lock */ for (node = engine->clients; node; node = jack_slist_next (node)) { if (((jack_client_internal_t *) node->data)->control->id == id) { @@ -2050,12 +2249,24 @@ jack_client_internal_by_id (jack_engine_t *engine, jack_client_id_t id) return client; } +static void +jack_deliver_event_to_all (jack_engine_t *engine, jack_event_t *event) +{ + JSList *node; + + jack_lock_graph (engine); + for (node = engine->clients; node; node = jack_slist_next (node)) { + jack_deliver_event (engine, (jack_client_internal_t *) node->data, event); + } + jack_unlock_graph (engine); +} + static int jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, jack_event_t *event) { char status; - /* caller must hold the client_lock */ + /* caller must hold the graph lock */ DEBUG ("delivering event (type %d)", event->type); @@ -2065,6 +2276,8 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, jack_ if (jack_client_is_inprocess (client)) { + fprintf (stderr, "delivering event %d to IP client %s\n", event->type, client->control->name); + switch (event->type) { case PortConnected: case PortDisconnected: @@ -2095,6 +2308,10 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, jack_ } break; + case NewPortBufferSegment: + jack_client_handle_new_port_segment (client->control->private_internal_client, event->x.key, event->y.addr); + break; + default: /* internal clients don't need to know */ break; @@ -2850,9 +3067,8 @@ jack_clear_fifos (jack_engine_t *engine) } } -int +static int jack_use_driver (jack_engine_t *engine, jack_driver_t *driver) - { if (engine->driver) { engine->driver->detach (engine->driver, engine); @@ -3074,6 +3290,7 @@ jack_do_get_port_connections (jack_engine_t *engine, jack_request_t *req, int re ret = 0; out: + req->status = ret; jack_unlock_graph (engine); return ret; } diff --git a/jackd/jackd.c b/jackd/jackd.c index b9e3f5e..6ec888d 100644 --- a/jackd/jackd.c +++ b/jackd/jackd.c @@ -60,87 +60,88 @@ typedef struct { char **argv; } waiter_arg_t; -#define ILOWER 0 -#define IRANGE 3000 -int wait_times[IRANGE]; -int unders = 0; -int overs = 0; -int max_over = 0; -int min_under = INT_MAX; - -#define WRANGE 3000 -int work_times[WRANGE]; -int work_overs = 0; -int work_max = 0; - -void -store_work_time (int howlong) +static void +signal_handler (int sig) { - if (howlong < WRANGE) { - work_times[howlong]++; - } else { - work_overs++; - } + /* this is used by the parent (waiter) process */ - if (work_max < howlong) { - work_max = howlong; - } + fprintf (stderr, "jackd: signal %d received\n", sig); + kill (jackd_pid, SIGTERM); } -void -show_work_times () +static void +do_nothing_handler (int sig) { - int i; - for (i = 0; i < WRANGE; ++i) { - printf ("%d %d\n", i, work_times[i]); - } - printf ("work overs = %d\nmax = %d\n", work_overs, work_max); + /* this is used by the child (active) process, but it never + gets called unless we are already shutting down + after another signal. + */ + + char buf[32]; + snprintf (buf, sizeof(buf), "received signal %d during shutdown (ignored)\n", sig); + write (1, buf, strlen (buf)); } -void -store_wait_time (int interval) +static void * +jack_engine_waiter_thread (void *arg) { - if (interval < ILOWER) { - unders++; - } else if (interval >= ILOWER + IRANGE) { - overs++; - } else { - wait_times[interval-ILOWER]++; - } + waiter_arg_t *warg = (waiter_arg_t *) arg; - if (interval > max_over) { - max_over = interval; + pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + if ((engine = jack_engine_new (realtime, realtime_priority, verbose)) == 0) { + fprintf (stderr, "cannot create engine\n"); + kill (warg->pid, SIGTERM); + return 0; } - if (interval < min_under) { - min_under = interval; + if (warg->argc) { + + fprintf (stderr, "loading driver ..\n"); + + if (jack_engine_load_driver (engine, warg->argc, warg->argv)) { + fprintf (stderr, "cannot load driver module %s\n", warg->argv[0]); + kill (warg->pid, SIGTERM); + return 0; + } + + } else { + + fprintf (stderr, "No driver specified ... hmm. JACK won't do anything when run like this.\n"); } -} -void -show_wait_times () -{ - int i; + if (asio_mode) { + jack_set_asio_mode (engine, TRUE); + } + + fprintf (stderr, "starting engine\n"); - for (i = 0; i < IRANGE; i++) { - printf ("%d %d\n", i+ILOWER, wait_times[i]); + if (jack_run (engine)) { + fprintf (stderr, "cannot start main JACK thread\n"); + kill (warg->pid, SIGTERM); + return 0; } - printf ("unders: %d\novers: %d\n", unders, overs); - printf ("max: %d\nmin: %d\n", max_over, min_under); -} + jack_wait (engine); -static void -signal_handler (int sig) -{ - fprintf (stderr, "jackd: signal %d received\n", sig); - kill (jackd_pid, SIGTERM); + fprintf (stderr, "telling signal thread that the engine is done\n"); + kill (warg->pid, SIGHUP); + + return 0; /* nobody cares what this returns */ } static void -posix_me_harder (void) - +jack_main (int argc, char **argv) { + int sig; + int i; + pthread_t waiter_thread; + waiter_arg_t warg; + sigset_t allsignals; + struct sigaction action; + + pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + /* what's this for? POSIX says that signals are delivered like this: @@ -182,80 +183,11 @@ posix_me_harder (void) sigaddset(&signals, SIGPIPE); sigaddset(&signals, SIGTERM); sigaddset(&signals, SIGUSR1); - - /* this can make debugging a pain, but it also makes - segv-exits cleanup_files after themselves rather than - leaving the audio thread active. i still - find it truly wierd that _exit() or whatever is done - by the default SIGSEGV handler does not - cancel all threads in a process, but what - else can we do? - */ - sigaddset(&signals, SIGSEGV); - /* all child threads will inherit this mask */ + /* all child threads will inherit this mask unless they explicitly reset it */ pthread_sigmask (SIG_BLOCK, &signals, 0); -} - -static void * -jack_engine_waiter_thread (void *arg) -{ - waiter_arg_t *warg = (waiter_arg_t *) arg; - jack_driver_t *driver; - - pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); - - if ((engine = jack_engine_new (realtime, realtime_priority, verbose)) == 0) { - fprintf (stderr, "cannot create engine\n"); - kill (warg->pid, SIGTERM); - return 0; - } - - if (warg->argc) { - - fprintf (stderr, "loading driver ..\n"); - - if ((driver = jack_driver_load (warg->argc, warg->argv)) == 0) { - fprintf (stderr, "cannot load driver module %s\n", warg->argv[0]); - kill (warg->pid, SIGTERM); - return 0; - } - - jack_use_driver (engine, driver); - } - - if (asio_mode) { - jack_set_asio_mode (engine, TRUE); - } - - fprintf (stderr, "starting engine\n"); - - if (jack_run (engine)) { - fprintf (stderr, "cannot start main JACK thread\n"); - kill (warg->pid, SIGTERM); - return 0; - } - - jack_wait (engine); - - fprintf (stderr, "telling signal thread that the engine is done\n"); - kill (warg->pid, SIGHUP); - - return 0; /* nobody cares what this returns */ -} - -static void -jack_main (int argc, char **argv) -{ - int sig; - pthread_t waiter_thread; - waiter_arg_t warg; - - pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); - - posix_me_harder (); /* what we'd really like to do here is to be able to wait for either the engine to stop or a POSIX signal, @@ -283,13 +215,23 @@ jack_main (int argc, char **argv) return; } - /* Note: normal operation has with_fork == 1 */ + /* install a do-nothing handler because otherwise + pthreads behaviour is undefined when we enter + sigwait. + */ + + sigfillset (&allsignals); + + action.sa_handler = do_nothing_handler; + action.sa_mask = allsignals; + action.sa_flags = SA_RESTART|SA_RESETHAND; - if (with_fork) { - /* let the parent handle SIGINT */ - sigdelset (&signals, SIGINT); + for (i = 0; i < NSIG; i++) { + if (sigismember (&signals, i)) { + sigaction (i, &action, 0); + } } - + if (verbose) { fprintf (stderr, "%d waiting for signals\n", getpid()); } @@ -297,7 +239,7 @@ jack_main (int argc, char **argv) while(1) { sigwait (&signals, &sig); - printf ("jack main caught signal %d\n", sig); + fprintf (stderr, "jack main caught signal %d\n", sig); if (sig == SIGUSR1) { jack_dump_configuration(engine, 1); @@ -307,6 +249,16 @@ jack_main (int argc, char **argv) } } + if (sig != SIGSEGV) { + + /* unblock signals so we can see them during shutdown. + this will help prod developers not to lose sight + of bugs that cause segfaults etc. during shutdown. + */ + + sigprocmask (SIG_UNBLOCK, &signals, 0); + } + pthread_cancel (waiter_thread); jack_engine_delete (engine); diff --git a/libjack/ChangeLog b/libjack/ChangeLog index 93f70e2..461b431 100644 --- a/libjack/ChangeLog +++ b/libjack/ChangeLog @@ -1,3 +1,11 @@ +2003-02-23 Paul Davis + + * client.c: + + added deliver_request(). + removed all use of strncpy(). + changed ClientDynamic to ClientInProcess. + 2003-02-10 Taybin Rutkin * client.c (jack_client_new): Checks jack_protocol_version returned diff --git a/libjack/client.c b/libjack/client.c index 6cc6d6a..3df34d2 100644 --- a/libjack/client.c +++ b/libjack/client.c @@ -87,6 +87,7 @@ struct _jack_client { char first_active : 1; float cpu_mhz; pthread_t thread_id; + }; #define event_fd pollfd[0].fd @@ -118,9 +119,36 @@ void default_jack_error_callback (const char *desc) void (*jack_error_callback)(const char *desc) = &default_jack_error_callback; +static int +oop_client_deliver_request (void *ptr, jack_request_t *req) +{ + jack_client_t *client = (jack_client_t*) ptr; + + if (write (client->request_fd, req, sizeof (*req)) != sizeof (*req)) { + jack_error ("cannot send request type %d to server", req->type); + req->status = -1; + } + if (read (client->request_fd, req, sizeof (*req)) != sizeof (*req)) { + jack_error ("cannot read result for request type %d from server (%s)", req->type, strerror (errno)); + req->status = -1; + } + + return req->status; +} + +static int +deliver_request (const jack_client_t *client, jack_request_t *req) +{ + /* indirect through the function pointer that was set + either by jack_client_new() (OOP) or handle_new_client() + in the server. + */ + + return client->control->deliver_request (client->control->deliver_arg, req); +} + jack_client_t * jack_client_alloc () - { jack_client_t *client; @@ -140,9 +168,32 @@ jack_client_alloc () client->first_active = TRUE; client->on_shutdown = NULL; client->cpu_mhz = (float) jack_get_mhz (); + + return client; +} + +jack_client_t * +jack_client_alloc_inprocess (jack_client_control_t *cc, jack_control_t *ec) +{ + jack_client_t* client; + + client = jack_client_alloc (); + client->control = cc; + client->engine = ec; + return client; } +static void +jack_client_free (jack_client_t *client) +{ + if (client->pollfd) { + free (client->pollfd); + } + + free (client); +} + jack_port_t * jack_port_by_id (const jack_client_t *client, jack_port_id_t id) { @@ -368,104 +419,116 @@ server_event_connect (jack_client_t *client) return fd; } -jack_client_t * -jack_client_new (const char *client_name) - +static int +jack_request_client (ClientType type, const char* client_name, const char* so_name, + const char* so_data, jack_client_connect_result_t *res, int *req_fd) { - int req_fd = -1; - int ev_fd = -1; - void *addr; jack_client_connect_request_t req; - jack_client_connect_result_t res; - jack_port_segment_info_t *si; - jack_client_t *client; - int client_shm_id; - int control_shm_id; - int port_segment_shm_id; - int n; + + *req_fd = -1; if (strlen (client_name) > sizeof (req.name) - 1) { jack_error ("\"%s\" is too long to be used as a JACK client name.\n" "Please use %lu characters or less.", - sizeof (req.name) - 1); - return NULL; + client_name, sizeof (req.name) - 1); + return -1; + } + + if (strlen (so_name) > sizeof (req.object_path) - 1) { + jack_error ("\"%s\" is too long to be used as a JACK shared object name.\n" + "Please use %lu characters or less.", + so_name, sizeof (req.object_path) - 1); + return -1; + } + + if (strlen (so_data) > sizeof (req.object_data) - 1) { + jack_error ("\"%s\" is too long to be used as a JACK shared object data string.\n" + "Please use %lu characters or less.", + so_data, sizeof (req.object_data) - 1); + return -1; } - if ((req_fd = server_connect (0)) < 0) { + if ((*req_fd = server_connect (0)) < 0) { jack_error ("cannot connect to default JACK server"); - return NULL; + goto fail; } - req.type = ClientOutOfProcess; - strncpy (req.name, client_name, sizeof (req.name) - 1); - - if (write (req_fd, &req, sizeof (req)) != sizeof (req)) { + req.load = TRUE; + req.type = type; + snprintf (req.name, sizeof (req.name), "%s", client_name); + snprintf (req.object_path, sizeof (req.object_path), "%s", so_name); + snprintf (req.object_data, sizeof (req.object_data), "%s", so_data); + + if (write (*req_fd, &req, sizeof (req)) != sizeof (req)) { jack_error ("cannot send request to jack server (%s)", strerror (errno)); - close (req_fd); - return NULL; + goto fail; } - if ((n = read (req_fd, &res, sizeof (res))) != sizeof (res)) { + if (read (*req_fd, res, sizeof (*res)) != sizeof (*res)) { if (errno == 0) { /* server shut the socket */ jack_error ("could not attach as client (duplicate client name?)"); - close (req_fd); - return NULL; + goto fail; } jack_error ("cannot read response from jack server (%s)", strerror (errno)); - close (req_fd); - return NULL; + goto fail; } - if (res.status) { - close (req_fd); + if (res->status) { jack_error ("could not attach as client (duplicate client name?)"); - return NULL; + goto fail; } - if (res.protocol_v != jack_protocol_version){ - close (req_fd); - jack_error ("application linked against too old of a version of libjack."); - return NULL; + if (res->protocol_v != jack_protocol_version){ + jack_error ("application linked against too wrong of a version of libjack."); + goto fail; } - client = jack_client_alloc (); - - strcpy (client->fifo_prefix, res.fifo_prefix); - client->request_fd = req_fd; + switch (type) { + case ClientDriver: + case ClientInProcess: + close (*req_fd); + *req_fd = -1; + break; - client->pollfd[0].events = POLLIN|POLLERR|POLLHUP|POLLNVAL; - client->pollfd[1].events = POLLIN|POLLERR|POLLHUP|POLLNVAL; + default: + break; + } - /* Lookup, attach and register the port/buffer segments in use - right now. - */ + return 0; - if ((port_segment_shm_id = shmget (res.port_segment_key, 0, 0)) < 0) { - jack_error ("cannot determine shared memory segment for port segment key 0x%x (%s)", res.port_segment_key, strerror (errno)); - goto fail; + fail: + if (*req_fd >= 0) { + close (*req_fd); + *req_fd = -1; } + return -1; +} - if ((addr = shmat (port_segment_shm_id, 0, 0)) == (void *) -1) { - jack_error ("cannot attached port segment shared memory (%s)", strerror (errno)); - goto fail; +jack_client_t * +jack_client_new (const char *client_name) +{ + int req_fd = -1; + int ev_fd = -1; + jack_client_connect_result_t res; + jack_client_t *client; + int client_shm_id; + int control_shm_id; + void *addr; + + if (jack_request_client (ClientOutOfProcess, client_name, "", "", &res, &req_fd)) { + return NULL; } - si = (jack_port_segment_info_t *) malloc (sizeof (jack_port_segment_info_t)); - si->shm_key = res.port_segment_key; - si->address = addr; - - /* the first chunk of the first port segment is always set by the engine - to be a conveniently-sized, zero-filled lump of memory. - */ + client = jack_client_alloc (); - if (client->port_segments == NULL) { - jack_zero_filled_buffer = si->address; - } + strcpy (client->fifo_prefix, res.fifo_prefix); + client->request_fd = req_fd; - client->port_segments = jack_slist_prepend (client->port_segments, si); + client->pollfd[0].events = POLLIN|POLLERR|POLLHUP|POLLNVAL; + client->pollfd[1].events = POLLIN|POLLERR|POLLHUP|POLLNVAL; /* attach the engine control/info block */ @@ -495,6 +558,13 @@ jack_client_new (const char *client_name) client->control = (jack_client_control_t *) addr; + jack_client_handle_new_port_segment (client, res.port_segment_key, 0); + + /* set up the client so that it does the right thing for an OOP client */ + + client->control->deliver_request = oop_client_deliver_request; + client->control->deliver_arg = client; + if ((ev_fd = server_event_connect (client)) < 0) { jack_error ("cannot connect to server for event stream (%s)", strerror (errno)); goto fail; @@ -521,6 +591,84 @@ jack_client_new (const char *client_name) return 0; } +int +jack_inprocess_client_new (const char *client_name, const char *so_name, const char *so_data) +{ + jack_client_connect_result_t res; + int req_fd; + + return jack_request_client (ClientInProcess, client_name, so_name, so_data, &res, &req_fd); +} + +void +jack_inprocess_client_close (const char *client_name) +{ + jack_client_connect_request_t req; + int fd; + + req.load = FALSE; + snprintf (req.name, sizeof (req.name), "%s", client_name); + + if ((fd = server_connect (0)) < 0) { + jack_error ("cannot connect to default JACK server."); + return; + } + + if (write (fd, &req, sizeof (req)) != sizeof(req)) { + jack_error ("cannot deliver ClientUnload request to JACK server."); + } + + /* no response to this request */ + + close (fd); + return; +} + +void +jack_client_handle_new_port_segment (jack_client_t *client, int key, void* addr) +{ + jack_port_segment_info_t *si; + int port_segment_shm_id; + + /* Lookup, attach and register the port/buffer segments in use + right now. + */ + + if (client->control->type == ClientOutOfProcess) { + + /* map shared memory */ + + if ((port_segment_shm_id = shmget (key, 0, 0)) < 0) { + jack_error ("cannot determine shared memory segment for port segment key 0x%x (%s)", + key, strerror (errno)); + return; + } + + if ((addr = shmat (port_segment_shm_id, 0, 0)) == (void *) -1) { + jack_error ("cannot attached port segment shared memory (%s)", strerror (errno)); + return; + } + + } else { + + /* client is in same address space as server, so just use `addr' directly */ + } + + si = (jack_port_segment_info_t *) malloc (sizeof (jack_port_segment_info_t)); + si->shm_key = key; + si->address = addr; + + /* the first chunk of the first port segment is always set by the engine + to be a conveniently-sized, zero-filled lump of memory. + */ + + if (client->port_segments == NULL) { + jack_zero_filled_buffer = si->address; + } + + client->port_segments = jack_slist_prepend (client->port_segments, si); +} + static void * jack_client_thread (void *arg) @@ -643,6 +791,7 @@ jack_client_thread (void *arg) break; case NewPortBufferSegment: + jack_client_handle_new_port_segment (client, event.x.key, event.y.addr); break; } @@ -892,7 +1041,12 @@ jack_activate (jack_client_t *client) #undef BIG_ENOUGH_STACK + if (client->control->type == ClientInProcess || client->control->type == ClientDriver) { + goto startit; + } + /* get the pid of the client process to pass it to engine */ + client->control->pid = getpid (); #ifdef USE_CAPABILITIES @@ -906,15 +1060,9 @@ jack_activate (jack_client_t *client) req.type = SetClientCapabilities; req.x.client_id = client->control->id; + + deliver_request (client, &request); - if (write (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot send set client capabilities request to server"); - return -1; - } - if (read (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot read set client capabilities result from server (%s)", strerror (errno)); - return -1; - } if (req.status) { /* what to do? engine is running realtime, it is using capabilities and has @@ -931,7 +1079,7 @@ jack_activate (jack_client_t *client) } #endif - if (client->control->type == ClientOutOfProcess && client->first_active) { + if (client->first_active) { pthread_mutex_init (&client_lock, NULL); pthread_cond_init (&client_ready, NULL); @@ -954,20 +1102,12 @@ jack_activate (jack_client_t *client) client->first_active = FALSE; } + startit: + req.type = ActivateClient; req.x.client_id = client->control->id; - if (write (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot send activate client request to server"); - return -1; - } - - if (read (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot read activate client result from server (%s)", strerror (errno)); - return -1; - } - - return req.status; + return deliver_request (client, &req); } int @@ -979,22 +1119,11 @@ jack_deactivate (jack_client_t *client) req.type = DeactivateClient; req.x.client_id = client->control->id; - if (write (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot send deactivate client request to server"); - return -1; - } - - if (read (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot read deactivate client result from server (%s)", strerror (errno)); - return -1; - } - - return req.status; + return deliver_request (client, &req); } int jack_client_close (jack_client_t *client) - { JSList *node; void *status; @@ -1003,155 +1132,41 @@ jack_client_close (jack_client_t *client) jack_deactivate (client); } - /* stop the thread that communicates with the jack server */ - pthread_cancel (client->thread); - pthread_join (client->thread, &status); + if (client->control->type == ClientOutOfProcess) { + /* stop the thread that communicates with the jack server */ + pthread_cancel (client->thread); + pthread_join (client->thread, &status); - shmdt ((char *) client->control); - shmdt (client->engine); + shmdt ((char *) client->control); + shmdt (client->engine); - for (node = client->port_segments; node; node = jack_slist_next (node)) { - shmdt (((jack_port_segment_info_t *) node->data)->address); - free (node->data); + for (node = client->port_segments; node; node = jack_slist_next (node)) { + shmdt (((jack_port_segment_info_t *) node->data)->address); + free (node->data); + } + jack_slist_free (client->port_segments); + + if (client->graph_wait_fd) { + close (client->graph_wait_fd); + } + + if (client->graph_next_fd) { + close (client->graph_next_fd); + } + + close (client->event_fd); + close (client->request_fd); } - jack_slist_free (client->port_segments); for (node = client->ports; node; node = jack_slist_next (node)) { free (node->data); } jack_slist_free (client->ports); - - if (client->graph_wait_fd) { - close (client->graph_wait_fd); - } - - if (client->graph_next_fd) { - close (client->graph_next_fd); - } - - close (client->event_fd); - close (client->request_fd); - - free (client->pollfd); - free (client); - + jack_client_free (client); + return 0; } -int -jack_load_client (const char *client_name, const char *path_to_so) -{ - int fd; - jack_client_connect_request_t req; - jack_client_connect_result_t res; - - if ((fd = server_connect (0)) < 0) { - jack_error ("cannot connect to jack server"); - return 0; - } - - req.type = ClientDynamic; - - strncpy (req.name, client_name, sizeof (req.name) - 1); - req.name[sizeof(req.name)-1] = '\0'; - strncpy (req.object_path, path_to_so, sizeof (req.name) - 1); - req.object_path[sizeof(req.object_path)-1] = '\0'; - - if (write (fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot send request to jack server (%s)", strerror (errno)); - close (fd); - return 0; - } - - if (read (fd, &res, sizeof (res)) != sizeof (res)) { - jack_error ("cannot read response from jack server (%s)", strerror (errno)); - close (fd); - return 0; - } - - close (fd); - return res.status; -} - -jack_client_t * -jack_driver_become_client (const char *client_name) -{ - int fd; - jack_client_connect_request_t req; - jack_client_connect_result_t res; - jack_client_t *client = 0; - int port_segment_shm_id; - jack_port_segment_info_t *si; - void *addr; - - if ((fd = server_connect (0)) < 0) { - jack_error ("cannot connect to jack server"); - return 0; - } - - req.type = ClientDriver; - strncpy (req.name, client_name, sizeof (req.name) - 1); - req.name[sizeof(req.name)-1] = '\0'; - - if (write (fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot send request to jack server (%s)", strerror (errno)); - close (fd); - return 0; - } - - if (read (fd, &res, sizeof (res)) != sizeof (res)) { - jack_error ("cannot read response from jack server (%s)", strerror (errno)); - close (fd); - return 0; - } - - if (res.status) { - return 0; - } - - client = jack_client_alloc (); - - client->request_fd = fd; - client->control = res.client_control; - client->engine = res.engine_control; - - /* Lookup, attach and register the port/buffer segments in use - right now. - */ - - if ((port_segment_shm_id = shmget (res.port_segment_key, 0, 0)) < 0) { - jack_error ("cannot determine shared memory segment for port segment key 0x%x (%s)", res.port_segment_key, strerror (errno)); - return NULL; - } - - if ((addr = shmat (port_segment_shm_id, 0, 0)) == (void *) -1) { - jack_error ("cannot attached port segment shared memory (%s)", strerror (errno)); - return NULL; - } - - si = (jack_port_segment_info_t *) malloc (sizeof (jack_port_segment_info_t)); - si->shm_key = res.port_segment_key; - si->address = addr; - - /* the first chunk of the first port segment is always set by the engine - to be a conveniently-sized, zero-filled lump of memory. - */ - - if (client->port_segments == NULL) { - jack_zero_filled_buffer = si->address; - } - - client->port_segments = jack_slist_prepend (client->port_segments, si); - - /* allow the engine to act on the client's behalf - when dealing with in-process clients. - */ - - client->control->private_internal_client = client; - - return client; -} - unsigned long jack_get_buffer_size (jack_client_t *client) { @@ -1183,11 +1198,11 @@ jack_port_new (const jack_client_t *client, jack_port_id_t port_id, jack_control port->shared->tied = NULL; si = NULL; - + for (node = client->port_segments; node; node = jack_slist_next (node)) { - + si = (jack_port_segment_info_t *) node->data; - + if (si->shm_key == port->shared->shm_key) { break; } @@ -1197,9 +1212,9 @@ jack_port_new (const jack_client_t *client, jack_port_id_t port_id, jack_control jack_error ("cannot find port segment to match newly registered port\n"); return NULL; } - + port->client_segment_base = si->address; - + return port; } @@ -1221,22 +1236,12 @@ jack_port_register (jack_client_t *client, strcat ((char *) req.x.port_info.name, ":"); strcat ((char *) req.x.port_info.name, port_name); - strncpy (req.x.port_info.type, port_type, sizeof (req.x.port_info.type) - 1); + snprintf (req.x.port_info.type, sizeof (req.x.port_info.type), "%s", port_type); req.x.port_info.flags = flags; req.x.port_info.buffer_size = buffer_size; req.x.port_info.client_id = client->control->id; - if (write (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot send port registration request to server"); - return 0; - } - - if (read (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot read port registration result from server"); - return 0; - } - - if (req.status != 0) { + if (deliver_request (client, &req)) { return NULL; } @@ -1283,17 +1288,7 @@ jack_port_unregister (jack_client_t *client, jack_port_t *port) req.x.port_info.port_id = port->shared->id; req.x.port_info.client_id = client->control->id; - if (write (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot send port registration request to server"); - return -1; - } - - if (read (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot read port registration result from server"); - return -1; - } - - return req.status; + return deliver_request (client, &req); } int @@ -1304,28 +1299,10 @@ jack_connect (jack_client_t *client, const char *source_port, const char *destin req.type = ConnectPorts; - strncpy (req.x.connect.source_port, source_port, sizeof (req.x.connect.source_port) - 1); - req.x.connect.source_port[sizeof(req.x.connect.source_port) - 1] = '\0'; - strncpy (req.x.connect.destination_port, destination_port, sizeof (req.x.connect.destination_port) - 1); - req.x.connect.destination_port[sizeof(req.x.connect.destination_port) - 1] = '\0'; - - DEBUG ("writing to request_fd"); - - if (write (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot send port connection request to server"); - return -1; - } + snprintf (req.x.connect.source_port, sizeof (req.x.connect.source_port), "%s", source_port); + snprintf (req.x.connect.destination_port, sizeof (req.x.connect.destination_port), "%s", destination_port); - DEBUG ("reading from request_fd"); - - if (read (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot read port connection result from server"); - return -1; - } - - DEBUG ("connected: %d", req.status); - - return req.status; + return deliver_request (client, &req); } int @@ -1345,17 +1322,7 @@ jack_port_disconnect (jack_client_t *client, jack_port_t *port) req.type = DisconnectPort; req.x.port_info.port_id = port->shared->id; - if (write (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot send port disconnect request to server"); - return -1; - } - - if (read (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot read port disconnect result from server"); - return -1; - } - - return req.status; + return deliver_request (client, &req); } int @@ -1365,22 +1332,10 @@ jack_disconnect (jack_client_t *client, const char *source_port, const char *des req.type = DisconnectPorts; - strncpy (req.x.connect.source_port, source_port, sizeof (req.x.connect.source_port) - 1); - req.x.connect.source_port[sizeof(req.x.connect.source_port) - 1] = '\0'; - strncpy (req.x.connect.destination_port, destination_port, sizeof (req.x.connect.destination_port) - 1); - req.x.connect.destination_port[sizeof(req.x.connect.destination_port) - 1] = '\0'; - - if (write (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot send port connection request to server"); - return -1; - } - - if (read (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot read port connection result from server"); - return -1; - } + snprintf (req.x.connect.source_port, sizeof (req.x.connect.source_port), "%s", source_port); + snprintf (req.x.connect.destination_port, sizeof (req.x.connect.destination_port), "%s", destination_port); - return req.status; + return deliver_request (client, &req); } int @@ -1392,17 +1347,7 @@ jack_engine_takeover_timebase (jack_client_t *client) req.type = SetTimeBaseClient; req.x.client_id = client->control->id; - if (write (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot send set time base request to server"); - return -1; - } - - if (read (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot read set time base result from server"); - return -1; - } - - return req.status; + return deliver_request (client, &req); } void @@ -1544,7 +1489,6 @@ jack_set_process_callback (jack_client_t *client, JackProcessCallback callback, int jack_set_buffer_size_callback (jack_client_t *client, JackBufferSizeCallback callback, void *arg) - { jack_error("\n*** libjack: WARNING! Use of function jack_set_buffer_size_callback() is deprecated! ***\n\n"); @@ -1553,7 +1497,6 @@ jack_set_buffer_size_callback (jack_client_t *client, JackBufferSizeCallback cal int jack_set_sample_rate_callback (jack_client_t *client, JackSampleRateCallback callback, void *arg) - { if (client->control->active) { jack_error ("You cannot set callbacks on an active client."); @@ -1992,17 +1935,9 @@ jack_port_get_all_connections (const jack_client_t *client, const jack_port_t *p req.x.port_info.client_id = 0; req.x.port_info.port_id = port->shared->id; - if (write (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot send port connections request to server"); - return 0; - } + deliver_request (client, &req); - if (read (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot read port connections result from server"); - return 0; - } - - if (req.x.nports == 0) { + if (req.status != 0 || req.x.nports == 0) { return NULL; } @@ -2126,18 +2061,8 @@ jack_add_alias (jack_client_t *client, const char *portname, const char *alias) req.type = AddAlias; snprintf (req.x.alias.port, sizeof (req.x.alias.port), "%s", portname); snprintf (req.x.alias.alias, sizeof (req.x.alias.alias), "%s", alias); - - if (write (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot send add alias request to server"); - return -1; - } - - if (read (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot read add alias result from server (%s)", strerror (errno)); - return -1; - } - - return req.status; + + return deliver_request (client, &req); } int @@ -2147,19 +2072,8 @@ jack_remove_alias (jack_client_t *client, const char *alias) req.type = RemoveAlias; snprintf (req.x.alias.alias, sizeof (req.x.alias.alias), "%s", alias); - - - if (write (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot send remove alias request to server"); - return -1; - } - - if (read (client->request_fd, &req, sizeof (req)) != sizeof (req)) { - jack_error ("cannot remove alias result from server (%s)", strerror (errno)); - return -1; - } - - return req.status; + + return deliver_request (client, &req); } pthread_t diff --git a/libjack/driver.c b/libjack/driver.c index 9c32512..7990258 100644 --- a/libjack/driver.c +++ b/libjack/driver.c @@ -39,7 +39,6 @@ static int dummy_start (jack_driver_t *drv) { return 0; } void jack_driver_init (jack_driver_t *driver) - { memset (driver, 0, sizeof (*driver)); @@ -51,58 +50,3 @@ jack_driver_init (jack_driver_t *driver) driver->stop = dummy_stop; } -jack_driver_t * -jack_driver_load (int argc, char **argv) - -{ - const char *errstr; - dlhandle handle; - jack_driver_t *driver; - jack_driver_t *(*initialize)(int, char **); - void (*finish)(jack_driver_t *); - char path_to_so[PATH_MAX+1]; - - snprintf (path_to_so, sizeof (path_to_so), ADDON_DIR "/jack_%s.so", argv[0]); - - handle = dlopen (path_to_so, RTLD_NOW|RTLD_GLOBAL); - - if (handle == 0) { - if ((errstr = dlerror ()) != 0) { - jack_error ("can't load \"%s\": %s", path_to_so, errstr); - } else { - jack_error ("bizarre error loading driver shared object %s", path_to_so); - } - return 0; - } - - initialize = dlsym (handle, "driver_initialize"); - - if ((errstr = dlerror ()) != 0) { - jack_error ("no initialize function in shared object %s\n", path_to_so); - dlclose (handle); - return 0; - } - - finish = dlsym (handle, "driver_finish"); - - if ((errstr = dlerror ()) != 0) { - jack_error ("no finish function in in shared driver object %s", path_to_so); - dlclose (handle); - return 0; - } - - if ((driver = initialize (argc, argv)) != 0) { - driver->handle = handle; - driver->finish = finish; - } - - return driver; - -} - -void -jack_driver_unload (jack_driver_t *driver) -{ - driver->finish (driver); - dlclose (driver->handle); -}