Index: jack/internal.h =================================================================== RCS file: /cvsroot/jackit/jack/jack/internal.h,v retrieving revision 1.52 diff -u -p -r1.52 internal.h --- jack/internal.h 27 Aug 2003 16:26:23 -0000 1.52 +++ jack/internal.h 3 Sep 2003 01:19:34 -0000 @@ -1,3 +1,4 @@ +/* -*- mode: c; c-file-style: "bsd"; -*- */ /* Internal shared data and functions. @@ -43,6 +44,7 @@ #include #include #include +#include #ifdef DEBUG_ENABLED #define DEBUG(format,args...) \ @@ -292,6 +294,8 @@ typedef enum { SetSyncClient = 13, ResetSyncClient = 14, SetSyncTimeout = 15, + GetDrivers = 16, + SwitchDriver = 17 } RequestType; struct _jack_request { @@ -321,6 +325,14 @@ struct _jack_request { jack_client_id_t client_id; jack_nframes_t nframes; jack_time_t timeout; + struct { + char name[JACK_DRIVER_NAME_MAX+1]; + uint32_t nparams; + } driver; + struct { + uint32_t ndrivers; + JSList * drivers; + } drivers; } x; int32_t status; }; Index: jackd/engine.c =================================================================== RCS file: /cvsroot/jackit/jack/jackd/engine.c,v retrieving revision 1.59 diff -u -p -r1.59 engine.c --- jackd/engine.c 28 Aug 2003 01:25:43 -0000 1.59 +++ jackd/engine.c 3 Sep 2003 01:19:37 -0000 @@ -98,6 +99,9 @@ static int jack_port_do_disconnect_all static int jack_port_do_unregister (jack_engine_t *engine, jack_request_t *); static int jack_port_do_register (jack_engine_t *engine, jack_request_t *); static int jack_do_get_port_connections (jack_engine_t *engine, jack_request_t *req, int reply_fd); +static int jack_do_get_drivers (jack_engine_t *engine, jack_request_t *req, int reply_fd); +static int jack_do_switch_driver (jack_engine_t *engine, jack_request_t *req, int *reply_fd, + pthread_mutex_t *request_lock, int *unlock_request_lock); static void jack_port_release (jack_engine_t *engine, jack_port_internal_t *); static void jack_port_clear_connections (jack_engine_t *engine, jack_port_internal_t *port); static int jack_port_disconnect_internal (jack_engine_t *engine, jack_port_internal_t *src, @@ -111,7 +115,7 @@ static void jack_engine_post_process (ja static int internal_client_request (void*, jack_request_t *); -static int jack_use_driver (jack_engine_t *engine, jack_driver_t *driver); +static int jack_attach_driver (jack_engine_t *engine, jack_driver_t *driver); static int jack_run_cycle (jack_engine_t *engine, jack_nframes_t nframes, float delayed_usecs); static char *client_state_names[] = { @@ -787,10 +795,11 @@ jack_client_unload (jack_client_internal } 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) +jack_create_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; + unsigned long i; for (node = engine->clients; node; node = jack_slist_next (node)) { client = (jack_client_internal_t *) node->data; @@ -863,20 +872,19 @@ setup_client (jack_engine_t *engine, int jack_unlock_graph (engine); - /* call its initialization function */ - if (client->control->type == ClientInternal) { - unsigned long i; + /* tell it about current port types and their shared memory information */ - /* tell it about current port types and their shared memory information */ + for (i = 0; i < engine->control->n_port_types; ++i) { + jack_client_handle_new_port_type (client->control->private_client, + engine->control->port_types[i].shm_info.shm_name, + engine->control->port_types[i].shm_info.size, + engine->control->port_types[i].shm_info.address); + } - for (i = 0; i < engine->control->n_port_types; ++i) { - jack_client_handle_new_port_type (client->control->private_client, - engine->control->port_types[i].shm_info.shm_name, - engine->control->port_types[i].shm_info.size, - engine->control->port_types[i].shm_info.address); - } + /* call its initialization function */ + if (client->control->type == ClientInternal) { if (client->initialize (client->control->private_client, req->object_data)) { jack_client_delete (engine, client); return 0; @@ -904,24 +912,65 @@ setup_client (jack_engine_t *engine, int return client; } +static int +jack_detach_driver (jack_engine_t *engine) +{ + if (engine->driver->detach (engine->driver, engine)) { + jack_error ("could not detach driver from engine"); + return -1; + } + + engine->driver = 0; + + return 0; +} + +static int +jack_uninstall_driver (jack_engine_t *engine) +{ + jack_driver_t *driver = engine->driver; + void *dlhandle = driver->handle; + + DEBUG ("detaching driver"); + + if (jack_detach_driver (engine)) { + return -1; + } + + DEBUG ("driver detached; removing its client"); + + jack_remove_client (engine, driver->internal_client); + + DEBUG ("driver's client removed; deleting and closing it"); + + if (driver->finish) { + driver->finish (driver); + } + /* driver deleted */ + + dlclose (dlhandle); + + DEBUG ("driver deleted and closed; finished"); + + return 0; +} + + @@ -958,15 +1007,23 @@ jack_load_driver (jack_engine_t *engine, } -void -jack_driver_unload (jack_driver_t *driver) +static int +jack_attach_driver (jack_engine_t *engine, jack_driver_t *driver) { - driver->finish (driver); - dlclose (driver->handle); + if (driver->attach (driver, engine)) { + jack_error ("could not attach driver to engine"); + return -1; + } + + engine->rolling_interval = (int) floor ((JACK_ENGINE_ROLLING_INTERVAL * 1000.0f) / driver->period_usecs); + + engine->driver = driver; + + return 0; } int -jack_engine_load_driver (jack_engine_t *engine, int argc, char *argv[]) +jack_install_driver (jack_engine_t *engine, jack_driver_desc_t * driver_desc, JSList * driver_params) { jack_client_connect_request_t req; jack_client_connect_result_t res; @@ -974,34 +1031,121 @@ jack_engine_load_driver (jack_engine_t * jack_driver_t *driver; jack_driver_info_t *info; - if ((info = jack_load_driver (engine, argv[0])) == NULL) { + if ((info = jack_load_driver (engine, driver_desc)) == NULL) { return -1; } req.type = ClientDriver; snprintf (req.name, sizeof (req.name), "%s", info->client_name); - if ((client = setup_client (engine, -1, &req, &res)) == NULL) { + if ((client = jack_create_client (engine, -1, &req, &res)) == NULL) { return -1; } - if ((driver = info->initialize (client->control->private_client, argc, argv)) != 0) { + if ((driver = info->initialize (client->control->private_client, driver_params)) != 0) { + driver->internal_client = client; driver->handle = info->handle; driver->finish = info->finish; } free (info); - if (jack_use_driver (engine, driver)) { - jack_driver_unload (driver); - jack_client_delete (engine, client); + if (jack_attach_driver (engine, driver)) { + if (driver->finish) { + driver->finish (driver); + } + jack_remove_client (engine, client); + dlclose (driver->handle); return -1; } + + + engine->driver_desc = driver_desc; + engine->driver_params = driver_params; + return 0; } static int +jack_engine_switch_driver (jack_engine_t * engine, jack_driver_desc_t * new_driver_desc, JSList * new_driver_params) +{ + JSList * node; + jack_driver_desc_t * old_driver_desc = engine->driver_desc; + JSList * old_driver_params = engine->driver_params; + + pthread_mutex_lock (&engine->driver_lock); + + DEBUG ("loading new driver, '%s'", new_driver_desc->name); + + /* discard the old driver */ + if (engine->driver->stop (engine->driver)) { + jack_error ("unable to stop current driver while switching drivers"); + pthread_mutex_unlock (&engine->driver_lock); + return -1; + } + + DEBUG ("stopped old driver; uninstalling it"); + + if (jack_uninstall_driver (engine)) { + jack_error ("unable to uninstall current driver while switching drivers"); + + if (engine->driver->start (engine->driver)) { + jack_error ("eek! can't restart driver!"); + /* FIXME: do what? */ + } + + pthread_mutex_unlock (&engine->driver_lock); + return -1; + } + + DEBUG ("uninstalled old driver; installing new one"); + + /* load the new one */ + if (jack_install_driver (engine, new_driver_desc, new_driver_params)) { + jack_error ("unable to install new driver, reloading old driver"); + + if (jack_install_driver (engine, old_driver_desc, old_driver_params)) { + jack_error ("eek! can't reload old driver!"); + goto error; + } + + if (engine->driver->start (engine->driver)) { + jack_error ("eek! can't restart old driver!"); + goto error; + } + + DEBUG ("reloaded and restarted old driver"); + + pthread_mutex_unlock (&engine->driver_lock); + return -1; + } + + DEBUG ("installed new driver; starting it"); + + if (engine->driver->start (engine->driver)) { + jack_error ("eek! can't start new driver!"); + goto error; + } + + DEBUG ("new driver '%s' started; finished", new_driver_desc->name); + + pthread_mutex_unlock (&engine->driver_lock); + + for (node = old_driver_params; node; node = jack_slist_next (node)) { + free (node->data); + } + jack_slist_free (old_driver_params); + + return 0; + + error: + engine->driver = NULL; + pthread_mutex_unlock (&engine->driver_lock); + return -1; +} + +static int handle_unload_client (jack_engine_t *engine, int client_fd, jack_client_connect_request_t *req) { JSList *node; @@ -1043,7 +1187,7 @@ handle_new_client (jack_engine_t *engine return handle_unload_client (engine, client_fd, &req); } - if ((client = setup_client (engine, client_fd, &req, &res)) == NULL) { + if ((client = jack_create_client (engine, client_fd, &req, &res)) == NULL) { return -1; } @@ -1403,6 +1547,9 @@ handle_client_socket_error (jack_engine_ static void do_request (jack_engine_t *engine, jack_request_t *req, int *reply_fd) { + int unlock_request_lock = TRUE; + + DEBUG ("locking request lock"); pthread_mutex_lock (&engine->request_lock); DEBUG ("got a request of type %d", req->type); @@ -1477,6 +1624,20 @@ do_request (jack_engine_t *engine, jack_ } break; + case GetDrivers: + if (jack_do_get_drivers (engine, req, *reply_fd) == 0) { + *reply_fd = -1; + } + break; + + case SwitchDriver: + if ((req->status = jack_do_switch_driver (engine, req, reply_fd, + &engine->request_lock, &unlock_request_lock)) == 0) { + /* FIXME: reply_fd == NULL with internal clients */ + *reply_fd = -1; + } + break; + default: /* some requests are handled entirely on the client side, by adjusting the shared memory area(s) @@ -1484,7 +1645,10 @@ do_request (jack_engine_t *engine, jack_ break; } - pthread_mutex_unlock (&engine->request_lock); + if (unlock_request_lock) { + DEBUG ("unlocking request lock"); + pthread_mutex_unlock (&engine->request_lock); + } DEBUG ("status of request: %d", req->status); } @@ -1683,7 +1847,10 @@ jack_engine_new (int realtime, int rtpri engine = (jack_engine_t *) malloc (sizeof (jack_engine_t)); + engine->drivers = drivers; engine->driver = 0; + engine->driver_desc = 0; + engine->driver_params = 0; engine->set_sample_rate = jack_set_sample_rate; engine->set_buffer_size = jack_set_buffer_size; engine->run_cycle = jack_run_cycle; @@ -1699,6 +1866,7 @@ jack_engine_new (int realtime, int rtpri jack_engine_reset_rolling_usecs (engine); + pthread_mutex_init (&engine->driver_lock, 0); pthread_mutex_init (&engine->client_lock, 0); pthread_mutex_init (&engine->port_lock, 0); pthread_mutex_init (&engine->request_lock, 0); @@ -3268,25 +3458,6 @@ jack_clear_fifos (jack_engine_t *engine) } } -static int -jack_use_driver (jack_engine_t *engine, jack_driver_t *driver) -{ - if (engine->driver) { - engine->driver->detach (engine->driver, engine); - engine->driver = 0; - } - - if (driver) { - if (driver->attach (driver, engine)) { - return -1; - } - - engine->rolling_interval = (int) floor ((JACK_ENGINE_ROLLING_INTERVAL * 1000.0f) / driver->period_usecs); - } - - engine->driver = driver; - return 0; -} /* PORT RELATED FUNCTIONS */ @@ -3461,6 +3632,132 @@ jack_port_do_unregister (jack_engine_t * return 0; } +static int +jack_do_get_drivers (jack_engine_t *engine, jack_request_t *req, int reply_fd) +{ + JSList * node; + jack_driver_desc_t * desc; + int internal = FALSE; + uint32_t l; + + req->x.drivers.ndrivers = jack_slist_length (engine->drivers); + req->status = 0; + + for (node = engine->clients; node; node = jack_slist_next (node)) { + if (((jack_client_internal_t *) node->data)->request_fd == reply_fd) { + internal = jack_client_is_internal((jack_client_internal_t *) node->data); + break; + } + } + + if (internal) { + req->x.drivers.drivers = engine->drivers; + return 0; + } + + if (write (reply_fd, req, sizeof (*req)) < (ssize_t) sizeof (*req)) { + jack_error ("cannot write GetDrivers result to client via fd = %d (%s)", + reply_fd, strerror (errno)); + return -1; + } + + for (node = engine->drivers; node; node = jack_slist_next (node)) { + desc = (jack_driver_desc_t *) node->data; + + if (write (reply_fd, desc, sizeof (jack_driver_desc_t)) < (ssize_t) sizeof (jack_driver_desc_t)) { + jack_error ("cannot write driver description to client via fd = %d (%s)", + reply_fd, strerror (errno)); + return -1; + } + + for (l = 0; l < desc->nparams; l++) { + if (write (reply_fd, desc->params + l, sizeof (jack_driver_param_desc_t)) < + (ssize_t) sizeof (jack_driver_param_desc_t)) { + jack_error ("cannot write driver param description to client via fd = %d (%s)", + reply_fd, strerror (errno)); + return -1; + } + } + + } + + return 0; +} + +int +jack_do_switch_driver (jack_engine_t *engine, jack_request_t *req, int *reply_fd, + pthread_mutex_t *request_lock, int *unlock_request_lock) +{ + uint32_t nparams = req->x.driver.nparams; + jack_driver_desc_t * desc; + jack_driver_param_t * param; + JSList * params = NULL; + JSList * node; + uint32_t i, j; + + for (node = engine->drivers; node; node = jack_slist_next (node)) { + desc = (jack_driver_desc_t *) node->data; + if (strcmp (req->x.driver.name, desc->name) == 0) + break; + else + desc = NULL; + } + + if (!desc) { + jack_error ("unknown driver '%s' in driver switch request", req->x.driver.name); + return -1; + } + + DEBUG ("recieved request to switch to driver '%s' with %d parameters", desc->name, nparams); + + req->status = 0; + if (write (*reply_fd, req, sizeof (*req)) < (ssize_t) sizeof (*req)) { + jack_error ("cannot write SwitchDriver result to client via fd = %d (%s)", + reply_fd, strerror (errno)); + return -1; + } + + + for (i = 0; i < nparams; i++) { + param = (jack_driver_param_t *) malloc (sizeof (jack_driver_param_t)); + + DEBUG ("reading parameter %d", i); + if (read (*reply_fd, param, sizeof (jack_driver_param_t)) < + (ssize_t) sizeof (jack_driver_param_t)) { + jack_error ("cannot read driver parameter from client via fd = %d (%s)", + *reply_fd, strerror (errno)); + free (param); + goto error; + } + DEBUG ("read parameter %d", i); + + /* check for sanity */ + for (j = 0; j < desc->nparams; j++) { + if (param->character == desc->params[j].character) { + break; + } + } + if (j == desc->nparams) { + jack_error ("unknown parameter with character '%c'; ignoring\n", param->character); + free (param); + continue; + } + + params = jack_slist_append (params, param); + } + + pthread_mutex_unlock (request_lock); + *unlock_request_lock = FALSE; + + jack_engine_switch_driver (engine, desc, params); + + return 0; + + error: + *reply_fd = -1; + return -1; +} + int jack_do_get_port_connections (jack_engine_t *engine, jack_request_t *req, int reply_fd) { @@ -3490,7 +3787,7 @@ jack_do_get_port_connections (jack_engin } if (!internal) { - if (write (reply_fd, req, sizeof (*req)) < (ssize_t) sizeof (req)) { + if (write (reply_fd, req, sizeof (*req)) < (ssize_t) sizeof (*req)) { jack_error ("cannot write GetPortConnections result to client via fd = %d (%s)", reply_fd, strerror (errno)); goto out; Index: jackd/jackd.c =================================================================== RCS file: /cvsroot/jackit/jack/jackd/jackd.c,v retrieving revision 1.20 diff -u -p -r1.20 jackd.c --- jackd/jackd.c 30 Aug 2003 22:31:51 -0000 1.20 +++ jackd/jackd.c 3 Sep 2003 01:19:38 -0000 Index: libjack/client.c =================================================================== RCS file: /cvsroot/jackit/jack/libjack/client.c,v retrieving revision 1.45 diff -u -p -r1.45 client.c --- libjack/client.c 29 Aug 2003 17:16:37 -0000 1.45 +++ libjack/client.c 3 Sep 2003 01:19:39 -0000 @@ -1,3 +1,4 @@ +/* -*- mode: c; c-file-style: "bsd"; -*- */ /* Copyright (C) 2001-2003 Paul Davis @@ -1492,6 +1493,92 @@ jack_get_ports (jack_client_t *client, } return matching_ports; +} + +jack_driver_desc_t ** +jack_get_drivers (jack_client_t * client) +{ + jack_request_t req; + jack_driver_desc_t ** descs; + unsigned long l, m; + + req.type = GetDrivers; + + jack_client_deliver_request (client, &req); + + if (req.status != 0 || req.x.drivers.ndrivers == 0) { + return NULL; + } + + descs = calloc (req.x.drivers.ndrivers + 1, sizeof (jack_driver_desc_t *)); + + if (client->request_fd < 0) { + /* internal client */ + unsigned long l; + JSList * node; + + for (l = 0, node = req.x.drivers.drivers; + l < req.x.drivers.ndrivers; + l++, node = jack_slist_next (node)) { + descs[l] = (jack_driver_desc_t *) node->data; + } + + return descs; + } + + for (l = 0; l < req.x.drivers.ndrivers; l++) { + descs[l] = (jack_driver_desc_t *) malloc (sizeof (jack_driver_desc_t)); + + if (read (client->request_fd, descs[l], sizeof (jack_driver_desc_t)) + < (ssize_t) sizeof (jack_driver_desc_t)) { + jack_error ("cannot read driver description from server"); + free (descs); + return NULL; + } + + descs[l]->params = calloc (descs[l]->nparams, sizeof (jack_driver_param_desc_t)); + for (m = 0; m < descs[l]->nparams; m++) { + if (read (client->request_fd, descs[l]->params + m, sizeof (jack_driver_param_desc_t)) + < (ssize_t) sizeof (jack_driver_param_desc_t)) { + jack_error ("cannot read driver parameter description from server"); + free (descs[l]->params); + free (descs); + return NULL; + } + } + } + + return descs; +} + +int jack_switch_driver (jack_client_t * client, + const char * const driver_name, + uint32_t param_count, + const jack_driver_param_t * params) +{ + jack_request_t req; + uint32_t i; + + req.type = SwitchDriver; + strcpy (req.x.driver.name, driver_name); + req.x.driver.nparams = param_count; + + jack_client_deliver_request (client, &req); + + if (req.status != 0) + return -1; + + + for (i = 0; i < param_count; i++) { + if (write (client->request_fd, params + i, sizeof (jack_driver_param_t)) + < (ssize_t) sizeof (jack_driver_param_t)) { + jack_error ("cannot send driver parameter to server (%s)", strerror (errno)); + return -1; + } + } + + + return 0; } float