Browse Source

in-process client support (many changes internally)

git-svn-id: svn+ssh://jackaudio.org/trunk/jack@330 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/0.109.0
pbd 23 years ago
parent
commit
479353a920
16 changed files with 927 additions and 744 deletions
  1. +4
    -4
      configure.in
  2. +4
    -4
      drivers/alsa/Makefile.am
  3. +9
    -13
      drivers/alsa/alsa_driver.c
  4. +26
    -1
      example-clients/Makefile.am
  5. +52
    -0
      example-clients/inprocess.c
  6. +34
    -0
      example-clients/ipload.c
  7. +10
    -0
      example-clients/ipunload.c
  8. +2
    -2
      jack/engine.h
  9. +25
    -6
      jack/internal.h
  10. +10
    -4
      jack/jack.h
  11. +6
    -0
      jackd/ChangeLog
  12. +380
    -163
      jackd/engine.c
  13. +88
    -136
      jackd/jackd.c
  14. +8
    -0
      libjack/ChangeLog
  15. +269
    -355
      libjack/client.c
  16. +0
    -56
      libjack/driver.c

+ 4
- 4
configure.in View File

@@ -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
- 4
drivers/alsa/Makefile.am View File

@@ -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)

+ 9
- 13
drivers/alsa/alsa_driver.c View File

@@ -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);
}


+ 26
- 1
example-clients/Makefile.am View File

@@ -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

+ 52
- 0
example-clients/inprocess.c View File

@@ -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 */
}

+ 34
- 0
example-clients/ipload.c View File

@@ -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;
}
}

+ 10
- 0
example-clients/ipunload.c View File

@@ -0,0 +1,10 @@
#include <jack/jack.h>

int
main (int argc, char *argv[])
{
jack_inprocess_client_close (argv[1]);
return 0;
}

+ 2
- 2
jack/engine.h View File

@@ -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);



+ 25
- 6
jack/internal.h View File

@@ -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;



+ 10
- 4
jack/jack.h View File

@@ -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.


+ 6
- 0
jackd/ChangeLog View File

@@ -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.

+ 380
- 163
jackd/engine.c View File

@@ -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;
}


+ 88
- 136
jackd/jackd.c View File

@@ -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);



+ 8
- 0
libjack/ChangeLog View File

@@ -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


+ 269
- 355
libjack/client.c View File

@@ -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


+ 0
- 56
libjack/driver.c View File

@@ -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);
}

Loading…
Cancel
Save