This changeset removes code duplication that was caused by lack of unified access to parameters in the control API. Adding new virtual parameters should be much easier now. git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@4315 0c269be4-1314-0410-8aa9-9f06e86f4224tags/1.9.8
| @@ -1,6 +1,6 @@ | |||
| /* -*- Mode: C ; c-basic-offset: 4 -*- */ | |||
| /* | |||
| Copyright (C) 2007,2008,2010 Nedko Arnaudov | |||
| 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 | |||
| @@ -159,19 +159,13 @@ jack_controller_select_driver( | |||
| struct jack_controller * controller_ptr, | |||
| const char * driver_name) | |||
| { | |||
| jackctl_driver_t *driver; | |||
| driver = jack_controller_find_driver(controller_ptr->server, driver_name); | |||
| if (driver == NULL) | |||
| if (!jack_params_set_driver(controller_ptr->params, driver_name)) | |||
| { | |||
| return false; | |||
| } | |||
| jack_info("driver \"%s\" selected", driver_name); | |||
| controller_ptr->driver = driver; | |||
| controller_ptr->driver_set = true; | |||
| return true; | |||
| } | |||
| @@ -195,17 +189,11 @@ jack_controller_start_server( | |||
| assert(!controller_ptr->started); /* should be ensured by caller */ | |||
| if (controller_ptr->driver == NULL) | |||
| { | |||
| jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Select driver first!"); | |||
| goto fail; | |||
| } | |||
| controller_ptr->xruns = 0; | |||
| if (!jackctl_server_open( | |||
| controller_ptr->server, | |||
| controller_ptr->driver)) | |||
| jack_params_get_driver(controller_ptr->params))) | |||
| { | |||
| jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to open server"); | |||
| goto fail; | |||
| @@ -337,12 +325,13 @@ jack_controller_switch_master( | |||
| { | |||
| if (!jackctl_server_switch_master( | |||
| controller_ptr->server, | |||
| controller_ptr->driver)) | |||
| jack_params_get_driver(controller_ptr->params))) | |||
| { | |||
| jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Failed to switch master"); | |||
| return FALSE; | |||
| } | |||
| return TRUE; | |||
| } | |||
| @@ -413,11 +402,6 @@ jack_controller_create( | |||
| DBusConnection *connection) | |||
| { | |||
| struct jack_controller *controller_ptr; | |||
| const JSList * node_ptr; | |||
| const char ** driver_name_target; | |||
| const char ** internal_name_target; | |||
| JSList * drivers; | |||
| JSList * internals; | |||
| DBusObjectPathVTable vtable = | |||
| { | |||
| jack_dbus_message_handler_unregister, | |||
| @@ -439,54 +423,16 @@ jack_controller_create( | |||
| goto fail_free; | |||
| } | |||
| controller_ptr->client = NULL; | |||
| controller_ptr->started = false; | |||
| controller_ptr->driver = NULL; | |||
| controller_ptr->driver_set = false; | |||
| INIT_LIST_HEAD(&controller_ptr->slave_drivers); | |||
| drivers = (JSList *)jackctl_server_get_drivers_list(controller_ptr->server); | |||
| controller_ptr->drivers_count = jack_slist_length(drivers); | |||
| controller_ptr->driver_names = malloc(controller_ptr->drivers_count * sizeof(const char *)); | |||
| if (controller_ptr->driver_names == NULL) | |||
| controller_ptr->params = jack_params_create(controller_ptr->server); | |||
| if (controller_ptr->params == NULL) | |||
| { | |||
| jack_error("Ran out of memory trying to allocate driver names array"); | |||
| jack_error("Failed to initialize parameter tree"); | |||
| goto fail_destroy_server; | |||
| } | |||
| driver_name_target = controller_ptr->driver_names; | |||
| node_ptr = jackctl_server_get_drivers_list(controller_ptr->server); | |||
| while (node_ptr != NULL) | |||
| { | |||
| *driver_name_target = jackctl_driver_get_name((jackctl_driver_t *)node_ptr->data); | |||
| /* select default driver */ | |||
| if (controller_ptr->driver == NULL && strcmp(*driver_name_target, DEFAULT_DRIVER) == 0) | |||
| { | |||
| controller_ptr->driver = (jackctl_driver_t *)node_ptr->data; | |||
| } | |||
| node_ptr = jack_slist_next(node_ptr); | |||
| driver_name_target++; | |||
| } | |||
| internals = (JSList *)jackctl_server_get_internals_list(controller_ptr->server); | |||
| controller_ptr->internals_count = jack_slist_length(internals); | |||
| controller_ptr->internal_names = malloc(controller_ptr->internals_count * sizeof(const char *)); | |||
| if (controller_ptr->internal_names == NULL) | |||
| { | |||
| jack_error("Ran out of memory trying to allocate internals names array"); | |||
| goto fail_free_driver_names_array; | |||
| } | |||
| internal_name_target = controller_ptr->internal_names; | |||
| node_ptr = jackctl_server_get_internals_list(controller_ptr->server); | |||
| while (node_ptr != NULL) | |||
| { | |||
| *internal_name_target = jackctl_internal_get_name((jackctl_internal_t *)node_ptr->data); | |||
| node_ptr = jack_slist_next(node_ptr); | |||
| internal_name_target++; | |||
| } | |||
| controller_ptr->client = NULL; | |||
| controller_ptr->started = false; | |||
| INIT_LIST_HEAD(&controller_ptr->slave_drivers); | |||
| controller_ptr->dbus_descriptor.context = controller_ptr; | |||
| controller_ptr->dbus_descriptor.interfaces = g_jackcontroller_interfaces; | |||
| @@ -498,18 +444,15 @@ jack_controller_create( | |||
| &controller_ptr->dbus_descriptor)) | |||
| { | |||
| jack_error("Ran out of memory trying to register D-Bus object path"); | |||
| goto fail_free_internal_names_array; | |||
| goto fail_destroy_params; | |||
| } | |||
| jack_controller_settings_load(controller_ptr); | |||
| return controller_ptr; | |||
| fail_free_internal_names_array: | |||
| free(controller_ptr->internal_names); | |||
| fail_free_driver_names_array: | |||
| free(controller_ptr->driver_names); | |||
| fail_destroy_params: | |||
| jack_params_destroy(controller_ptr->params); | |||
| fail_destroy_server: | |||
| jackctl_server_destroy(controller_ptr->server); | |||
| @@ -623,9 +566,7 @@ jack_controller_destroy( | |||
| jack_controller_stop_server(controller_ptr, NULL); | |||
| } | |||
| free(controller_ptr->driver_names); | |||
| free(controller_ptr->internal_names); | |||
| jack_params_destroy(controller_ptr->params); | |||
| jackctl_server_destroy(controller_ptr->server); | |||
| free(controller_ptr); | |||
| @@ -1,6 +1,6 @@ | |||
| /* -*- Mode: C ; c-basic-offset: 4 -*- */ | |||
| /* | |||
| Copyright (C) 2007,2008 Nedko Arnaudov | |||
| Copyright (C) 2007,2008,2011 Nedko Arnaudov | |||
| Copyright (C) 2007-2008 Juuso Alasuutari | |||
| This program is free software; you can redistribute it and/or modify | |||
| @@ -27,6 +27,7 @@ | |||
| #include "jack/jack.h" | |||
| #include "jackdbus.h" | |||
| #include "list.h" | |||
| #include "params.h" | |||
| struct jack_controller_slave_driver | |||
| { | |||
| @@ -38,6 +39,7 @@ struct jack_controller_slave_driver | |||
| struct jack_controller | |||
| { | |||
| jackctl_server_t *server; | |||
| jack_params_handle params; | |||
| void *patchbay_context; | |||
| @@ -45,14 +47,6 @@ struct jack_controller | |||
| jack_client_t *client; | |||
| unsigned int xruns; | |||
| const char **driver_names; | |||
| unsigned int drivers_count; | |||
| const char **internal_names; | |||
| unsigned int internals_count; | |||
| jackctl_driver_t *driver; | |||
| bool driver_set; /* whether driver is manually set, if false - DEFAULT_DRIVER is auto set */ | |||
| struct list_head slave_drivers; | |||
| struct jack_dbus_object_descriptor dbus_descriptor; | |||
| @@ -121,47 +115,15 @@ jack_controller_unload_internal( | |||
| const char * internal_name); | |||
| void | |||
| jack_controller_settings_set_driver_option( | |||
| jackctl_driver_t *driver, | |||
| const char *option_name, | |||
| const char *option_value); | |||
| void | |||
| jack_controller_settings_set_internal_option( | |||
| jackctl_internal_t *internal, | |||
| const char *option_name, | |||
| const char *option_value); | |||
| void | |||
| jack_controller_settings_set_engine_option( | |||
| jack_controller_deserialize_parameter_value( | |||
| struct jack_controller *controller_ptr, | |||
| const char *option_name, | |||
| const char *option_value); | |||
| bool | |||
| jack_controller_settings_save_engine_options( | |||
| void *context, | |||
| struct jack_controller *controller_ptr, | |||
| void *dbus_call_context_ptr); | |||
| const char * const * address, | |||
| const char * value); | |||
| bool | |||
| jack_controller_settings_write_option( | |||
| void *context, | |||
| const char *name, | |||
| const char *content, | |||
| void *dbus_call_context_ptr); | |||
| bool | |||
| jack_controller_settings_save_driver_options( | |||
| void *context, | |||
| jackctl_driver_t *driver, | |||
| void *dbus_call_context_ptr); | |||
| bool | |||
| jack_controller_settings_save_internal_options( | |||
| void *context, | |||
| jackctl_internal_t *internal, | |||
| void *dbus_call_context_ptr); | |||
| void | |||
| jack_controller_serialize_parameter_value( | |||
| const struct jack_parameter * param_ptr, | |||
| char * value_buffer); | |||
| bool | |||
| jack_controller_patchbay_init( | |||
| @@ -0,0 +1,717 @@ | |||
| /* -*- Mode: C ; c-basic-offset: 4 -*- */ | |||
| /* | |||
| Copyright (C) 2011 Nedko Arnaudov | |||
| 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. | |||
| */ | |||
| /* | |||
| * Parameter addresses: | |||
| * | |||
| * "engine" | |||
| * "engine", "driver" | |||
| * "engine", "realtime" | |||
| * "engine", ...more engine parameters | |||
| * | |||
| * "driver", "device" | |||
| * "driver", ...more driver parameters | |||
| * | |||
| * "drivers", "alsa", "device" | |||
| * "drivers", "alsa", ...more alsa driver parameters | |||
| * | |||
| * "drivers", ...more drivers | |||
| * | |||
| * "internals", "netmanager", "multicast_ip" | |||
| * "internals", "netmanager", ...more netmanager parameters | |||
| * | |||
| * "internals", ...more internals | |||
| * | |||
| */ | |||
| #include <stdbool.h> | |||
| #include <string.h> | |||
| #include <assert.h> | |||
| #include <dbus/dbus.h> | |||
| #include "params.h" | |||
| #include "controller_internal.h" | |||
| #define PTNODE_ENGINE "engine" | |||
| #define PTNODE_DRIVER "driver" | |||
| #define PTNODE_DRIVERS "drivers" | |||
| #define PTNODE_INTERNALS "internals" | |||
| struct jack_parameter_container | |||
| { | |||
| struct list_head siblings; | |||
| char * name; | |||
| struct jack_parameter_container * symlink; | |||
| bool leaf; | |||
| struct list_head children; | |||
| void * obj; | |||
| }; | |||
| struct jack_params | |||
| { | |||
| jackctl_server_t * server; | |||
| struct jack_parameter_container root; | |||
| struct list_head * drivers_ptr; | |||
| uint32_t drivers_count; | |||
| struct jack_parameter_container * driver_ptr; | |||
| bool driver_set; /* whether driver is manually set, if false - DEFAULT_DRIVER is auto set */ | |||
| }; | |||
| static bool controlapi_parameter_is_set(void * obj) | |||
| { | |||
| return jackctl_parameter_is_set((jackctl_parameter_t *)obj); | |||
| } | |||
| static bool controlapi_parameter_reset(void * obj) | |||
| { | |||
| return jackctl_parameter_reset((jackctl_parameter_t *)obj); | |||
| } | |||
| union jackctl_parameter_value controlapi_parameter_get_value(void * obj) | |||
| { | |||
| return jackctl_parameter_get_value((jackctl_parameter_t *)obj); | |||
| } | |||
| bool controlapi_parameter_set_value(void * obj, const union jackctl_parameter_value * value_ptr) | |||
| { | |||
| return jackctl_parameter_set_value((jackctl_parameter_t *)obj, value_ptr); | |||
| } | |||
| union jackctl_parameter_value controlapi_parameter_get_default_value(void * obj) | |||
| { | |||
| return jackctl_parameter_get_default_value((jackctl_parameter_t *)obj); | |||
| } | |||
| static struct jack_parameter_container * create_container(struct list_head * parent_list_ptr, const char * name) | |||
| { | |||
| struct jack_parameter_container * container_ptr; | |||
| container_ptr = malloc(sizeof(struct jack_parameter_container)); | |||
| if (container_ptr == NULL) | |||
| { | |||
| jack_error("Ran out of memory trying to allocate struct jack_parameter_container"); | |||
| goto fail; | |||
| } | |||
| container_ptr->name = strdup(name); | |||
| if (container_ptr->name == NULL) | |||
| { | |||
| jack_error("Ran out of memory trying to strdup parameter container name"); | |||
| goto free; | |||
| } | |||
| container_ptr->leaf = false; | |||
| container_ptr->symlink = NULL; | |||
| container_ptr->obj = NULL; | |||
| INIT_LIST_HEAD(&container_ptr->children); | |||
| list_add_tail(&container_ptr->siblings, parent_list_ptr); | |||
| return container_ptr; | |||
| free: | |||
| free(container_ptr); | |||
| fail: | |||
| return NULL; | |||
| } | |||
| static bool add_controlapi_param(struct list_head * parent_list_ptr, jackctl_parameter_t * param) | |||
| { | |||
| struct jack_parameter * param_ptr; | |||
| uint32_t i; | |||
| param_ptr = malloc(sizeof(struct jack_parameter)); | |||
| if (param_ptr == NULL) | |||
| { | |||
| jack_error("Ran out of memory trying to allocate struct jack_parameter"); | |||
| goto fail; | |||
| } | |||
| param_ptr->obj = param; | |||
| param_ptr->vtable.is_set = controlapi_parameter_is_set; | |||
| param_ptr->vtable.reset = controlapi_parameter_reset; | |||
| param_ptr->vtable.get_value = controlapi_parameter_get_value; | |||
| param_ptr->vtable.set_value = controlapi_parameter_set_value; | |||
| param_ptr->vtable.get_default_value = controlapi_parameter_get_default_value; | |||
| param_ptr->type = jackctl_parameter_get_type(param); | |||
| param_ptr->name = jackctl_parameter_get_name(param); | |||
| param_ptr->short_decr = jackctl_parameter_get_short_description(param); | |||
| param_ptr->long_descr = jackctl_parameter_get_long_description(param); | |||
| if (jackctl_parameter_has_range_constraint(param)) | |||
| { | |||
| param_ptr->constraint_flags = JACK_CONSTRAINT_FLAG_VALID; | |||
| param_ptr->constraint_range = true; | |||
| jackctl_parameter_get_range_constraint(param, ¶m_ptr->constraint.range.min, ¶m_ptr->constraint.range.max); | |||
| } | |||
| else if (jackctl_parameter_has_enum_constraint(param)) | |||
| { | |||
| param_ptr->constraint_flags = JACK_CONSTRAINT_FLAG_VALID; | |||
| param_ptr->constraint_range = false; | |||
| param_ptr->constraint.enumeration.count = jackctl_parameter_get_enum_constraints_count(param); | |||
| param_ptr->constraint.enumeration.possible_values_array = malloc(sizeof(struct jack_parameter_enum) * param_ptr->constraint.enumeration.count); | |||
| if (param_ptr->constraint.enumeration.possible_values_array == NULL) | |||
| { | |||
| goto free; | |||
| } | |||
| for (i = 0; i < param_ptr->constraint.enumeration.count; i++) | |||
| { | |||
| param_ptr->constraint.enumeration.possible_values_array[i].value = jackctl_parameter_get_enum_constraint_value(param, i); | |||
| param_ptr->constraint.enumeration.possible_values_array[i].short_desc = jackctl_parameter_get_enum_constraint_description(param, i); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| param_ptr->constraint_flags = 0; | |||
| goto add; | |||
| } | |||
| if (jackctl_parameter_constraint_is_strict(param)) | |||
| { | |||
| param_ptr->constraint_flags |= JACK_CONSTRAINT_FLAG_STRICT; | |||
| } | |||
| if (jackctl_parameter_constraint_is_fake_value(param)) | |||
| { | |||
| param_ptr->constraint_flags |= JACK_CONSTRAINT_FLAG_FAKE_VALUE; | |||
| } | |||
| add: | |||
| list_add_tail(¶m_ptr->siblings, parent_list_ptr); | |||
| return true; | |||
| free: | |||
| free(param_ptr); | |||
| fail: | |||
| return false; | |||
| } | |||
| static void free_params(struct list_head * parent_list_ptr) | |||
| { | |||
| struct jack_parameter * param_ptr; | |||
| while (!list_empty(parent_list_ptr)) | |||
| { | |||
| param_ptr = list_entry(parent_list_ptr->next, struct jack_parameter, siblings); | |||
| list_del(¶m_ptr->siblings); | |||
| if ((param_ptr->constraint_flags & JACK_CONSTRAINT_FLAG_VALID) != 0 && | |||
| !param_ptr->constraint_range && | |||
| param_ptr->constraint.enumeration.possible_values_array != NULL) | |||
| { | |||
| free(param_ptr->constraint.enumeration.possible_values_array); | |||
| } | |||
| free(param_ptr); | |||
| } | |||
| } | |||
| static void free_containers(struct list_head * parent_list_ptr) | |||
| { | |||
| struct jack_parameter_container * container_ptr; | |||
| while (!list_empty(parent_list_ptr)) | |||
| { | |||
| container_ptr = list_entry(parent_list_ptr->next, struct jack_parameter_container, siblings); | |||
| list_del(&container_ptr->siblings); | |||
| if (container_ptr->leaf) | |||
| { | |||
| free_params(&container_ptr->children); | |||
| } | |||
| else | |||
| { | |||
| free_containers(&container_ptr->children); | |||
| } | |||
| free(container_ptr->name); | |||
| free(container_ptr); | |||
| } | |||
| } | |||
| static struct jack_parameter_container * find_container(struct jack_parameter_container * parent_ptr, const char * const * address, int max_depth) | |||
| { | |||
| struct list_head * node_ptr; | |||
| struct jack_parameter_container * container_ptr; | |||
| if (max_depth == 0 || *address == NULL) | |||
| { | |||
| return parent_ptr; | |||
| } | |||
| if (parent_ptr->leaf) | |||
| { | |||
| return NULL; | |||
| } | |||
| if (max_depth > 0) | |||
| { | |||
| max_depth--; | |||
| } | |||
| list_for_each(node_ptr, &parent_ptr->children) | |||
| { | |||
| container_ptr = list_entry(node_ptr, struct jack_parameter_container, siblings); | |||
| if (strcmp(container_ptr->name, *address) == 0) | |||
| { | |||
| if (container_ptr->symlink != NULL) | |||
| { | |||
| container_ptr = container_ptr->symlink; | |||
| } | |||
| return find_container(container_ptr, address + 1, max_depth); | |||
| } | |||
| } | |||
| return NULL; | |||
| } | |||
| static bool init_leaf(struct list_head * parent_list_ptr, const char * name, const JSList * params_list, void * obj) | |||
| { | |||
| struct jack_parameter_container * container_ptr; | |||
| container_ptr = create_container(parent_list_ptr, name); | |||
| if (container_ptr == NULL) | |||
| { | |||
| return false; | |||
| } | |||
| container_ptr->leaf = true; | |||
| container_ptr->obj = obj; | |||
| while (params_list) | |||
| { | |||
| if (!add_controlapi_param(&container_ptr->children, params_list->data)) | |||
| { | |||
| return false; | |||
| } | |||
| params_list = jack_slist_next(params_list); | |||
| } | |||
| return true; | |||
| } | |||
| static bool init_engine(struct jack_params * params_ptr) | |||
| { | |||
| return init_leaf(¶ms_ptr->root.children, PTNODE_ENGINE, jackctl_server_get_parameters(params_ptr->server), NULL); | |||
| } | |||
| static bool init_drivers(struct jack_params * params_ptr) | |||
| { | |||
| const JSList * list; | |||
| struct jack_parameter_container * container_ptr; | |||
| container_ptr = create_container(¶ms_ptr->root.children, PTNODE_DRIVERS); | |||
| if (container_ptr == NULL) | |||
| { | |||
| return false; | |||
| } | |||
| params_ptr->drivers_ptr = &container_ptr->children; | |||
| params_ptr->drivers_count = 0; | |||
| list = jackctl_server_get_drivers_list(params_ptr->server); | |||
| while (list) | |||
| { | |||
| if (!init_leaf(&container_ptr->children, jackctl_driver_get_name(list->data), jackctl_driver_get_parameters(list->data), list->data)) | |||
| { | |||
| return false; | |||
| } | |||
| params_ptr->drivers_count++; | |||
| list = jack_slist_next(list); | |||
| } | |||
| return true; | |||
| } | |||
| static bool init_internals(struct jack_params * params_ptr) | |||
| { | |||
| const JSList * list; | |||
| struct jack_parameter_container * container_ptr; | |||
| container_ptr = create_container(¶ms_ptr->root.children, PTNODE_INTERNALS); | |||
| if (container_ptr == NULL) | |||
| { | |||
| return false; | |||
| } | |||
| list = jackctl_server_get_internals_list(params_ptr->server); | |||
| while (list) | |||
| { | |||
| if (!init_leaf(&container_ptr->children, jackctl_internal_get_name(list->data), jackctl_internal_get_parameters(list->data), NULL)) | |||
| { | |||
| return false; | |||
| } | |||
| list = jack_slist_next(list); | |||
| } | |||
| return true; | |||
| } | |||
| static bool init_driver(struct jack_params * params_ptr) | |||
| { | |||
| struct jack_parameter_container * container_ptr; | |||
| container_ptr = create_container(¶ms_ptr->root.children, PTNODE_DRIVER); | |||
| if (container_ptr == NULL) | |||
| { | |||
| return false; | |||
| } | |||
| params_ptr->driver_ptr = container_ptr; | |||
| return true; | |||
| } | |||
| #define params_ptr ((struct jack_params *)obj) | |||
| static bool engine_driver_parameter_is_set(void * obj) | |||
| { | |||
| return params_ptr->driver_set; | |||
| } | |||
| static bool engine_driver_parameter_reset(void * obj) | |||
| { | |||
| if (!jack_params_set_driver(obj, DEFAULT_DRIVER)) | |||
| { | |||
| return false; | |||
| } | |||
| params_ptr->driver_set = false; | |||
| return true; | |||
| } | |||
| union jackctl_parameter_value engine_driver_parameter_get_value(void * obj) | |||
| { | |||
| union jackctl_parameter_value value; | |||
| strcpy(value.str, params_ptr->driver_ptr->symlink->name); | |||
| return value; | |||
| } | |||
| bool engine_driver_parameter_set_value(void * obj, const union jackctl_parameter_value * value_ptr) | |||
| { | |||
| return jack_params_set_driver(obj, value_ptr->str); | |||
| } | |||
| union jackctl_parameter_value engine_driver_parameter_get_default_value(void * obj) | |||
| { | |||
| union jackctl_parameter_value value; | |||
| strcpy(value.str, DEFAULT_DRIVER); | |||
| return value; | |||
| } | |||
| #undef params_ptr | |||
| static bool add_engine_driver_enum_constraint(void * context, const char * name) | |||
| { | |||
| strcpy((*((struct jack_parameter_enum **)context))->value.str, name); | |||
| (*((struct jack_parameter_enum **)context))->short_desc = name; | |||
| (*((struct jack_parameter_enum **)context))++; | |||
| return true; | |||
| } | |||
| static bool init_engine_driver_parameter(struct jack_params * params_ptr) | |||
| { | |||
| struct jack_parameter * param_ptr; | |||
| const char * address[PARAM_ADDRESS_SIZE] = {PTNODE_ENGINE, NULL}; | |||
| struct jack_parameter_container * engine_ptr; | |||
| struct jack_parameter_enum * possible_value; | |||
| engine_ptr = find_container(¶ms_ptr->root, address, PARAM_ADDRESS_SIZE); | |||
| if (engine_ptr == NULL) | |||
| { | |||
| return false; | |||
| } | |||
| param_ptr = malloc(sizeof(struct jack_parameter)); | |||
| if (param_ptr == NULL) | |||
| { | |||
| jack_error("Ran out of memory trying to allocate struct jack_parameter"); | |||
| goto fail; | |||
| } | |||
| param_ptr->obj = params_ptr; | |||
| param_ptr->vtable.is_set = engine_driver_parameter_is_set; | |||
| param_ptr->vtable.reset = engine_driver_parameter_reset; | |||
| param_ptr->vtable.get_value = engine_driver_parameter_get_value; | |||
| param_ptr->vtable.set_value = engine_driver_parameter_set_value; | |||
| param_ptr->vtable.get_default_value = engine_driver_parameter_get_default_value; | |||
| param_ptr->type = JackParamString; | |||
| param_ptr->name = "driver"; | |||
| param_ptr->short_decr = "Driver to use"; | |||
| param_ptr->long_descr = ""; | |||
| param_ptr->constraint_flags = JACK_CONSTRAINT_FLAG_VALID | JACK_CONSTRAINT_FLAG_STRICT | JACK_CONSTRAINT_FLAG_FAKE_VALUE; | |||
| param_ptr->constraint_range = false; | |||
| param_ptr->constraint.enumeration.count = params_ptr->drivers_count; | |||
| param_ptr->constraint.enumeration.possible_values_array = malloc(sizeof(struct jack_parameter_enum) * params_ptr->drivers_count); | |||
| if (param_ptr->constraint.enumeration.possible_values_array == NULL) | |||
| { | |||
| goto free; | |||
| } | |||
| address[0] = PTNODE_DRIVERS; | |||
| possible_value = param_ptr->constraint.enumeration.possible_values_array; | |||
| jack_params_iterate_container((jack_params_handle)params_ptr, address, add_engine_driver_enum_constraint, &possible_value); | |||
| list_add(¶m_ptr->siblings, &engine_ptr->children); | |||
| return true; | |||
| free: | |||
| free(param_ptr); | |||
| fail: | |||
| return false; | |||
| } | |||
| jack_params_handle jack_params_create(jackctl_server_t * server) | |||
| { | |||
| struct jack_params * params_ptr; | |||
| params_ptr = malloc(sizeof(struct jack_params)); | |||
| if (params_ptr == NULL) | |||
| { | |||
| jack_error("Ran out of memory trying to allocate struct jack_params"); | |||
| return NULL; | |||
| } | |||
| params_ptr->server = server; | |||
| INIT_LIST_HEAD(¶ms_ptr->root.children); | |||
| params_ptr->root.leaf = false; | |||
| params_ptr->root.name = NULL; | |||
| if (!init_engine(params_ptr) || | |||
| !init_drivers(params_ptr) || | |||
| !init_driver(params_ptr) || | |||
| !init_engine_driver_parameter(params_ptr) || | |||
| !jack_params_set_driver((jack_params_handle)params_ptr, DEFAULT_DRIVER) || | |||
| !init_internals(params_ptr)) | |||
| { | |||
| jack_params_destroy((jack_params_handle)params_ptr); | |||
| return NULL; | |||
| } | |||
| params_ptr->driver_set = false; | |||
| assert(strcmp(params_ptr->driver_ptr->symlink->name, DEFAULT_DRIVER) == 0); | |||
| return (jack_params_handle)params_ptr; | |||
| } | |||
| #define params_ptr ((struct jack_params *)params) | |||
| void jack_params_destroy(jack_params_handle params) | |||
| { | |||
| free_containers(¶ms_ptr->root.children); | |||
| free(params); | |||
| } | |||
| bool jack_params_set_driver(jack_params_handle params, const char * name) | |||
| { | |||
| struct list_head * node_ptr; | |||
| struct jack_parameter_container * container_ptr; | |||
| list_for_each(node_ptr, params_ptr->drivers_ptr) | |||
| { | |||
| container_ptr = list_entry(node_ptr, struct jack_parameter_container, siblings); | |||
| if (strcmp(container_ptr->name, name) == 0) | |||
| { | |||
| params_ptr->driver_ptr->symlink = container_ptr; | |||
| params_ptr->driver_set = true; | |||
| return true; | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| jackctl_driver_t * jack_params_get_driver(jack_params_handle params) | |||
| { | |||
| return params_ptr->driver_ptr->symlink->obj; | |||
| } | |||
| bool jack_params_check_address(jack_params_handle params, const char * const * address, bool want_leaf) | |||
| { | |||
| struct jack_parameter_container * container_ptr; | |||
| container_ptr = find_container(¶ms_ptr->root, address, PARAM_ADDRESS_SIZE); | |||
| if (container_ptr == NULL) | |||
| { | |||
| return false; | |||
| } | |||
| if (want_leaf && !container_ptr->leaf) | |||
| { | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| bool jack_params_is_leaf_container(jack_params_handle params, const char * const * address) | |||
| { | |||
| struct jack_parameter_container * container_ptr; | |||
| container_ptr = find_container(¶ms_ptr->root, address, PARAM_ADDRESS_SIZE); | |||
| if (container_ptr == NULL) | |||
| { | |||
| assert(false); | |||
| return false; | |||
| } | |||
| return container_ptr->leaf; | |||
| } | |||
| bool | |||
| jack_params_iterate_container( | |||
| jack_params_handle params, | |||
| const char * const * address, | |||
| bool (* callback)(void * context, const char * name), | |||
| void * context) | |||
| { | |||
| struct jack_parameter_container * container_ptr; | |||
| struct list_head * node_ptr; | |||
| const char * name; | |||
| container_ptr = find_container(¶ms_ptr->root, address, PARAM_ADDRESS_SIZE); | |||
| if (container_ptr == NULL) | |||
| { | |||
| assert(false); | |||
| return true; | |||
| } | |||
| list_for_each(node_ptr, &container_ptr->children) | |||
| { | |||
| if (container_ptr->leaf) | |||
| { | |||
| name = list_entry(node_ptr, struct jack_parameter, siblings)->name; | |||
| } | |||
| else | |||
| { | |||
| name = list_entry(node_ptr, struct jack_parameter_container, siblings)->name; | |||
| } | |||
| if (!callback(context, name)) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| bool | |||
| jack_params_iterate_params( | |||
| jack_params_handle params, | |||
| const char * const * address, | |||
| bool (* callback)(void * context, const struct jack_parameter * param_ptr), | |||
| void * context) | |||
| { | |||
| struct jack_parameter_container * container_ptr; | |||
| struct list_head * node_ptr; | |||
| struct jack_parameter * param_ptr; | |||
| container_ptr = find_container(¶ms_ptr->root, address, PARAM_ADDRESS_SIZE); | |||
| if (container_ptr == NULL || !container_ptr->leaf) | |||
| { | |||
| assert(false); | |||
| return true; | |||
| } | |||
| list_for_each(node_ptr, &container_ptr->children) | |||
| { | |||
| param_ptr = list_entry(node_ptr, struct jack_parameter, siblings); | |||
| if (!callback(context, param_ptr)) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| const struct jack_parameter * jack_params_get_parameter(jack_params_handle params, const char * const * address) | |||
| { | |||
| int depth; | |||
| struct jack_parameter_container * container_ptr; | |||
| struct list_head * node_ptr; | |||
| struct jack_parameter * param_ptr; | |||
| for (depth = 0; depth < PARAM_ADDRESS_SIZE; depth++) | |||
| { | |||
| if (address[depth] == NULL) | |||
| { | |||
| break; | |||
| } | |||
| } | |||
| depth--; | |||
| container_ptr = find_container(¶ms_ptr->root, address, depth); | |||
| if (container_ptr == NULL || !container_ptr->leaf) | |||
| { | |||
| return NULL; | |||
| } | |||
| list_for_each(node_ptr, &container_ptr->children) | |||
| { | |||
| param_ptr = list_entry(node_ptr, struct jack_parameter, siblings); | |||
| if (strcmp(param_ptr->name, address[depth]) == 0) | |||
| { | |||
| return param_ptr; | |||
| } | |||
| } | |||
| return NULL; | |||
| } | |||
| bool jack_params_add_parameter(jack_params_handle params, const char * const * address, bool end, struct jack_parameter * param_ptr) | |||
| { | |||
| struct jack_parameter_container * container_ptr; | |||
| container_ptr = find_container(¶ms_ptr->root, address, PARAM_ADDRESS_SIZE); | |||
| if (container_ptr == NULL || !container_ptr->leaf) | |||
| { | |||
| assert(false); | |||
| return false; | |||
| } | |||
| if (end) | |||
| { | |||
| list_add_tail(¶m_ptr->siblings, &container_ptr->children); | |||
| } | |||
| else | |||
| { | |||
| list_add(¶m_ptr->siblings, &container_ptr->children); | |||
| } | |||
| return true; | |||
| } | |||
| #undef params_ptr | |||
| @@ -0,0 +1,110 @@ | |||
| /* -*- Mode: C ; c-basic-offset: 4 -*- */ | |||
| /* | |||
| Copyright (C) 2011 Nedko Arnaudov | |||
| 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. | |||
| */ | |||
| #ifndef PARAMS_H__A23EDE06_C1C9_4489_B253_FD1B26B66929__INCLUDED | |||
| #define PARAMS_H__A23EDE06_C1C9_4489_B253_FD1B26B66929__INCLUDED | |||
| #include "jack/control.h" | |||
| #include "list.h" | |||
| #define PARAM_ADDRESS_SIZE 3 | |||
| #define PTNODE_ENGINE "engine" | |||
| #define PTNODE_DRIVER "driver" | |||
| #define PTNODE_DRIVERS "drivers" | |||
| #define PTNODE_INTERNALS "internals" | |||
| struct jack_parameter_vtable | |||
| { | |||
| bool (* is_set)(void * obj); | |||
| bool (* reset)(void * obj); | |||
| union jackctl_parameter_value (* get_value)(void * obj); | |||
| bool (* set_value)(void * obj, const union jackctl_parameter_value * value_ptr); | |||
| union jackctl_parameter_value (* get_default_value)(void * obj); | |||
| }; | |||
| #define JACK_CONSTRAINT_FLAG_VALID ((uint32_t)1) /**< if not set, there is no constraint */ | |||
| #define JACK_CONSTRAINT_FLAG_STRICT ((uint32_t)2) /**< if set, constraint is strict, i.e. supplying non-matching value will not work */ | |||
| #define JACK_CONSTRAINT_FLAG_FAKE_VALUE ((uint32_t)4) /**< if set, values have no user meaningful meaning */ | |||
| struct jack_parameter_enum | |||
| { | |||
| union jackctl_parameter_value value; | |||
| const char * short_desc; | |||
| }; | |||
| struct jack_parameter | |||
| { | |||
| void * obj; | |||
| struct jack_parameter_vtable vtable; | |||
| struct list_head siblings; | |||
| jackctl_param_type_t type; | |||
| const char * name; | |||
| const char * short_decr; | |||
| const char * long_descr; | |||
| uint32_t constraint_flags; /**< JACK_CONSTRAINT_FLAG_XXX */ | |||
| bool constraint_range; /**< if true, constraint is a range (min-max), otherwise it is an enumeration */ | |||
| union | |||
| { | |||
| struct | |||
| { | |||
| union jackctl_parameter_value min; | |||
| union jackctl_parameter_value max; | |||
| } range; /**< valid when JACK_CONSTRAINT_FLAG_RANGE flag is set */ | |||
| struct | |||
| { | |||
| uint32_t count; | |||
| struct jack_parameter_enum * possible_values_array; | |||
| } enumeration; /**< valid when JACK_CONSTRAINT_FLAG_RANGE flag is not set */ | |||
| } constraint; | |||
| }; | |||
| typedef struct _jack_params { int unused; } * jack_params_handle; | |||
| jack_params_handle jack_params_create(jackctl_server_t * server); | |||
| void jack_params_destroy(jack_params_handle params); | |||
| bool jack_params_set_driver(jack_params_handle params, const char * name); | |||
| jackctl_driver_t * jack_params_get_driver(jack_params_handle params); | |||
| bool jack_params_check_address(jack_params_handle params, const char * const * address, bool want_leaf); | |||
| bool jack_params_is_leaf_container(jack_params_handle params, const char * const * address); | |||
| bool | |||
| jack_params_iterate_container( | |||
| jack_params_handle params, | |||
| const char * const * address, | |||
| bool (* callback)(void * context, const char * name), | |||
| void * context); | |||
| bool | |||
| jack_params_iterate_params( | |||
| jack_params_handle params, | |||
| const char * const * address, | |||
| bool (* callback)(void * context, const struct jack_parameter * param_ptr), | |||
| void * context); | |||
| const struct jack_parameter * jack_params_get_parameter(jack_params_handle params, const char * const * address); | |||
| bool jack_params_add_parameter(jack_params_handle params, const char * const * address, bool end, struct jack_parameter * param_ptr); | |||
| #endif /* #ifndef PARAMS_H__A23EDE06_C1C9_4489_B253_FD1B26B66929__INCLUDED */ | |||
| @@ -52,6 +52,7 @@ def build(bld): | |||
| obj.source = [ | |||
| 'jackdbus.c', | |||
| 'controller.c', | |||
| 'params.c', | |||
| 'controller_iface_configure.c', | |||
| 'controller_iface_control.c', | |||
| 'controller_iface_introspectable.c', | |||
| @@ -1,6 +1,6 @@ | |||
| /* -*- Mode: C ; c-basic-offset: 4 -*- */ | |||
| /* | |||
| Copyright (C) 2007,2008 Nedko Arnaudov | |||
| Copyright (C) 2007,2008,2011 Nedko Arnaudov | |||
| 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 | |||
| @@ -25,358 +25,116 @@ | |||
| #include <stdint.h> | |||
| #include <string.h> | |||
| #include <stdio.h> | |||
| #include <assert.h> | |||
| #include <dbus/dbus.h> | |||
| #include "controller_internal.h" | |||
| void | |||
| jack_controller_settings_set_bool_option( | |||
| const char *value_str, | |||
| int *value_ptr) | |||
| { | |||
| if (strcmp(value_str, "true") == 0) | |||
| { | |||
| *value_ptr = true; | |||
| } | |||
| else if (strcmp(value_str, "false") == 0) | |||
| { | |||
| *value_ptr = false; | |||
| } | |||
| else | |||
| { | |||
| jack_error("ignoring unknown bool value \"%s\"", value_str); | |||
| } | |||
| } | |||
| void | |||
| jack_controller_settings_set_sint_option( | |||
| const char *value_str, | |||
| int *value_ptr) | |||
| { | |||
| *value_ptr = atoi(value_str); | |||
| } | |||
| void | |||
| jack_controller_settings_set_uint_option( | |||
| const char *value_str, | |||
| unsigned int *value_ptr) | |||
| { | |||
| *value_ptr = strtoul(value_str, NULL, 10); | |||
| } | |||
| void | |||
| jack_controller_settings_set_char_option( | |||
| const char *value_str, | |||
| char *value_ptr) | |||
| { | |||
| if (value_str[0] == 0 || value_str[1] != 0) | |||
| { | |||
| jack_error("invalid char option value \"%s\"", value_str); | |||
| return; | |||
| } | |||
| *value_ptr = *value_str; | |||
| } | |||
| void | |||
| jack_controller_settings_set_string_option( | |||
| const char *value_str, | |||
| char *value_ptr, | |||
| size_t max_size) | |||
| { | |||
| size_t size; | |||
| size = strlen(value_str); | |||
| if (size >= max_size) | |||
| { | |||
| jack_error("string option value \"%s\" is too long, max is %u chars (including terminating zero)", value_str, (unsigned int)max_size); | |||
| return; | |||
| } | |||
| strcpy(value_ptr, value_str); | |||
| } | |||
| void | |||
| jack_controller_settings_set_driver_option( | |||
| jackctl_driver_t *driver, | |||
| const char *option_name, | |||
| const char *option_value) | |||
| jack_controller_deserialize_parameter_value( | |||
| struct jack_controller *controller_ptr, | |||
| const char * const * address, | |||
| const char * option_value) | |||
| { | |||
| jackctl_parameter_t *parameter; | |||
| jackctl_param_type_t type; | |||
| int value_int = 0; | |||
| unsigned int value_uint = 0; | |||
| const struct jack_parameter * param_ptr; | |||
| union jackctl_parameter_value value; | |||
| size_t size; | |||
| jack_info("setting driver option \"%s\" to value \"%s\"", option_name, option_value); | |||
| parameter = jack_controller_find_parameter(jackctl_driver_get_parameters(driver), option_name); | |||
| if (parameter == NULL) | |||
| param_ptr = jack_params_get_parameter(controller_ptr->params, address); | |||
| if (param_ptr == NULL) | |||
| { | |||
| jack_error( | |||
| "Unknown parameter \"%s\" of driver \"%s\"", | |||
| option_name, | |||
| jackctl_driver_get_name(driver)); | |||
| return; | |||
| jack_error("Unknown parameter"); | |||
| goto ignore; | |||
| } | |||
| type = jackctl_parameter_get_type(parameter); | |||
| jack_info("setting parameter '%s':'%s':'%s' to value \"%s\"", address[0], address[1], address[2], option_value); | |||
| switch (type) | |||
| switch (param_ptr->type) | |||
| { | |||
| case JackParamInt: | |||
| jack_controller_settings_set_sint_option(option_value, &value_int); | |||
| value.i = value_int; | |||
| value.i = atoi(option_value); | |||
| break; | |||
| case JackParamUInt: | |||
| jack_controller_settings_set_uint_option(option_value, &value_uint); | |||
| value.ui = value_uint; | |||
| value.ui = strtoul(option_value, NULL, 10); | |||
| break; | |||
| case JackParamChar: | |||
| jack_controller_settings_set_char_option(option_value, &value.c); | |||
| if (option_value[0] == 0 || option_value[1] != 0) | |||
| { | |||
| jack_error("invalid char option value \"%s\"", option_value); | |||
| goto ignore; | |||
| } | |||
| value.c = *option_value; | |||
| break; | |||
| case JackParamString: | |||
| jack_controller_settings_set_string_option(option_value, value.str, sizeof(value.str)); | |||
| size = strlen(option_value); | |||
| if (size >= sizeof(value.str)) | |||
| { | |||
| jack_error("string option value \"%s\" is too long, max is %zu chars (including terminating zero)", option_value, sizeof(value.str)); | |||
| goto ignore; | |||
| } | |||
| strcpy(value.str, option_value); | |||
| break; | |||
| case JackParamBool: | |||
| jack_controller_settings_set_bool_option(option_value, &value_int); | |||
| value.i = value_int; | |||
| if (strcmp(option_value, "true") == 0) | |||
| { | |||
| value.b = true; | |||
| } | |||
| else if (strcmp(option_value, "false") == 0) | |||
| { | |||
| value.b = false; | |||
| } | |||
| else | |||
| { | |||
| jack_error("ignoring unknown bool value \"%s\"", option_value); | |||
| goto ignore; | |||
| } | |||
| break; | |||
| default: | |||
| jack_error("Parameter \"%s\" of driver \"%s\" is of unknown type %d", | |||
| jackctl_parameter_get_name(parameter), | |||
| jackctl_driver_get_name(driver), | |||
| type); | |||
| jack_error("Unknown type %d", (int)param_ptr->type); | |||
| goto ignore; | |||
| } | |||
| jackctl_parameter_set_value(parameter, &value); | |||
| } | |||
| void | |||
| jack_controller_settings_set_internal_option( | |||
| jackctl_internal_t *internal, | |||
| const char *option_name, | |||
| const char *option_value) | |||
| { | |||
| jackctl_parameter_t *parameter; | |||
| jackctl_param_type_t type; | |||
| int value_int = 0; | |||
| unsigned int value_uint = 0; | |||
| union jackctl_parameter_value value; | |||
| jack_info("setting internal option \"%s\" to value \"%s\"", option_name, option_value); | |||
| parameter = jack_controller_find_parameter(jackctl_internal_get_parameters(internal), option_name); | |||
| if (parameter == NULL) | |||
| if (param_ptr->vtable.set_value(param_ptr->obj, &value)) | |||
| { | |||
| jack_error( | |||
| "Unknown parameter \"%s\" of internal \"%s\"", | |||
| option_name, | |||
| jackctl_internal_get_name(internal)); | |||
| return; | |||
| } | |||
| type = jackctl_parameter_get_type(parameter); | |||
| switch (type) | |||
| { | |||
| case JackParamInt: | |||
| jack_controller_settings_set_sint_option(option_value, &value_int); | |||
| value.i = value_int; | |||
| break; | |||
| case JackParamUInt: | |||
| jack_controller_settings_set_uint_option(option_value, &value_uint); | |||
| value.ui = value_uint; | |||
| break; | |||
| case JackParamChar: | |||
| jack_controller_settings_set_char_option(option_value, &value.c); | |||
| break; | |||
| case JackParamString: | |||
| jack_controller_settings_set_string_option(option_value, value.str, sizeof(value.str)); | |||
| break; | |||
| case JackParamBool: | |||
| jack_controller_settings_set_bool_option(option_value, &value_int); | |||
| value.i = value_int; | |||
| break; | |||
| default: | |||
| jack_error("Parameter \"%s\" of internal \"%s\" is of unknown type %d", | |||
| jackctl_parameter_get_name(parameter), | |||
| jackctl_internal_get_name(internal), | |||
| type); | |||
| } | |||
| jack_error("Parameter set failed"); | |||
| jackctl_parameter_set_value(parameter, &value); | |||
| ignore: | |||
| jack_error("Ignoring restore attempt of parameter '%s':'%s':'%s'", address[0], address[1], address[2]); | |||
| } | |||
| void | |||
| jack_controller_settings_set_engine_option( | |||
| struct jack_controller *controller_ptr, | |||
| const char *option_name, | |||
| const char *option_value) | |||
| jack_controller_serialize_parameter_value( | |||
| const struct jack_parameter * param_ptr, | |||
| char * value_buffer) | |||
| { | |||
| jackctl_parameter_t *parameter; | |||
| jackctl_param_type_t type; | |||
| int value_int = 0; | |||
| unsigned int value_uint = 0; | |||
| union jackctl_parameter_value value; | |||
| jack_info("setting engine option \"%s\" to value \"%s\"", option_name, option_value); | |||
| value = param_ptr->vtable.get_value(param_ptr->obj); | |||
| if (strcmp(option_name, "driver") == 0) | |||
| { | |||
| if (!jack_controller_select_driver(controller_ptr, option_value)) | |||
| { | |||
| jack_error("unknown driver '%s'", option_value); | |||
| } | |||
| return; | |||
| } | |||
| parameter = jack_controller_find_parameter(jackctl_server_get_parameters(controller_ptr->server), option_name); | |||
| if (parameter == NULL) | |||
| { | |||
| jack_error( | |||
| "Unknown engine parameter \"%s\"", | |||
| option_name); | |||
| return; | |||
| } | |||
| type = jackctl_parameter_get_type(parameter); | |||
| switch (type) | |||
| switch (param_ptr->type) | |||
| { | |||
| case JackParamInt: | |||
| jack_controller_settings_set_sint_option(option_value, &value_int); | |||
| value.i = value_int; | |||
| break; | |||
| sprintf(value_buffer, "%d", (int)value.i); | |||
| return; | |||
| case JackParamUInt: | |||
| jack_controller_settings_set_uint_option(option_value, &value_uint); | |||
| value.ui = value_uint; | |||
| break; | |||
| sprintf(value_buffer, "%u", (unsigned int)value.ui); | |||
| return; | |||
| case JackParamChar: | |||
| jack_controller_settings_set_char_option(option_value, &value.c); | |||
| break; | |||
| sprintf(value_buffer, "%c", (char)value.c); | |||
| return; | |||
| case JackParamString: | |||
| jack_controller_settings_set_string_option(option_value, value.str, sizeof(value.str)); | |||
| break; | |||
| strcpy(value_buffer, value.str); | |||
| return; | |||
| case JackParamBool: | |||
| jack_controller_settings_set_bool_option(option_value, &value_int); | |||
| value.i = value_int; | |||
| break; | |||
| default: | |||
| jack_error("Engine parameter \"%s\" is of unknown type %d", | |||
| jackctl_parameter_get_name(parameter), | |||
| type); | |||
| } | |||
| jackctl_parameter_set_value(parameter, &value); | |||
| } | |||
| static | |||
| bool | |||
| jack_controller_settings_save_options( | |||
| void *context, | |||
| const JSList * parameters_list, | |||
| void *dbus_call_context_ptr) | |||
| { | |||
| jackctl_parameter_t *parameter; | |||
| jackctl_param_type_t type; | |||
| union jackctl_parameter_value value; | |||
| const char * name; | |||
| char value_str[50]; | |||
| while (parameters_list != NULL) | |||
| { | |||
| parameter = (jackctl_parameter_t *)parameters_list->data; | |||
| if (jackctl_parameter_is_set(parameter)) | |||
| { | |||
| type = jackctl_parameter_get_type(parameter); | |||
| value = jackctl_parameter_get_value(parameter); | |||
| name = jackctl_parameter_get_name(parameter); | |||
| switch (type) | |||
| { | |||
| case JackParamInt: | |||
| sprintf(value_str, "%d", (int)value.i); | |||
| if (!jack_controller_settings_write_option(context, name, value_str, dbus_call_context_ptr)) | |||
| { | |||
| return false; | |||
| } | |||
| break; | |||
| case JackParamUInt: | |||
| sprintf(value_str, "%u", (unsigned int)value.ui); | |||
| if (!jack_controller_settings_write_option(context, name, value_str, dbus_call_context_ptr)) | |||
| { | |||
| return false; | |||
| } | |||
| break; | |||
| case JackParamChar: | |||
| sprintf(value_str, "%c", (char)value.c); | |||
| if (!jack_controller_settings_write_option(context, name, value_str, dbus_call_context_ptr)) | |||
| { | |||
| return false; | |||
| } | |||
| break; | |||
| case JackParamString: | |||
| if (!jack_controller_settings_write_option(context, name, value.str, dbus_call_context_ptr)) | |||
| { | |||
| return false; | |||
| } | |||
| break; | |||
| case JackParamBool: | |||
| if (!jack_controller_settings_write_option(context, name, value.b ? "true" : "false", dbus_call_context_ptr)) | |||
| { | |||
| return false; | |||
| } | |||
| break; | |||
| default: | |||
| jack_error("parameter of unknown type %d", type); | |||
| } | |||
| } | |||
| parameters_list = jack_slist_next(parameters_list); | |||
| } | |||
| return true; | |||
| } | |||
| bool | |||
| jack_controller_settings_save_engine_options( | |||
| void *context, | |||
| struct jack_controller *controller_ptr, | |||
| void *dbus_call_context_ptr) | |||
| { | |||
| if (controller_ptr->driver != NULL) | |||
| { | |||
| if (!jack_controller_settings_write_option( | |||
| context, | |||
| "driver", | |||
| jackctl_driver_get_name(controller_ptr->driver), | |||
| dbus_call_context_ptr)) | |||
| { | |||
| return false; | |||
| } | |||
| strcpy(value_buffer, value.b ? "true" : "false"); | |||
| return; | |||
| } | |||
| return jack_controller_settings_save_options(context, jackctl_server_get_parameters(controller_ptr->server), dbus_call_context_ptr); | |||
| } | |||
| bool | |||
| jack_controller_settings_save_driver_options( | |||
| void *context, | |||
| jackctl_driver_t *driver, | |||
| void *dbus_call_context_ptr) | |||
| { | |||
| return jack_controller_settings_save_options(context, jackctl_driver_get_parameters(driver), dbus_call_context_ptr); | |||
| } | |||
| bool | |||
| jack_controller_settings_save_internal_options( | |||
| void *context, | |||
| jackctl_internal_t *internal, | |||
| void *dbus_call_context_ptr) | |||
| { | |||
| return jack_controller_settings_save_options(context, jackctl_internal_get_parameters(internal), dbus_call_context_ptr); | |||
| jack_error("parameter of unknown type %d", (int)param_ptr->type); | |||
| assert(false); | |||
| *value_buffer = 0; | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| /* -*- Mode: C ; c-basic-offset: 4 -*- */ | |||
| /* | |||
| Copyright (C) 2007,2008 Nedko Arnaudov | |||
| Copyright (C) 2007,2008,2011 Nedko Arnaudov | |||
| 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 | |||
| @@ -29,6 +29,7 @@ | |||
| #include <fcntl.h> | |||
| #include <errno.h> | |||
| #include <string.h> | |||
| #include <assert.h> | |||
| #include <expat.h> | |||
| #include <dbus/dbus.h> | |||
| @@ -46,27 +47,16 @@ jack_controller_settings_uninit() | |||
| { | |||
| } | |||
| #define PARSE_CONTEXT_ROOT 0 | |||
| #define PARSE_CONTEXT_JACK 1 | |||
| #define PARSE_CONTEXT_ENGINE 1 | |||
| #define PARSE_CONTEXT_DRIVERS 2 | |||
| #define PARSE_CONTEXT_DRIVER 3 | |||
| #define PARSE_CONTEXT_OPTION 4 | |||
| #define PARSE_CONTEXT_INTERNALS 5 | |||
| #define PARSE_CONTEXT_INTERNAL 6 | |||
| #define MAX_STACK_DEPTH 10 | |||
| struct parse_context | |||
| { | |||
| struct jack_controller *controller_ptr; | |||
| XML_Bool error; | |||
| unsigned int element[MAX_STACK_DEPTH]; | |||
| signed int depth; | |||
| jackctl_driver_t *driver; | |||
| jackctl_internal_t *internal; | |||
| bool option_value_capture; | |||
| char option[JACK_PARAM_STRING_MAX+1]; | |||
| int option_used; | |||
| const char * address[PARAM_ADDRESS_SIZE]; | |||
| int address_index; | |||
| char * container; | |||
| char *name; | |||
| }; | |||
| @@ -80,7 +70,7 @@ jack_controller_settings_callback_chrdata(void *data, const XML_Char *s, int len | |||
| return; | |||
| } | |||
| if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_OPTION) | |||
| if (context_ptr->option_value_capture) | |||
| { | |||
| if (context_ptr->option_used + len >= JACK_PARAM_STRING_MAX) | |||
| { | |||
| @@ -97,107 +87,69 @@ jack_controller_settings_callback_chrdata(void *data, const XML_Char *s, int len | |||
| void | |||
| jack_controller_settings_callback_elstart(void *data, const char *el, const char **attr) | |||
| { | |||
| jackctl_driver_t *driver; | |||
| jackctl_internal_t *internal; | |||
| if (context_ptr->error) | |||
| { | |||
| return; | |||
| } | |||
| if (context_ptr->depth + 1 >= MAX_STACK_DEPTH) | |||
| if (context_ptr->address_index >= PARAM_ADDRESS_SIZE) | |||
| { | |||
| jack_error("xml parse max stack depth reached"); | |||
| assert(context_ptr->address_index == PARAM_ADDRESS_SIZE); | |||
| jack_error("xml param address max depth reached"); | |||
| context_ptr->error = XML_TRUE; | |||
| return; | |||
| } | |||
| //jack_info("<%s>", el); | |||
| if (strcmp(el, "jack") == 0) | |||
| { | |||
| //jack_info("<jack>"); | |||
| context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_JACK; | |||
| return; | |||
| } | |||
| if (strcmp(el, "engine") == 0) | |||
| if (strcmp(el, PTNODE_ENGINE) == 0) | |||
| { | |||
| //jack_info("<engine>"); | |||
| context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_ENGINE; | |||
| context_ptr->address[context_ptr->address_index++] = PTNODE_ENGINE; | |||
| return; | |||
| } | |||
| if (strcmp(el, "drivers") == 0) | |||
| if (strcmp(el, PTNODE_DRIVERS) == 0) | |||
| { | |||
| //jack_info("<drivers>"); | |||
| context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVERS; | |||
| context_ptr->address[context_ptr->address_index++] = PTNODE_DRIVERS; | |||
| return; | |||
| } | |||
| if (strcmp(el, "internals") == 0) | |||
| if (strcmp(el, PTNODE_INTERNALS) == 0) | |||
| { | |||
| //jack_info("<internals>"); | |||
| context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_INTERNALS; | |||
| context_ptr->address[context_ptr->address_index++] = PTNODE_INTERNALS; | |||
| return; | |||
| } | |||
| if (strcmp(el, "driver") == 0) | |||
| if (strcmp(el, "driver") == 0 || | |||
| strcmp(el, "internal") == 0) | |||
| { | |||
| if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0) | |||
| { | |||
| jack_error("<driver> XML element must contain exactly one attribute, named \"name\""); | |||
| jack_error("<%s> XML element must contain exactly one attribute, named \"name\"", el); | |||
| context_ptr->error = XML_TRUE; | |||
| return; | |||
| } | |||
| //jack_info("<driver>"); | |||
| context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVER; | |||
| driver = jack_controller_find_driver(context_ptr->controller_ptr->server, attr[1]); | |||
| if (driver == NULL) | |||
| { | |||
| jack_error("ignoring settings for unknown driver \"%s\"", attr[1]); | |||
| } | |||
| else | |||
| { | |||
| jack_info("setting for driver \"%s\" found", attr[1]); | |||
| } | |||
| context_ptr->driver = driver; | |||
| return; | |||
| } | |||
| if (strcmp(el, "internal") == 0) | |||
| { | |||
| if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0) | |||
| context_ptr->container = strdup(attr[1]); | |||
| if (context_ptr->container == NULL) | |||
| { | |||
| jack_error("<internal> XML element must contain exactly one attribute, named \"name\""); | |||
| jack_error("strdup() failed"); | |||
| context_ptr->error = XML_TRUE; | |||
| return; | |||
| } | |||
| //jack_info("<internal>"); | |||
| context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_INTERNAL; | |||
| internal = jack_controller_find_internal(context_ptr->controller_ptr->server, attr[1]); | |||
| if (internal == NULL) | |||
| { | |||
| jack_error("ignoring settings for unknown internal \"%s\"", attr[1]); | |||
| } | |||
| else | |||
| { | |||
| jack_info("setting for internal \"%s\" found", attr[1]); | |||
| } | |||
| context_ptr->internal = internal; | |||
| context_ptr->address[context_ptr->address_index++] = context_ptr->container; | |||
| return; | |||
| } | |||
| if (strcmp(el, "option") == 0) | |||
| { | |||
| //jack_info("<option>"); | |||
| if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0) | |||
| { | |||
| jack_error("<option> XML element must contain exactly one attribute, named \"name\""); | |||
| @@ -213,7 +165,8 @@ jack_controller_settings_callback_elstart(void *data, const char *el, const char | |||
| return; | |||
| } | |||
| context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_OPTION; | |||
| context_ptr->address[context_ptr->address_index++] = context_ptr->name; | |||
| context_ptr->option_value_capture = true; | |||
| context_ptr->option_used = 0; | |||
| return; | |||
| } | |||
| @@ -225,49 +178,48 @@ jack_controller_settings_callback_elstart(void *data, const char *el, const char | |||
| void | |||
| jack_controller_settings_callback_elend(void *data, const char *el) | |||
| { | |||
| int i; | |||
| if (context_ptr->error) | |||
| { | |||
| return; | |||
| } | |||
| //jack_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]); | |||
| //jack_info("</%s> (depth = %d)", el, context_ptr->address_index); | |||
| if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_OPTION) | |||
| if (strcmp(el, "option") == 0) | |||
| { | |||
| assert(context_ptr->option_value_capture); | |||
| context_ptr->option[context_ptr->option_used] = 0; | |||
| if (context_ptr->depth == 2 && | |||
| context_ptr->element[0] == PARSE_CONTEXT_JACK && | |||
| context_ptr->element[1] == PARSE_CONTEXT_ENGINE) | |||
| for (i = context_ptr->address_index; i < PARAM_ADDRESS_SIZE; i++) | |||
| { | |||
| jack_controller_settings_set_engine_option(context_ptr->controller_ptr, context_ptr->name, context_ptr->option); | |||
| context_ptr->address[context_ptr->address_index] = NULL; | |||
| } | |||
| if (context_ptr->depth == 3 && | |||
| context_ptr->element[0] == PARSE_CONTEXT_JACK && | |||
| context_ptr->element[1] == PARSE_CONTEXT_DRIVERS && | |||
| context_ptr->element[2] == PARSE_CONTEXT_DRIVER && | |||
| context_ptr->driver != NULL) | |||
| { | |||
| jack_controller_settings_set_driver_option(context_ptr->driver, context_ptr->name, context_ptr->option); | |||
| } | |||
| if (context_ptr->depth == 3 && | |||
| context_ptr->element[0] == PARSE_CONTEXT_JACK && | |||
| context_ptr->element[1] == PARSE_CONTEXT_INTERNALS && | |||
| context_ptr->element[2] == PARSE_CONTEXT_INTERNAL && | |||
| context_ptr->internal != NULL) | |||
| { | |||
| jack_controller_settings_set_internal_option(context_ptr->internal, context_ptr->name, context_ptr->option); | |||
| } | |||
| } | |||
| jack_controller_deserialize_parameter_value(context_ptr->controller_ptr, context_ptr->address, context_ptr->option); | |||
| context_ptr->depth--; | |||
| if (context_ptr->name != NULL) | |||
| { | |||
| free(context_ptr->name); | |||
| context_ptr->name = NULL; | |||
| context_ptr->option_value_capture = false; | |||
| context_ptr->address_index--; | |||
| } | |||
| else if (context_ptr->container != NULL) | |||
| { | |||
| //jack_info("'%s'", context_ptr->container); | |||
| free(context_ptr->container); | |||
| context_ptr->container = NULL; | |||
| context_ptr->address_index--; | |||
| } | |||
| else if (strcmp(el, PTNODE_ENGINE) == 0 || | |||
| strcmp(el, PTNODE_DRIVERS) == 0 || | |||
| strcmp(el, PTNODE_INTERNALS) == 0) | |||
| { | |||
| context_ptr->address_index--; | |||
| } | |||
| else | |||
| { | |||
| //jack_info("no depth decrement"); | |||
| } | |||
| } | |||
| @@ -341,14 +293,20 @@ jack_controller_settings_load( | |||
| context.controller_ptr = controller_ptr; | |||
| context.error = XML_FALSE; | |||
| context.depth = -1; | |||
| context.option_value_capture = false; | |||
| context.address_index = 0; | |||
| context.name = NULL; | |||
| context.container = NULL; | |||
| XML_SetElementHandler(parser, jack_controller_settings_callback_elstart, jack_controller_settings_callback_elend); | |||
| XML_SetCharacterDataHandler(parser, jack_controller_settings_callback_chrdata); | |||
| XML_SetUserData(parser, &context); | |||
| xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE); | |||
| free(context.name); | |||
| free(context.container); | |||
| if (xmls == XML_STATUS_ERROR) | |||
| { | |||
| jack_error("XML_ParseBuffer() failed."); | |||
| @@ -53,54 +53,57 @@ jack_controller_settings_write_string(int fd, const char * string, void *dbus_ca | |||
| struct save_context | |||
| { | |||
| void * call; | |||
| int fd; | |||
| const char *indent; | |||
| const char * indent; | |||
| jack_params_handle params; | |||
| const char * address[PARAM_ADDRESS_SIZE]; | |||
| const char * str; | |||
| }; | |||
| #define save_context_ptr ((struct save_context *)context) | |||
| #define fd (save_context_ptr->fd) | |||
| #define ctx_ptr ((struct save_context *)context) | |||
| #define fd (ctx_ptr->fd) | |||
| bool | |||
| jack_controller_settings_write_option( | |||
| void *context, | |||
| const char *name, | |||
| const char *content, | |||
| void *dbus_call_context_ptr) | |||
| static bool jack_controller_serialize_parameter(void * context, const struct jack_parameter * param_ptr) | |||
| { | |||
| if (!jack_controller_settings_write_string(fd, save_context_ptr->indent, dbus_call_context_ptr)) | |||
| { | |||
| return false; | |||
| } | |||
| if (!jack_controller_settings_write_string(fd, "<option name=\"", dbus_call_context_ptr)) | |||
| { | |||
| return false; | |||
| } | |||
| char value[JACK_PARAM_STRING_MAX + 1]; | |||
| if (!jack_controller_settings_write_string(fd, name, dbus_call_context_ptr)) | |||
| if (!param_ptr->vtable.is_set(param_ptr->obj)) | |||
| { | |||
| return false; | |||
| return true; | |||
| } | |||
| if (!jack_controller_settings_write_string(fd, "\">", dbus_call_context_ptr)) | |||
| { | |||
| return false; | |||
| } | |||
| jack_controller_serialize_parameter_value(param_ptr, value); | |||
| if (!jack_controller_settings_write_string(fd, content, dbus_call_context_ptr)) | |||
| { | |||
| return false; | |||
| } | |||
| if (!jack_controller_settings_write_string(fd, "</option>\n", dbus_call_context_ptr)) | |||
| { | |||
| return false; | |||
| } | |||
| return | |||
| jack_controller_settings_write_string(fd, ctx_ptr->indent, ctx_ptr->call) && | |||
| jack_controller_settings_write_string(fd, "<option name=\"", ctx_ptr->call) && | |||
| jack_controller_settings_write_string(fd, param_ptr->name, ctx_ptr->call) && | |||
| jack_controller_settings_write_string(fd, "\">", ctx_ptr->call) && | |||
| jack_controller_settings_write_string(fd, value, ctx_ptr->call) && | |||
| jack_controller_settings_write_string(fd, "</option>\n", ctx_ptr->call); | |||
| } | |||
| return true; | |||
| bool serialize_modules(void * context, const char * name) | |||
| { | |||
| ctx_ptr->indent = " "; | |||
| ctx_ptr->address[1] = name; | |||
| ctx_ptr->address[2] = NULL; | |||
| return | |||
| jack_controller_settings_write_string(fd, " <", ctx_ptr->call) && | |||
| jack_controller_settings_write_string(fd, ctx_ptr->str, ctx_ptr->call) && | |||
| jack_controller_settings_write_string(fd, " name=\"", ctx_ptr->call) && | |||
| jack_controller_settings_write_string(fd, name, ctx_ptr->call) && | |||
| jack_controller_settings_write_string(fd, "\">\n", ctx_ptr->call) && | |||
| jack_params_iterate_params(ctx_ptr->params, ctx_ptr->address, jack_controller_serialize_parameter, ctx_ptr) && | |||
| jack_controller_settings_write_string(fd, " </", ctx_ptr->call) && | |||
| jack_controller_settings_write_string(fd, ctx_ptr->str, ctx_ptr->call) && | |||
| jack_controller_settings_write_string(fd, ">\n", ctx_ptr->call); | |||
| } | |||
| #undef fd | |||
| #undef ctx_ptr | |||
| bool | |||
| jack_controller_settings_save( | |||
| @@ -114,9 +117,9 @@ jack_controller_settings_save( | |||
| time_t timestamp; | |||
| char timestamp_str[26]; | |||
| struct save_context context; | |||
| const JSList * node_ptr; | |||
| jackctl_driver_t *driver; | |||
| jackctl_internal_t *internal; | |||
| const char * modules[] = {"driver", "internal", NULL}; | |||
| char buffer[100]; | |||
| unsigned int i; | |||
| time(×tamp); | |||
| ctime_r(×tamp, timestamp_str); | |||
| @@ -147,6 +150,7 @@ jack_controller_settings_save( | |||
| } | |||
| context.fd = fd; | |||
| context.call = dbus_call_context_ptr; | |||
| if (!jack_controller_settings_write_string(fd, "<?xml version=\"1.0\"?>\n", dbus_call_context_ptr)) | |||
| { | |||
| @@ -196,7 +200,9 @@ jack_controller_settings_save( | |||
| } | |||
| context.indent = " "; | |||
| if (!jack_controller_settings_save_engine_options(&context, controller_ptr, dbus_call_context_ptr)) | |||
| context.address[0] = PTNODE_ENGINE; | |||
| context.address[1] = NULL; | |||
| if (!jack_params_iterate_params(controller_ptr->params, context.address, jack_controller_serialize_parameter, &context)) | |||
| { | |||
| goto exit_close; | |||
| } | |||
| @@ -206,100 +212,50 @@ jack_controller_settings_save( | |||
| goto exit_close; | |||
| } | |||
| /* drivers */ | |||
| if (!jack_controller_settings_write_string(fd, " <drivers>\n", dbus_call_context_ptr)) | |||
| for (i = 0; modules[i] != NULL; i++) | |||
| { | |||
| goto exit_close; | |||
| } | |||
| node_ptr = jackctl_server_get_drivers_list(controller_ptr->server); | |||
| while (node_ptr != NULL) | |||
| { | |||
| driver = (jackctl_driver_t *)node_ptr->data; | |||
| if (!jack_controller_settings_write_string(fd, " <driver name=\"", dbus_call_context_ptr)) | |||
| { | |||
| goto exit_close; | |||
| } | |||
| if (!jack_controller_settings_write_string(fd, jackctl_driver_get_name(driver), dbus_call_context_ptr)) | |||
| { | |||
| goto exit_close; | |||
| } | |||
| if (!jack_controller_settings_write_string(fd, "\">\n", dbus_call_context_ptr)) | |||
| if (!jack_controller_settings_write_string(fd, " <", dbus_call_context_ptr)) | |||
| { | |||
| goto exit_close; | |||
| } | |||
| context.indent = " "; | |||
| if (!jack_controller_settings_save_driver_options(&context, driver, dbus_call_context_ptr)) | |||
| if (!jack_controller_settings_write_string(fd, modules[i], dbus_call_context_ptr)) | |||
| { | |||
| goto exit_close; | |||
| } | |||
| if (!jack_controller_settings_write_string(fd, " </driver>\n", dbus_call_context_ptr)) | |||
| if (!jack_controller_settings_write_string(fd, "s>\n", dbus_call_context_ptr)) | |||
| { | |||
| goto exit_close; | |||
| } | |||
| node_ptr = jack_slist_next(node_ptr); | |||
| } | |||
| context.indent = " "; | |||
| context.params = controller_ptr->params; | |||
| context.str = modules[i]; | |||
| strcpy(buffer, modules[i]); | |||
| strcat(buffer, "s"); | |||
| context.address[0] = buffer; | |||
| context.address[1] = NULL; | |||
| if (!jack_controller_settings_write_string(fd, " </drivers>\n", dbus_call_context_ptr)) | |||
| { | |||
| goto exit_close; | |||
| } | |||
| /* internals */ | |||
| if (!jack_controller_settings_write_string(fd, " <internals>\n", dbus_call_context_ptr)) | |||
| { | |||
| goto exit_close; | |||
| } | |||
| node_ptr = jackctl_server_get_internals_list(controller_ptr->server); | |||
| while (node_ptr != NULL) | |||
| { | |||
| internal = (jackctl_internal_t *)node_ptr->data; | |||
| if (!jack_controller_settings_write_string(fd, " <internal name=\"", dbus_call_context_ptr)) | |||
| if (!jack_params_iterate_container(controller_ptr->params, context.address, serialize_modules, &context)) | |||
| { | |||
| goto exit_close; | |||
| } | |||
| if (!jack_controller_settings_write_string(fd, jackctl_internal_get_name(internal), dbus_call_context_ptr)) | |||
| if (!jack_controller_settings_write_string(fd, " </", dbus_call_context_ptr)) | |||
| { | |||
| goto exit_close; | |||
| } | |||
| if (!jack_controller_settings_write_string(fd, "\">\n", dbus_call_context_ptr)) | |||
| if (!jack_controller_settings_write_string(fd, modules[i], dbus_call_context_ptr)) | |||
| { | |||
| goto exit_close; | |||
| } | |||
| context.indent = " "; | |||
| if (!jack_controller_settings_save_internal_options(&context, internal, dbus_call_context_ptr)) | |||
| if (!jack_controller_settings_write_string(fd, "s>\n", dbus_call_context_ptr)) | |||
| { | |||
| goto exit_close; | |||
| } | |||
| if (!jack_controller_settings_write_string(fd, " </internal>\n", dbus_call_context_ptr)) | |||
| { | |||
| goto exit_close; | |||
| } | |||
| node_ptr = jack_slist_next(node_ptr); | |||
| } | |||
| if (!jack_controller_settings_write_string(fd, " </internals>\n", dbus_call_context_ptr)) | |||
| { | |||
| goto exit_close; | |||
| } | |||
| if (!jack_controller_settings_write_string(fd, "</jack>\n", dbus_call_context_ptr)) | |||