From 6642ea118da620fbe684c56dcd675290fdae4065 Mon Sep 17 00:00:00 2001 From: sletz Date: Wed, 3 Sep 2008 10:57:27 +0000 Subject: [PATCH] Implement DBUS entry points to handle internal clients, add new commands in jack_control. git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@2866 0c269be4-1314-0410-8aa9-9f06e86f4224 --- ChangeLog | 4 + example-clients/jack_control | 122 +++++++++-- linux/dbus/controller.c | 58 +++++ linux/dbus/controller_iface_configure.c | 269 ++++++++++++++++++++++++ linux/dbus/controller_iface_control.c | 42 +++- linux/dbus/controller_internal.h | 27 +++ linux/dbus/jackdbus.c | 51 +++++ linux/dbus/jackdbus.h | 9 + linux/dbus/xml.c | 65 ++++++ linux/dbus/xml_expat.c | 60 +++++- linux/dbus/xml_libxml.c | 221 +++++++++++++++++++ linux/dbus/xml_write_raw.c | 53 +++++ 12 files changed, 957 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9fa9f670..4772c87c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,6 +22,10 @@ Florian Faber Jackdmp changes log --------------------------- +2008-09-03 Stephane Letz + + * Implement DBUS entry points to handle internal clients, add new commands in jack_control." + 2008-09-01 Stephane Letz * Add new jack_set_port_rename_callback API, jack_port_set_name is now a server request that call port rename callbacks. diff --git a/example-clients/jack_control b/example-clients/jack_control index 676c0b27..3a95af38 100755 --- a/example-clients/jack_control +++ b/example-clients/jack_control @@ -84,19 +84,25 @@ def main(): if len(sys.argv) == 1: print "Usage: %s [command] [command] ..." % os.path.basename(sys.argv[0]) print "Commands:" - print " exit - exit jack dbus service (stops jack server if currently running)" - print " status - check whether jack server is started, return value is 0 if runing and 1 otherwise" - print " start - start jack server if not currently started" - print " stop - stop jack server if currenly started" - print " dl - get list of available drivers" - print " dg - get currently selected driver" - print " ds - select driver" - print " dp - get parameters of currently selected driver" - print " dpd - get long description for driver parameter" - print " dps - set driver parameter" - print " ep - get engine parameters" - print " epd - get long description for engine parameter" - print " eps - set engine parameter" + print " exit - exit jack dbus service (stops jack server if currently running)" + print " status - check whether jack server is started, return value is 0 if runing and 1 otherwise" + print " start - start jack server if not currently started" + print " stop - stop jack server if currenly started" + print " dl - get list of available drivers" + print " dg - get currently selected driver" + print " ds - select driver" + print " dp - get parameters of currently selected driver" + print " dpd - get long description for driver parameter" + print " dps - set driver parameter" + print " il - get list of available internals" + print " ip - get parameters of given internal" + print " ipd - get long description for internal parameter" + print " ips - set internal parameter" + print " iload - load internal" + print " iunload - unload internal" + print " ep - get engine parameters" + print " epd - get long description for engine parameter" + print " eps - set engine parameter" sys.exit(0) bus = dbus.SessionBus() @@ -179,7 +185,7 @@ def main(): print "%20s: %s (%s:%s:%s:%s)" %(name, descr, typestr, isset, default, value) elif arg == 'dpd': if index >= len(sys.argv): - print "get driver parameter long description command requires driver name argument" + print "get driver parameter long description command requires parameter name argument" sys.exit() param = sys.argv[index] @@ -190,7 +196,7 @@ def main(): print long_descr, elif arg == 'dps': if index + 1 >= len(sys.argv): - print "driver parameter set command requires parametr name and value arguments" + print "driver parameter set command requires parameter name and value arguments" sys.exit() param = sys.argv[index] @@ -226,7 +232,7 @@ def main(): print "%20s: %s (%s:%s:%s:%s)" %(name, descr, typestr, isset, default, value) elif arg == 'epd': if index >= len(sys.argv): - print "get engine parameter long description command requires driver name argument" + print "get engine parameter long description command requires parameter name argument" sys.exit() param_name = sys.argv[index] @@ -238,7 +244,7 @@ def main(): print long_descr, elif arg == 'eps': if index + 1 >= len(sys.argv): - print "engine parameter set command requires parametr name and value arguments" + print "engine parameter set command requires parameter name and value arguments" sys.exit() param = sys.argv[index] @@ -250,6 +256,88 @@ def main(): type_char, name, short_descr, long_descr = configure_iface.GetEngineParameterInfo(param) configure_iface.SetEngineParameterValue(param, python_type_to_jackdbus_type(value, type_char)) + elif arg == 'il': + print "--- internals list" + internals = configure_iface.GetAvailableInternals() + for internal in internals: + print internal + elif arg == 'ip': + print "--- get internal parameters (type:isset:default:value)" + + if index >= len(sys.argv): + print "internal parameters command requires internal name argument" + sys.exit() + + internal_name = sys.argv[index] + index += 1 + params = configure_iface.GetInternalParametersInfo(internal_name) + + #print params + for param in params: + typestr = dbus_typesig_to_type_string(param[0]) + name = param[1] + #print name + descr = param[2] + #print descr + isset, default, value = configure_iface.GetInternalParameterValue(internal_name, name) + #print typestr + if bool(isset): + isset = "set" + else: + isset = "notset" + value = dbus_type_to_python_type(value) + default = dbus_type_to_python_type(default) + + print "%20s: %s (%s:%s:%s:%s)" %(name, descr, typestr, isset, default, value) + elif arg == 'ipd': + if index + 1 >= len(sys.argv): + print "get internal parameter long description command requires internal and parameter name arguments" + sys.exit() + + name = sys.argv[index] + index += 1 + param = sys.argv[index] + index += 1 + + print "--- get internal parameter description (%s)" % param + type_char, name, short_descr, long_descr = configure_iface.GetInternalParameterInfo(name, param) + print long_descr + elif arg == 'ips': + if index + 2 >= len(sys.argv): + print "get internal parameter long description command requires internal, parameter name and value arguments" + sys.exit() + + internal_name = sys.argv[index] + index += 1 + param = sys.argv[index] + index += 1 + value = sys.argv[index] + index += 1 + + print "--- internal param set \"%s\" -> \"%s\"" % (param, value) + + type_char, name, short_descr, long_descr = configure_iface.GetInternalParameterInfo(internal_name, param) + configure_iface.SetInternalParameterValue(internal_name, param, python_type_to_jackdbus_type(value, type_char)) + elif arg == 'iload': + print "--- load internal" + + if index >= len(sys.argv): + print "load internal command requires internal name argument" + sys.exit() + + name = sys.argv[index] + index += 1 + result = control_iface.LoadInternal(name) + elif arg == 'iunload': + print "--- unload internal" + + if index >= len(sys.argv): + print "unload internal command requires internal name argument" + sys.exit() + + name = sys.argv[index] + index += 1 + result = control_iface.UnloadInternal(name) else: print "Unknown command '%s'" % arg except dbus.DBusException, e: diff --git a/linux/dbus/controller.c b/linux/dbus/controller.c index 31e0bfaa..01bc3b3b 100644 --- a/linux/dbus/controller.c +++ b/linux/dbus/controller.c @@ -62,6 +62,28 @@ jack_controller_find_driver( return NULL; } +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; +} + jackctl_parameter_t * jack_controller_find_parameter( const JSList * parameters_list, @@ -344,6 +366,42 @@ fail: return NULL; } +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 diff --git a/linux/dbus/controller_iface_configure.c b/linux/dbus/controller_iface_configure.c index 99a46c05..804b19b2 100644 --- a/linux/dbus/controller_iface_configure.c +++ b/linux/dbus/controller_iface_configure.c @@ -764,6 +764,241 @@ jack_controller_dbus_set_engine_parameter_value( jack_dbus_construct_method_return_empty(call); } +static +void +jack_controller_dbus_get_available_internals( + struct jack_dbus_method_call *call) +{ + jack_dbus_construct_method_return_array_of_strings( + call, + controller_ptr->internals_count, + controller_ptr->internal_names); +} + +/* + * Execute GetInternalParametersInfo method call. + */ +static +void +jack_controller_dbus_get_internal_parameters_info( + struct jack_dbus_method_call *call) +{ + const char *internal_name; + jackctl_internal_t * internal; + + if (!jack_dbus_get_method_args(call, DBUS_TYPE_STRING, &internal_name, DBUS_TYPE_INVALID)) + { + /* The method call had invalid arguments meaning that + * get_method_args() has constructed an error for us. + */ + return; + } + + internal = jack_controller_find_internal(controller_ptr->server, internal_name); + if (internal == NULL) + { + jack_dbus_error( + call, + JACK_DBUS_ERROR_UNKNOWN_INTERNAL, + "Unknown internal \"%s\"", + internal_name); + return; + } + + jack_controller_get_parameters_info(call, jackctl_internal_get_parameters(internal)); +} + +/* + * Execute GetInternalParameterInfo method call. + */ +static +void +jack_controller_dbus_get_internal_parameter_info( + struct jack_dbus_method_call *call) +{ + const char *internal_name; + const char *parameter_name; + jackctl_parameter_t *parameter; + jackctl_internal_t * internal; + + if (!jack_dbus_get_method_args(call, DBUS_TYPE_STRING, &internal_name, DBUS_TYPE_STRING, ¶meter_name, DBUS_TYPE_INVALID)) + { + /* The method call had invalid arguments meaning that + * get_method_args() has constructed an error for us. + */ + return; + } + + internal = jack_controller_find_internal(controller_ptr->server, internal_name); + if (internal == NULL) + { + jack_dbus_error( + call, + JACK_DBUS_ERROR_UNKNOWN_INTERNAL, + "Unknown internal \"%s\"", + internal_name); + return; + } + + parameter = jack_controller_find_parameter(jackctl_internal_get_parameters(internal), parameter_name); + if (parameter == NULL) + { + jack_dbus_error( + call, + JACK_DBUS_ERROR_UNKNOWN_DRIVER_PARAMETER, + "Unknown parameter \"%s\" for driver \"%s\"", + parameter_name, + jackctl_driver_get_name(controller_ptr->driver)); + return; + } + + jack_controller_get_parameter_info(call, parameter); +} + +/* + * Execute GetInternalParameterValue method call. + */ +static void +jack_controller_dbus_get_internal_parameter_value( + struct jack_dbus_method_call *call) +{ + const char *internal_name; + const char *parameter_name; + jackctl_parameter_t *parameter; + jackctl_internal_t * internal; + int type; + union jackctl_parameter_value jackctl_value; + union jackctl_parameter_value jackctl_default_value; + message_arg_t value; + message_arg_t default_value; + + if (!jack_dbus_get_method_args(call, DBUS_TYPE_STRING, &internal_name, DBUS_TYPE_STRING, ¶meter_name, DBUS_TYPE_INVALID)) + { + /* The method call had invalid arguments meaning that + * get_method_args() has constructed an error for us. + */ + return; + } + + internal = jack_controller_find_internal(controller_ptr->server, internal_name); + if (internal == NULL) + { + jack_dbus_error( + call, + JACK_DBUS_ERROR_UNKNOWN_INTERNAL, + "Unknown internal \"%s\"", + internal_name); + return; + } + + parameter = jack_controller_find_parameter(jackctl_internal_get_parameters(internal), parameter_name); + if (parameter == NULL) + { + jack_dbus_error( + call, + JACK_DBUS_ERROR_UNKNOWN_DRIVER_PARAMETER, + "Unknown parameter \"%s\" for driver \"%s\"", + parameter, + jackctl_driver_get_name(controller_ptr->driver)); + return; + } + + type = jackctl_parameter_get_type(parameter); + jackctl_default_value = jackctl_parameter_get_default_value(parameter); + jackctl_value = jackctl_parameter_get_value(parameter); + + jack_controller_jack_to_dbus_variant(type, &jackctl_value, &value); + jack_controller_jack_to_dbus_variant(type, &jackctl_default_value, &default_value); + + /* Construct the reply. */ + jack_dbus_construct_method_return_parameter( + call, + (dbus_bool_t)(jackctl_parameter_is_set(parameter) ? TRUE : FALSE), + PARAM_TYPE_JACK_TO_DBUS(type), + PARAM_TYPE_JACK_TO_DBUS_SIGNATURE(type), + default_value, + value); +} + +static +void +jack_controller_dbus_set_internal_parameter_value( + struct jack_dbus_method_call *call) +{ + const char *internal_name; + const char *parameter_name; + jackctl_internal_t * internal; + message_arg_t arg; + int arg_type; + jackctl_parameter_t *parameter; + jackctl_param_type_t type; + union jackctl_parameter_value value; + + if (!jack_dbus_get_method_args_two_strings_and_variant(call, &internal_name, ¶meter_name, &arg, &arg_type)) + { + /* The method call had invalid arguments meaning that + * jack_dbus_get_method_args_two_strings_and_variant() has constructed + * an error for us. + */ + return; + } + + internal = jack_controller_find_internal(controller_ptr->server, internal_name); + if (internal == NULL) + { + jack_dbus_error( + call, + JACK_DBUS_ERROR_UNKNOWN_INTERNAL, + "Unknown internal \"%s\"", + internal_name); + return; + } + + parameter = jack_controller_find_parameter(jackctl_internal_get_parameters(internal), parameter_name); + if (parameter == NULL) + { + jack_dbus_error( + call, + JACK_DBUS_ERROR_UNKNOWN_DRIVER_PARAMETER, + "Unknown parameter \"%s\" for driver \"%s\"", + parameter, + jackctl_driver_get_name(controller_ptr->driver)); + return; + } + + type = jackctl_parameter_get_type(parameter); + + if (PARAM_TYPE_JACK_TO_DBUS(type) != arg_type) + { + jack_dbus_error( + call, + JACK_DBUS_ERROR_INVALID_ARGS, + "Engine parameter value type mismatch: was expecting '%c', got '%c'", + (char)PARAM_TYPE_JACK_TO_DBUS(type), + (char)arg_type); + return; + } + + if (!jack_controller_dbus_to_jack_variant( + arg_type, + &arg, + &value)) + { + jack_dbus_error( + call, + JACK_DBUS_ERROR_INVALID_ARGS, + "Cannot convert engine parameter value"); + return; + } + + jackctl_parameter_set_value(parameter, &value); + + jack_controller_settings_save_auto(controller_ptr); + + jack_dbus_construct_method_return_empty(call); +} + + #undef controller_ptr JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetAvailableDrivers) @@ -820,6 +1055,35 @@ JACK_DBUS_METHOD_ARGUMENTS_BEGIN(SetEngineParameterValue) JACK_DBUS_METHOD_ARGUMENT("value", "v", false) JACK_DBUS_METHOD_ARGUMENTS_END +JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetAvailableInternals) + JACK_DBUS_METHOD_ARGUMENT("internals_list", "as", true) +JACK_DBUS_METHOD_ARGUMENTS_END + +JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetInternalParametersInfo) + JACK_DBUS_METHOD_ARGUMENT("internal", "s", false) + JACK_DBUS_METHOD_ARGUMENT("parameter_info_array", "a(ysss)", true) +JACK_DBUS_METHOD_ARGUMENTS_END + +JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetInternalParameterInfo) + JACK_DBUS_METHOD_ARGUMENT("internal", "s", false) + JACK_DBUS_METHOD_ARGUMENT("parameter", "s", false) + JACK_DBUS_METHOD_ARGUMENT("parameter_info", "(ysss)", true) +JACK_DBUS_METHOD_ARGUMENTS_END + +JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetInternalParameterValue) + JACK_DBUS_METHOD_ARGUMENT("internal", "s", false) + JACK_DBUS_METHOD_ARGUMENT("parameter", "s", false) + JACK_DBUS_METHOD_ARGUMENT("is_set", "b", true) + JACK_DBUS_METHOD_ARGUMENT("default", "v", true) + JACK_DBUS_METHOD_ARGUMENT("value", "v", true) +JACK_DBUS_METHOD_ARGUMENTS_END + +JACK_DBUS_METHOD_ARGUMENTS_BEGIN(SetInternalParameterValue) + JACK_DBUS_METHOD_ARGUMENT("internal", "s", false) + JACK_DBUS_METHOD_ARGUMENT("parameter", "s", false) + JACK_DBUS_METHOD_ARGUMENT("value", "v", false) +JACK_DBUS_METHOD_ARGUMENTS_END + JACK_DBUS_METHODS_BEGIN JACK_DBUS_METHOD_DESCRIBE(GetAvailableDrivers, jack_controller_dbus_get_available_drivers) JACK_DBUS_METHOD_DESCRIBE(GetSelectedDriver, jack_controller_dbus_get_selected_driver) @@ -832,6 +1096,11 @@ JACK_DBUS_METHODS_BEGIN JACK_DBUS_METHOD_DESCRIBE(GetEngineParameterInfo, jack_controller_dbus_get_engine_parameter_info) JACK_DBUS_METHOD_DESCRIBE(GetEngineParameterValue, jack_controller_dbus_get_engine_parameter_value) JACK_DBUS_METHOD_DESCRIBE(SetEngineParameterValue, jack_controller_dbus_set_engine_parameter_value) + JACK_DBUS_METHOD_DESCRIBE(GetAvailableInternals, jack_controller_dbus_get_available_internals) + JACK_DBUS_METHOD_DESCRIBE(GetInternalParametersInfo, jack_controller_dbus_get_internal_parameters_info) + JACK_DBUS_METHOD_DESCRIBE(GetInternalParameterInfo, jack_controller_dbus_get_internal_parameter_info) + JACK_DBUS_METHOD_DESCRIBE(GetInternalParameterValue, jack_controller_dbus_get_internal_parameter_value) + JACK_DBUS_METHOD_DESCRIBE(SetInternalParameterValue, jack_controller_dbus_set_internal_parameter_value) JACK_DBUS_METHODS_END JACK_DBUS_IFACE_BEGIN(g_jack_controller_iface_configure, "org.jackaudio.JackConfigure") diff --git a/linux/dbus/controller_iface_control.c b/linux/dbus/controller_iface_control.c index 5394ebcd..7dfc8016 100644 --- a/linux/dbus/controller_iface_control.c +++ b/linux/dbus/controller_iface_control.c @@ -76,7 +76,7 @@ jack_control_run_method( if (strcmp (call->method_name, "Exit") == 0) { - g_exit_command = TRUE; + g_exit_command = TRUE; } else if (strcmp (call->method_name, "IsStarted") == 0) { @@ -185,6 +185,34 @@ jack_control_run_method( { controller_ptr->xruns = 0; } + else if (strcmp (call->method_name, "LoadInternal") == 0) + { + const char *internal_name; + + if (!jack_dbus_get_method_args(call, DBUS_TYPE_STRING, &internal_name, DBUS_TYPE_INVALID)) + { + /* The method call had invalid arguments meaning that + * get_method_args() has constructed an error for us. + */ + goto exit; + } + type = DBUS_TYPE_BOOLEAN; + arg.boolean = jack_controller_load_internal(controller_ptr, internal_name) ? TRUE : FALSE; + } + else if (strcmp (call->method_name, "UnloadInternal") == 0) + { + const char *internal_name; + + if (!jack_dbus_get_method_args(call, DBUS_TYPE_STRING, &internal_name, DBUS_TYPE_INVALID)) + { + /* The method call had invalid arguments meaning that + * get_method_args() has constructed an error for us. + */ + goto exit; + } + type = DBUS_TYPE_BOOLEAN; + arg.boolean = jack_controller_unload_internal(controller_ptr, internal_name) ? TRUE : FALSE; + } else { return false; @@ -245,6 +273,16 @@ JACK_DBUS_METHOD_ARGUMENTS_END JACK_DBUS_METHOD_ARGUMENTS_BEGIN(ResetXruns) JACK_DBUS_METHOD_ARGUMENTS_END +JACK_DBUS_METHOD_ARGUMENTS_BEGIN(LoadInternal) + JACK_DBUS_METHOD_ARGUMENT("internal", "s", false) + JACK_DBUS_METHOD_ARGUMENT("result", "b", true) +JACK_DBUS_METHOD_ARGUMENTS_END + +JACK_DBUS_METHOD_ARGUMENTS_BEGIN(UnlooadInternal) + JACK_DBUS_METHOD_ARGUMENT("internal", "s", false) + JACK_DBUS_METHOD_ARGUMENT("result", "b", true) +JACK_DBUS_METHOD_ARGUMENTS_END + JACK_DBUS_METHODS_BEGIN JACK_DBUS_METHOD_DESCRIBE(IsStarted, NULL) JACK_DBUS_METHOD_DESCRIBE(StartServer, NULL) @@ -257,6 +295,8 @@ JACK_DBUS_METHODS_BEGIN JACK_DBUS_METHOD_DESCRIBE(SetBufferSize, NULL) JACK_DBUS_METHOD_DESCRIBE(IsRealtime, NULL) JACK_DBUS_METHOD_DESCRIBE(ResetXruns, NULL) + JACK_DBUS_METHOD_DESCRIBE(LoadInternal, NULL) + JACK_DBUS_METHOD_DESCRIBE(UnlooadInternal, NULL) JACK_DBUS_METHODS_END JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(ServerStarted) diff --git a/linux/dbus/controller_internal.h b/linux/dbus/controller_internal.h index aad44eed..df875bca 100644 --- a/linux/dbus/controller_internal.h +++ b/linux/dbus/controller_internal.h @@ -58,6 +58,11 @@ jackctl_driver_t * jack_controller_find_driver( jackctl_server_t *server, const char *driver_name); + +jackctl_internal_t * +jack_controller_find_internal( + jackctl_server_t *server, + const char *internal_name); jackctl_parameter_t * jack_controller_find_parameter( @@ -79,12 +84,28 @@ jack_controller_select_driver( struct jack_controller *controller_ptr, const char * driver_name); +bool +jack_controller_load_internal( + struct jack_controller *controller_ptr, + const char * internal_name); + +bool +jack_controller_unload_internal( + struct jack_controller *controller_ptr, + 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( struct jack_controller *controller_ptr, @@ -110,6 +131,12 @@ jack_controller_settings_save_driver_options( 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); + bool jack_controller_patchbay_init( struct jack_controller *controller_ptr); diff --git a/linux/dbus/jackdbus.c b/linux/dbus/jackdbus.c index 685ad8b8..186741e5 100644 --- a/linux/dbus/jackdbus.c +++ b/linux/dbus/jackdbus.c @@ -339,6 +339,57 @@ jack_dbus_get_method_args_string_and_variant( return false; } +/* + * Read two strings and a variant argument from a method call. + * If the operation fails construct an error and return false, + * otherwise return true. + */ +bool +jack_dbus_get_method_args_two_strings_and_variant( + struct jack_dbus_method_call *call, + const char **arg1, + const char **arg2, + message_arg_t *arg3, + int *type_ptr) +{ + DBusMessageIter iter, sub_iter; + + /* First we want a string... */ + if (dbus_message_iter_init (call->message, &iter) + && dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING) + { + dbus_message_iter_get_basic (&iter, arg1); + dbus_message_iter_next (&iter); + + /* ...and then a second string. */ + if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING) + { + return false; + } + + /* Got what we wanted. */ + dbus_message_iter_get_basic (&iter, arg2); + dbus_message_iter_next (&iter); + + /* ...and then a variant. */ + if (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_VARIANT) + { + dbus_message_iter_recurse (&iter, &sub_iter); + dbus_message_iter_get_basic (&sub_iter, arg3); + *type_ptr = dbus_message_iter_get_arg_type (&sub_iter); + + /* Got what we wanted. */ + return true; + } + } + + jack_dbus_error (call, JACK_DBUS_ERROR_INVALID_ARGS, + "Invalid arguments to method \"%s\"", + call->method_name); + + return false; +} + /* * Append a variant type to a D-Bus message. * Return false if something fails, true otherwise. diff --git a/linux/dbus/jackdbus.h b/linux/dbus/jackdbus.h index 245a8c02..e2ebef2c 100644 --- a/linux/dbus/jackdbus.h +++ b/linux/dbus/jackdbus.h @@ -50,6 +50,7 @@ jack_controller_settings_uninit(); #define JACK_DBUS_ERROR_NEED_DRIVER "org.jackaudio.Error.NeedDriver" #define JACK_DBUS_ERROR_UNKNOWN_DRIVER_PARAMETER "org.jackaudio.Error.UnknownDriverParameter" #define JACK_DBUS_ERROR_UNKNOWN_ENGINE_PARAMETER "org.jackaudio.Error.UnknownEngineParameter" +#define JACK_DBUS_ERROR_UNKNOWN_INTERNAL "org.jackaudio.Error.UnknownInternal" #define JACK_DBUS_ERROR_INVALID_ARGS "org.jackaudio.Error.InvalidArgs" #define JACK_DBUS_ERROR_GENERIC "org.jackaudio.Error.Generic" #define JACK_DBUS_ERROR_FATAL "org.jackaudio.Error.Fatal" @@ -245,6 +246,14 @@ jack_dbus_get_method_args_string_and_variant( message_arg_t *arg2, int *type_ptr); +bool +jack_dbus_get_method_args_two_strings_and_variant( + struct jack_dbus_method_call *call, + const char **arg1, + const char **arg2, + message_arg_t *arg3, + int *type_ptr); + bool jack_dbus_message_append_variant( DBusMessageIter *iter, diff --git a/linux/dbus/xml.c b/linux/dbus/xml.c index c5ad2eb9..182b60ff 100644 --- a/linux/dbus/xml.c +++ b/linux/dbus/xml.c @@ -153,6 +153,62 @@ jack_controller_settings_set_driver_option( 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; + unsigned int value_uint; + 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) + { + 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); + } + + jackctl_parameter_set_value(parameter, &value); +} + void jack_controller_settings_set_engine_option( struct jack_controller *controller_ptr, @@ -315,3 +371,12 @@ jack_controller_settings_save_driver_options( { 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); +} diff --git a/linux/dbus/xml_expat.c b/linux/dbus/xml_expat.c index 05c684a7..a2b2dc28 100644 --- a/linux/dbus/xml_expat.c +++ b/linux/dbus/xml_expat.c @@ -46,12 +46,14 @@ 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_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 @@ -62,6 +64,7 @@ struct parse_context unsigned int element[MAX_STACK_DEPTH]; signed int depth; jackctl_driver_t *driver; + jackctl_internal_t *internal; char option[JACK_PARAM_STRING_MAX+1]; int option_used; char *name; @@ -95,6 +98,7 @@ 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) { @@ -128,6 +132,13 @@ jack_controller_settings_callback_elstart(void *data, const char *el, const char context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVERS; return; } + + if (strcmp(el, "internals") == 0) + { + //jack_info(""); + context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_INTERNALS; + return; + } if (strcmp(el, "driver") == 0) { @@ -155,6 +166,34 @@ jack_controller_settings_callback_elstart(void *data, const char *el, const char return; } + + if (strcmp(el, "internal") == 0) + { + if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "name") != 0) + { + jack_error(" XML element must contain exactly one attribute, named \"name\""); + context_ptr->error = XML_TRUE; + return; + } + + //jack_info(""); + 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; + + return; + } + if (strcmp(el, "option") == 0) { @@ -212,6 +251,15 @@ jack_controller_settings_callback_elend(void *data, const char *el) { 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); + } } context_ptr->depth--; diff --git a/linux/dbus/xml_libxml.c b/linux/dbus/xml_libxml.c index df4b49ef..8644182d 100644 --- a/linux/dbus/xml_libxml.c +++ b/linux/dbus/xml_libxml.c @@ -215,6 +215,87 @@ jack_controller_settings_write_drivers( return true; } +bool +jack_controller_settings_write_internal( + struct jack_controller * controller_ptr, + xmlTextWriterPtr writer, + jackctl_internal internal, + void *dbus_call_context_ptr) +{ +/* if (xmlTextWriterWriteComment(writer, BAD_CAST "driver parameters") == -1) */ +/* { */ +/* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */ +/* return false; */ +/* } */ + + if (xmlTextWriterStartElement(writer, BAD_CAST "internal") == -1) + { + jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed."); + return false; + } + + if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST jackctl_internal_get_name(driver)) == -1) + { + jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed."); + return false; + } + + if (!jack_controller_settings_save_internal_options(writer, internal, dbus_call_context_ptr)) + { + return false; + } + + if (xmlTextWriterEndElement(writer) == -1) + { + jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed."); + return false; + } + + return true; +} + +bool +jack_controller_settings_write_internals( + struct jack_controller * controller_ptr, + xmlTextWriterPtr writer, + void *dbus_call_context_ptr) +{ + const JSList * node_ptr; + jackctl_driver internal; + + if (xmlTextWriterStartElement(writer, BAD_CAST "internals") == -1) + { + jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed."); + return false; + } + + node_ptr = jackctl_server_get_internals_list(controller_ptr->server); + + while (node_ptr != NULL) + { + internal = (jackctl_internal)node_ptr->data; + + if (!jack_controller_settings_write_internal( + controller_ptr, + writer, + internal, + dbus_call_context_ptr)) + { + return false; + } + + node_ptr = jack_slist_next(node_ptr); + } + + if (xmlTextWriterEndElement(writer) == -1) + { + jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed."); + return false; + } + + return true; +} + bool jack_controller_settings_save( struct jack_controller * controller_ptr, @@ -295,6 +376,11 @@ jack_controller_settings_save( { goto fail_free_writter; } + + if (!jack_controller_settings_write_internals(controller_ptr, writer, dbus_call_context_ptr)) + { + goto fail_free_writter; + } if (xmlTextWriterEndElement(writer) == -1) { @@ -466,6 +552,91 @@ exit: return; } +void +jack_controller_settings_read_internal( + struct jack_controller * controller_ptr, + xmlXPathContextPtr xpath_ctx_ptr, + jackctl_internal internal) +{ + char *xpath; + size_t xpath_len; + xmlXPathObjectPtr xpath_obj_ptr; + xmlBufferPtr content_buffer_ptr; + int i; + const char *option_name; + const char *option_value; + const char *internal_name; + + internal_name = jackctl_internal_get_name(internal); + + jack_info("reading options for internal \"%s\"", internal_name); + + xpath_len = snprintf(NULL, 0, XPATH_DRIVER_OPTIONS_EXPRESSION, internal_name); + + xpath = malloc(xpath_len); + if (xpath == NULL) + { + jack_error("Out of memory."); + goto exit; + } + + snprintf(xpath, xpath_len, XPATH_DRIVER_OPTIONS_EXPRESSION, internal_name); + + //jack_info("xpath = \"%s\"", xpath); + + /* Evaluate xpath expression */ + xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)xpath, xpath_ctx_ptr); + if (xpath_obj_ptr == NULL) + { + jack_error("Unable to evaluate XPath expression \"%s\"", xpath); + goto free_xpath; + } + + if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0) + { + //jack_info("XPath \"%s\" evaluation returned no data", xpath); + goto free_xpath_obj; + } + + content_buffer_ptr = xmlBufferCreate(); + if (content_buffer_ptr == NULL) + { + jack_error("xmlBufferCreate() failed."); + goto free_xpath_obj; + } + + for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++) + { + //jack_info("driver option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i); + + if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1) + { + jack_error("xmlNodeBufGetContent() failed."); + goto next_option; + } + + option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"); + option_value = (const char *)xmlBufferContent(content_buffer_ptr); + + jack_controller_settings_set_internal_option(internal, option_name, option_value); + + next_option: + xmlBufferEmpty(content_buffer_ptr); + } + +//free_buffer: + xmlBufferFree(content_buffer_ptr); + +free_xpath_obj: + xmlXPathFreeObject(xpath_obj_ptr); + +free_xpath: + free(xpath); + +exit: + return; +} + void jack_controller_settings_read_drivers( struct jack_controller * controller_ptr, @@ -514,6 +685,55 @@ exit: return; } +void +jack_controller_settings_read_internals( + struct jack_controller * controller_ptr, + xmlXPathContextPtr xpath_ctx_ptr) +{ + xmlXPathObjectPtr xpath_obj_ptr; + int i; + const char *internal_name; + jackctl_internal internal; + + /* Evaluate xpath expression */ + xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_DRIVERS_EXPRESSION, xpath_ctx_ptr); + if (xpath_obj_ptr == NULL) + { + jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_DRIVERS_EXPRESSION); + goto exit; + } + + if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0) + { + jack_error("XPath \"%s\" evaluation returned no data", XPATH_DRIVERS_EXPRESSION); + goto free_xpath_obj; + } + + for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++) + { + internal_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"); + + driver = jack_controller_find_internal(controller_ptr->server, driver_name); + if (driver == NULL) + { + jack_error("ignoring settings for unknown internal \"%s\"", internal_name); + } + else + { + jack_info("setting for internal \"%s\" found", internal_name); + + jack_controller_settings_read_internal(controller_ptr, xpath_ctx_ptr, driver); + } + } + +free_xpath_obj: + xmlXPathFreeObject(xpath_obj_ptr); + +exit: + return; +} + + void jack_controller_settings_load( struct jack_controller * controller_ptr) @@ -555,6 +775,7 @@ jack_controller_settings_load( jack_controller_settings_read_engine(controller_ptr, xpath_ctx_ptr); jack_controller_settings_read_drivers(controller_ptr, xpath_ctx_ptr); + jack_controller_settings_read_internals(controller_ptr, xpath_ctx_ptr); xmlXPathFreeContext(xpath_ctx_ptr); diff --git a/linux/dbus/xml_write_raw.c b/linux/dbus/xml_write_raw.c index 864dbed4..13b96345 100644 --- a/linux/dbus/xml_write_raw.c +++ b/linux/dbus/xml_write_raw.c @@ -116,6 +116,7 @@ jack_controller_settings_save( struct save_context context; const JSList * node_ptr; jackctl_driver_t *driver; + jackctl_internal_t *internal; time(×tamp); ctime_r(×tamp, timestamp_str); @@ -186,6 +187,8 @@ jack_controller_settings_save( { goto exit_close; } + + /* engine */ if (!jack_controller_settings_write_string(fd, " \n", dbus_call_context_ptr)) { @@ -203,6 +206,8 @@ jack_controller_settings_save( goto exit_close; } + /* drivers */ + if (!jack_controller_settings_write_string(fd, " \n", dbus_call_context_ptr)) { goto exit_close; @@ -248,6 +253,54 @@ jack_controller_settings_save( { goto exit_close; } + + /* internals */ + + if (!jack_controller_settings_write_string(fd, " \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, " \n", dbus_call_context_ptr)) + { + goto exit_close; + } + + context.indent = " "; + + if (!jack_controller_settings_save_internal_options(&context, internal, dbus_call_context_ptr)) + { + goto exit_close; + } + + if (!jack_controller_settings_write_string(fd, " \n", dbus_call_context_ptr)) + { + goto exit_close; + } + + node_ptr = jack_slist_next(node_ptr); + } + + if (!jack_controller_settings_write_string(fd, " \n", dbus_call_context_ptr)) + { + goto exit_close; + } if (!jack_controller_settings_write_string(fd, "\n", dbus_call_context_ptr)) {