From 3f71b1bc2d2065b7ab3d85b247987afce741895e Mon Sep 17 00:00:00 2001 From: Nedko Arnaudov Date: Sun, 26 Jul 2009 23:26:29 +0300 Subject: [PATCH] When JACK server is started, create studio object and store JACK conf as part of it --- daemon/common.h | 54 +++++++++ daemon/jack.c | 287 +++++++++++++++++++++++++++++++++++++++++--- daemon/jack.h | 8 ++ daemon/jack_proxy.h | 31 ----- daemon/main.c | 7 ++ daemon/studio.c | 64 ++++++++++ daemon/studio.h | 22 ++++ wscript | 1 + 8 files changed, 427 insertions(+), 47 deletions(-) create mode 100644 daemon/studio.c create mode 100644 daemon/studio.h diff --git a/daemon/common.h b/daemon/common.h index f44455d0..fe58e781 100644 --- a/daemon/common.h +++ b/daemon/common.h @@ -104,12 +104,66 @@ struct studio struct list_head rooms; /* Rooms connected to the studio */ struct list_head clients; /* studio clients (studio guts and room links) */ struct list_head ports; /* studio ports (studio guts and room links) */ + + bool persisted:1; /* Studio has on-disk representation, i.e. can be reloaded from disk */ + bool modified:1; /* Studio needs saving */ + bool jack_conf_obsolete:1; /* JACK server was stopped during configuration retrieval */ + bool jack_conf_stable:1; /* JACK server configuration obtained successfully */ + + struct list_head jack_conf; +}; + +struct jack_parameter_variant +{ + enum + { + jack_byte, + jack_boolean, + jack_int16, + jack_uint16, + jack_int32, + jack_uint32, + jack_int64, + jack_uint64, + jack_doubl, + jack_string, + } type; + + union + { + unsigned char byte; + bool boolean; + int16_t int16; + uint16_t uint16; + int32_t int32; + uint32_t uint32; + int64_t int64; + uint64_t uint64; + double doubl; + char *string; + } value; +}; + +struct jack_conf_container +{ + struct list_head siblings; + char * name; + bool children_leafs; /* if true, children are "jack_conf_parameter"s, if false, children are "jack_conf_container"s */ + struct list_head children; +}; + +struct jack_conf_parameter +{ + struct list_head siblings; + char * name; + struct jack_parameter_variant parameter; }; extern service_t * g_dbus_service; #define g_dbus_connection (g_dbus_service->connection) extern DBusError g_dbus_error; extern bool g_quit; +extern struct studio * g_studio_ptr; #define DBUS_CALL_DEFAULT_TIMEOUT 1000 // in milliseconds diff --git a/daemon/jack.c b/daemon/jack.c index 36a8162d..ef35af3b 100644 --- a/daemon/jack.c +++ b/daemon/jack.c @@ -8,6 +8,142 @@ #include "jack.h" #include "jack_proxy.h" +#include "studio.h" + +bool +jack_conf_container_create( + struct jack_conf_container ** container_ptr_ptr, + const char * name) +{ + struct jack_conf_container * container_ptr; + + container_ptr = malloc(sizeof(struct jack_conf_container)); + if (container_ptr == NULL) + { + lash_error("malloc() failed to allocate struct jack_conf_container"); + goto fail; + } + + container_ptr->name = strdup(name); + if (container_ptr->name == NULL) + { + lash_error("strdup() failed to duplicate \"%s\"", name); + goto fail_free; + } + + INIT_LIST_HEAD(&container_ptr->children); + container_ptr->children_leafs = false; + + *container_ptr_ptr = container_ptr; + return true; + +fail_free: + free(container_ptr); + +fail: + return false; +} + +void +jack_conf_container_destroy( + struct jack_conf_container * container_ptr) +{ + struct list_head * node_ptr; + + //lash_info("\"%s\" jack_conf_parameter destroy", container_ptr->name); + + if (!container_ptr->children_leafs) + { + while (!list_empty(&container_ptr->children)) + { + node_ptr = container_ptr->children.next; + list_del(node_ptr); + jack_conf_container_destroy(list_entry(node_ptr, struct jack_conf_container, siblings)); + } + } + else + { + while (!list_empty(&container_ptr->children)) + { + node_ptr = container_ptr->children.next; + list_del(node_ptr); + jack_conf_parameter_destroy(list_entry(node_ptr, struct jack_conf_parameter, siblings)); + } + } + + free(container_ptr->name); + free(container_ptr); +} + +bool +jack_conf_parameter_create( + struct jack_conf_parameter ** parameter_ptr_ptr, + const char * name) +{ + struct jack_conf_parameter * parameter_ptr; + + parameter_ptr = malloc(sizeof(struct jack_conf_parameter)); + if (parameter_ptr == NULL) + { + lash_error("malloc() failed to allocate struct jack_conf_parameter"); + goto fail; + } + + parameter_ptr->name = strdup(name); + if (parameter_ptr->name == NULL) + { + lash_error("strdup() failed to duplicate \"%s\"", name); + goto fail_free; + } + + *parameter_ptr_ptr = parameter_ptr; + return true; + +fail_free: + free(parameter_ptr); + +fail: + return false; +} + +void +jack_conf_parameter_destroy( + struct jack_conf_parameter * parameter_ptr) +{ +#if 0 + lash_info("jack_conf_parameter destroy"); + + switch (parameter_ptr->parameter.type) + { + case jack_boolean: + lash_info("%s value is %s (boolean)", parameter_ptr->name, parameter_ptr->parameter.value.boolean ? "true" : "false"); + break; + case jack_string: + lash_info("%s value is %s (string)", parameter_ptr->name, parameter_ptr->parameter.value.string); + break; + case jack_byte: + lash_info("%s value is %u/%c (byte/char)", parameter_ptr->name, parameter_ptr->parameter.value.byte, (char)parameter_ptr->parameter.value.byte); + break; + case jack_uint32: + lash_info("%s value is %u (uint32)", parameter_ptr->name, (unsigned int)parameter_ptr->parameter.value.uint32); + break; + case jack_int32: + lash_info("%s value is %u (int32)", parameter_ptr->name, (signed int)parameter_ptr->parameter.value.int32); + break; + default: + lash_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr->parameter.type, parameter_ptr->name); + break; + } +#endif + + if (parameter_ptr->parameter.type == jack_string) + { + free(parameter_ptr->parameter.value.string); + } + + free(parameter_ptr->name); + free(parameter_ptr); +} bool jack_init( @@ -81,6 +217,16 @@ on_jack_ports_disconnected( lash_info("JACK ports disconnected."); } +struct conf_callback_context +{ + char address[1024]; + struct list_head * container_ptr; + struct studio * studio_ptr; + struct jack_conf_container * parent_ptr; +}; + +#define context_ptr ((struct conf_callback_context *)context) + bool conf_callback( void * context, @@ -92,8 +238,20 @@ conf_callback( const char * component; char * dst; size_t len; - struct jack_parameter_variant parameter; bool is_set; + struct jack_conf_container * parent_ptr; + struct jack_conf_container * container_ptr; + struct jack_conf_parameter * parameter_ptr; + + if (context_ptr->studio_ptr->jack_conf_obsolete) + { + context_ptr->studio_ptr = NULL; + return false; + } + + assert(context_ptr->studio_ptr); + + parent_ptr = context_ptr->parent_ptr; dst = path; component = address; @@ -109,7 +267,7 @@ conf_callback( strcpy(dst, child); /* address always is same buffer as the one supplied through context pointer */ - assert(context == address); + assert(context_ptr->address == address); dst = (char *)component; len = strlen(child) + 1; @@ -120,7 +278,30 @@ conf_callback( { lash_debug("%s (leaf)", path); - if (!jack_proxy_get_parameter_value(context, &is_set, ¶meter)) + if (parent_ptr == NULL) + { + lash_error("jack conf parameters can't appear in root container"); + return false; + } + + if (!parent_ptr->children_leafs) + { + if (!list_empty(&parent_ptr->children)) + { + lash_error("jack conf parameters cant be mixed with containers at same hierarchy level"); + return false; + } + + parent_ptr->children_leafs = true; + } + + if (!jack_conf_parameter_create(¶meter_ptr, child)) + { + lash_error("jack_conf_parameter_create() failed"); + return false; + } + + if (!jack_proxy_get_parameter_value(context_ptr->address, &is_set, ¶meter_ptr->parameter)) { lash_error("cannot get value of %s", path); return false; @@ -128,42 +309,70 @@ conf_callback( if (is_set) { - switch (parameter.type) + switch (parameter_ptr->parameter.type) { case jack_boolean: - lash_info("%s value is %s (boolean)", path, parameter.value.boolean ? "true" : "false"); + lash_info("%s value is %s (boolean)", path, parameter_ptr->parameter.value.boolean ? "true" : "false"); break; case jack_string: - lash_info("%s value is %s (string)", path, parameter.value.string); + lash_info("%s value is %s (string)", path, parameter_ptr->parameter.value.string); break; case jack_byte: - lash_info("%s value is %u/%c (byte/char)", path, parameter.value.byte, (char)parameter.value.byte); + lash_info("%s value is %u/%c (byte/char)", path, parameter_ptr->parameter.value.byte, (char)parameter_ptr->parameter.value.byte); break; case jack_uint32: - lash_info("%s value is %u (uint32)", path, (unsigned int)parameter.value.uint32); + lash_info("%s value is %u (uint32)", path, (unsigned int)parameter_ptr->parameter.value.uint32); break; case jack_int32: - lash_info("%s value is %u (int32)", path, (signed int)parameter.value.int32); + lash_info("%s value is %u (int32)", path, (signed int)parameter_ptr->parameter.value.int32); break; default: - lash_error("ignoring unknown jack parameter type %d (%s)", (int)parameter.type, path); + lash_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr->parameter.type, path); + jack_conf_parameter_destroy(parameter_ptr); + return false; } - } - if (parameter.type == jack_string) + list_add_tail(¶meter_ptr->siblings, &parent_ptr->children); + } + else { - free(parameter.value.string); + jack_conf_parameter_destroy(parameter_ptr); } } else { lash_debug("%s (container)", path); - if (!jack_proxy_read_conf_container(context, context, conf_callback)) + if (parent_ptr != NULL && parent_ptr->children_leafs) + { + lash_error("jack conf containers cant be mixed with parameters at same hierarchy level"); + return false; + } + + if (!jack_conf_container_create(&container_ptr, child)) + { + lash_error("jack_conf_container_create() failed"); + return false; + } + + if (parent_ptr == NULL) + { + list_add_tail(&container_ptr->siblings, &context_ptr->studio_ptr->jack_conf); + } + else + { + list_add_tail(&container_ptr->siblings, &parent_ptr->children); + } + + context_ptr->parent_ptr = container_ptr; + + if (!jack_proxy_read_conf_container(context_ptr->address, context, conf_callback)) { lash_error("cannot read container %s", path); return false; } + + context_ptr->parent_ptr = parent_ptr; } *dst = 0; @@ -171,17 +380,47 @@ conf_callback( return true; } +#undef context_ptr + void on_jack_server_started( void) { - char buffer[1024] = ""; + struct conf_callback_context context; + lash_info("JACK server start detected."); - if (!jack_proxy_read_conf_container(buffer, buffer, conf_callback)) + if (g_studio_ptr == NULL) + { + if (!studio_create(&g_studio_ptr)) + { + lash_error("failed to create studio object"); + return; + } + } + + context.address[0] = 0; + context.container_ptr = &g_studio_ptr->jack_conf; + context.studio_ptr = g_studio_ptr; + context.parent_ptr = NULL; + + if (jack_proxy_read_conf_container(context.address, &context, conf_callback)) + { + if (g_studio_ptr == context.studio_ptr && + !g_studio_ptr->jack_conf_obsolete) + { + g_studio_ptr->jack_conf_stable = true; + lash_info("jack conf successfully retrieved"); + return; + } + } + else { lash_error("jack_proxy_read_conf_container() failed."); + g_studio_ptr = NULL; } + + studio_destroy(context.studio_ptr); } void @@ -189,6 +428,22 @@ on_jack_server_stopped( void) { lash_info("JACK server stop detected."); + + if (g_studio_ptr == NULL) + { + return; + } + + g_studio_ptr->jack_conf_obsolete = true; + + if (!g_studio_ptr->persisted) + { + studio_destroy(g_studio_ptr); + g_studio_ptr = NULL; + return; + } + + /* TODO: if user wants, restart jack server and reconnect all jack apps to it */ } void diff --git a/daemon/jack.h b/daemon/jack.h index 5c3baaed..b1ec1205 100644 --- a/daemon/jack.h +++ b/daemon/jack.h @@ -19,4 +19,12 @@ void jack_uninit( void); +void +jack_conf_container_destroy( + struct jack_conf_container * container_ptr); + +void +jack_conf_parameter_destroy( + struct jack_conf_parameter * parameter_ptr); + #endif /* #ifndef JACK_H__1C44BAEA_280C_4235_94AB_839499BDE47F__INCLUDED */ diff --git a/daemon/jack_proxy.h b/daemon/jack_proxy.h index 806fec28..5391f328 100644 --- a/daemon/jack_proxy.h +++ b/daemon/jack_proxy.h @@ -11,37 +11,6 @@ #include "common.h" -struct jack_parameter_variant -{ - enum - { - jack_byte, - jack_boolean, - jack_int16, - jack_uint16, - jack_int32, - jack_uint32, - jack_int64, - jack_uint64, - jack_doubl, - jack_string, - } type; - - union - { - unsigned char byte; - bool boolean; - int16_t int16; - uint16_t uint16; - int32_t int32; - uint32_t uint32; - int64_t int64; - uint64_t uint64; - double doubl; - char *string; - } value; -}; - bool jack_proxy_init( void); diff --git a/daemon/main.c b/daemon/main.c index 5155bd4c..b5b5b857 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -32,10 +32,12 @@ #include "sigsegv.h" #include "dbus_iface_control.h" #include "jack.h" +#include "studio.h" bool g_quit; service_t * g_dbus_service; DBusError g_dbus_error; +struct studio * g_studio_ptr; #if 0 static DBusHandlerResult lashd_client_disconnect_handler(DBusConnection * connection, DBusMessage * message, void * data) @@ -228,6 +230,11 @@ int main(int argc, char ** argv, char ** envp) loader_run(); } + if (g_studio_ptr != NULL) + { + studio_destroy(g_studio_ptr); + } + ret = EXIT_SUCCESS; lash_debug("Finished, cleaning up"); diff --git a/daemon/studio.c b/daemon/studio.c new file mode 100644 index 00000000..4634f49e --- /dev/null +++ b/daemon/studio.c @@ -0,0 +1,64 @@ +/* -*- Mode: C ; c-basic-offset: 2 -*- */ +/***************************************************************************** + * + * DESCRIPTION: + * Studio object helpers + * + *****************************************************************************/ + +#include "common.h" +#include "jack.h" + +bool +studio_create( + struct studio ** studio_ptr_ptr) +{ + struct studio * studio_ptr; + + lash_info("studio object construct"); + + studio_ptr = malloc(sizeof(struct studio)); + if (studio_ptr == NULL) + { + lash_error("malloc() failed to allocate struct studio"); + return false; + } + + INIT_LIST_HEAD(&studio_ptr->all_connections); + INIT_LIST_HEAD(&studio_ptr->all_ports); + INIT_LIST_HEAD(&studio_ptr->all_clients); + INIT_LIST_HEAD(&studio_ptr->jack_connections); + INIT_LIST_HEAD(&studio_ptr->jack_ports); + INIT_LIST_HEAD(&studio_ptr->jack_clients); + INIT_LIST_HEAD(&studio_ptr->rooms); + INIT_LIST_HEAD(&studio_ptr->clients); + INIT_LIST_HEAD(&studio_ptr->ports); + + studio_ptr->modified = false; + studio_ptr->persisted = false; + studio_ptr->jack_conf_obsolete = false; + studio_ptr->jack_conf_stable = false; + + INIT_LIST_HEAD(&studio_ptr->jack_conf); + + *studio_ptr_ptr = studio_ptr; + + return true; +} + +void +studio_destroy( + struct studio * studio_ptr) +{ + struct list_head * node_ptr; + + while (!list_empty(&studio_ptr->jack_conf)) + { + node_ptr = studio_ptr->jack_conf.next; + list_del(node_ptr); + jack_conf_container_destroy(list_entry(node_ptr, struct jack_conf_container, siblings)); + } + + free(studio_ptr); + lash_info("studio object destroy"); +} diff --git a/daemon/studio.h b/daemon/studio.h new file mode 100644 index 00000000..b9af883a --- /dev/null +++ b/daemon/studio.h @@ -0,0 +1,22 @@ +/* -*- Mode: C ; c-basic-offset: 2 -*- */ +/***************************************************************************** + * + * DESCRIPTION: + * Studio object helpers + * + *****************************************************************************/ + +#ifndef STUDIO_H__0BEDE85E_4FB3_4D74_BC08_C373A22409C0__INCLUDED +#define STUDIO_H__0BEDE85E_4FB3_4D74_BC08_C373A22409C0__INCLUDED + +#include "common.h" + +bool +studio_create( + struct studio ** studio_ptr_ptr); + +void +studio_destroy( + struct studio * studio_ptr); + +#endif /* #ifndef STUDIO_H__0BEDE85E_4FB3_4D74_BC08_C373A22409C0__INCLUDED */ diff --git a/wscript b/wscript index 418cb9eb..a369b900 100644 --- a/wscript +++ b/wscript @@ -173,6 +173,7 @@ def build(bld): 'dbus_iface_control.c', 'jack_proxy.c', 'jack.c', + 'studio.c', ]: daemon.source.append(os.path.join("daemon", source))