From 2b66a82e9a1f0366ed8a94a1042fa3ac7e794f29 Mon Sep 17 00:00:00 2001 From: Nedko Arnaudov Date: Sat, 3 Sep 2011 03:16:11 +0300 Subject: [PATCH] ladishd: new function - ladish_js_save_app() --- daemon/client.c | 41 ++++++- daemon/client.h | 7 ++ daemon/jack_session.c | 274 ++++++++++++++++++++++++++++++++++++++++++ daemon/jack_session.h | 41 +++++++ daemon/virtualizer.c | 3 + wscript | 1 + 6 files changed, 366 insertions(+), 1 deletion(-) create mode 100644 daemon/jack_session.c create mode 100644 daemon/jack_session.h diff --git a/daemon/client.c b/daemon/client.c index 0d55a198..0a962b11 100644 --- a/daemon/client.c +++ b/daemon/client.c @@ -33,7 +33,9 @@ struct ladish_client uuid_t uuid_interlink; /* The UUID of the linked client (vgraph <-> jack graph) */ uuid_t uuid_app; /* The UUID of the app that owns this client */ uint64_t jack_id; /* JACK client ID */ + char * jack_name; /* JACK client name */ pid_t pid; /* process id. */ + bool has_js_callback; /* Whether the client has set jack session callback */ ladish_dict_handle dict; void * vgraph; /* virtual graph */ }; @@ -72,7 +74,9 @@ ladish_client_create( uuid_clear(client_ptr->uuid_app); client_ptr->jack_id = 0; + client_ptr->jack_name = NULL; client_ptr->pid = 0; + client_ptr->has_js_callback = false; client_ptr->vgraph = NULL; #if 0 @@ -105,7 +109,7 @@ ladish_client_destroy( log_info("client %p destroy", client_ptr); ladish_dict_destroy(client_ptr->dict); - + free(client_ptr->jack_name); free(client_ptr); } @@ -130,6 +134,26 @@ uint64_t ladish_client_get_jack_id(ladish_client_handle client_handle) return client_ptr->jack_id; } +void ladish_client_set_jack_name(ladish_client_handle client_handle, const char * jack_name) +{ + char * name_dup; + + name_dup = strdup(jack_name); + if (name_dup == NULL) + { + log_error("stdup(\"%s\") failed", jack_name); + return; + } + + free(client_ptr->jack_name); + client_ptr->jack_name = name_dup; +} + +const char * ladish_client_get_jack_name(ladish_client_handle client_handle) +{ + return client_ptr->jack_name; +} + void ladish_client_set_pid(ladish_client_handle client_handle, pid_t pid) { client_ptr->pid = pid; @@ -213,9 +237,24 @@ bool ladish_client_get_app(ladish_client_handle client_handle, uuid_t uuid) return true; } +bool ladish_client_is_app(ladish_client_handle client_handle, uuid_t uuid) +{ + return uuid_compare(uuid, client_ptr->uuid_app) == 0; +} + bool ladish_client_has_app(ladish_client_handle client_handle) { return !uuid_is_null(client_ptr->uuid_app); } +void ladish_client_set_js(ladish_client_handle client_handle, bool has_js_callback) +{ + client_ptr->has_js_callback = has_js_callback; +} + +bool ladish_client_is_js(ladish_client_handle client_handle) +{ + return client_ptr->has_js_callback; +} + #undef client_ptr diff --git a/daemon/client.h b/daemon/client.h index 1cf7f77c..fe8e83a4 100644 --- a/daemon/client.h +++ b/daemon/client.h @@ -52,6 +52,9 @@ void ladish_client_get_uuid(ladish_client_handle client_handle, uuid_t uuid); void ladish_client_set_jack_id(ladish_client_handle client_handle, uint64_t jack_id); uint64_t ladish_client_get_jack_id(ladish_client_handle client_handle); +void ladish_client_set_jack_name(ladish_client_handle client_handle, const char * jack_name); +const char * ladish_client_get_jack_name(ladish_client_handle client_handle); + void ladish_client_set_pid(ladish_client_handle client_handle, pid_t pid); pid_t ladish_client_get_pid(ladish_client_handle client_handle); @@ -65,7 +68,11 @@ void ladish_client_clear_interlink(ladish_client_handle client_handle); void ladish_client_set_app(ladish_client_handle client_handle, const uuid_t uuid); bool ladish_client_get_app(ladish_client_handle client_handle, uuid_t uuid); +bool ladish_client_is_app(ladish_client_handle client_handle, uuid_t uuid); bool ladish_client_has_app(ladish_client_handle client_handle); void ladish_client_copy_app(ladish_client_handle dst_client_handle, ladish_client_handle src_client_handle); +void ladish_client_set_js(ladish_client_handle client_handle, bool has_js_callback); +bool ladish_client_is_js(ladish_client_handle client_handle); + #endif /* #ifndef CLIENT_H__2160B4BA_D6D1_464D_9DC5_ECA50B0958AD__INCLUDED */ diff --git a/daemon/jack_session.c b/daemon/jack_session.c new file mode 100644 index 00000000..eef50551 --- /dev/null +++ b/daemon/jack_session.c @@ -0,0 +1,274 @@ +/* -*- Mode: C ; c-basic-offset: 2 -*- */ +/* + * LADI Session Handler (ladish) + * + * Copyright (C) 2011 Nedko Arnaudov + * + ************************************************************************** + * This file contains interface to jack session helper functionality + ************************************************************************** + * + * LADI Session Handler 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, or + * (at your option) any later version. + * + * LADI Session Handler 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 LADI Session Handler. If not, see + * or write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include "jack_session.h" +#include "../common/catdup.h" +#include "studio.h" +#include "../proxies/jack_proxy.h" + +struct ladish_js_find_app_client_context +{ + uuid_t app_uuid; + bool query; + const char * client_name; +}; + +#define ctx_ptr ((struct ladish_js_find_app_client_context *)context) + +bool +ladish_js_find_app_client_callback( + void * context, + ladish_graph_handle graph_handle, + bool hidden, + ladish_client_handle client_handle, + const char * client_name, + void ** client_iteration_context_ptr_ptr) +{ + bool has_callback; + const char * jack_name; + + //log_info("checking client '%s'", client_name); + + if (hidden) + { + return true; /* continue iteration */ + } + + jack_name = ladish_client_get_jack_name(client_handle); + if (jack_name == NULL) + { + log_error("visible client '%s' in JACK graph without jack client name", client_name); + ASSERT_NO_PASS; + return true; /* continue iteration */ + } + + if (ctx_ptr->query) + { + if (!jack_proxy_session_has_callback(jack_name, &has_callback)) + { + return true; /* continue iteration */ + } + + //log_info("client '%s' %s session callback", jack_name, has_callback ? "has" : "hasn't"); + ladish_client_set_js(client_handle, has_callback); + + if (!has_callback) + { + return true; /* continue iteration */ + } + } + else + { + if (!ladish_client_is_js(client_handle)) + { + return true; /* continue iteration */ + } + } + + log_info("client '%s' has session callback", jack_name); + + if (!ladish_client_is_app(client_handle, ctx_ptr->app_uuid)) + { + return true; /* continue iteration */ + } + + ctx_ptr->client_name = jack_name; + return false; /* stop iteration */ +} + +#undef ctx_ptr + +static +const char * +ladish_js_find_app_client( + uuid_t app_uuid) +{ + struct ladish_js_find_app_client_context ctx; + + ctx.client_name = NULL; + ctx.query = false; + + uuid_copy(ctx.app_uuid, app_uuid); + ladish_graph_iterate_nodes(ladish_studio_get_jack_graph(), &ctx, ladish_js_find_app_client_callback, NULL, NULL); + + /* app registered the callback after the client activation, try harder */ + if (ctx.client_name == NULL) + { + ctx.query = true; + ladish_graph_iterate_nodes(ladish_studio_get_jack_graph(), &ctx, ladish_js_find_app_client_callback, NULL, NULL); + } + + return ctx.client_name; +} + +struct ladish_js_save_app_context +{ + void * context; + void (* callback)( + void * context, + const char * commandline); + + char * target_dir; /* the dir supplied as parameter to ladish_js_save_app() */ + char * temp_dir; /* temp dir that is passed to jack session notify */ + char * client_dir; /* client dir within the temp dir */ +}; + +#define ctx_ptr ((struct ladish_js_save_app_context *)context) + +void ladish_js_save_app_complete(void * context, const char * commandline) +{ + int iret; + + if (commandline == NULL) + { + goto call; + } + + iret = rename(ctx_ptr->client_dir, ctx_ptr->target_dir); + if (iret != 0) + { + log_error("rename('%s' -> '%s') failed. errno = %d (%s)", ctx_ptr->client_dir, ctx_ptr->target_dir, errno, strerror(errno)); + commandline = NULL; + goto call; + } + + log_debug("removing temp dir '%s'", ctx_ptr->temp_dir); + iret = rmdir(ctx_ptr->temp_dir); + if (iret < 0) + { + log_error("rmdir('%s') failed. errno = %d (%s)", ctx_ptr->temp_dir, errno, strerror(errno)); + commandline = NULL; + } + +call: + ctx_ptr->callback(ctx_ptr->context, commandline); + + free(ctx_ptr->client_dir); + free(ctx_ptr->temp_dir); + free(ctx_ptr->target_dir); + free(ctx_ptr); +} + +#undef ctx_ptr + +bool +ladish_js_save_app( + uuid_t app_uuid, + const char * parent_dir, + void * completion_context, + void (* completion_callback)( + void * completion_context, + const char * commandline)) +{ + struct ladish_js_save_app_context * ctx_ptr; + char app_uuid_str[37]; + int ret; + const char * js_client; + size_t ofs; + + js_client = ladish_js_find_app_client(app_uuid); + if (js_client == NULL) + { + log_error("cannot find js app client"); + goto fail; + } + + ctx_ptr = malloc(sizeof(struct ladish_js_save_app_context)); + if (ctx_ptr == NULL) + { + log_error("malloc() failed to allocate ladish_js_save_app_context struct"); + goto fail; + } + + uuid_unparse(app_uuid, app_uuid_str); + ctx_ptr->target_dir = catdup3(parent_dir, "/", app_uuid_str); + if (ctx_ptr->target_dir == NULL) + { + log_error("strdup3(\"%s\", \"/\", \"%s\") failed for compose js target app dir", parent_dir, app_uuid_str); + goto fail_free_struct; + } + + log_info("JS target app dir is '%s'", ctx_ptr->target_dir); + + ctx_ptr->temp_dir = catdup(ctx_ptr->target_dir, ".tmpXXXXXX/"); + if (ctx_ptr->temp_dir == NULL) + { + log_error("catdup() failed to compose app js temp dir path template"); + goto fail_free_target_dir; + } + + ofs = strlen(ctx_ptr->temp_dir) - 1; + ctx_ptr->temp_dir[ofs] = 0; /* mkdtemp wants last chars six chars to be XXXXXX */ + + if (mkdtemp(ctx_ptr->temp_dir) == NULL) + { + log_error("mkdtemp('%s') failed. errno = %d (%s)", ctx_ptr->temp_dir, errno, strerror(errno)); + goto fail_free_temp_dir; + } + + ctx_ptr->temp_dir[ofs] = '/'; /* jack session wants last char to be / */ + + log_info("JS temp app dir is '%s'", ctx_ptr->temp_dir); + + ctx_ptr->client_dir = catdup(ctx_ptr->temp_dir, js_client); + if (ctx_ptr->client_dir == NULL) + { + log_error("catdup3() failed to compose js client dir path"); + goto fail_rm_temp_dir; + } + + ctx_ptr->callback = completion_callback; + ctx_ptr->context = completion_context; + + if (!jack_proxy_session_save_one(true, js_client, ctx_ptr->temp_dir, ctx_ptr, ladish_js_save_app_complete)) + { + log_error("jack session failed to initiate save of '%s' app state to '%s'", js_client, ctx_ptr->temp_dir); + goto fail_rm_temp_dir; + } + + log_info("JS app save initiated"); + + return true; + +fail_rm_temp_dir: + ret = rmdir(ctx_ptr->temp_dir); + if (ret < 0) + { + log_error("rmdir('%s') failed. errno = %d (%s)", ctx_ptr->temp_dir, errno, strerror(errno)); + } +//fail_free_client_dir: + free(ctx_ptr->client_dir); +fail_free_temp_dir: + free(ctx_ptr->temp_dir); +fail_free_target_dir: + free(ctx_ptr->target_dir); +fail_free_struct: + free(ctx_ptr); +fail: + return false; +} diff --git a/daemon/jack_session.h b/daemon/jack_session.h new file mode 100644 index 00000000..120451aa --- /dev/null +++ b/daemon/jack_session.h @@ -0,0 +1,41 @@ +/* -*- Mode: C ; c-basic-offset: 2 -*- */ +/* + * LADI Session Handler (ladish) + * + * Copyright (C) 2011 Nedko Arnaudov + * + ************************************************************************** + * This file contains interface to jack session helper functionality + ************************************************************************** + * + * LADI Session Handler 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, or + * (at your option) any later version. + * + * LADI Session Handler 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 LADI Session Handler. If not, see + * or write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef JACK_SESSION_H__3C0F2ED2_7FAB_460F_A34F_4E3CAB6AC552__INCLUDED +#define JACK_SESSION_H__3C0F2ED2_7FAB_460F_A34F_4E3CAB6AC552__INCLUDED + +#include "common.h" + +bool +ladish_js_save_app( + uuid_t app_uuid, + const char * parent_dir, + void * completion_context, + void (* completion_callback)( + void * completion_context, + const char * commandline)); + +#endif /* #ifndef JACK_SESSION_H__3C0F2ED2_7FAB_460F_A34F_4E3CAB6AC552__INCLUDED */ diff --git a/daemon/virtualizer.c b/daemon/virtualizer.c index 2ea8e32f..2b708412 100644 --- a/daemon/virtualizer.c +++ b/daemon/virtualizer.c @@ -337,6 +337,8 @@ static void client_appeared(void * context, uint64_t id, const char * jack_name) goto exit; } + ladish_client_set_jack_name(client, jack_name); + ladish_client_set_jack_id(client, id); ladish_graph_show_client(virtualizer_ptr->jack_graph, client); goto done; @@ -350,6 +352,7 @@ static void client_appeared(void * context, uint64_t id, const char * jack_name) } ladish_client_set_jack_id(client, id); + ladish_client_set_jack_name(client, jack_name); if (!ladish_graph_add_client(virtualizer_ptr->jack_graph, client, name, false)) { diff --git a/wscript b/wscript index 773f9e7d..811448f3 100644 --- a/wscript +++ b/wscript @@ -369,6 +369,7 @@ def build(bld): 'recent_projects.c', 'check_integrity.c', 'lash_server.c', + 'jack_session.c', ]: daemon.source.append(os.path.join("daemon", source))