| 
							- /* -*- Mode: C ; c-basic-offset: 4 -*- */
 - /*
 -     Copyright (C) 2007,2008,2010,2011 Nedko Arnaudov
 -     Copyright (C) 2007-2008 Juuso Alasuutari
 - 
 -     This program is free software; you can redistribute it and/or modify
 -     it under the terms of the GNU General Public License as published by
 -     the Free Software Foundation; either version 2 of the License.
 - 
 -     This program is distributed in the hope that it will be useful,
 -     but WITHOUT ANY WARRANTY; without even the implied warranty of
 -     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 -     GNU General Public License for more details.
 - 
 -     You should have received a copy of the GNU General Public License
 -     along with this program; if not, write to the Free Software
 -     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 - 
 - */
 - 
 - #if defined(HAVE_CONFIG_H)
 - #include "config.h"
 - #endif
 - 
 - #include <stdint.h>
 - #include <string.h>
 - #include <dbus/dbus.h>
 - #include <assert.h>
 - #include <unistd.h>
 - #include <errno.h>
 - 
 - #include "controller.h"
 - #include "controller_internal.h"
 - #include "xml.h"
 - #include "reserve.h"
 - #include "uptime.h"
 - 
 - struct jack_dbus_interface_descriptor * g_jackcontroller_interfaces[] =
 - {
 -     &g_jack_controller_iface_introspectable,
 -     &g_jack_controller_iface_control,
 -     &g_jack_controller_iface_configure,
 -     &g_jack_controller_iface_patchbay,
 -     &g_jack_controller_iface_session_manager,
 -     &g_jack_controller_iface_transport,
 -     NULL
 - };
 - 
 - static
 - jackctl_driver_t *
 - jack_controller_find_driver(
 -     jackctl_server_t *server,
 -     const char *driver_name)
 - {
 -     const JSList * node_ptr;
 - 
 -     node_ptr = jackctl_server_get_drivers_list(server);
 - 
 -     while (node_ptr)
 -     {
 -         if (strcmp(jackctl_driver_get_name((jackctl_driver_t *)node_ptr->data), driver_name) == 0)
 -         {
 -             return node_ptr->data;
 -         }
 - 
 -         node_ptr = jack_slist_next(node_ptr);
 -     }
 - 
 -     return NULL;
 - }
 - 
 - static bool jack_controller_check_slave_driver(struct jack_controller * controller_ptr, const char * name)
 - {
 -     struct list_head * node_ptr;
 -     struct jack_controller_slave_driver * driver_ptr;
 - 
 -     list_for_each(node_ptr, &controller_ptr->slave_drivers)
 -     {
 -         driver_ptr = list_entry(node_ptr, struct jack_controller_slave_driver, siblings);
 -         if (strcmp(name, driver_ptr->name) == 0)
 -         {
 -             return true;
 -         }
 -     }
 - 
 -     return false;
 - }
 - 
 - static bool jack_controller_load_slave_drivers(struct jack_controller * controller_ptr)
 - {
 -     struct list_head * node_ptr;
 -     struct jack_controller_slave_driver * driver_ptr;
 - 
 -     list_for_each(node_ptr, &controller_ptr->slave_drivers)
 -     {
 -         driver_ptr = list_entry(node_ptr, struct jack_controller_slave_driver, siblings);
 - 
 -         assert(driver_ptr->handle != NULL);
 -         assert(!driver_ptr->loaded);
 - 
 -         if (!jackctl_server_add_slave(controller_ptr->server, driver_ptr->handle))
 -         {
 -             jack_error("Driver \"%s\" cannot be loaded", driver_ptr->name);
 -             return false;
 -         }
 - 
 -         driver_ptr->loaded = true;
 -     }
 - 
 -     return true;
 - }
 - 
 - static void jack_controller_unload_slave_drivers(struct jack_controller * controller_ptr)
 - {
 -     struct list_head * node_ptr;
 -     struct jack_controller_slave_driver * driver_ptr;
 - 
 -     list_for_each(node_ptr, &controller_ptr->slave_drivers)
 -     {
 -         driver_ptr = list_entry(node_ptr, struct jack_controller_slave_driver, siblings);
 -         if (driver_ptr->loaded)
 -         {
 -             jackctl_server_remove_slave(controller_ptr->server, driver_ptr->handle);
 -             driver_ptr->loaded = false;
 -         }
 -     }
 - }
 - 
 - static void jack_controller_remove_slave_drivers(struct jack_controller * controller_ptr)
 - {
 -     struct jack_controller_slave_driver * driver_ptr;
 - 
 -     while (!list_empty(&controller_ptr->slave_drivers))
 -     {
 -         driver_ptr = list_entry(controller_ptr->slave_drivers.next, struct jack_controller_slave_driver, siblings);
 -         assert(!driver_ptr->loaded);
 -         list_del(&driver_ptr->siblings);
 -         free(driver_ptr->name);
 -         free(driver_ptr);
 -     }
 - 
 -     controller_ptr->slave_drivers_vparam_value.str[0] = 0;
 - }
 - 
 - static
 - jackctl_internal_t *
 - jack_controller_find_internal(
 -     jackctl_server_t *server,
 -     const char *internal_name)
 - {
 -     const JSList * node_ptr;
 - 
 -     node_ptr = jackctl_server_get_internals_list(server);
 - 
 -     while (node_ptr)
 -     {
 -         if (strcmp(jackctl_internal_get_name((jackctl_internal_t *)node_ptr->data), internal_name) == 0)
 -         {
 -             return node_ptr->data;
 -         }
 - 
 -         node_ptr = jack_slist_next(node_ptr);
 -     }
 - 
 -     return NULL;
 - }
 - 
 - bool
 - jack_controller_select_driver(
 -     struct jack_controller * controller_ptr,
 -     const char * driver_name)
 - {
 -     if (!jack_params_set_driver(controller_ptr->params, driver_name))
 -     {
 -         return false;
 -     }
 - 
 -     jack_info("driver \"%s\" selected", driver_name);
 - 
 -     return true;
 - }
 - 
 - static
 - int
 - jack_controller_xrun(void * arg)
 - {
 - 	((struct jack_controller *)arg)->xruns++;
 - 
 - 	return 0;
 - }
 - 
 - bool
 - jack_controller_start_server(
 -     struct jack_controller * controller_ptr,
 -     void *dbus_call_context_ptr)
 - {
 -     int ret;
 - 
 -     jack_info("Starting jack server...");
 - 
 -     assert(!controller_ptr->started); /* should be ensured by caller */
 - 
 -     controller_ptr->xruns = 0;
 - 
 -     if (!jackctl_server_open(
 -             controller_ptr->server,
 -             jack_params_get_driver(controller_ptr->params)))
 -     {
 -         jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to open server");
 -         goto fail;
 -     }
 - 
 -     jack_controller_load_slave_drivers(controller_ptr);
 - 
 -     if (!jackctl_server_start(
 -             controller_ptr->server))
 -     {
 -         jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to start server");
 -         goto fail_close_server;
 -     }
 - 
 -     controller_ptr->client = jack_client_open(
 -         "dbusapi",
 -         JackNoStartServer,
 -         NULL);
 -     if (controller_ptr->client == NULL)
 -     {
 -         jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "failed to create dbusapi jack client");
 -         goto fail_stop_server;
 -     }
 - 
 -     ret = jack_set_xrun_callback(controller_ptr->client, jack_controller_xrun, controller_ptr);
 -     if (ret != 0)
 -     {
 -         jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "failed to set xrun callback. error is %d", ret);
 -         goto fail_close_client;
 -     }
 - 
 -     if (!jack_controller_patchbay_init(controller_ptr))
 -     {
 -         jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to initialize patchbay district");
 -         goto fail_close_client;
 -     }
 - 
 -     ret = jack_activate(controller_ptr->client);
 -     if (ret != 0)
 -     {
 -         jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "failed to activate dbusapi jack client. error is %d", ret);
 -         goto fail_patchbay_uninit;
 -     }
 - 
 -     controller_ptr->started = true;
 - 
 -     return TRUE;
 - 
 - fail_patchbay_uninit:
 -     jack_controller_patchbay_uninit(controller_ptr);
 - 
 - fail_close_client:
 -     ret = jack_client_close(controller_ptr->client);
 -     if (ret != 0)
 -     {
 -         jack_error("jack_client_close() failed with error %d", ret);
 -     }
 - 
 -     controller_ptr->client = NULL;
 - 
 - fail_stop_server:
 -     if (!jackctl_server_stop(controller_ptr->server))
 -     {
 -         jack_error("failed to stop jack server");
 -     }
 - 
 - fail_close_server:
 -     jack_controller_unload_slave_drivers(controller_ptr);
 - 
 -     if (!jackctl_server_close(controller_ptr->server))
 -     {
 -         jack_error("failed to close jack server");
 -     }
 - 
 - fail:
 -     return FALSE;
 - }
 - 
 - bool
 - jack_controller_stop_server(
 -     struct jack_controller * controller_ptr,
 -     void *dbus_call_context_ptr)
 - {
 -     int ret;
 - 
 -     pthread_mutex_lock(&controller_ptr->lock);
 -     if (!list_empty(&controller_ptr->session_pending_commands))
 -     {
 -         pthread_mutex_unlock(&controller_ptr->lock);
 -         jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Refusing to stop JACK server because of pending session commands");
 -         return false;
 -     }
 -     pthread_mutex_unlock(&controller_ptr->lock);
 - 
 -     jack_info("Stopping jack server...");
 - 
 -     assert(controller_ptr->started); /* should be ensured by caller */
 - 
 -     ret = jack_deactivate(controller_ptr->client);
 -     if (ret != 0)
 -     {
 -         jack_error("failed to deactivate dbusapi jack client. error is %d", ret);
 -     }
 - 
 -     jack_controller_patchbay_uninit(controller_ptr);
 - 
 -     ret = jack_client_close(controller_ptr->client);
 -     if (ret != 0)
 -     {
 -         jack_error("jack_client_close() failed with error %d", ret);
 -     }
 - 
 -     controller_ptr->client = NULL;
 - 
 -     if (!jackctl_server_stop(controller_ptr->server))
 -     {
 -         jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to stop server");
 -         return FALSE;
 -     }
 - 
 -     jack_controller_unload_slave_drivers(controller_ptr);
 - 
 -     if (!jackctl_server_close(controller_ptr->server))
 -     {
 -         jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to close server");
 -         return FALSE;
 -     }
 - 
 -     controller_ptr->started = false;
 - 
 -     return TRUE;
 - }
 - 
 - bool
 - jack_controller_switch_master(
 -     struct jack_controller * controller_ptr,
 -     void *dbus_call_context_ptr)
 - {
 -     assert(controller_ptr->started); /* should be ensured by caller */
 - 
 -     if (!jackctl_server_switch_master(
 -             controller_ptr->server,
 -             jack_params_get_driver(controller_ptr->params)))
 -     {
 -         jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to switch master");
 -         controller_ptr->started = false;
 -         return FALSE;
 -     }
 - 
 -     return TRUE;
 - }
 - 
 - #define DEVICE_MAX 2
 - 
 - typedef struct reserved_audio_device {
 - 
 -      char device_name[64];
 -      rd_device * reserved_device;
 - 
 - } reserved_audio_device;
 - 
 - 
 - int g_device_count = 0;
 - static reserved_audio_device g_reserved_device[DEVICE_MAX];
 - 
 - static
 - bool
 - on_device_acquire(const char * device_name)
 - {
 -     int ret;
 -     DBusError error;
 - 
 -     dbus_error_init(&error);
 - 
 -     ret = rd_acquire(
 -         &g_reserved_device[g_device_count].reserved_device,
 -         g_connection,
 -         device_name,
 -         "Jack audio server",
 -         INT32_MAX,
 -         NULL,
 -         &error);
 -     if (ret  < 0)
 -     {
 -         jack_error("Failed to acquire device name : %s error : %s", device_name, (error.message ? error.message : strerror(-ret)));
 -         dbus_error_free(&error);
 -         return false;
 -     }
 - 
 -     strcpy(g_reserved_device[g_device_count].device_name, device_name);
 -     g_device_count++;
 -     jack_info("Acquired audio card %s", device_name);
 -     return true;
 - }
 - 
 - static
 - void
 - on_device_release(const char * device_name)
 - {
 -     int i;
 - 
 -     // Look for corresponding reserved device
 -     for (i = 0; i < DEVICE_MAX; i++) {
 -  	if (strcmp(g_reserved_device[i].device_name, device_name) == 0)
 - 	    break;
 -     }
 - 
 -     if (i < DEVICE_MAX) {
 - 	jack_info("Released audio card %s", device_name);
 -         rd_release(g_reserved_device[i].reserved_device);
 -     } else {
 - 	jack_error("Audio card %s not found!!", device_name);
 -     }
 - 
 -     g_device_count--;
 - }
 - 
 - #define controller_ptr ((struct jack_controller *)obj)
 - 
 - static bool slave_drivers_parameter_is_set(void * obj)
 - {
 -     return controller_ptr->slave_drivers_set;
 - }
 - 
 - static bool slave_drivers_parameter_reset(void * obj)
 - {
 -     if (controller_ptr->started)
 -     {
 -         jack_error("Cannot modify slave-drivers when server is started");
 -         return false;
 -     }
 - 
 -     jack_controller_remove_slave_drivers(controller_ptr);
 -     controller_ptr->slave_drivers_set = false;
 -     return true;
 - }
 - 
 - static union jackctl_parameter_value slave_drivers_parameter_get_value(void * obj)
 - {
 -     return controller_ptr->slave_drivers_vparam_value;
 - }
 - 
 - static bool slave_drivers_parameter_set_value(void * obj, const union jackctl_parameter_value * value_ptr)
 - {
 -     char * buffer;
 -     char * save;
 -     const char * token;
 -     struct list_head old_list;
 -     struct list_head new_list;
 -     union jackctl_parameter_value old_value;
 -     union jackctl_parameter_value new_value;
 -     bool old_set;
 - 
 -     if (controller_ptr->started)
 -     {
 -         jack_error("Cannot modify slave-drivers when server is started");
 -         return false;
 -     }
 - 
 -     old_set = controller_ptr->slave_drivers_set;
 -     old_value = controller_ptr->slave_drivers_vparam_value;
 -     controller_ptr->slave_drivers_vparam_value.str[0] = 0;
 -     old_list = controller_ptr->slave_drivers;
 -     INIT_LIST_HEAD(&controller_ptr->slave_drivers);
 - 
 -     buffer = strdup(value_ptr->str);
 -     if (buffer == NULL)
 -     {
 -         jack_error("strdup() failed.");
 -         return false;
 -     }
 - 
 -     token = strtok_r(buffer, ",", &save);
 -     while (token)
 -     {
 -         //jack_info("slave driver '%s'", token);
 -         if (!jack_controller_add_slave_driver(controller_ptr, token))
 -         {
 -             jack_controller_remove_slave_drivers(controller_ptr);
 -             controller_ptr->slave_drivers = old_list;
 -             controller_ptr->slave_drivers_vparam_value = old_value;
 -             controller_ptr->slave_drivers_set = old_set;
 - 
 -             free(buffer);
 - 
 -             return false;
 -         }
 - 
 -         token = strtok_r(NULL, ",", &save);
 -     }
 - 
 -     new_value = controller_ptr->slave_drivers_vparam_value;
 -     new_list = controller_ptr->slave_drivers;
 -     controller_ptr->slave_drivers = old_list;
 -     jack_controller_remove_slave_drivers(controller_ptr);
 -     controller_ptr->slave_drivers_vparam_value = new_value;
 -     controller_ptr->slave_drivers = new_list;
 -     controller_ptr->slave_drivers_set = true;
 - 
 -     free(buffer);
 - 
 -     return true;
 - }
 - 
 - static union jackctl_parameter_value slave_drivers_parameter_get_default_value(void * obj)
 - {
 -     union jackctl_parameter_value value;
 -     value.str[0] = 0;
 -     return value;
 - }
 - 
 - #undef controller_ptr
 - 
 - void *
 - jack_controller_create(
 -         DBusConnection *connection)
 - {
 -     int error;
 -     struct jack_controller *controller_ptr;
 -     const char * address[PARAM_ADDRESS_SIZE];
 -     DBusObjectPathVTable vtable =
 -     {
 -         jack_dbus_message_handler_unregister,
 -         jack_dbus_message_handler,
 -         NULL
 -     };
 - 
 -     controller_ptr = malloc(sizeof(struct jack_controller));
 -     if (!controller_ptr)
 -     {
 -         jack_error("Ran out of memory trying to allocate struct jack_controller");
 -         goto fail;
 -     }
 - 
 -     error = pthread_mutex_init(&controller_ptr->lock, NULL);
 -     if (error != 0)
 -     {
 -         jack_error("Failed to initialize mutex. error %d", error);
 -         goto fail_free;
 -     }
 - 
 -     INIT_LIST_HEAD(&controller_ptr->session_pending_commands);
 - 
 -     controller_ptr->server = jackctl_server_create(on_device_acquire, on_device_release);
 -     if (controller_ptr->server == NULL)
 -     {
 -         jack_error("Failed to create server object");
 -         goto fail_uninit_mutex;
 -     }
 - 
 -     controller_ptr->params = jack_params_create(controller_ptr->server);
 -     if (controller_ptr->params == NULL)
 -     {
 -         jack_error("Failed to initialize parameter tree");
 -         goto fail_destroy_server;
 -     }
 - 
 -     controller_ptr->client = NULL;
 -     controller_ptr->started = false;
 - 
 -     controller_ptr->pending_save = 0;
 - 
 -     INIT_LIST_HEAD(&controller_ptr->slave_drivers);
 -     controller_ptr->slave_drivers_set = false;
 -     controller_ptr->slave_drivers_vparam_value.str[0] = 0;
 - 
 -     controller_ptr->slave_drivers_vparam.obj = controller_ptr;
 - 
 -     controller_ptr->slave_drivers_vparam.vtable.is_set = slave_drivers_parameter_is_set;
 -     controller_ptr->slave_drivers_vparam.vtable.reset = slave_drivers_parameter_reset;
 -     controller_ptr->slave_drivers_vparam.vtable.get_value = slave_drivers_parameter_get_value;
 -     controller_ptr->slave_drivers_vparam.vtable.set_value = slave_drivers_parameter_set_value;
 -     controller_ptr->slave_drivers_vparam.vtable.get_default_value = slave_drivers_parameter_get_default_value;
 - 
 -     controller_ptr->slave_drivers_vparam.type = JackParamString;
 -     controller_ptr->slave_drivers_vparam.name = "slave-drivers";
 -     controller_ptr->slave_drivers_vparam.short_decr = "Slave drivers to use";
 -     controller_ptr->slave_drivers_vparam.long_descr = "A comma separated list of slave drivers";
 -     controller_ptr->slave_drivers_vparam.constraint_flags = 0;
 - 
 -     address[0] = PTNODE_ENGINE;
 -     address[1] = NULL;
 -     jack_params_add_parameter(controller_ptr->params, address, true, &controller_ptr->slave_drivers_vparam);
 - 
 -     controller_ptr->dbus_descriptor.context = controller_ptr;
 -     controller_ptr->dbus_descriptor.interfaces = g_jackcontroller_interfaces;
 - 
 -     if (!dbus_connection_register_object_path(
 -             connection,
 -             JACK_CONTROLLER_OBJECT_PATH,
 -             &vtable,
 -             &controller_ptr->dbus_descriptor))
 -     {
 -         jack_error("Ran out of memory trying to register D-Bus object path");
 -         goto fail_destroy_params;
 -     }
 - 
 -     jack_controller_settings_load(controller_ptr);
 - 
 -     return controller_ptr;
 - 
 - fail_destroy_params:
 -     jack_params_destroy(controller_ptr->params);
 - 
 - fail_destroy_server:
 -     jackctl_server_destroy(controller_ptr->server);
 - 
 - fail_uninit_mutex:
 -     pthread_mutex_destroy(&controller_ptr->lock);
 - 
 - fail_free:
 -     free(controller_ptr);
 - 
 - fail:
 -     return NULL;
 - }
 - 
 - bool
 - jack_controller_add_slave_driver(
 -     struct jack_controller * controller_ptr,
 -     const char * driver_name)
 - {
 -     jackctl_driver_t * driver;
 -     struct jack_controller_slave_driver * driver_ptr;
 -     size_t len_old;
 -     size_t len_new;
 - 
 -     len_old = strlen(controller_ptr->slave_drivers_vparam_value.str);
 -     len_new = strlen(driver_name);
 -     if (len_old + len_new + 2 > sizeof(controller_ptr->slave_drivers_vparam_value.str))
 -     {
 -         jack_error("No more space for slave drivers.");
 -         return false;
 -     }
 - 
 -     driver = jack_controller_find_driver(controller_ptr->server, driver_name);
 -     if (driver == NULL)
 -     {
 -         jack_error("Unknown driver \"%s\"", driver_name);
 -         return false;
 -     }
 - 
 -     if (jack_controller_check_slave_driver(controller_ptr, driver_name))
 -     {
 -         jack_info("Driver \"%s\" is already slave", driver_name);
 -         return true;
 -     }
 - 
 -     driver_ptr = malloc(sizeof(struct jack_controller_slave_driver));
 -     if (driver_ptr == NULL)
 -     {
 -         jack_error("malloc() failed to allocate jack_controller_slave_driver struct");
 -         return false;
 -     }
 - 
 -     driver_ptr->name = strdup(driver_name);
 -     if (driver_ptr->name == NULL)
 -     {
 -         jack_error("strdup() failed for slave driver name \"%s\"", driver_name);
 -         free(driver_ptr);
 -         return false;
 -     }
 - 
 -     driver_ptr->handle = driver;
 -     driver_ptr->loaded = false;
 - 
 -     jack_info("driver \"%s\" set as slave", driver_name);
 - 
 -     list_add_tail(&driver_ptr->siblings, &controller_ptr->slave_drivers);
 - 
 -     if (len_old != 0)
 -     {
 -         controller_ptr->slave_drivers_vparam_value.str[len_old++] = ',';
 -     }
 - 
 -     memcpy(controller_ptr->slave_drivers_vparam_value.str + len_old, driver_name, len_new + 1);
 -     controller_ptr->slave_drivers_set = true;
 - 
 -     return true;
 - }
 - 
 - bool
 - jack_controller_remove_slave_driver(
 -     struct jack_controller * controller_ptr,
 -     const char * driver_name)
 - {
 -     struct list_head * node_ptr;
 -     struct jack_controller_slave_driver * driver_ptr;
 - 
 -     list_for_each(node_ptr, &controller_ptr->slave_drivers)
 -     {
 -         driver_ptr = list_entry(node_ptr, struct jack_controller_slave_driver, siblings);
 -         if (strcmp(driver_ptr->name, driver_name) == 0)
 -         {
 -             list_del(&driver_ptr->siblings);
 -             free(driver_ptr->name);
 -             free(driver_ptr);
 - 
 -             /* update the slave-drivers param value */
 -             controller_ptr->slave_drivers_vparam_value.str[0] = 0;
 -             list_for_each(node_ptr, &controller_ptr->slave_drivers)
 -             {
 -                 driver_ptr = list_entry(node_ptr, struct jack_controller_slave_driver, siblings);
 -                 if (controller_ptr->slave_drivers_vparam_value.str[0] != 0)
 -                 {
 -                     strcat(controller_ptr->slave_drivers_vparam_value.str, ",");
 -                 }
 - 
 -                 strcat(controller_ptr->slave_drivers_vparam_value.str, driver_ptr->name);
 -             }
 - 
 -             jack_info("driver \"%s\" is not slave anymore", driver_name);
 - 
 -             return true;
 -         }
 -     }
 - 
 -     return false;
 - }
 - 
 - bool
 - jack_controller_load_internal(
 -     struct jack_controller *controller_ptr,
 -     const char * internal_name)
 - {
 -     jackctl_internal_t *internal;
 - 
 -     internal = jack_controller_find_internal(controller_ptr->server, internal_name);
 -     if (internal == NULL)
 -     {
 -         return false;
 -     }
 - 
 -     jack_info("internal \"%s\" selected", internal_name);
 - 
 -     return jackctl_server_load_internal(controller_ptr->server, internal);
 - }
 - 
 - bool
 - jack_controller_unload_internal(
 -     struct jack_controller *controller_ptr,
 -     const char * internal_name)
 - {
 -     jackctl_internal_t *internal;
 - 
 -     internal = jack_controller_find_internal(controller_ptr->server, internal_name);
 -     if (internal == NULL)
 -     {
 -         return false;
 -     }
 - 
 -     jack_info("internal \"%s\" selected", internal_name);
 - 
 -     return jackctl_server_unload_internal(controller_ptr->server, internal);
 - }
 - 
 - #define controller_ptr ((struct jack_controller *)context)
 - 
 - void
 - jack_controller_destroy(
 -         void * context)
 - {
 -     if (controller_ptr->started)
 -     {
 -         while (!jack_controller_stop_server(controller_ptr, NULL))
 -         {
 -             jack_info("jack server failed to stop, retrying in 3 seconds...");
 -             usleep(3000000);
 -         }
 -     }
 - 
 -     jack_controller_remove_slave_drivers(controller_ptr);
 -     jack_params_destroy(controller_ptr->params);
 -     jackctl_server_destroy(controller_ptr->server);
 -     pthread_mutex_destroy(&controller_ptr->lock);
 -     free(controller_ptr);
 - }
 - 
 - void
 - jack_controller_run(
 -     void * context)
 - {
 -     long ut;
 - 
 -     if (controller_ptr->pending_save == 0)
 -     {
 -         return;
 -     }
 - 
 -     if ((ut = uptime()) < 0)
 -     {
 -         jack_error(UPTIME_FUNCTION_NAME "() failed with %d", errno);
 -     }
 -     else if (ut < controller_ptr->pending_save + 2) /* delay save by two seconds */
 -     {
 -         return;
 -     }
 - 
 -     controller_ptr->pending_save = 0;
 -     jack_controller_settings_save_auto(controller_ptr);
 - }
 - 
 - #undef controller_ptr
 - 
 - void
 - jack_controller_pending_save(
 -     struct jack_controller * controller_ptr)
 - {
 -     long ut;
 - 
 -     if ((ut = uptime()) < 0)
 -     {
 -         jack_error(UPTIME_FUNCTION_NAME "() failed with %d.", errno);
 -         controller_ptr->pending_save = 0;
 -         jack_controller_settings_save_auto(controller_ptr);
 -         return;
 -     }
 - 
 -     controller_ptr->pending_save = ut;
 - }
 
 
  |