diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -547,6 +547,35 @@ 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 + # 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. @@ -749,6 +778,19 @@ 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 +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 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,64 @@ +#!/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 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 " isr - check whether jack server is running, return value is 0 if runing and 1 otherwise" +# print " status - get string describing jack server status" + print " start - start jack server if not currently started" + print " stop - stop jack server if currenly started" + sys.exit(0) + + bus = dbus.SessionBus() + + controller = bus.get_object(service_name, "/DefaultController") + iface = dbus.Interface(controller, controller_interface_name) + + # check arguments + for arg in sys.argv[1:]: + try: + if arg == "exit": + print "--- exit" + iface.Exit() + elif arg == "isr": + print "--- isr" + if iface.IsRunning(): + sys.exit(0) + else: + sys.exit(1) + elif arg == 'status': + print "--- status" + print iface.GetStatus() + 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" + 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) + +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,26 @@ 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 +jackdbus_LDADD = $(COMMON_LIBS) $(DBUSGLIB_LIBS) + +# 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,645 @@ +/* -*- 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" + +static JSList *drivers = NULL; +static sigset_t signals; +static jack_engine_t *engine = NULL; +static char *server_name = NULL; +static int realtime = 0; +static int realtime_priority = 10; +static int do_mlock = 1; +static int temporary = 0; +static int verbose = 1; +static int client_timeout = 0; /* msecs; if zero, use period size. */ +static unsigned int port_max = 256; +static int do_unlock = 0; +static jack_nframes_t frame_time_offset = 0; +static int nozombies = 0; + +struct jack_controller +{ + gboolean dispose_has_run; + + GMainLoop *loop; + gboolean manually_started; + jack_driver_desc_t * desc; + JSList * driver_params; +}; + +static jack_driver_desc_t * +jack_drivers_get_descriptor (JSList * drivers, const char * sofile) +{ + jack_driver_desc_t * descriptor, * other_descriptor; + JackDriverDescFunction so_get_descriptor; + JSList * node; + void * dlhandle; + char * filename; + const char * dlerr; + int err; + char* driver_dir; + + if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) { + driver_dir = ADDON_DIR; + } + filename = malloc (strlen (driver_dir) + 1 + strlen (sofile) + 1); + sprintf (filename, "%s/%s", driver_dir, sofile); + + if (verbose) { + jack_info ("getting driver descriptor from %s", filename); + } + + if ((dlhandle = dlopen (filename, RTLD_NOW|RTLD_GLOBAL)) == NULL) { + jack_error ("could not open driver .so '%s': %s", filename, dlerror ()); + free (filename); + return NULL; + } + + so_get_descriptor = (JackDriverDescFunction) + dlsym (dlhandle, "driver_get_descriptor"); + + if ((dlerr = dlerror ()) != NULL) { + jack_error("%s", dlerr); + dlclose (dlhandle); + free (filename); + return NULL; + } + + if ((descriptor = so_get_descriptor ()) == NULL) { + jack_error ("driver from '%s' returned NULL descriptor\n", filename); + dlclose (dlhandle); + free (filename); + return NULL; + } + + if ((err = dlclose (dlhandle)) != 0) { + jack_error ("error closing driver .so '%s': %s\n", filename, dlerror ()); + } + + /* check it doesn't exist already */ + for (node = drivers; node; node = jack_slist_next (node)) { + other_descriptor = (jack_driver_desc_t *) node->data; + + if (strcmp (descriptor->name, other_descriptor->name) == 0) { + jack_error ("the drivers in '%s' and '%s' both have the name '%s'; using the first\n", + other_descriptor->file, filename, other_descriptor->name); + /* FIXME: delete the descriptor */ + free (filename); + return NULL; + } + } + + snprintf (descriptor->file, sizeof(descriptor->file), "%s", filename); + free (filename); + + return descriptor; +} + +static JSList * +jack_drivers_load () +{ + struct dirent * dir_entry; + DIR * dir_stream; + const char * ptr; + int err; + JSList * driver_list = NULL; + jack_driver_desc_t * desc; + char* driver_dir; + + if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) { + driver_dir = ADDON_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\n", + driver_dir, strerror (errno)); + return NULL; + } + + while ( (dir_entry = readdir (dir_stream)) ) { + /* check the filename is of the right format */ + if (strncmp ("jack_", dir_entry->d_name, 5) != 0) { + continue; + } + + ptr = strrchr (dir_entry->d_name, '.'); + if (!ptr) { + continue; + } + ptr++; + if (strncmp ("so", ptr, 2) != 0) { + continue; + } + + desc = jack_drivers_get_descriptor (drivers, dir_entry->d_name); + if (desc) { + driver_list = jack_slist_append (driver_list, desc); + } + } + + err = closedir (dir_stream); + if (err) { + jack_error ("error closing driver directory %s: %s\n", + driver_dir, strerror (errno)); + } + + if (!driver_list) { + jack_error ("could not find any drivers in %s!\n", driver_dir); + return NULL; + } + + return driver_list; +} + +static jack_driver_desc_t * +jack_find_driver_descriptor (const char * name) +{ + jack_driver_desc_t * desc = 0; + JSList * node; + + for (node = drivers; node; node = jack_slist_next (node)) { + desc = (jack_driver_desc_t *) node->data; + + if (strcmp (desc->name, name) != 0) { + desc = NULL; + } else { + break; + } + } + + return desc; +} + +static void +do_nothing_handler (int sig) +{ + /* this is used by the child (active) process, but it never + gets called unless we are already shutting down after + another signal. + */ + char buf[64]; + snprintf (buf, sizeof(buf), + "received signal %d during shutdown (ignored)\n", sig); + write (1, buf, strlen (buf)); +} + +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; +} + +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_ptr_ptr) +{ + jack_info("Test!"); + g_set_error(error_ptr_ptr, jack_controller_error_quark(), 0, "Muhahaha!"); + return FALSE; +} + +gboolean +jack_controller_exit( + JackController * object_ptr, + GError ** error_ptr_ptr) +{ + struct jack_controller * controller_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + jack_info("Exit!"); + g_main_quit(controller_ptr->loop); + return TRUE; +} + +void +jack_controller_run( + JackController * object_ptr) +{ + struct jack_controller * controller_ptr; + char *driver_name = "alsa"; + int rc; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + controller_ptr->loop = g_main_loop_new(NULL, FALSE); + controller_ptr->manually_started = FALSE; + + drivers = jack_drivers_load (); + if (!drivers) { + jack_error ("no drivers found; exiting"); + exit (1); + } + + controller_ptr->desc = jack_find_driver_descriptor (driver_name); + if (!controller_ptr->desc) { + jack_error (" unknown driver '%s'", driver_name); + exit (1); + } + + if (jack_parse_driver_params (controller_ptr->desc, 0, NULL, &controller_ptr->driver_params)) { + exit (0); + } + + if (server_name == NULL) + server_name = jack_default_server_name (); + + rc = jack_register_server (server_name); + switch (rc) { + case EEXIST: + jack_error ("`%s' server already active", server_name); + exit (1); + case ENOSPC: + jack_error ("too many servers already active"); + exit (2); + case ENOMEM: + jack_error ("no access to shm registry"); + exit (3); + default: + if (verbose) + jack_info ("server `%s' registered", + server_name); + } + + /* clean up shared memory and files from any previous + * instance of this server name */ + jack_cleanup_shm (); + jack_cleanup_files (server_name); + + /* ensure that we are in our own process group so that + kill (SIG, -pgrp) does the right thing. + */ + + setsid (); + + pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + /* what's this for? + + POSIX says that signals are delivered like this: + + * if a thread has blocked that signal, it is not + a candidate to receive the signal. + * of all threads not blocking the signal, pick + one at random, and deliver the signal. + + this means that a simple-minded multi-threaded program can + expect to get POSIX signals delivered randomly to any one + of its threads, + + here, we block all signals that we think we might receive + and want to catch. all "child" threads will inherit this + setting. if we create a thread that calls sigwait() on the + same set of signals, implicitly unblocking all those + signals. any of those signals that are delivered to the + process will be delivered to that thread, and that thread + alone. this makes cleanup for a signal-driven exit much + easier, since we know which thread is doing it and more + importantly, we are free to call async-unsafe functions, + because the code is executing in normal thread context + after a return from sigwait(). + */ + + sigemptyset (&signals); + sigaddset(&signals, SIGHUP); + sigaddset(&signals, SIGINT); + sigaddset(&signals, SIGQUIT); + sigaddset(&signals, SIGPIPE); + sigaddset(&signals, SIGTERM); + sigaddset(&signals, SIGUSR1); + sigaddset(&signals, SIGUSR2); + + /* all child threads will inherit this mask unless they + * explicitly reset it + */ + + pthread_sigmask (SIG_BLOCK, &signals, 0); + + jack_info("Starting loop..."); + g_main_loop_run(controller_ptr->loop); + + if (engine != NULL) + { + jack_controller_stop_server(object_ptr, NULL); + + } +} + +gboolean +jack_controller_is_manually_activated( + JackController * object_ptr, + gboolean * manually_started_ptr, + GError ** error_ptr_ptr) +{ + 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; +} + +gboolean +jack_controller_start_server( + JackController * object_ptr, + GError ** error_ptr_ptr) +{ + struct jack_controller * controller_ptr; + int i; + sigset_t allsignals; + struct sigaction action; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + jack_info("Starting jack server..."); + + if (!realtime && client_timeout == 0) + client_timeout = 500; /* 0.5 sec; usable when non realtime. */ + + /* get the engine/driver started */ + + if ((engine = jack_engine_new (realtime, realtime_priority, + do_mlock, do_unlock, server_name, + temporary, verbose, client_timeout, + port_max, getpid(), frame_time_offset, + nozombies, drivers)) == 0) { + g_set_error(error_ptr_ptr, jack_controller_error_quark(), 0, "Cannot create engine!"); + goto fail; + } + + jack_info ("loading driver .."); + + if (jack_engine_load_driver (engine, controller_ptr->desc, controller_ptr->driver_params)) { + g_set_error(error_ptr_ptr, jack_controller_error_quark(), 0, "Cannot load driver module!"); + jack_error ("cannot load driver module %s", controller_ptr->desc->name); + goto fail_delete_engine; + } + + if (engine->driver->start (engine->driver) != 0) { + jack_error ("cannot start driver"); + goto fail_delete_engine; + } + + /* install a do-nothing handler because otherwise pthreads + behaviour is undefined when we enter sigwait. + */ + + sigfillset (&allsignals); + action.sa_handler = do_nothing_handler; + action.sa_mask = allsignals; + action.sa_flags = SA_RESTART|SA_RESETHAND; + + for (i = 1; i < NSIG; i++) { + if (sigismember (&signals, i)) { + sigaction (i, &action, 0); + } + } + + return TRUE; + +fail_delete_engine: + jack_engine_delete (engine); + +fail: + return FALSE; +} + +gboolean +jack_controller_stop_server( + JackController * object_ptr, + GError ** error_ptr_ptr) +{ + struct jack_controller * controller_ptr; + + controller_ptr = JACK_CONTROLLER_GET_PRIVATE(object_ptr); + + if (engine == NULL) + { + return TRUE; + } + + jack_info("Stop jack server..."); + + jack_engine_delete (engine); + + /* clean up shared memory and files from this server instance */ + if (verbose) + jack_info ("cleaning up shared memory"); + jack_cleanup_shm (); + if (verbose) + jack_info ("cleaning up files"); + jack_cleanup_files (server_name); + if (verbose) + jack_info ("unregistering server `%s'", server_name); + jack_unregister_server (server_name); + + engine = NULL; + + 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,82 @@ +/* -*- 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_ptr_ptr); + +gboolean +jack_controller_exit( + JackController * object_ptr, + GError ** error_ptr_ptr); + +gboolean +jack_controller_is_manually_activated( + JackController * object_ptr, + gboolean * manually_started_ptr, + GError ** error_ptr_ptr); + +gboolean +jack_controller_start_server( + JackController * object_ptr, + GError ** error_ptr_ptr); + +gboolean +jack_controller_stop_server( + JackController * object_ptr, + GError ** error_ptr_ptr); + +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,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/jackd/org.jackaudio.service.in b/jackd/org.jackaudio.service.in new file mode 100644 --- /dev/null +++ b/jackd/org.jackaudio.service.in @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.jackaudio.service +Exec=@bindir@/jackdbus