diff --git a/TODO.dbus b/TODO.dbus new file mode 100644 --- /dev/null +++ b/TODO.dbus @@ -0,0 +1,5 @@ + * Provide access to clock source parameter (tricky) + * Provide access to debug-timer parameter (not fully documented - optarg) + * Send signals to (control) apps (status changes, connections, clients, port renames, xruns, error and info logs) + * In client library, when compiled with dbus support, try to start via dbus frontend first (auto-activation) + * Implement configurator supporting multiple user configurations (separate D-Bus object) diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -547,6 +547,43 @@ fi # PKG_CHECK_MODULES inside a --disable-whatever check, you need to # do it somewhere *below* this comment. +AC_ARG_ENABLE(dbus, [ --disable-dbus don't build D-Bus integration ], + TRY_DBUS=$enableval , TRY_DBUS=yes ) +HAVE_DBUS=false +if test "x$TRY_DBUS" = "xyes" +then + PKG_CHECK_MODULES(DBUSGLIB, dbus-glib-1, [AC_DEFINE([HAVE_DBUS], 1, [Defined if D-Bus support needs to be built.]) HAVE_DBUS=true], [true]) +fi + +AM_CONDITIONAL(HAVE_DBUS, $HAVE_DBUS) + +AC_ARG_ENABLE(pkg-config-dbus-service-dir, + [ --enable-pkg-config-dbus-service-dir force D-Bus service install dir to be one returned by pkg-config ], + DBUS_SERVICES_DIR_FORCE_REAL=$enableval , DBUS_SERVICES_DIR_FORCE_REAL=no ) + +if test "x$HAVE_DBUS" = "xtrue" +then + DBUS_SERVICES_DIR_REAL=`$PKG_CONFIG --variable=session_bus_services_dir dbus-1` + if test "x$DBUS_SERVICES_DIR_FORCE_REAL" = "xyes" + then + AC_MSG_WARN([overriding D-Bus service install dir]) + DBUS_SERVICES_DIR="$DBUS_SERVICES_DIR_REAL" + else + AS_AC_EXPAND(DATADIR, $datadir) + DBUS_SERVICES_DIR="$DATADIR/dbus-1/services" + fi + AC_SUBST(DBUS_SERVICES_DIR) + AC_DEFINE_UNQUOTED(DBUS_SERVICES_DIR, "$DBUS_SERVICES_DIR", [Where services dir for DBUS is]) +fi + +HAVE_LIBXML2=false +PKG_CHECK_MODULES(LIBXML2, libxml-2.0, [AC_DEFINE([HAVE_LIBXML2], 1, [Defined if libxml2 is present.]) HAVE_LIBXML2=true], [true]) +AM_CONDITIONAL(HAVE_LIBXML2, $HAVE_LIBXML2) + +AC_CHECK_LIB(expat, XML_ParserCreate_MM, + [ AC_CHECK_HEADERS(expat.h, HAVE_EXPAT=true, HAVE_EXPAT=false) ], + HAVE_EXPAT=false) + # Check which backend drivers can be built. The last one successfully # configured becomes the default JACK driver; so the order of # precedence is: alsa, oss, coreaudio, portaudio, dummy. @@ -690,6 +727,39 @@ AM_CONDITIONAL(USE_CAPABILITIES, $USE_CA AM_CONDITIONAL(USE_CAPABILITIES, $USE_CAPABILITIES) AM_CONDITIONAL(STRIPPED_JACKD, $STRIPPED_JACKD) +SETTINGS_PERSISTENCE_WARNING= +SETTINGS_PERSISTENCE_USE_LIBXML2=false +SETTINGS_PERSISTENCE_USE_EXPAT=false +SETTINGS_PERSISTENCE_DISABLED=true + +if test x$HAVE_EXPAT = xtrue +then + SETTINGS_PERSISTENCE=expat + SETTINGS_PERSISTENCE_USE_EXPAT=true + SETTINGS_PERSISTENCE_DISABLED=false + AC_DEFINE_UNQUOTED(SETTINGS_PERSISTENCE_USE_EXPAT, 1, [Whether expat is used as settings persistence backend]) +else + if test x$HAVE_LIBXML2 = xtrue + then + if test x$HAVE_FIREWIRE = xtrue + then + SETTINGS_PERSISTENCE=no + SETTINGS_PERSISTENCE_WARNING="libxml2 usage is incompatible with FireWire (FFADO) driver. If you want settings persistence, install expat or disable FireWire (FFADO) driver." + else + SETTINGS_PERSISTENCE=libxml2 + SETTINGS_PERSISTENCE_USE_LIBXML2=true + SETTINGS_PERSISTENCE_DISABLED=false + AC_DEFINE_UNQUOTED(SETTINGS_PERSISTENCE_USE_LIBXML2, 1, [Whether libxml2 is used as settings persistence backend]) + fi + else + SETTINGS_PERSISTENCE=no + fi +fi + +AM_CONDITIONAL(SETTINGS_PERSISTENCE_USE_LIBXML2, $SETTINGS_PERSISTENCE_USE_LIBXML2) +AM_CONDITIONAL(SETTINGS_PERSISTENCE_USE_EXPAT, $SETTINGS_PERSISTENCE_USE_EXPAT) +AM_CONDITIONAL(SETTINGS_PERSISTENCE_DISABLED, $SETTINGS_PERSISTENCE_DISABLED) + AC_OUTPUT( Makefile config/Makefile @@ -749,6 +819,25 @@ echo \| echo \| echo \| Default driver backend................................ : $JACK_DEFAULT_DRIVER echo \| Shared memory interface............................... : $JACK_SHM_TYPE +echo \| D-Bus integration .................................... : $HAVE_DBUS +if test "x$HAVE_DBUS" = "xtrue" +then +echo \| D-Bus service install dir............................. : $DBUS_SERVICES_DIR +echo \| Settings persistence.................................. : $SETTINGS_PERSISTENCE +fi echo \| Install prefix........................................ : $prefix echo +if test "x$HAVE_DBUS" = "xtrue" -a "x$DBUS_SERVICES_DIR_REAL" != "x$DBUS_SERVICES_DIR" +then + AC_MSG_WARN([D-Bus session services directory as reported by pkg-config is $DBUS_SERVICES_DIR_REAL]) + AC_MSG_WARN([but service file will be installed in $DBUS_SERVICES_DIR]) + AC_MSG_WARN([You may need to adjust your D-Bus configuration after installing jackdbus]) + AC_MSG_WARN([You can override dbus service install dir]) + AC_MSG_WARN([with --enable-pkg-config-dbus-service-dir option to this script]) +fi + +if test "$SETTINGS_PERSISTENCE_WARNING" +then + AC_MSG_WARN($SETTINGS_PERSISTENCE_WARNING) +fi diff --git a/example-clients/Makefile.am b/example-clients/Makefile.am --- a/example-clients/Makefile.am +++ b/example-clients/Makefile.am @@ -42,6 +42,10 @@ bin_PROGRAMS = jack_load \ $(JACK_TRANSPORT) \ jack_midisine \ jack_midiseq + +if HAVE_DBUS +bin_SCRIPTS = jack_control +endif noinst_PROGRAMS = jack_thread_wait diff --git a/example-clients/jack_control b/example-clients/jack_control new file mode 100755 --- /dev/null +++ b/example-clients/jack_control @@ -0,0 +1,248 @@ +#!/usr/bin/env python + +name_base = 'org.jackaudio' +controller_interface_name = name_base + '.JackController' +service_name = name_base + '.service' + +import sys +import os +from traceback import print_exc + +import dbus + +def bool_convert(str_value): + if str_value.lower() == "false": + return False + + if str_value.lower() == "off": + return False + + if str_value.lower() == "no": + return False + + if str_value == "0": + return False + + if str_value.lower() == "(null)": + return False + + return bool(str_value) + +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" + sys.exit(0) + + bus = dbus.SessionBus() + + controller = bus.get_object(service_name, "/DefaultController") + iface = dbus.Interface(controller, controller_interface_name) + + # check arguments + index = 1 + while index < len(sys.argv): + arg = sys.argv[index] + index += 1 + try: + if arg == "exit": + print "--- exit" + iface.Exit() + elif arg == "status": + print "--- status" + if iface.IsStarted(): + print "started" + sys.exit(0) + else: + print "stopped" + sys.exit(1) + elif arg == 'start': + print "--- start" + iface.StartServer() + elif arg == 'stop': + print "--- stop" + iface.StopServer() + elif arg == 'test': + print "--- test" + iface.Test() + elif arg == 'ism': + if iface.IsManuallyActivated(): + print "Manually activated" + else: + print "Automatically activated" + elif arg == 'dl': + print "--- drivers list" + drivers = iface.GetAvailableDrivers() + for driver in drivers: + print driver + elif arg == 'dg': + print "--- get selected driver" + driver = iface.GetSelectedDriver() + if not driver: + print "no driver selected" + else: + print driver + elif arg == 'ds': + if index >= len(sys.argv): + print "driver select command requires driver name argument" + sys.exit() + + arg = sys.argv[index] + index += 1 + + print "--- driver select \"%s\"" % arg + iface.SelectDriver(arg) + elif arg == 'dp': + print "--- get driver parameters (type:isset:default:value)" + params = iface.GetDriverParameterNames() + for param in params: + descr = iface.GetDriverParameterShortDescription(param) + typestr = iface.GetDriverParameterTypeString(param) + + if typestr == "str": + isset, default, value = iface.GetDriverParameterValueString(param) + elif typestr == "bool": + isset, default, value = iface.GetDriverParameterValueBool(param) + value = bool(value) + default = bool(default) + elif typestr == "char": + isset, default, value = iface.GetDriverParameterValueChar(param) + elif typestr == "sint": + isset, default, value = iface.GetDriverParameterValueInt(param) + value = int(value) + default = int(default) + elif typestr == "uint": + isset, default, value = iface.GetDriverParameterValueUint(param) + value = int(value) + default = int(default) + else: + isset = None + default = None + value = None + + isset = bool(isset) + + print "%20s: %s (%s:%s:%s:%s)" %(param, descr, typestr, isset, default, value) + elif arg == 'dpd': + if index >= len(sys.argv): + print "get driver parameter long description command requires driver name argument" + sys.exit() + + param = sys.argv[index] + index += 1 + + print "--- get driver parameter description (%s)" % param + descr = iface.GetDriverParameterLongDescription(param) + print descr, + elif arg == 'dps': + if index + 1 >= len(sys.argv): + print "driver parameter set command requires parametr name and value arguments" + sys.exit() + + param = sys.argv[index] + index += 1 + value = sys.argv[index] + index += 1 + + print "--- driver param set \"%s\" -> \"%s\"" % (param, value) + + typestr = iface.GetDriverParameterTypeString(param) + + if typestr == "str": + iface.SetDriverParameterValueString(param, value) + elif typestr == "bool": + iface.SetDriverParameterValueBool(param, bool_convert(value)) + elif typestr == "char": + iface.SetDriverParameterValueChar(param, value) + elif typestr == "sint": + iface.SetDriverParameterValueInt(param, int(value)) + elif typestr == "uint": + iface.SetDriverParameterValueUint(param, int(value)) + else: + print "driver parameter \"%s\" is of unknown type \"%s\"" % (param, typestr) + sys.exit() + elif arg == 'ep': + print "--- get engine parameters (type:value)" + params = iface.GetEngineParameterNames() + #print params + for param in params: + descr = iface.GetEngineParameterShortDescription(param) + typestr = iface.GetEngineParameterTypeString(param) + #print descr + #print typestr + + if typestr == "str": + value = iface.GetEngineParameterValueString(param) + elif typestr == "bool": + value = iface.GetEngineParameterValueBool(param) + value = bool(value) + elif typestr == "char": + value = iface.GetEngineParameterValueChar(param) + elif typestr == "sint": + value = iface.GetEngineParameterValueInt(param) + value = int(value) + elif typestr == "uint": + value = iface.GetEngineParameterValueUint(param) + value = int(value) + else: + value = None + + print "%20s: %s (%s:%s)" %(param, descr, typestr, value) + elif arg == 'epd': + if index >= len(sys.argv): + print "get engine parameter long description command requires driver name argument" + sys.exit() + + param = sys.argv[index] + index += 1 + + print "--- get engine parameter description (%s)" % param + descr = iface.GetEngineParameterLongDescription(param) + print descr, + elif arg == 'eps': + if index + 1 >= len(sys.argv): + print "engine parameter set command requires parametr name and value arguments" + sys.exit() + + param = sys.argv[index] + index += 1 + value = sys.argv[index] + index += 1 + + print "--- engine param set \"%s\" -> \"%s\"" % (param, value) + + typestr = iface.GetEngineParameterTypeString(param) + + if typestr == "str": + iface.SetEngineParameterValueString(param, value) + elif typestr == "bool": + iface.SetEngineParameterValueBool(param, bool_convert(value)) + elif typestr == "char": + iface.SetEngineParameterValueChar(param, value) + elif typestr == "sint": + iface.SetEngineParameterValueInt(param, int(value)) + elif typestr == "uint": + iface.SetEngineParameterValueUint(param, int(value)) + else: + print "engine parameter \"%s\" is of unknown type \"%s\"" % (param, typestr) + sys.exit() + else: + print "Unknown command '%s'" % arg + except dbus.DBusException, e: + print "DBus exception: %s" % str(e) + +if __name__ == '__main__': + main() diff --git a/jackd/Makefile.am b/jackd/Makefile.am --- a/jackd/Makefile.am +++ b/jackd/Makefile.am @@ -21,14 +21,21 @@ endif bin_PROGRAMS = jackd $(CAP_PROGS) -AM_CFLAGS = $(JACK_CFLAGS) -DJACK_LOCATION=\"$(bindir)\" +if HAVE_DBUS +bin_PROGRAMS += jackdbus +endif -jackd_SOURCES = jackd.c engine.c clientengine.c transengine.c -jackd_LDADD = ../libjack/libjack.la $(CAP_LIBS) @OS_LDFLAGS@ +AM_CFLAGS = $(JACK_CFLAGS) -DJACK_LOCATION=\"$(bindir)\" $(DBUSGLIB_CFLAGS) $(LIBXML2_CFLAGS) + +COMMON_SOURCES = engine.c clientengine.c transengine.c +COMMON_LIBS = ../libjack/libjack.la $(CAP_LIBS) @OS_LDFLAGS@ + +jackd_SOURCES = jackd.c $(COMMON_SOURCES) +jackd_LDADD = $(COMMON_LIBS) noinst_HEADERS = jack_md5.h md5.h md5_loc.h \ clientengine.h transengine.h -BUILT_SOURCES = jack_md5.h +BUILT_SOURCES = jack_md5.h jackcontroller-glue.h jack_md5.h: jackd if STRIPPED_JACKD @@ -39,6 +46,40 @@ jackstart_SOURCES = jackstart.c md5.c jackstart_SOURCES = jackstart.c md5.c jackstart_LDFLAGS = -lcap +if HAVE_DBUS +jackcontroller-glue.h: jackcontroller.xml + dbus-binding-tool --mode=glib-server --prefix=jackcontroller jackcontroller.xml > jackcontroller-glue.h + +jackdbus_SOURCES = jackdbus.c $(COMMON_SOURCES) jackcontroller.c jackcontroller.h jackcontroller.xml jackcontroller_xml.h jackcontroller_internal.h +jackdbus_LDADD = $(COMMON_LIBS) $(DBUSGLIB_LIBS) + +if SETTINGS_PERSISTENCE_USE_LIBXML2 +jackdbus_SOURCES += jackcontroller_xml_libxml.c jackcontroller_xml.c +jackdbus_LDADD += $(LIBXML2_LIBS) +endif + +if SETTINGS_PERSISTENCE_USE_EXPAT +jackdbus_SOURCES += jackcontroller_xml_expat.c jackcontroller_xml.c jackcontroller_xml_write_raw.c +jackdbus_LDADD += -lexpat +endif + +if SETTINGS_PERSISTENCE_DISABLED +jackdbus_SOURCES += jackcontroller_xml_nop.c +endif + +# Dbus service file +servicedir = $(DBUS_SERVICES_DIR) +service_in_files = org.jackaudio.service.in +service_DATA = $(service_in_files:.service.in=.service) + +# Rule to make the service file with bindir expanded +$(service_DATA): $(service_in_files) Makefile + @sed -e "s|\@bindir\@|$(bindir)|" $< > $@ + +jackdbus_EXTRA_DIST = $(service_in_files) + +endif + man_MANS = jackd.1 jackstart.1 EXTRA_DIST = $(man_MANS) diff --git a/jackd/jackcontroller.c b/jackd/jackcontroller.c new file mode 100644 --- /dev/null +++ b/jackd/jackcontroller.c @@ -0,0 +1,2096 @@ +/* -*- mode: c; c-file-style: "bsd"; -*- */ +/* + Copyright (C) 2007 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. + +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "jackcontroller.h" +#include "jackcontroller-glue.h" + +#include "jackdbus.h" +#include "jackcontroller_internal.h" +#include "jackcontroller_xml.h" + +struct jack_engine_parameter_descriptor jack_engine_parameters[] = +{ + {"realtime", JackParamBool, "Whether to use realtime mode", "Use realtime scheduling. This is needed for reliable low-latency performance. On most systems, it requires JACK to run with special scheduler and memory allocation privileges, which may be obtained in several ways. On Linux you should use PAM."}, + {"realtime-priority", JackParamInt, "Scheduler priority when running in realtime mode.", NULL}, + {"no-mem-lock", JackParamBool, "Do not attempt to lock memory, even in realtime mode.", NULL}, + {"temporary", JackParamBool, "Exit once all clients have closed their connections.", NULL}, + {"verbose", JackParamBool, "Verbose mode", NULL}, + {"client-timeout", JackParamInt, "Client timeout limit in milliseconds", "Client timeout limit in milliseconds. In realtime mode the client timeout must be smaller than the watchdog timeout (5000 msec)."}, + {"no-zombies", JackParamBool, "Prevent JACK from ever kicking out clients because they were too slow.", "Prevent JACK from ever kicking out clients because they were too slow. JACK and its clients are still subject to the supervision of the watchdog thread or its equivalent."}, + {"port-max", JackParamUInt, "Maximum number of ports the JACK server can manage", NULL}, + {"libs-unlock", JackParamBool, "Unlock libraries GTK+, QT, FLTK, Wine.", NULL}, +}; + +#define JACK_ENGINE_PARAMS_COUNT (sizeof(jack_engine_parameters)/sizeof(struct jack_engine_parameter_descriptor)) + +gboolean +jack_controller_load_descriptor( + struct jack_controller * controller_ptr, + struct jack_controller_driver * driver_ptr) +{ + jack_driver_desc_t * descriptor; + JackDriverDescFunction so_get_descriptor; + void * dlhandle; + const char * dlerr; + int err; + + if (controller_ptr->verbose) { + jack_info ("getting driver descriptor from %s", driver_ptr->filename); + } + + dlhandle = dlopen(driver_ptr->filename, RTLD_NOW|RTLD_GLOBAL); + if (dlhandle == NULL) { + jack_error("could not open driver .so '%s': %s", driver_ptr->filename, dlerror()); + return FALSE; + } + + so_get_descriptor = (JackDriverDescFunction) + dlsym(dlhandle, "driver_get_descriptor"); + + dlerr = dlerror(); + if (dlerr != NULL) { + jack_error("cannot find driver_get_descriptor symbol: %s", dlerr); + dlclose(dlhandle); + return FALSE; + } + + descriptor = so_get_descriptor(); + if (descriptor == NULL) { + jack_error("driver from '%s' returned NULL descriptor", driver_ptr->filename); + dlclose(dlhandle); + return FALSE; + } + + err = dlclose(dlhandle); + if (err != 0) { + jack_error("error closing driver .so '%s': %s", driver_ptr->filename, dlerror()); + free(descriptor->params); + free(descriptor); + return FALSE; + } + + /* for some mad reason we are storing filename in descriptor allocated by driver + instead of reusing dlhandle when another dlsym() call is needed */ + snprintf (descriptor->file, sizeof(descriptor->file), "%s", driver_ptr->filename); + + driver_ptr->desc_ptr = descriptor; + + return TRUE; +} + +static +gboolean +jack_drivers_load( + struct jack_controller *controller_ptr) +{ + struct dirent * dir_entry; + DIR * dir_stream; + const char * ptr; + int err; + char* driver_dir; + struct jack_controller_driver * driver_ptr; + struct jack_controller_driver * other_driver_ptr; + JSList * node_ptr; + + if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) { + driver_dir = ADDON_DIR; + } + + if (controller_ptr->verbose) { + jack_info ("searching for drivers in %s", driver_dir); + } + + /* search through the driver_dir and add get descriptors + from the .so files in it */ + dir_stream = opendir (driver_dir); + if (!dir_stream) { + jack_error ("could not open driver directory %s: %s", + driver_dir, strerror (errno)); + return FALSE; + } + + while ( (dir_entry = readdir (dir_stream)) ) { + /* check the filename is of the right format */ + if (strncmp ("jack_", dir_entry->d_name, 5) != 0) { + continue; + } + +#if SETTINGS_PERSISTENCE_USE_LIBXML2 + /* disable ffado driver. + it is incompatible with using libxml2 by other module, + be it jackdbus or some other driver. + libxml2 has global hooks used by libxml++, used by libffado */ + if (strcmp ("jack_firewire.so", dir_entry->d_name) == 0) { + continue; + } +#endif + + ptr = strrchr (dir_entry->d_name, '.'); + if (!ptr) { + continue; + } + ptr++; + if (strncmp ("so", ptr, 2) != 0) { + continue; + } + + driver_ptr = malloc(sizeof(struct jack_controller_driver)); + if (driver_ptr == NULL) + { + jack_error("memory allocation of jack_controller_driver structure failed."); + continue; + } + + driver_ptr->filename = malloc(strlen(driver_dir) + 1 + strlen(dir_entry->d_name) + 1); + + sprintf(driver_ptr->filename, "%s/%s", driver_dir, dir_entry->d_name); + + if (!jack_controller_load_descriptor(controller_ptr, driver_ptr)) + { + goto dealloc_driver; + } + + /* check it doesn't exist already */ + for (node_ptr = controller_ptr->drivers; node_ptr != NULL; node_ptr = jack_slist_next(node_ptr)) + { + other_driver_ptr = (struct jack_controller_driver *)node_ptr->data; + + if (strcmp(driver_ptr->desc_ptr->name, other_driver_ptr->desc_ptr->name) == 0) + { + jack_error( + "the drivers in '%s' and '%s' both have the name '%s'; using the first", + other_driver_ptr->filename, + driver_ptr->filename, + driver_ptr->desc_ptr->name); + goto dealloc_descriptor; + } + } + + driver_ptr->params = NULL; + + controller_ptr->drivers = jack_slist_append(controller_ptr->drivers, driver_ptr); + controller_ptr->drivers_count++; + + continue; + + dealloc_descriptor: + free(driver_ptr->desc_ptr->params); + free(driver_ptr->desc_ptr); + + dealloc_driver: + free(driver_ptr->filename); + free(driver_ptr); + } + + err = closedir (dir_stream); + if (err) { + jack_error ("error closing driver directory %s: %s", + driver_dir, strerror (errno)); + } + + if (controller_ptr->drivers_count == 0) + { + jack_error ("could not find any drivers in %s!", driver_dir); + return FALSE; + } + + return TRUE; +} + +static void +jack_cleanup_files (const char *server_name) +{ + DIR *dir; + struct dirent *dirent; + char dir_name[PATH_MAX+1] = ""; + jack_server_dir (server_name, dir_name); + + /* On termination, we remove all files that jackd creates so + * subsequent attempts to start jackd will not believe that an + * instance is already running. If the server crashes or is + * terminated with SIGKILL, this is not possible. So, cleanup + * is also attempted when jackd starts. + * + * There are several tricky issues. First, the previous JACK + * server may have run for a different user ID, so its files + * may be inaccessible. This is handled by using a separate + * JACK_TMP_DIR subdirectory for each user. Second, there may + * be other servers running with different names. Each gets + * its own subdirectory within the per-user directory. The + * current process has already registered as `server_name', so + * we know there is no other server actively using that name. + */ + + /* nothing to do if the server directory does not exist */ + if ((dir = opendir (dir_name)) == NULL) { + return; + } + + /* unlink all the files in this directory, they are mine */ + while ((dirent = readdir (dir)) != NULL) { + + char fullpath[PATH_MAX+1]; + + if ((strcmp (dirent->d_name, ".") == 0) + || (strcmp (dirent->d_name, "..") == 0)) { + continue; + } + + snprintf (fullpath, sizeof (fullpath), "%s/%s", + dir_name, dirent->d_name); + + if (unlink (fullpath)) { + jack_error ("cannot unlink `%s' (%s)", fullpath, + strerror (errno)); + } + } + + closedir (dir); + + /* now, delete the per-server subdirectory, itself */ + if (rmdir (dir_name)) { + jack_error ("cannot remove `%s' (%s)", dir_name, + strerror (errno)); + } + + /* finally, delete the per-user subdirectory, if empty */ + if (rmdir (jack_user_dir ())) { + if (errno != ENOTEMPTY) { + jack_error ("cannot remove `%s' (%s)", + jack_user_dir (), strerror (errno)); + } + } +} + +#define JACK_CONTROLLER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), JACK_CONTROLLER_TYPE, struct jack_controller)) + +static void +jack_controller_dispose(GObject * obj) +{ + struct jack_controller * controller_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(obj); + + if (controller_ptr->dispose_has_run) + { + /* If dispose did already run, return. */ + return; + } + + /* Make sure dispose does not run twice. */ + controller_ptr->dispose_has_run = TRUE; + + /* + * In dispose, you are supposed to free all types referenced from this + * object which might themselves hold a reference to self. Generally, + * the most simple solution is to unref all members on which you own a + * reference. + */ + + /* Chain up to the parent class */ + G_OBJECT_CLASS(g_type_class_peek_parent(G_OBJECT_GET_CLASS(obj)))->dispose(obj); +} + +static void +jack_controller_finalize(GObject * obj) +{ +// struct jack_controller * self = JACK_CONTROLLER_GET_PRIVATE(obj); + + /* + * Here, complete object destruction. + * You might not need to do much... + */ + //g_free(self->private); + + /* Chain up to the parent class */ + G_OBJECT_CLASS(g_type_class_peek_parent(G_OBJECT_GET_CLASS(obj)))->finalize(obj); +} + +static void +jack_controller_class_init( + gpointer class_ptr, + gpointer class_data_ptr) +{ + G_OBJECT_CLASS(class_ptr)->dispose = jack_controller_dispose; + G_OBJECT_CLASS(class_ptr)->finalize = jack_controller_finalize; + + g_type_class_add_private(G_OBJECT_CLASS(class_ptr), sizeof(struct jack_controller)); + dbus_g_object_type_install_info (JACK_CONTROLLER_TYPE, &dbus_glib_jackcontroller_object_info); +} + +static void +jack_controller_init( + GTypeInstance * instance, + gpointer g_class) +{ + struct jack_controller * controller_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(instance); + + controller_ptr->dispose_has_run = FALSE; + + controller_ptr->loop = NULL; + controller_ptr->manually_started = FALSE; + + controller_ptr->drivers = NULL; + controller_ptr->drivers_count = 0; + + controller_ptr->engine = NULL; + controller_ptr->server_name = jack_default_server_name(); + controller_ptr->realtime = 0; + controller_ptr->realtime_priority = 10; + controller_ptr->do_mlock = 1; + controller_ptr->temporary = 0; + controller_ptr->verbose = 0; + controller_ptr->client_timeout = 500; + controller_ptr->port_max = 256; + controller_ptr->do_unlock = 0; + controller_ptr->frame_time_offset = 0; + controller_ptr->nozombies = 0; + controller_ptr->xruns = 0; +} + +GType jack_controller_get_type() +{ + static GType type = 0; + if (type == 0) + { + type = g_type_register_static_simple( + G_TYPE_OBJECT, + "jack_controller_type", + sizeof(JackControllerClass), + jack_controller_class_init, + sizeof(JackController), + jack_controller_init, + 0); + } + + return type; +} + +GQuark +jack_controller_error_quark() +{ + static GQuark quark = 0; + if (!quark) + quark = g_quark_from_static_string ("jack_controller_error"); + + return quark; +} + +gboolean +jack_controller_test( + JackController * object_ptr, + GError ** error) +{ + jack_info("Test!"); + g_set_error(error, jack_controller_error_quark(), 0, "Muhahaha!"); + return FALSE; +} + +gboolean +jack_controller_exit( + JackController * object_ptr, + GError ** error) +{ + struct jack_controller * controller_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + jack_info("Exit!"); + g_main_quit(controller_ptr->loop); + return TRUE; +} + +gboolean +jack_controller_is_manually_activated( + JackController * object_ptr, + gboolean * manually_started_ptr, + GError ** error) +{ + struct jack_controller * controller_ptr; + + jack_info("Is manually started?"); + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + *manually_started_ptr = controller_ptr->manually_started; + return TRUE; +} + +void +jack_controller_error( + GError **error, + const gchar *format, + ...) +{ + va_list ap; + char buffer[300]; + + va_start(ap, format); + + vsnprintf(buffer, sizeof(buffer), format, ap); + + jack_error_callback(buffer); + if (error != NULL) + { + g_set_error(error, jack_controller_error_quark(), 0, buffer); + } + + va_end(ap); +} + +jack_driver_param_desc_t * +jack_controller_find_parameter_descriptor( + struct jack_controller_driver *driver_ptr, + jack_driver_param_t * param_ptr) +{ + unsigned int i; + + for (i = 0; i < driver_ptr->desc_ptr->nparams ; i++) + { + if (driver_ptr->desc_ptr->params[i].character == param_ptr->character) + { + return driver_ptr->desc_ptr->params + i; + } + } + + return NULL; +} + +jack_driver_param_desc_t * +jack_controller_find_parameter_descriptor_by_name( + struct jack_controller_driver *driver_ptr, + const char *param_name) +{ + unsigned int i; + + for (i = 0; i < driver_ptr->desc_ptr->nparams ; i++) + { + if (strcmp(driver_ptr->desc_ptr->params[i].name, param_name) == 0) + { + return driver_ptr->desc_ptr->params + i; + } + } + + return NULL; +} + +jack_driver_param_desc_t * +jack_controller_find_parameter_descriptor_by_name_current_driver( + struct jack_controller *controller_ptr, + const gchar *param_name) +{ + return jack_controller_find_parameter_descriptor_by_name(controller_ptr->driver_ptr, param_name); +} + +/* search for parameter matching parameter descriptor, return NULL if not found */ +jack_driver_param_t * +jack_controller_find_parameter( + struct jack_controller_driver *driver_ptr, + const jack_driver_param_desc_t *descr_ptr) +{ + JSList * node_ptr; + jack_driver_param_t * param_ptr; + + for (node_ptr = driver_ptr->params; node_ptr != NULL; node_ptr = jack_slist_next(node_ptr)) + { + param_ptr = (jack_driver_param_t *)node_ptr->data; + + if (param_ptr->character == descr_ptr->character) + { + return param_ptr; + } + } + + return NULL; +} + +jack_driver_param_t * +jack_controller_find_parameter_current_driver( + struct jack_controller *controller_ptr, + const jack_driver_param_desc_t *descr_ptr) +{ + return jack_controller_find_parameter(controller_ptr->driver_ptr, descr_ptr); +} + +/* search for parameter matching parameter descriptor, if not found, create new one */ +jack_driver_param_t * +jack_controller_find_or_create_parameter( + struct jack_controller_driver *driver_ptr, + const jack_driver_param_desc_t *descr_ptr) +{ + jack_driver_param_t * param_ptr; + + param_ptr = jack_controller_find_parameter(driver_ptr, descr_ptr); + if (param_ptr != NULL) + { + return param_ptr; + } + + param_ptr = malloc(sizeof(jack_driver_param_t)); + if (param_ptr == NULL) + { + jack_error("Allocation of jack_driver_param_t structure failed."); + return NULL; + } + + param_ptr->character = descr_ptr->character; + param_ptr->value = descr_ptr->value; + + driver_ptr->params = jack_slist_append(driver_ptr->params, param_ptr); + + return param_ptr; +} + +/* search for parameter matching parameter descriptor, if not found, create new one */ +jack_driver_param_t * +jack_controller_find_or_create_parameter_current_driver( + struct jack_controller *controller_ptr, + const jack_driver_param_desc_t *descr_ptr) +{ + return jack_controller_find_or_create_parameter(controller_ptr->driver_ptr, descr_ptr); +} + +void +jack_controller_run( + JackController * object_ptr) +{ + struct jack_controller * controller_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + controller_ptr->loop = g_main_loop_new(NULL, FALSE); + controller_ptr->manually_started = FALSE; + + if (!jack_drivers_load(controller_ptr)) + { + return; + } + + jack_controller_settings_load(controller_ptr); + + jack_info("Starting loop..."); + g_main_loop_run(controller_ptr->loop); + + if (controller_ptr->engine != NULL) + { + jack_controller_stop_server(object_ptr, NULL); + + } +} + +int +jack_controller_xrun(void *arg) +{ + ((struct jack_controller *)arg)->xruns++; + + return 0; +} + +gboolean +jack_controller_start_server( + JackController * object_ptr, + GError ** error) +{ + struct jack_controller * controller_ptr; + int rc; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + jack_info("Starting jack server..."); + + if (controller_ptr->engine != NULL) + { + jack_info("Already started."); + return TRUE; + } + + if (controller_ptr->driver_ptr == NULL) + { + jack_controller_error(error, "Select driver first!"); + goto fail; + } + + rc = jack_register_server(controller_ptr->server_name); + switch (rc) + { + case EEXIST: + jack_controller_error(error, "`%s' server already active", controller_ptr->server_name); + goto fail; + case ENOSPC: + jack_controller_error(error, "too many servers already active"); + goto fail; + case ENOMEM: + jack_controller_error(error, "no access to shm registry"); + goto fail; + } + + if (controller_ptr->verbose) + { + jack_info ("server `%s' registered", controller_ptr->server_name); + } + + /* clean up shared memory and files from any previous + * instance of this server name */ + jack_cleanup_shm(); + jack_cleanup_files(controller_ptr->server_name); + + if (!controller_ptr->realtime && controller_ptr->client_timeout == 0) + controller_ptr->client_timeout = 500; /* 0.5 sec; usable when non realtime. */ + + /* get the engine/driver started */ + + controller_ptr->engine = jack_engine_new( + controller_ptr->realtime, + controller_ptr->realtime_priority, + controller_ptr->do_mlock, + controller_ptr->do_unlock, + controller_ptr->server_name, + controller_ptr->temporary, + controller_ptr->verbose, + controller_ptr->client_timeout, + controller_ptr->port_max, + getpid(), + controller_ptr->frame_time_offset, + controller_ptr->nozombies, + NULL); + if (controller_ptr->engine == NULL) + { + jack_controller_error(error, "Cannot create engine!"); + goto fail_unregister_server; + } + + jack_info("loading driver \"%s\" ...", controller_ptr->driver_ptr->desc_ptr->name); + + if (jack_engine_load_driver(controller_ptr->engine, controller_ptr->driver_ptr->desc_ptr, controller_ptr->driver_ptr->params)) { + jack_controller_error(error, "cannot load driver module %s", controller_ptr->driver_ptr->desc_ptr->name); + goto fail_delete_engine; + } + + controller_ptr->xruns = 0; + controller_ptr->engine->driver->internal_client->control->xrun = jack_controller_xrun; + controller_ptr->engine->driver->internal_client->control->xrun_arg = controller_ptr; + + if (controller_ptr->engine->driver->start(controller_ptr->engine->driver) != 0) { + jack_controller_error(error, "cannot start \"%s\" driver", controller_ptr->driver_ptr->desc_ptr->name); + goto fail_delete_engine; + } + + return TRUE; + +fail_unregister_server: + if (controller_ptr->verbose) + { + jack_info("cleaning up shared memory"); + } + + jack_cleanup_shm(); + + if (controller_ptr->verbose) + { + jack_info("cleaning up files"); + } + + jack_cleanup_files(controller_ptr->server_name); + + if (controller_ptr->verbose) + { + jack_info("unregistering server `%s'", controller_ptr->server_name); + } + + jack_unregister_server(controller_ptr->server_name); + +fail_delete_engine: + jack_engine_delete(controller_ptr->engine); + controller_ptr->engine = NULL; + +fail: + return FALSE; +} + +gboolean +jack_controller_stop_server( + JackController * object_ptr, + GError ** error) +{ + struct jack_controller * controller_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->engine == NULL) + { + return TRUE; + } + + jack_info("Stop jack server..."); + + jack_engine_delete(controller_ptr->engine); + + /* clean up shared memory and files from this server instance */ + if (controller_ptr->verbose) + { + jack_info("cleaning up shared memory"); + } + + jack_cleanup_shm(); + + if (controller_ptr->verbose) + { + jack_info("cleaning up files"); + } + + jack_cleanup_files(controller_ptr->server_name); + + if (controller_ptr->verbose) + { + jack_info("unregistering server `%s'", controller_ptr->server_name); + } + + jack_unregister_server(controller_ptr->server_name); + + controller_ptr->engine = NULL; + + return TRUE; +} + +gboolean +jack_controller_is_started( + JackController * object_ptr, + gboolean * started_ptr, + GError ** error) +{ + struct jack_controller * controller_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + *started_ptr = controller_ptr->engine == NULL ? FALSE : TRUE; + + return TRUE; +} + +gboolean +jack_controller_get_load( + JackController * object_ptr, + gdouble * load_ptr, + GError ** error) +{ + struct jack_controller * controller_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->engine == NULL) + { + jack_controller_error(error, "There is no much sense of getting load of not started JACK server"); + return FALSE; + } + + *load_ptr = controller_ptr->engine->control->cpu_load; + + return TRUE; +} + +gboolean +jack_controller_get_xruns( + JackController * object_ptr, + guint * xruns_ptr, + GError ** error) +{ + struct jack_controller * controller_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->engine == NULL) + { + jack_controller_error(error, "There is no much sense of getting xruns of not started JACK server"); + return FALSE; + } + + *xruns_ptr = controller_ptr->xruns; + + return TRUE; +} + +gboolean +jack_controller_get_sample_rate( + JackController * object_ptr, + guint * sample_rate_ptr, + GError ** error) +{ + struct jack_controller * controller_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->engine == NULL) + { + jack_controller_error(error, "There is no much sense of getting load of not started JACK server"); + return FALSE; + } + + *sample_rate_ptr = controller_ptr->engine->control->current_time.frame_rate; + + return TRUE; +} + +gboolean +jack_controller_get_latency( + JackController * object_ptr, + gdouble * latency_ptr, + GError ** error) +{ + struct jack_controller * controller_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->engine == NULL) + { + jack_controller_error(error, "There is no much sense of getting load of not started JACK server"); + return FALSE; + } + + *latency_ptr = controller_ptr->engine->driver->period_usecs / 1000.0; + + return TRUE; +} + +gboolean +jack_controller_get_available_drivers( + JackController * object_ptr, + gchar *** drivers_list, + GError ** error) +{ + struct jack_controller * controller_ptr; + gchar ** array; + unsigned int i; + struct jack_controller_driver * driver_ptr; + JSList * node_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + array = g_malloc((controller_ptr->drivers_count + 1) * sizeof(gchar *)); + + node_ptr = controller_ptr->drivers; + i = 0; + + while (node_ptr != NULL) + { + assert(i < controller_ptr->drivers_count); + + driver_ptr = (struct jack_controller_driver *)node_ptr->data; + + array[i] = g_strdup(driver_ptr->desc_ptr->name); + + node_ptr = jack_slist_next(node_ptr); + i++; + } + + assert(i == controller_ptr->drivers_count); + array[i] = NULL; + + *drivers_list = array; + + return TRUE; +} + +gboolean +jack_controller_get_selected_driver( + JackController * object_ptr, + gchar ** driver_name, + GError ** error) +{ + struct jack_controller * controller_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->driver_ptr == NULL) + { + *driver_name = NULL; + } + else + { + *driver_name = g_strdup(controller_ptr->driver_ptr->desc_ptr->name); + } + + return TRUE; +} + +gboolean +jack_controller_select_driver( + JackController * object_ptr, + const gchar * driver_name, + GError ** error) +{ + struct jack_controller * controller_ptr; + struct jack_controller_driver * driver_ptr; + JSList * node_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + for (node_ptr = controller_ptr->drivers ; node_ptr != NULL ; node_ptr = jack_slist_next(node_ptr)) + { + driver_ptr = (struct jack_controller_driver *)node_ptr->data; + + if (strcmp(driver_ptr->desc_ptr->name, driver_name) == 0) { + goto found; + } + } + + jack_controller_error(error, "unknown driver '%s'", driver_name); + return FALSE; + +found: + jack_info("driver \"%s\" selected", driver_ptr->desc_ptr->name); + + controller_ptr->driver_ptr = driver_ptr; + + jack_controller_settings_save_auto(controller_ptr); + + return TRUE; +} + +gboolean +jack_controller_get_driver_parameter_names( + JackController * object_ptr, + gchar *** params_list, + GError ** error) +{ + struct jack_controller * controller_ptr; + gchar ** array; + unsigned int i; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->driver_ptr == NULL) + { + jack_controller_error(error, "Select driver before operating on its parameters!"); + return FALSE; + } + + if (controller_ptr->verbose) + { + jack_info("Getting parameters for driver \"%s\"", controller_ptr->driver_ptr->desc_ptr->name); + } + + array = g_malloc((controller_ptr->driver_ptr->desc_ptr->nparams + 1) * sizeof(gchar *)); + + for (i = 0; i < controller_ptr->driver_ptr->desc_ptr->nparams ; i++) + { + array[i] = g_strdup(controller_ptr->driver_ptr->desc_ptr->params[i].name); + } + + array[i] = NULL; + + *params_list = array; + + return TRUE; +} + +gboolean +jack_controller_get_driver_parameter_short_description( + JackController * object_ptr, + const gchar * parameter, + gchar ** description, + GError ** error) +{ + struct jack_controller * controller_ptr; + unsigned int i; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->driver_ptr == NULL) + { + jack_controller_error(error, "Select driver before operating on its parameters!"); + return FALSE; + } + + for (i = 0; i < controller_ptr->driver_ptr->desc_ptr->nparams ; i++) + { + if (strcmp(controller_ptr->driver_ptr->desc_ptr->params[i].name, parameter) == 0) + { + *description = g_strdup(controller_ptr->driver_ptr->desc_ptr->params[i].short_desc); + return TRUE; + } + } + + jack_controller_error(error, "Unknown parameter \"%s\" of driver \"%s\"", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; +} + +gboolean +jack_controller_get_driver_parameter_long_description( + JackController * object_ptr, + const gchar * parameter, + gchar ** description, + GError ** error) +{ + struct jack_controller * controller_ptr; + unsigned int i; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->driver_ptr == NULL) + { + jack_controller_error(error, "Select driver before operating on its parameters!"); + return FALSE; + } + + for (i = 0; i < controller_ptr->driver_ptr->desc_ptr->nparams ; i++) + { + if (strcmp(controller_ptr->driver_ptr->desc_ptr->params[i].name, parameter) == 0) + { + *description = g_strdup(controller_ptr->driver_ptr->desc_ptr->params[i].long_desc); + return TRUE; + } + } + + jack_controller_error(error, "Unknown parameter \"%s\" of driver \"%s\"", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; +} + +gboolean +jack_controller_get_driver_parameter_type( + JackController * object_ptr, + const gchar * parameter, + guchar * type, + GError ** error) +{ + struct jack_controller * controller_ptr; + unsigned int i; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->driver_ptr == NULL) + { + jack_controller_error(error, "Select driver before operating on its parameters!"); + return FALSE; + } + + for (i = 0; i < controller_ptr->driver_ptr->desc_ptr->nparams ; i++) + { + if (strcmp(controller_ptr->driver_ptr->desc_ptr->params[i].name, parameter) == 0) + { + *type = controller_ptr->driver_ptr->desc_ptr->params[i].type; + return TRUE; + } + } + + jack_controller_error(error, "Unknown parameter \"%s\" of driver \"%s\"", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; +} + +gboolean +jack_controller_get_driver_parameter_type_string( + JackController * object_ptr, + const gchar * parameter, + gchar ** type, + GError ** error) +{ + struct jack_controller * controller_ptr; + unsigned int i; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->driver_ptr == NULL) + { + jack_controller_error(error, "Select driver before operating on its parameters!"); + return FALSE; + } + + for (i = 0; i < controller_ptr->driver_ptr->desc_ptr->nparams ; i++) + { + if (strcmp(controller_ptr->driver_ptr->desc_ptr->params[i].name, parameter) == 0) + { + switch (controller_ptr->driver_ptr->desc_ptr->params[i].type) + { + case JackDriverParamInt: + *type = g_strdup("sint"); + return TRUE; + case JackDriverParamUInt: + *type = g_strdup("uint"); + return TRUE; + case JackDriverParamChar: + *type = g_strdup("char"); + return TRUE; + case JackDriverParamString: + *type = g_strdup("str"); + return TRUE; + case JackDriverParamBool: + *type = g_strdup("bool"); + return TRUE; + } + + jack_controller_error( + error, + "Parameter \"%s\" of driver \"%s\" is of unknown type %d", + parameter, + controller_ptr->driver_ptr->desc_ptr->name, + controller_ptr->driver_ptr->desc_ptr->params[i].type); + return FALSE; + } + } + + jack_controller_error(error, "Unknown parameter \"%s\" of driver \"%s\"", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; +} + +gboolean +jack_controller_get_driver_parameter_value_string( + JackController * object_ptr, + const gchar * parameter, + gboolean * isset, + gchar ** default_value, + gchar ** value, + GError ** error) +{ + struct jack_controller * controller_ptr; + jack_driver_param_desc_t * param_desc_ptr; + jack_driver_param_t * param_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->driver_ptr == NULL) + { + jack_controller_error(error, "Select driver before operating on its parameters!"); + return FALSE; + } + + param_desc_ptr = jack_controller_find_parameter_descriptor_by_name_current_driver(controller_ptr, parameter); + if (param_desc_ptr == NULL) + { + jack_controller_error(error, "Unknown parameter \"%s\" of driver \"%s\"", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + if (param_desc_ptr->type != JackDriverParamString) + { + jack_controller_error(error, "Parameter \"%s\" of driver \"%s\" is not string", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + *default_value = g_strdup(param_desc_ptr->value.str); + + param_ptr = jack_controller_find_parameter_current_driver(controller_ptr, param_desc_ptr); + if (param_ptr == NULL) + { + *isset = FALSE; + *value = g_strdup(*default_value); + } + else + { + *isset = TRUE; + *value = g_strdup(param_ptr->value.str); + } + + return TRUE; +} + +gboolean +jack_controller_get_driver_parameter_value_bool( + JackController * object_ptr, + const gchar * parameter, + gboolean * isset, + gboolean * default_value, + gboolean * value, + GError ** error) +{ + struct jack_controller * controller_ptr; + jack_driver_param_desc_t * param_desc_ptr; + jack_driver_param_t * param_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->driver_ptr == NULL) + { + jack_controller_error(error, "Select driver before operating on its parameters!"); + return FALSE; + } + + param_desc_ptr = jack_controller_find_parameter_descriptor_by_name_current_driver(controller_ptr, parameter); + if (param_desc_ptr == NULL) + { + jack_controller_error(error, "Unknown parameter \"%s\" of driver \"%s\"", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + if (param_desc_ptr->type != JackDriverParamBool) + { + jack_controller_error(error, "Parameter \"%s\" of driver \"%s\" is not boolean", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + *default_value = param_desc_ptr->value.i ? TRUE : FALSE; + + param_ptr = jack_controller_find_parameter_current_driver(controller_ptr, param_desc_ptr); + if (param_ptr == NULL) + { + *isset = FALSE; + *value = *default_value; + } + else + { + *isset = TRUE; + *value = param_ptr->value.i ? TRUE : FALSE; + } + + return TRUE; +} + +gboolean +jack_controller_get_driver_parameter_value_char( + JackController * object_ptr, + const gchar * parameter, + gboolean * isset, + guchar * default_value, + guchar * value, + GError ** error) +{ + struct jack_controller * controller_ptr; + jack_driver_param_desc_t * param_desc_ptr; + jack_driver_param_t * param_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->driver_ptr == NULL) + { + jack_controller_error(error, "Select driver before operating on its parameters!"); + return FALSE; + } + + param_desc_ptr = jack_controller_find_parameter_descriptor_by_name_current_driver(controller_ptr, parameter); + if (param_desc_ptr == NULL) + { + jack_controller_error(error, "Unknown parameter \"%s\" of driver \"%s\"", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + if (param_desc_ptr->type != JackDriverParamChar) + { + jack_controller_error(error, "Parameter \"%s\" of driver \"%s\" is not char", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + *default_value = param_desc_ptr->value.c; + + param_ptr = jack_controller_find_parameter_current_driver(controller_ptr, param_desc_ptr); + if (param_ptr == NULL) + { + *isset = FALSE; + *value = *default_value; + } + else + { + *isset = TRUE; + *value = param_ptr->value.c; + } + + return TRUE; +} + +gboolean +jack_controller_get_driver_parameter_value_int( + JackController * object_ptr, + const gchar * parameter, + gboolean * isset, + gint * default_value, + gint * value, + GError ** error) +{ + struct jack_controller * controller_ptr; + jack_driver_param_desc_t * param_desc_ptr; + jack_driver_param_t * param_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->driver_ptr == NULL) + { + jack_controller_error(error, "Select driver before operating on its parameters!"); + return FALSE; + } + + param_desc_ptr = jack_controller_find_parameter_descriptor_by_name_current_driver(controller_ptr, parameter); + if (param_desc_ptr == NULL) + { + jack_controller_error(error, "Unknown parameter \"%s\" of driver \"%s\"", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + if (param_desc_ptr->type != JackDriverParamInt) + { + jack_controller_error(error, "Parameter \"%s\" of driver \"%s\" is not int", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + *default_value = param_desc_ptr->value.i; + + param_ptr = jack_controller_find_parameter_current_driver(controller_ptr, param_desc_ptr); + if (param_ptr == NULL) + { + *isset = FALSE; + *value = *default_value; + } + else + { + *isset = TRUE; + *value = param_ptr->value.i; + } + + return TRUE; +} + +gboolean +jack_controller_get_driver_parameter_value_uint( + JackController * object_ptr, + const gchar * parameter, + gboolean * isset, + guint * default_value, + guint * value, + GError ** error) +{ + struct jack_controller * controller_ptr; + jack_driver_param_desc_t * param_desc_ptr; + jack_driver_param_t * param_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->driver_ptr == NULL) + { + jack_controller_error(error, "Select driver before operating on its parameters!"); + return FALSE; + } + + param_desc_ptr = jack_controller_find_parameter_descriptor_by_name_current_driver(controller_ptr, parameter); + if (param_desc_ptr == NULL) + { + jack_controller_error(error, "Unknown parameter \"%s\" of driver \"%s\"", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + if (param_desc_ptr->type != JackDriverParamUInt) + { + jack_controller_error(error, "Parameter \"%s\" of driver \"%s\" is not uint", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + *default_value = param_desc_ptr->value.ui; + + param_ptr = jack_controller_find_parameter_current_driver(controller_ptr, param_desc_ptr); + if (param_ptr == NULL) + { + *isset = FALSE; + *value = *default_value; + } + else + { + *isset = TRUE; + *value = param_ptr->value.ui; + } + + return TRUE; +} + +gboolean +jack_controller_set_driver_parameter_value_string( + JackController * object_ptr, + const gchar * parameter, + gchar * value, + GError ** error) +{ + struct jack_controller * controller_ptr; + jack_driver_param_desc_t * param_desc_ptr; + jack_driver_param_t * param_ptr; + size_t value_len; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->driver_ptr == NULL) + { + jack_controller_error(error, "Select driver before operating on its parameters!"); + return FALSE; + } + + param_desc_ptr = jack_controller_find_parameter_descriptor_by_name_current_driver(controller_ptr, parameter); + if (param_desc_ptr == NULL) + { + jack_controller_error(error, "Unknown parameter \"%s\" of driver \"%s\"", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + if (param_desc_ptr->type != JackDriverParamString) + { + jack_controller_error(error, "Parameter \"%s\" of driver \"%s\" is not string", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + value_len = strlen(value); + + if (value_len > JACK_DRIVER_PARAM_STRING_MAX) + { + jack_controller_error( + error, + "Max size of string parameter values is %u chars but value supplied is %u chars", + JACK_DRIVER_PARAM_STRING_MAX, + value_len); + return FALSE; + } + + jack_info("Setting parameter \"%s\" of driver \"%s\" to \"%s\"", parameter, controller_ptr->driver_ptr->desc_ptr->name, value); + + param_ptr = jack_controller_find_or_create_parameter_current_driver(controller_ptr, param_desc_ptr); + if (param_ptr == NULL) + { + jack_controller_error(error, "driver parameter creation failed"); + return FALSE; + } + + memcpy(param_ptr->value.str, value, value_len + 1); + + jack_controller_settings_save_auto(controller_ptr); + + return TRUE; +} + +gboolean +jack_controller_set_driver_parameter_value_bool( + JackController * object_ptr, + const gchar * parameter, + gboolean value, + GError ** error) +{ + struct jack_controller * controller_ptr; + jack_driver_param_desc_t * param_desc_ptr; + jack_driver_param_t * param_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->driver_ptr == NULL) + { + jack_controller_error(error, "Select driver before operating on its parameters!"); + return FALSE; + } + + param_desc_ptr = jack_controller_find_parameter_descriptor_by_name_current_driver(controller_ptr, parameter); + if (param_desc_ptr == NULL) + { + jack_controller_error(error, "Unknown parameter \"%s\" of driver \"%s\"", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + if (param_desc_ptr->type != JackDriverParamBool) + { + jack_controller_error(error, "Parameter \"%s\" of driver \"%s\" is not boolean", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + jack_info("Setting parameter \"%s\" of driver \"%s\" to %s", parameter, controller_ptr->driver_ptr->desc_ptr->name, value ? "true" : "false"); + + param_ptr = jack_controller_find_or_create_parameter_current_driver(controller_ptr, param_desc_ptr); + if (param_ptr == NULL) + { + jack_controller_error(error, "driver parameter creation failed"); + return FALSE; + } + + param_ptr->value.i = value ? TRUE : FALSE; + + jack_controller_settings_save_auto(controller_ptr); + + return TRUE; +} + +gboolean +jack_controller_set_driver_parameter_value_char( + JackController * object_ptr, + const gchar * parameter, + guchar value, + GError ** error) +{ + struct jack_controller * controller_ptr; + jack_driver_param_desc_t * param_desc_ptr; + jack_driver_param_t * param_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->driver_ptr == NULL) + { + jack_controller_error(error, "Select driver before operating on its parameters!"); + return FALSE; + } + + param_desc_ptr = jack_controller_find_parameter_descriptor_by_name_current_driver(controller_ptr, parameter); + if (param_desc_ptr == NULL) + { + jack_controller_error(error, "Unknown parameter \"%s\" of driver \"%s\"", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + if (param_desc_ptr->type != JackDriverParamChar) + { + jack_controller_error(error, "Parameter \"%s\" of driver \"%s\" is not char", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + jack_info("Setting parameter \"%s\" of driver \"%s\" to %c", parameter, controller_ptr->driver_ptr->desc_ptr->name, value); + + param_ptr = jack_controller_find_or_create_parameter_current_driver(controller_ptr, param_desc_ptr); + if (param_ptr == NULL) + { + jack_controller_error(error, "driver parameter creation failed"); + return FALSE; + } + + param_ptr->value.c = value; + + jack_controller_settings_save_auto(controller_ptr); + + return TRUE; +} + +gboolean +jack_controller_set_driver_parameter_value_int( + JackController * object_ptr, + const gchar * parameter, + gint value, + GError ** error) +{ + struct jack_controller * controller_ptr; + jack_driver_param_desc_t * param_desc_ptr; + jack_driver_param_t * param_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->driver_ptr == NULL) + { + jack_controller_error(error, "Select driver before operating on its parameters!"); + return FALSE; + } + + param_desc_ptr = jack_controller_find_parameter_descriptor_by_name_current_driver(controller_ptr, parameter); + if (param_desc_ptr == NULL) + { + jack_controller_error(error, "Unknown parameter \"%s\" of driver \"%s\"", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + if (param_desc_ptr->type != JackDriverParamInt) + { + jack_controller_error(error, "Parameter \"%s\" of driver \"%s\" is not sint", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + jack_info("Setting parameter \"%s\" of driver \"%s\" to %d", parameter, controller_ptr->driver_ptr->desc_ptr->name, value); + + param_ptr = jack_controller_find_or_create_parameter_current_driver(controller_ptr, param_desc_ptr); + if (param_ptr == NULL) + { + jack_controller_error(error, "driver parameter creation failed"); + return FALSE; + } + + param_ptr->value.i = value; + + jack_controller_settings_save_auto(controller_ptr); + + return TRUE; +} + +gboolean +jack_controller_set_driver_parameter_value_uint( + JackController * object_ptr, + const gchar * parameter, + guint value, + GError ** error) +{ + struct jack_controller * controller_ptr; + jack_driver_param_desc_t * param_desc_ptr; + jack_driver_param_t * param_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->driver_ptr == NULL) + { + jack_controller_error(error, "Select driver before operating on its parameters!"); + return FALSE; + } + + param_desc_ptr = jack_controller_find_parameter_descriptor_by_name_current_driver(controller_ptr, parameter); + if (param_desc_ptr == NULL) + { + jack_controller_error(error, "Unknown parameter \"%s\" of driver \"%s\"", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + if (param_desc_ptr->type != JackDriverParamUInt) + { + jack_controller_error(error, "Parameter \"%s\" of driver \"%s\" is not uint", parameter, controller_ptr->driver_ptr->desc_ptr->name); + return FALSE; + } + + jack_info("Setting parameter \"%s\" of driver \"%s\" to %u", parameter, controller_ptr->driver_ptr->desc_ptr->name, value); + + param_ptr = jack_controller_find_or_create_parameter_current_driver(controller_ptr, param_desc_ptr); + if (param_ptr == NULL) + { + jack_controller_error(error, "driver parameter creation failed"); + return FALSE; + } + + param_ptr->value.ui = value; + + jack_controller_settings_save_auto(controller_ptr); + + return TRUE; +} + +gboolean +jack_controller_get_engine_parameter_names( + JackController * object_ptr, + gchar *** params_list, + GError ** error) +{ + struct jack_controller * controller_ptr; + gchar **array; + unsigned int i; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->verbose) + { + jack_info("Getting engine parameters"); + } + + array = g_malloc((JACK_ENGINE_PARAMS_COUNT + 1) * sizeof(gchar *)); + + for (i = 0; i < JACK_ENGINE_PARAMS_COUNT ; i++) + { + array[i] = g_strdup(jack_engine_parameters[i].name); + } + + array[i] = NULL; + + *params_list = array; + + return TRUE; +} + +gboolean +jack_controller_get_engine_parameter_short_description( + JackController * object_ptr, + const gchar * parameter, + gchar ** description, + GError ** error) +{ + unsigned int i; + + for (i = 0; i < JACK_ENGINE_PARAMS_COUNT ; i++) + { + if (strcmp(jack_engine_parameters[i].name, parameter) == 0) + { + *description = g_strdup(jack_engine_parameters[i].description_short); + return TRUE; + } + } + + jack_controller_error(error, "Unknown engine parameter \"%s\"", parameter); + return FALSE; +} + +gboolean +jack_controller_get_engine_parameter_long_description( + JackController * object_ptr, + const gchar * parameter, + gchar ** description, + GError ** error) +{ + unsigned int i; + + for (i = 0; i < JACK_ENGINE_PARAMS_COUNT ; i++) + { + if (strcmp(jack_engine_parameters[i].name, parameter) == 0) + { + if (jack_engine_parameters[i].description_long == NULL) + { + *description = g_strdup(jack_engine_parameters[i].description_short); + } + else + { + *description = g_strdup(jack_engine_parameters[i].description_long); + } + + return TRUE; + } + } + + jack_controller_error(error, "Unknown engine parameter \"%s\"", parameter); + return FALSE; +} + +gboolean +jack_controller_get_engine_parameter_type( + JackController * object_ptr, + const gchar * parameter, + guchar * type, + GError ** error) +{ + unsigned int i; + + for (i = 0; i < JACK_ENGINE_PARAMS_COUNT ; i++) + { + if (strcmp(jack_engine_parameters[i].name, parameter) == 0) + { + *type = jack_engine_parameters[i].type; + return TRUE; + } + } + + jack_controller_error(error, "Unknown engine parameter \"%s\"", parameter); + return FALSE; +} + +gboolean +jack_controller_get_engine_parameter_type_string( + JackController * object_ptr, + const gchar * parameter, + gchar ** type, + GError ** error) +{ + unsigned int i; + + for (i = 0; i < JACK_ENGINE_PARAMS_COUNT ; i++) + { + if (strcmp(jack_engine_parameters[i].name, parameter) == 0) + { + switch (jack_engine_parameters[i].type) + { + case JackParamInt: + *type = g_strdup("sint"); + return TRUE; + case JackParamUInt: + *type = g_strdup("uint"); + return TRUE; + case JackParamChar: + *type = g_strdup("char"); + return TRUE; + case JackParamString: + *type = g_strdup("str"); + return TRUE; + case JackParamBool: + *type = g_strdup("bool"); + return TRUE; + } + + jack_controller_error( + error, + "Engine parameter \"%s\" is of unknown type %d", + parameter, + jack_engine_parameters[i].type); + return FALSE; + } + } + + jack_controller_error(error, "Unknown engine parameter \"%s\"", parameter); + return FALSE; +} + +gboolean +jack_controller_get_engine_parameter_value_string( + JackController * object_ptr, + const gchar * parameter, + gchar ** value, + GError ** error) +{ + jack_controller_error(error, "Unknown engine string parameter \"%s\"", parameter); + return FALSE; +} + +gboolean +jack_controller_set_engine_parameter_value_string( + JackController * object_ptr, + const gchar * parameter, + gchar * value, + GError ** error) +{ + jack_controller_error(error, "Unknown engine string parameter \"%s\"", parameter); + return FALSE; +} + +gboolean +jack_controller_get_engine_parameter_value_bool( + JackController * object_ptr, + const gchar * parameter, + gboolean * value, + GError ** error) +{ + struct jack_controller * controller_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (strcmp(parameter, "realtime") == 0) + { + *value = controller_ptr->realtime ? TRUE : FALSE; + return TRUE; + } + + if (strcmp(parameter, "no-mem-lock") == 0) + { + *value = controller_ptr->do_mlock ? FALSE : TRUE; /* reverse logic */ + return TRUE; + } + + if (strcmp(parameter, "temporary") == 0) + { + *value = controller_ptr->temporary ? TRUE : FALSE; + return TRUE; + } + + if (strcmp(parameter, "verbose") == 0) + { + *value = controller_ptr->verbose ? TRUE : FALSE; + return TRUE; + } + + if (strcmp(parameter, "no-zombies") == 0) + { + *value = controller_ptr->nozombies ? TRUE : FALSE; + return TRUE; + } + + if (strcmp(parameter, "libs-unlock") == 0) + { + *value = controller_ptr->do_unlock ? TRUE : FALSE; + return TRUE; + } + + jack_controller_error(error, "Unknown engine boolean parameter \"%s\"", parameter); + return FALSE; +} + +gboolean +jack_controller_set_engine_parameter_value_bool( + JackController * object_ptr, + const gchar * parameter, + gboolean value, + GError ** error) +{ + struct jack_controller * controller_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (controller_ptr->verbose) + { + jack_info("Setting boolean parameter \"%s\" to %s", parameter, value ? "true" : "false"); + } + + if (strcmp(parameter, "realtime") == 0) + { + controller_ptr->realtime = value; + goto save; + } + + if (strcmp(parameter, "no-mem-lock") == 0) + { + controller_ptr->do_mlock = !value; /* reverse logic */ + goto save; + } + + if (strcmp(parameter, "temporary") == 0) + { + controller_ptr->temporary = value; + goto save; + } + + if (strcmp(parameter, "verbose") == 0) + { + if (!controller_ptr->verbose && value) + { + jack_info("Setting boolean parameter \"%s\" to %s", parameter, value ? "true" : "false"); + } + + controller_ptr->verbose = value; + goto save; + } + + if (strcmp(parameter, "no-zombies") == 0) + { + controller_ptr->nozombies = value; + goto save; + } + + if (strcmp(parameter, "libs-unlock") == 0) + { + controller_ptr->do_unlock = value; + goto save; + } + + jack_controller_error(error, "Unknown engine boolean parameter \"%s\"", parameter); + return FALSE; + +save: + jack_controller_settings_save_auto(controller_ptr); + return TRUE; +} + +gboolean +jack_controller_get_engine_parameter_value_char( + JackController * object_ptr, + const gchar * parameter, + guchar * value, + GError ** error) +{ + jack_controller_error(error, "Unknown engine char parameter \"%s\"", parameter); + return FALSE; +} + +gboolean +jack_controller_set_engine_parameter_value_char( + JackController * object_ptr, + const gchar * parameter, + guchar value, + GError ** error) +{ + jack_controller_error(error, "Unknown engine char parameter \"%s\"", parameter); + return FALSE; +} + +gboolean +jack_controller_get_engine_parameter_value_int( + JackController * object_ptr, + const gchar * parameter, + gint * value, + GError ** error) +{ + struct jack_controller * controller_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (strcmp(parameter, "realtime-priority") == 0) + { + *value = controller_ptr->realtime_priority; + return TRUE; + } + + if (strcmp(parameter, "client-timeout") == 0) + { + *value = controller_ptr->client_timeout; + return TRUE; + } + + jack_controller_error(error, "Unknown engine sint parameter \"%s\"", parameter); + return FALSE; +} + +gboolean +jack_controller_set_engine_parameter_value_int( + JackController * object_ptr, + const gchar * parameter, + gint value, + GError ** error) +{ + struct jack_controller * controller_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (strcmp(parameter, "realtime-priority") == 0) + { + controller_ptr->realtime_priority = value; + goto save; + } + + if (strcmp(parameter, "client-timeout") == 0) + { + controller_ptr->client_timeout = value; + goto save; + } + + jack_controller_error(error, "Unknown engine sint parameter \"%s\"", parameter); + return FALSE; + +save: + jack_controller_settings_save_auto(controller_ptr); + return TRUE; +} + +gboolean +jack_controller_get_engine_parameter_value_uint( + JackController * object_ptr, + const gchar * parameter, + guint * value, + GError ** error) +{ + struct jack_controller * controller_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (strcmp(parameter, "port-max") == 0) + { + *value = controller_ptr->port_max; + return TRUE; + } + + jack_controller_error(error, "Unknown engine uint parameter \"%s\"", parameter); + return FALSE; +} + +gboolean +jack_controller_set_engine_parameter_value_uint( + JackController * object_ptr, + const gchar * parameter, + guint value, + GError ** error) +{ + struct jack_controller * controller_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (strcmp(parameter, "port-max") == 0) + { + controller_ptr->port_max = value; + goto save; + } + + jack_controller_error(error, "Unknown engine uint parameter \"%s\"", parameter); + return FALSE; + +save: + jack_controller_settings_save_auto(controller_ptr); + return TRUE; +} diff --git a/jackd/jackcontroller.h b/jackd/jackcontroller.h new file mode 100644 --- /dev/null +++ b/jackd/jackcontroller.h @@ -0,0 +1,354 @@ +/* -*- mode: c; c-file-style: "bsd"; -*- */ +/* + Copyright (C) 2007 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 JACKCONTROLLER_H__2CC80B1E_8D5D_45E3_A9D8_9086DDF68BB5__INCLUDED +#define JACKCONTROLLER_H__2CC80B1E_8D5D_45E3_A9D8_9086DDF68BB5__INCLUDED + +G_BEGIN_DECLS + +#define JACK_CONTROLLER_TYPE (jack_controller_get_type()) +#define JACK_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), JACK_CONTROLLER_TYPE, JackController)) +#define JACK_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), JACK_CONTROLLER_TYPE, JackControllerClass)) +#define JACK_IS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), JACK_CONTROLLER_TYPE)) +#define JACK_IS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), JACK_CONTROLLER_TYPE)) +#define JACK_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), JACK_CONTROLLER_TYPE, JackControllerClass)) + +#define JACK_TYPE_CONTROLLER JACK_CONTROLLER_TYPE + +typedef struct _JackController JackController; +typedef struct _JackControllerClass JackControllerClass; + +struct _JackController { + GObject parent; + /* instance members */ +}; + +struct _JackControllerClass { + GObjectClass parent; + /* class members */ +}; + +/* used by JACK_CONTROLLER_TYPE */ +GType jack_controller_get_type(); + +void +jack_controller_run( + JackController * object_ptr); + +gboolean +jack_controller_test( + JackController * object_ptr, + GError ** error); + +gboolean +jack_controller_exit( + JackController * object_ptr, + GError ** error); + +gboolean +jack_controller_is_manually_activated( + JackController * object_ptr, + gboolean * manually_started_ptr, + GError ** error); + +gboolean +jack_controller_is_started( + JackController * object_ptr, + gboolean * started_ptr, + GError ** error); + +gboolean +jack_controller_start_server( + JackController * object_ptr, + GError ** error); + +gboolean +jack_controller_stop_server( + JackController * object_ptr, + GError ** error); + +gboolean +jack_controller_get_load( + JackController * object_ptr, + gdouble * load_ptr, + GError ** error); + +gboolean +jack_controller_get_xruns( + JackController * object_ptr, + guint * xruns_ptr, + GError ** error); + +gboolean +jack_controller_get_sample_rate( + JackController * object_ptr, + guint * sample_rate_ptr, + GError ** error); + +gboolean +jack_controller_get_latency( + JackController * object_ptr, + gdouble * latency_ptr, + GError ** error); + +gboolean +jack_controller_is_manually_activated( + JackController * object_ptr, + gboolean * manually_started_ptr, + GError ** error); + +gboolean +jack_controller_get_available_drivers( + JackController * object_ptr, + gchar *** drivers_list, + GError ** error); + +gboolean +jack_controller_get_selected_driver( + JackController * object_ptr, + gchar ** driver_name, + GError ** error); + +gboolean +jack_controller_select_driver( + JackController * object_ptr, + const gchar * driver_name, + GError ** error); + +gboolean +jack_controller_get_driver_parameter_names( + JackController * object_ptr, + gchar *** params_list, + GError ** error); + +gboolean +jack_controller_get_driver_parameter_short_description( + JackController * object_ptr, + const gchar * parameter, + gchar ** description, + GError ** error); + +gboolean +jack_controller_get_driver_parameter_long_description( + JackController * object_ptr, + const gchar * parameter, + gchar ** description, + GError ** error); + +gboolean +jack_controller_get_driver_parameter_type( + JackController * object_ptr, + const gchar * parameter, + guchar * type, + GError ** error); + +gboolean +jack_controller_get_driver_parameter_type_string( + JackController * object_ptr, + const gchar * parameter, + gchar ** type, + GError ** error); + +gboolean +jack_controller_get_driver_parameter_value_string( + JackController * object_ptr, + const gchar * parameter, + gboolean * isset, + gchar ** default_value, + gchar ** value, + GError ** error); + +gboolean +jack_controller_get_driver_parameter_value_bool( + JackController * object_ptr, + const gchar * parameter, + gboolean * isset, + gboolean * default_value, + gboolean * value, + GError ** error); + +gboolean +jack_controller_get_driver_parameter_value_char( + JackController * object_ptr, + const gchar * parameter, + gboolean * isset, + guchar * default_value, + guchar * value, + GError ** error); + +gboolean +jack_controller_get_driver_parameter_value_int( + JackController * object_ptr, + const gchar * parameter, + gboolean * isset, + gint * default_value, + gint * value, + GError ** error); + +gboolean +jack_controller_get_driver_parameter_value_uint( + JackController * object_ptr, + const gchar * parameter, + gboolean * isset, + guint * default_value, + guint * value, + GError ** error); + +gboolean +jack_controller_set_driver_parameter_value_string( + JackController * object_ptr, + const gchar * parameter, + gchar * value, + GError ** error); + +gboolean +jack_controller_set_driver_parameter_value_bool( + JackController * object_ptr, + const gchar * parameter, + gboolean value, + GError ** error); + +gboolean +jack_controller_set_driver_parameter_value_char( + JackController * object_ptr, + const gchar * parameter, + guchar value, + GError ** error); + +gboolean +jack_controller_set_driver_parameter_value_int( + JackController * object_ptr, + const gchar * parameter, + gint value, + GError ** error); + +gboolean +jack_controller_set_driver_parameter_value_uint( + JackController * object_ptr, + const gchar * parameter, + guint value, + GError ** error); + +gboolean +jack_controller_get_engine_parameter_names( + JackController * object_ptr, + gchar *** params_list, + GError ** error); + +gboolean +jack_controller_get_engine_parameter_short_description( + JackController * object_ptr, + const gchar * parameter, + gchar ** description, + GError ** error); + +gboolean +jack_controller_get_engine_parameter_long_description( + JackController * object_ptr, + const gchar * parameter, + gchar ** description, + GError ** error); + +gboolean +jack_controller_get_engine_parameter_type( + JackController * object_ptr, + const gchar * parameter, + guchar * type, + GError ** error); + +gboolean +jack_controller_get_engine_parameter_type_string( + JackController * object_ptr, + const gchar * parameter, + gchar ** type, + GError ** error); + +gboolean +jack_controller_get_engine_parameter_value_string( + JackController * object_ptr, + const gchar * parameter, + gchar ** value, + GError ** error); + +gboolean +jack_controller_get_engine_parameter_value_bool( + JackController * object_ptr, + const gchar * parameter, + gboolean * value, + GError ** error); + +gboolean +jack_controller_get_engine_parameter_value_char( + JackController * object_ptr, + const gchar * parameter, + guchar * value, + GError ** error); + +gboolean +jack_controller_get_engine_parameter_value_int( + JackController * object_ptr, + const gchar * parameter, + gint * value, + GError ** error); + +gboolean +jack_controller_get_engine_parameter_value_uint( + JackController * object_ptr, + const gchar * parameter, + guint * value, + GError ** error); + +gboolean +jack_controller_set_engine_parameter_value_string( + JackController * object_ptr, + const gchar * parameter, + gchar * value, + GError ** error); + +gboolean +jack_controller_set_engine_parameter_value_bool( + JackController * object_ptr, + const gchar * parameter, + gboolean value, + GError ** error); + +gboolean +jack_controller_set_engine_parameter_value_char( + JackController * object_ptr, + const gchar * parameter, + guchar value, + GError ** error); + +gboolean +jack_controller_set_engine_parameter_value_int( + JackController * object_ptr, + const gchar * parameter, + gint value, + GError ** error); + +gboolean +jack_controller_set_engine_parameter_value_uint( + JackController * object_ptr, + const gchar * parameter, + guint value, + GError ** error); + +G_END_DECLS + +#endif /* #ifndef JACKCONTROLLER_H__2CC80B1E_8D5D_45E3_A9D8_9086DDF68BB5__INCLUDED */ diff --git a/jackd/jackcontroller.xml b/jackd/jackcontroller.xml new file mode 100644 --- /dev/null +++ b/jackd/jackcontroller.xml @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jackd/jackcontroller_internal.h b/jackd/jackcontroller_internal.h new file mode 100644 --- /dev/null +++ b/jackd/jackcontroller_internal.h @@ -0,0 +1,138 @@ +/* -*- mode: c; c-file-style: "bsd"; -*- */ +/* + Copyright (C) 2007 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 JACKCONTROLLER_INTERNAL_H__04D54D51_3D79_49A2_A1DA_F8587E9E7F42__INCLUDED +#define JACKCONTROLLER_INTERNAL_H__04D54D51_3D79_49A2_A1DA_F8587E9E7F42__INCLUDED + +struct jack_controller_driver +{ + char * filename; + jack_driver_desc_t * desc_ptr; + JSList * params; +}; + +struct jack_controller +{ + gboolean dispose_has_run; + + GMainLoop *loop; + gboolean manually_started; + + unsigned int drivers_count; + JSList *drivers; + + /* current driver, NULL if not driver is selected */ + struct jack_controller_driver *driver_ptr; + + jack_engine_t *engine; + + int realtime; /* boolean, whether to be "realtime" */ + int realtime_priority; + + char *server_name; + + int do_mlock; /* boolean, whether to do memory locking */ + int temporary; /* boolean, whether to exit once all clients have closed their connections */ + int verbose; /* boolean, whether to be verbose */ + int client_timeout; /* msecs; if zero, use period size. */ + unsigned int port_max; /* maximum number of ports the JACK server can manage */ + int do_unlock; /* boolean, whether to unlock libraries GTK+, QT, FLTK, Wine */ + jack_nframes_t frame_time_offset; + int nozombies; /* boolean, whether to prevent from ever kicking out clients because they were too slow */ + + guint xruns; +}; + +/** Parameter types, intentionally similar to jack_driver_param_type_t */ +typedef enum +{ + JackParamInt = 1, + JackParamUInt, + JackParamChar, + JackParamString, + JackParamBool + +} jack_param_type_t; + +struct jack_engine_parameter_descriptor +{ + const char *name; + jack_param_type_t type; + const char *description_short; + const char *description_long; +}; + +#define JACK_CONF_HEADER_TEXT \ + "JACK settings, as persisted by D-Bus object.\n" \ + "You probably don't want to edit this because\n" \ + "it will be overwritten next time jackdbus saves.\n" + +void +jack_controller_error( + GError **error, + const gchar *format, + ...); + +jack_driver_param_desc_t * +jack_controller_find_parameter_descriptor( + struct jack_controller_driver *driver_ptr, + jack_driver_param_t * param_ptr); + +jack_driver_param_desc_t * +jack_controller_find_parameter_descriptor_by_name( + struct jack_controller_driver *driver_ptr, + const char *param_name); + +jack_driver_param_t * +jack_controller_find_or_create_parameter( + struct jack_controller_driver *driver_ptr, + const jack_driver_param_desc_t *descr_ptr); + +void +jack_controller_settings_set_driver_option( + struct jack_controller_driver *driver_ptr, + const char *option_name, + const char *option_value); + +void +jack_controller_settings_set_engine_option( + struct jack_controller *controller_ptr, + const char *option_name, + const char *option_value); + +gboolean +jack_controller_settings_save_engine_options( + void *context, + struct jack_controller *controller_ptr, + GError **error); + +gboolean +jack_controller_settings_write_option( + void *context, + const char *name, + const char *content, + GError **error); + +gboolean +jack_controller_settings_save_driver_options( + void *context, + struct jack_controller_driver *driver_ptr, + GError **error); + +#endif /* #ifndef JACKCONTROLLER_INTERNAL_H__04D54D51_3D79_49A2_A1DA_F8587E9E7F42__INCLUDED */ diff --git a/jackd/jackcontroller_xml.c b/jackd/jackcontroller_xml.c new file mode 100644 --- /dev/null +++ b/jackd/jackcontroller_xml.c @@ -0,0 +1,344 @@ +/* -*- mode: c; c-file-style: "bsd"; -*- */ +/* + Copyright (C) 2007 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. + +*/ + +#include +#include +#include + +#include +#include +#include "jackcontroller_internal.h" + +void +jack_controller_settings_set_bool_option( + const char *value_str, + int *value_ptr, + gboolean reverse) +{ + if (strcmp(value_str, "true") == 0) + { + *value_ptr = !reverse; + } + else if (strcmp(value_str, "false") == 0) + { + *value_ptr = reverse; + } + 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( + struct jack_controller_driver *driver_ptr, + const char *option_name, + const char *option_value) +{ + jack_driver_param_desc_t *param_desc_ptr; + jack_driver_param_t *param_ptr; + int value_int; + unsigned int value_uint; + + jack_info("setting driver option \"%s\" to value \"%s\"", option_name, option_value); + + param_desc_ptr = jack_controller_find_parameter_descriptor_by_name(driver_ptr, option_name); + if (param_desc_ptr == NULL) + { + jack_error("Unknown parameter \"%s\" of driver \"%s\"", option_name, driver_ptr->desc_ptr->name); + return; + } + + param_ptr = jack_controller_find_or_create_parameter(driver_ptr, param_desc_ptr); + if (param_ptr == NULL) + { + jack_error("driver parameter creation failed"); + return; + } + + switch (param_desc_ptr->type) + { + case JackDriverParamInt: + jack_controller_settings_set_sint_option(option_value, &value_int); + param_ptr->value.i = value_int; + return; + case JackDriverParamUInt: + jack_controller_settings_set_uint_option(option_value, &value_uint); + param_ptr->value.ui = value_uint; + return; + case JackDriverParamChar: + jack_controller_settings_set_char_option(option_value, ¶m_ptr->value.c); + return; + case JackDriverParamString: + jack_controller_settings_set_string_option(option_value, param_ptr->value.str, sizeof(param_ptr->value.str)); + return; + case JackDriverParamBool: + jack_controller_settings_set_bool_option(option_value, &value_int, FALSE); + param_ptr->value.i = value_int; + return; + } + + jack_error("Parameter \"%s\" of driver \"%s\" is of unknown type %d", + param_desc_ptr->name, + driver_ptr->desc_ptr->name, + param_desc_ptr->type); +} + +void +jack_controller_settings_set_engine_option( + struct jack_controller *controller_ptr, + const char *option_name, + const char *option_value) +{ + struct jack_controller_driver * driver_ptr; + JSList * node_ptr; + + jack_info("setting engine option \"%s\" to value \"%s\"", option_name, option_value); + + if (strcmp(option_name, "driver") == 0) + { + for (node_ptr = controller_ptr->drivers ; node_ptr != NULL ; node_ptr = jack_slist_next(node_ptr)) + { + driver_ptr = (struct jack_controller_driver *)node_ptr->data; + + if (strcmp(driver_ptr->desc_ptr->name, option_value) == 0) { + jack_info("driver \"%s\" selected", driver_ptr->desc_ptr->name); + controller_ptr->driver_ptr = driver_ptr; + return; + } + } + + jack_error("unknown driver '%s'", option_value); + } + else if (strcmp(option_name, "realtime") == 0) + { + jack_controller_settings_set_bool_option(option_value, &controller_ptr->realtime, FALSE); + } + else if (strcmp(option_name, "realtime-priority") == 0) + { + jack_controller_settings_set_sint_option(option_value, &controller_ptr->realtime_priority); + } + else if (strcmp(option_name, "no-mem-lock") == 0) + { + jack_controller_settings_set_bool_option(option_value, &controller_ptr->do_mlock, TRUE); + } + else if (strcmp(option_name, "temporary") == 0) + { + jack_controller_settings_set_bool_option(option_value, &controller_ptr->temporary, FALSE); + } + else if (strcmp(option_name, "verbose") == 0) + { + jack_controller_settings_set_bool_option(option_value, &controller_ptr->verbose, FALSE); + } + else if (strcmp(option_name, "client-timeout") == 0) + { + jack_controller_settings_set_sint_option(option_value, &controller_ptr->client_timeout); + } + else if (strcmp(option_name, "no-zombies") == 0) + { + jack_controller_settings_set_bool_option(option_value, &controller_ptr->nozombies, FALSE); + } + else if (strcmp(option_name, "port-max") == 0) + { + jack_controller_settings_set_uint_option(option_value, &controller_ptr->port_max); + } + else if (strcmp(option_name, "libs-unlock") == 0) + { + jack_controller_settings_set_bool_option(option_value, &controller_ptr->do_unlock, FALSE); + } + else + { + jack_error("ignoring unknown option \"%s\" with value \"%s\"", option_name, option_value); + } +} + +gboolean +jack_controller_settings_save_engine_options( + void *context, + struct jack_controller *controller_ptr, + GError **error) +{ + gchar value_str[50]; + + if (controller_ptr->driver_ptr != NULL) + { + if (!jack_controller_settings_write_option(context, "driver", controller_ptr->driver_ptr->desc_ptr->name, error)) + { + return FALSE; + } + } + + if (!jack_controller_settings_write_option(context, "realtime", controller_ptr->realtime ? "true" : "false", error)) + { + return FALSE; + } + + sprintf(value_str, "%d", controller_ptr->realtime_priority); + if (!jack_controller_settings_write_option(context, "realtime-priority", value_str, error)) + { + return FALSE; + } + + if (!jack_controller_settings_write_option(context, "no-mem-lock", controller_ptr->do_mlock ? "false" : "true", error)) /* reverse */ + { + return FALSE; + } + + if (!jack_controller_settings_write_option(context, "temporary", controller_ptr->temporary ? "true" : "false", error)) + { + return FALSE; + } + + if (!jack_controller_settings_write_option(context, "verbose", controller_ptr->verbose ? "true" : "false", error)) + { + return FALSE; + } + + sprintf(value_str, "%d", controller_ptr->client_timeout); + if (!jack_controller_settings_write_option(context, "client-timeout", value_str, error)) + { + return FALSE; + } + + if (!jack_controller_settings_write_option(context, "no-zombies", controller_ptr->nozombies ? "true" : "false", error)) + { + return FALSE; + } + + sprintf(value_str, "%d", controller_ptr->port_max); + if (!jack_controller_settings_write_option(context, "port-max", value_str, error)) + { + return FALSE; + } + + if (!jack_controller_settings_write_option(context, "libs-unlock", controller_ptr->do_unlock ? "true" : "false", error)) + { + return FALSE; + } + + return TRUE; +} + +gboolean +jack_controller_settings_save_driver_options( + void *context, + struct jack_controller_driver *driver_ptr, + GError **error) +{ + JSList * node_ptr; + jack_driver_param_desc_t *param_desc_ptr; + jack_driver_param_t *param_ptr; + gchar value_str[50]; + + for (node_ptr = driver_ptr->params; node_ptr != NULL; node_ptr = jack_slist_next(node_ptr)) + { + param_ptr = (jack_driver_param_t *)node_ptr->data; + param_desc_ptr = jack_controller_find_parameter_descriptor(driver_ptr, param_ptr); + + switch (param_desc_ptr->type) + { + case JackDriverParamInt: + sprintf(value_str, "%d", param_ptr->value.i); + if (!jack_controller_settings_write_option(context, param_desc_ptr->name, value_str, error)) + { + return FALSE; + } + break; + case JackDriverParamUInt: + sprintf(value_str, "%u", param_ptr->value.ui); + if (!jack_controller_settings_write_option(context, param_desc_ptr->name, value_str, error)) + { + return FALSE; + } + break; + case JackDriverParamChar: + sprintf(value_str, "%c", param_ptr->value.c); + if (!jack_controller_settings_write_option(context, param_desc_ptr->name, value_str, error)) + { + return FALSE; + } + break; + case JackDriverParamString: + if (!jack_controller_settings_write_option(context, param_desc_ptr->name, param_ptr->value.str, error)) + { + return FALSE; + } + break; + case JackDriverParamBool: + if (!jack_controller_settings_write_option(context, param_desc_ptr->name, param_ptr->value.i ? "true" : "false", error)) + { + return FALSE; + } + break; + default: + jack_error("parameter of unknown type %d", param_desc_ptr->type); + } + } + + return TRUE; +} diff --git a/jackd/jackcontroller_xml.h b/jackd/jackcontroller_xml.h new file mode 100644 --- /dev/null +++ b/jackd/jackcontroller_xml.h @@ -0,0 +1,42 @@ +/* -*- mode: c; c-file-style: "bsd"; -*- */ +/* + Copyright (C) 2007 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 JACKCONTROLLER_XML_H__4F102BD2_3354_41C9_B842_DC00E1557A0F__INCLUDED +#define JACKCONTROLLER_XML_H__4F102BD2_3354_41C9_B842_DC00E1557A0F__INCLUDED + +gboolean +jack_controller_settings_init(); + +void +jack_controller_settings_uninit(); + +gboolean +jack_controller_settings_save( + struct jack_controller * controller_ptr, + GError **error); + +void +jack_controller_settings_load( + struct jack_controller * controller_ptr); + +void +jack_controller_settings_save_auto( + struct jack_controller * controller_ptr); + +#endif /* #ifndef JACKCONTROLLER_XML_H__4F102BD2_3354_41C9_B842_DC00E1557A0F__INCLUDED */ diff --git a/jackd/jackcontroller_xml_expat.c b/jackd/jackcontroller_xml_expat.c new file mode 100644 --- /dev/null +++ b/jackd/jackcontroller_xml_expat.c @@ -0,0 +1,313 @@ +/* -*- mode: c; c-file-style: "bsd"; -*- */ +/* + Copyright (C) 2007 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. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "jackcontroller_internal.h" +#include "jackdbus.h" + +gboolean +jack_controller_settings_init() +{ + return TRUE; +} + +void +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 MAX_STACK_DEPTH 10 + +struct parse_context +{ + struct jack_controller *controller_ptr; + XML_Bool error; + unsigned int element[MAX_STACK_DEPTH]; + signed int depth; + struct jack_controller_driver * driver_ptr; + char option[JACK_DRIVER_PARAM_STRING_MAX+1]; + int option_used; + char *name; +}; + +#define context_ptr ((struct parse_context *)data) + +void +jack_controller_settings_callback_chrdata(void *data, const XML_Char *s, int len) +{ + if (context_ptr->error) + { + return; + } + + if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_OPTION) + { + if (context_ptr->option_used + len >= JACK_DRIVER_PARAM_STRING_MAX) + { + jack_error("xml parse max char data length reached"); + context_ptr->error = TRUE; + return; + } + + memcpy(context_ptr->option + context_ptr->option_used, s, len); + context_ptr->option_used += len; + } +} + +void +jack_controller_settings_callback_elstart(void *data, const char *el, const char **attr) +{ + struct jack_controller_driver * driver_ptr; + JSList * node_ptr; + + if (context_ptr->error) + { + return; + } + + if (context_ptr->depth + 1 >= MAX_STACK_DEPTH) + { + jack_error("xml parse max stack depth reached"); + context_ptr->error = TRUE; + return; + } + + if (strcmp(el, "jack") == 0) + { + //jack_info(""); + context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_JACK; + return; + } + + if (strcmp(el, "engine") == 0) + { + //jack_info(""); + context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_ENGINE; + return; + } + + if (strcmp(el, "drivers") == 0) + { + //jack_info(""); + context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DRIVERS; + return; + } + + if (strcmp(el, "driver") == 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_DRIVER; + + for (node_ptr = context_ptr->controller_ptr->drivers ; node_ptr != NULL ; node_ptr = jack_slist_next(node_ptr)) + { + driver_ptr = (struct jack_controller_driver *)node_ptr->data; + + if (strcmp(driver_ptr->desc_ptr->name, attr[1]) == 0) { + jack_info("setting for driver \"%s\" found", attr[1]); + context_ptr->driver_ptr = driver_ptr; + return; + } + } + + jack_error("ignoring settings for unknown driver \"%s\"", attr[1]); + + context_ptr->driver_ptr = NULL; + return; + } + + if (strcmp(el, "option") == 0) + { + //jack_info("