git-svn-id: svn+ssh://jackaudio.org/trunk/jack@330 0c269be4-1314-0410-8aa9-9f06e86f4224tags/0.109.0
| @@ -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], | |||
| @@ -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) | |||
| @@ -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); | |||
| } | |||
| @@ -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 | |||
| @@ -0,0 +1,52 @@ | |||
| #include <stdio.h> | |||
| #include <memory.h> | |||
| #include <jack/jack.h> | |||
| 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 */ | |||
| } | |||
| @@ -0,0 +1,34 @@ | |||
| #include <stdio.h> | |||
| #include <jack/jack.h> | |||
| 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; | |||
| } | |||
| } | |||
| @@ -0,0 +1,10 @@ | |||
| #include <jack/jack.h> | |||
| int | |||
| main (int argc, char *argv[]) | |||
| { | |||
| jack_inprocess_client_close (argv[1]); | |||
| return 0; | |||
| } | |||
| @@ -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); | |||
| @@ -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; | |||
| @@ -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. | |||
| @@ -1,3 +1,9 @@ | |||
| 2003-02-21 Paul Davis <paul> | |||
| * 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 <trutkin@physics.clarku.edu> | |||
| * Initial Changelog | |||
| * engine.c (handle_new_client): Returns protocol version for checking. | |||
| @@ -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; | |||
| } | |||
| @@ -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); | |||
| @@ -1,3 +1,11 @@ | |||
| 2003-02-23 Paul Davis <paul> | |||
| * client.c: | |||
| added deliver_request(). | |||
| removed all use of strncpy(). | |||
| changed ClientDynamic to ClientInProcess. | |||
| 2003-02-10 Taybin Rutkin <trutkin@physics.clarku.edu> | |||
| * client.c (jack_client_new): Checks jack_protocol_version returned | |||
| @@ -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 | |||
| @@ -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); | |||
| } | |||