Merge branch 'stable' into 'main'
[ladish.git] / daemon / jack_session.c
blob8b5f2fb9a521552f575661ce0fd1a345687ecf1d
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2011,2012 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains interface to jack session helper functionality
9 **************************************************************************
11 * LADI Session Handler is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * LADI Session Handler is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
23 * or write to the Free Software Foundation, Inc.,
24 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include <unistd.h>
29 #include "jack_session.h"
30 #include "../common/catdup.h"
31 #include "studio.h"
32 #include "../proxies/jack_proxy.h"
33 #include "../proxies/conf_proxy.h"
34 #include "conf.h"
36 struct ladish_js_find_app_client_context
38 uuid_t app_uuid;
39 bool query;
40 const char * client_name;
43 #define ctx_ptr ((struct ladish_js_find_app_client_context *)context)
45 bool
46 ladish_js_find_app_client_callback(
47 void * context,
48 ladish_graph_handle UNUSED(graph_handle),
49 bool hidden,
50 ladish_client_handle client_handle,
51 const char * client_name,
52 void ** UNUSED(client_iteration_context_ptr_ptr))
54 bool has_callback;
55 const char * jack_name;
57 //log_info("checking client '%s'", client_name);
59 if (hidden)
61 return true; /* continue iteration */
64 jack_name = ladish_client_get_jack_name(client_handle);
65 if (jack_name == NULL)
67 log_error("visible client '%s' in JACK graph without jack client name", client_name);
68 ASSERT_NO_PASS;
69 return true; /* continue iteration */
72 if (ctx_ptr->query)
74 if (!jack_proxy_session_has_callback(jack_name, &has_callback))
76 return true; /* continue iteration */
79 //log_info("client '%s' %s session callback", jack_name, has_callback ? "has" : "hasn't");
80 ladish_client_set_js(client_handle, has_callback);
82 if (!has_callback)
84 return true; /* continue iteration */
87 else
89 if (!ladish_client_is_js(client_handle))
91 return true; /* continue iteration */
95 log_info("client '%s' has session callback", jack_name);
97 if (!ladish_client_is_app(client_handle, ctx_ptr->app_uuid))
99 return true; /* continue iteration */
102 ctx_ptr->client_name = jack_name;
103 return false; /* stop iteration */
106 #undef ctx_ptr
108 static
109 const char *
110 ladish_js_find_app_client(
111 uuid_t app_uuid)
113 struct ladish_js_find_app_client_context ctx;
115 ctx.client_name = NULL;
116 ctx.query = false;
118 uuid_copy(ctx.app_uuid, app_uuid);
119 ladish_graph_iterate_nodes(ladish_studio_get_jack_graph(), &ctx, ladish_js_find_app_client_callback, NULL, NULL);
121 /* app registered the callback after the client activation, try harder */
122 if (ctx.client_name == NULL)
124 ctx.query = true;
125 ladish_graph_iterate_nodes(ladish_studio_get_jack_graph(), &ctx, ladish_js_find_app_client_callback, NULL, NULL);
128 return ctx.client_name;
131 struct ladish_js_save_app_context
133 void * context;
134 void (* callback)(
135 void * context,
136 const char * commandline);
138 char * target_dir; /* the dir supplied as parameter to ladish_js_save_app() */
139 char * temp_dir; /* temp dir that is passed to jack session notify */
140 char * client_dir; /* client dir within the temp dir */
143 #define ctx_ptr ((struct ladish_js_save_app_context *)context)
145 void ladish_js_save_app_complete(void * context, const char * commandline)
147 int iret;
148 unsigned int delay;
150 if (commandline == NULL)
152 goto call;
155 log_info("JS app save complete. commandline='%s'", commandline);
157 if (!conf_get_uint(LADISH_CONF_KEY_DAEMON_JS_SAVE_DELAY, &delay))
159 delay = LADISH_CONF_KEY_DAEMON_JS_SAVE_DELAY_DEFAULT;
162 if (delay > 0)
164 log_info("sleeping for %u seconds...", delay);
165 sleep(delay);
168 iret = rename(ctx_ptr->client_dir, ctx_ptr->target_dir);
169 if (iret != 0)
171 log_error("rename('%s' -> '%s') failed. errno = %d (%s)", ctx_ptr->client_dir, ctx_ptr->target_dir, errno, strerror(errno));
172 commandline = NULL;
173 goto call;
176 log_debug("removing temp dir '%s'", ctx_ptr->temp_dir);
177 iret = rmdir(ctx_ptr->temp_dir);
178 if (iret < 0)
180 log_error("rmdir('%s') failed. errno = %d (%s)", ctx_ptr->temp_dir, errno, strerror(errno));
181 commandline = NULL;
184 call:
185 ctx_ptr->callback(ctx_ptr->context, commandline);
187 free(ctx_ptr->client_dir);
188 free(ctx_ptr->temp_dir);
189 free(ctx_ptr->target_dir);
190 free(ctx_ptr);
193 #undef ctx_ptr
195 bool
196 ladish_js_save_app(
197 uuid_t app_uuid,
198 const char * parent_dir,
199 void * completion_context,
200 void (* completion_callback)(
201 void * completion_context,
202 const char * commandline))
204 struct ladish_js_save_app_context * ctx_ptr;
205 char app_uuid_str[37];
206 int ret;
207 const char * js_client;
208 size_t ofs;
210 js_client = ladish_js_find_app_client(app_uuid);
211 if (js_client == NULL)
213 log_error("cannot find js app client");
214 goto fail;
217 ctx_ptr = malloc(sizeof(struct ladish_js_save_app_context));
218 if (ctx_ptr == NULL)
220 log_error("malloc() failed to allocate ladish_js_save_app_context struct");
221 goto fail;
224 uuid_unparse(app_uuid, app_uuid_str);
225 ctx_ptr->target_dir = catdup3(parent_dir, "/", app_uuid_str);
226 if (ctx_ptr->target_dir == NULL)
228 log_error("strdup3(\"%s\", \"/\", \"%s\") failed for compose js target app dir", parent_dir, app_uuid_str);
229 goto fail_free_struct;
232 log_info("JS target app dir is '%s'", ctx_ptr->target_dir);
234 ctx_ptr->temp_dir = catdup(ctx_ptr->target_dir, ".tmpXXXXXX/");
235 if (ctx_ptr->temp_dir == NULL)
237 log_error("catdup() failed to compose app js temp dir path template");
238 goto fail_free_target_dir;
241 ofs = strlen(ctx_ptr->temp_dir) - 1;
242 ctx_ptr->temp_dir[ofs] = 0; /* mkdtemp wants last chars six chars to be XXXXXX */
244 if (mkdtemp(ctx_ptr->temp_dir) == NULL)
246 log_error("mkdtemp('%s') failed. errno = %d (%s)", ctx_ptr->temp_dir, errno, strerror(errno));
247 goto fail_free_temp_dir;
250 ctx_ptr->temp_dir[ofs] = '/'; /* jack session wants last char to be / */
252 log_info("JS temp app dir is '%s'", ctx_ptr->temp_dir);
254 ctx_ptr->client_dir = catdup(ctx_ptr->temp_dir, js_client);
255 if (ctx_ptr->client_dir == NULL)
257 log_error("catdup3() failed to compose js client dir path");
258 goto fail_rm_temp_dir;
261 ctx_ptr->callback = completion_callback;
262 ctx_ptr->context = completion_context;
264 if (!jack_proxy_session_save_one(true, js_client, ctx_ptr->temp_dir, ctx_ptr, ladish_js_save_app_complete))
266 log_error("jack session failed to initiate save of '%s' app state to '%s'", js_client, ctx_ptr->temp_dir);
267 goto fail_rm_temp_dir;
270 log_info("JS app save initiated");
272 return true;
274 fail_rm_temp_dir:
275 ret = rmdir(ctx_ptr->temp_dir);
276 if (ret < 0)
278 log_error("rmdir('%s') failed. errno = %d (%s)", ctx_ptr->temp_dir, errno, strerror(errno));
280 //fail_free_client_dir:
281 free(ctx_ptr->client_dir);
282 fail_free_temp_dir:
283 free(ctx_ptr->temp_dir);
284 fail_free_target_dir:
285 free(ctx_ptr->target_dir);
286 fail_free_struct:
287 free(ctx_ptr);
288 fail:
289 return false;