1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2009,2010 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains implementation of the "save studio" command
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 <sys/types.h>
32 #include <sys/types.h>
38 #include "studio_internal.h"
40 #include "../proxies/notify_proxy.h"
43 #define STUDIO_HEADER_TEXT BASE_NAME " Studio configuration.\n"
49 struct jack_conf_parameter
* parameter_ptr
)
53 char path
[JACK_CONF_MAX_ADDRESS_SIZE
* 3]; /* encode each char in three bytes (percent encoding) */
57 /* compose the parameter path, percent-encode "bad" chars */
58 src
= parameter_ptr
->address
;
69 if (!ladish_write_indented_string(fd
, indent
, "<parameter path=\""))
74 if (!ladish_write_string(fd
, path
))
79 if (!ladish_write_string(fd
, "\">"))
84 switch (parameter_ptr
->parameter
.type
)
87 content
= parameter_ptr
->parameter
.value
.boolean
? "true" : "false";
88 log_debug("%s value is %s (boolean)", path
, content
);
91 content
= parameter_ptr
->parameter
.value
.string
;
92 log_debug("%s value is %s (string)", path
, content
);
95 valbuf
[0] = (char)parameter_ptr
->parameter
.value
.byte
;
98 log_debug("%s value is %u/%c (byte/char)", path
, parameter_ptr
->parameter
.value
.byte
, (char)parameter_ptr
->parameter
.value
.byte
);
101 snprintf(valbuf
, sizeof(valbuf
), "%" PRIu32
, parameter_ptr
->parameter
.value
.uint32
);
103 log_debug("%s value is %s (uint32)", path
, content
);
106 snprintf(valbuf
, sizeof(valbuf
), "%" PRIi32
, parameter_ptr
->parameter
.value
.int32
);
108 log_debug("%s value is %s (int32)", path
, content
);
111 log_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr
->parameter
.type
, path
);
115 if (!ladish_write_string(fd
, content
))
120 if (!ladish_write_string(fd
, "</parameter>\n"))
128 #define fd (((struct ladish_write_context *)context)->fd)
129 #define indent (((struct ladish_write_context *)context)->indent)
131 static bool save_studio_room(void * context
, ladish_room_handle room
)
136 log_info("saving room '%s'", ladish_room_get_name(room
));
138 if (!ladish_write_indented_string(fd
, indent
, "<room name=\""))
143 if (!ladish_write_string(fd
, ladish_room_get_name(room
)))
148 if (!ladish_write_string(fd
, "\" uuid=\""))
153 ladish_room_get_uuid(room
, uuid
);
154 uuid_unparse(uuid
, str
);
156 if (!ladish_write_string(fd
, str
))
161 if (!ladish_write_string(fd
, "\">\n"))
166 if (!ladish_write_room_link_ports(fd
, indent
+ 1, room
))
168 log_error("ladish_write_room_link_ports() failed");
172 if (!ladish_write_indented_string(fd
, indent
, " </room>\n"))
183 struct ladish_command_save_studio
185 struct ladish_command command
;
189 #define cmd_ptr ((struct ladish_command_save_studio *)command_context)
191 static bool run(void * command_context
)
193 struct list_head
* node_ptr
;
194 struct jack_conf_parameter
* parameter_ptr
;
197 char timestamp_str
[26];
199 char * filename
; /* filename */
200 char * bak_filename
; /* filename of the backup file */
201 char * old_filename
; /* filename where studio was persisted before save */
203 struct ladish_write_context save_context
;
206 ASSERT(cmd_ptr
->command
.state
== LADISH_COMMAND_STATE_PENDING
);
209 ctime_r(×tamp
, timestamp_str
);
210 timestamp_str
[24] = 0;
214 ladish_app_supervisor_save_L1(g_studio
.app_supervisor
);
216 if (!ladish_studio_is_started())
218 log_error("Cannot save not-started studio");
219 ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH
, "Cannot save not-started studio", NULL
);
223 if (!ladish_studio_compose_filename(cmd_ptr
->studio_name
, &filename
, &bak_filename
))
225 log_error("failed to compose studio filename");
229 /* whether save will initiate a rename */
230 renaming
= strcmp(cmd_ptr
->studio_name
, g_studio
.name
) != 0;
232 if (g_studio
.filename
== NULL
)
234 /* saving studio for first time */
235 g_studio
.filename
= filename
;
240 else if (strcmp(g_studio
.filename
, filename
) == 0)
242 /* saving already persisted studio that was not renamed */
243 old_filename
= filename
;
247 /* saving already renamed studio */
248 old_filename
= g_studio
.filename
;
249 g_studio
.filename
= filename
;
253 /* saving studio copy (save as) */
254 old_filename
= filename
;
255 g_studio
.filename
= filename
;
259 ASSERT(g_studio
.filename
!= NULL
);
260 ASSERT(g_studio
.filename
!= bak_filename
);
262 if (bak_filename
!= NULL
)
264 ASSERT(old_filename
!= NULL
);
266 if (stat(old_filename
, &st
) == 0) /* if old filename does not exist, rename with fail */
268 if (rename(old_filename
, bak_filename
) != 0)
270 log_error("rename(%s, %s) failed: %d (%s)", old_filename
, bak_filename
, errno
, strerror(errno
));
276 /* mark that there is no backup file */
282 log_info("saving studio... (%s)", g_studio
.filename
);
284 fd
= open(g_studio
.filename
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0666);
287 log_error("open(%s) failed: %d (%s)", g_studio
.filename
, errno
, strerror(errno
));
291 if (!ladish_write_string(fd
, "<?xml version=\"1.0\"?>\n"))
296 if (!ladish_write_string(fd
, "<!--\n"))
301 if (!ladish_write_string(fd
, STUDIO_HEADER_TEXT
))
306 if (!ladish_write_string(fd
, "-->\n"))
311 if (!ladish_write_string(fd
, "<!-- "))
316 if (!ladish_write_string(fd
, timestamp_str
))
321 if (!ladish_write_string(fd
, " -->\n"))
326 if (!ladish_write_string(fd
, "<studio>\n"))
331 if (!ladish_write_indented_string(fd
, 1, "<jack>\n"))
336 if (!ladish_write_indented_string(fd
, 2, "<conf>\n"))
341 list_for_each(node_ptr
, &g_studio
.jack_params
)
343 parameter_ptr
= list_entry(node_ptr
, struct jack_conf_parameter
, leaves
);
345 if (!write_jack_parameter(fd
, 3, parameter_ptr
))
351 if (!ladish_write_indented_string(fd
, 2, "</conf>\n"))
356 if (!ladish_write_jgraph(fd
, 2, ladish_studio_get_studio_graph()))
358 log_error("ladish_write_jgraph() failed for studio graph");
362 if (!ladish_write_indented_string(fd
, 1, "</jack>\n"))
367 if (ladish_studio_has_rooms())
369 if (!ladish_write_indented_string(fd
, 1, "<rooms>\n"))
374 save_context
.indent
= 2;
375 save_context
.fd
= fd
;
377 if (!ladish_studio_iterate_rooms(&save_context
, save_studio_room
))
379 log_error("ladish_studio_iterate_rooms() failed");
383 if (!ladish_write_indented_string(fd
, 1, "</rooms>\n"))
389 if (!ladish_write_vgraph(fd
, 1, g_studio
.studio_graph
, g_studio
.app_supervisor
))
391 log_error("ladish_write_vgraph() failed for studio");
395 if (!ladish_write_dict(fd
, 1, ladish_graph_get_dict(g_studio
.studio_graph
)))
400 if (!ladish_write_string(fd
, "</studio>\n"))
405 log_info("studio saved. (%s)", g_studio
.filename
);
406 g_studio
.persisted
= true;
407 g_studio
.automatic
= false; /* even if it was automatic, it is not anymore because it is saved */
409 cmd_ptr
->command
.state
= LADISH_COMMAND_STATE_DONE
;
416 g_studio
.name
= cmd_ptr
->studio_name
;
417 cmd_ptr
->studio_name
= NULL
; /* mark that descructor does not need to free the new name buffer */
418 ladish_studio_emit_renamed(); /* uses g_studio.name */
425 if (!ret
&& bak_filename
!= NULL
)
427 /* save failed - try to rename the backup file back */
428 ASSERT(old_filename
!= NULL
);
429 if (rename(bak_filename
, old_filename
) != 0)
431 log_error("rename(%s, %s) failed: %d (%s)", bak_filename
, g_studio
.filename
, errno
, strerror(errno
));
436 if (bak_filename
!= NULL
)
441 if (old_filename
!= NULL
&& old_filename
!= g_studio
.filename
)
446 ASSERT(filename
== NULL
);
447 ASSERT(g_studio
.filename
!= NULL
);
452 ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH
, "Studio save failed", "Please inspect the ladishd log (~/.ladish/ladish.log) for more info");
458 static void destructor(void * command_context
)
460 log_info("save studio command destructor");
461 if (cmd_ptr
->studio_name
!= NULL
)
463 free(cmd_ptr
->studio_name
);
469 bool ladish_command_save_studio(void * call_ptr
, struct ladish_cqueue
* queue_ptr
, const char * new_studio_name
)
471 struct ladish_command_save_studio
* cmd_ptr
;
472 char * studio_name_dup
;
474 studio_name_dup
= strdup(new_studio_name
);
475 if (studio_name_dup
== NULL
)
477 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "strdup('%s') failed.", new_studio_name
);
481 cmd_ptr
= ladish_command_new(sizeof(struct ladish_command_save_studio
));
484 log_error("ladish_command_new() failed.");
488 cmd_ptr
->command
.run
= run
;
489 cmd_ptr
->command
.destructor
= destructor
;
490 cmd_ptr
->studio_name
= studio_name_dup
;
492 if (!ladish_cqueue_add_command(queue_ptr
, &cmd_ptr
->command
))
494 lash_dbus_error(call_ptr
, LASH_DBUS_ERROR_GENERIC
, "ladish_cqueue_add_command() failed.");
495 goto fail_destroy_command
;
500 fail_destroy_command
:
503 free(studio_name_dup
);