1 /* -*- Mode: C ; c-basic-offset: 4 -*- */
3 Copyright (C) 2007,2008 Nedko Arnaudov
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #if defined(HAVE_CONFIG_H)
26 #include <dbus/dbus.h>
28 #include <libxml/xmlwriter.h>
29 #include <libxml/parser.h>
30 #include <libxml/xpath.h>
32 #include <jack/driver.h>
33 #include <jack/engine.h>
34 #include "controller_internal.h"
37 /* XPath expression used for engine options selection */
38 #define XPATH_ENGINE_OPTIONS_EXPRESSION "/jack/engine/option"
40 /* XPath expression used for drivers selection */
41 #define XPATH_DRIVERS_EXPRESSION "/jack/drivers/driver"
43 /* XPath expression used for driver options selection */
44 #define XPATH_DRIVER_OPTIONS_EXPRESSION "/jack/drivers/driver[@name = '%s']/option"
47 jack_controller_settings_init()
50 * this initialize the library and check potential ABI mismatches
51 * between the version it was compiled for and the actual shared
60 jack_controller_settings_uninit()
64 #define writer ((xmlTextWriterPtr)context)
67 jack_controller_settings_write_option(
71 void *dbus_call_context_ptr
)
73 if (xmlTextWriterStartElement(writer
, BAD_CAST
"option") == -1)
75 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterStartElement() failed.");
79 if (xmlTextWriterWriteAttribute(writer
, BAD_CAST
"name", BAD_CAST name
) == -1)
81 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterWriteAttribute() failed.");
85 if (xmlTextWriterWriteString(writer
, BAD_CAST content
) == -1)
87 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterWriteString() failed.");
91 if (xmlTextWriterEndElement(writer
) == -1)
93 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterEndElement() failed.");
103 jack_controller_settings_write_engine(
104 struct jack_controller
* controller_ptr
,
105 xmlTextWriterPtr writer
,
106 void *dbus_call_context_ptr
)
108 /* jack_info("engine settings begin"); */
110 /* if (xmlTextWriterWriteComment(writer, BAD_CAST "engine parameters") == -1) */
112 /* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */
116 if (xmlTextWriterStartElement(writer
, BAD_CAST
"engine") == -1)
118 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterStartElement() failed.");
122 if (!jack_controller_settings_save_engine_options(writer
, controller_ptr
, dbus_call_context_ptr
))
127 if (xmlTextWriterEndElement(writer
) == -1)
129 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterEndElement() failed.");
133 /* jack_info("engine settings end"); */
138 jack_controller_settings_write_driver(
139 struct jack_controller
* controller_ptr
,
140 xmlTextWriterPtr writer
,
141 jackctl_driver driver
,
142 void *dbus_call_context_ptr
)
144 /* if (xmlTextWriterWriteComment(writer, BAD_CAST "driver parameters") == -1) */
146 /* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */
150 if (xmlTextWriterStartElement(writer
, BAD_CAST
"driver") == -1)
152 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterStartElement() failed.");
156 if (xmlTextWriterWriteAttribute(writer
, BAD_CAST
"name", BAD_CAST
jackctl_driver_get_name(driver
)) == -1)
158 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterWriteAttribute() failed.");
162 if (!jack_controller_settings_save_driver_options(writer
, driver
, dbus_call_context_ptr
))
167 if (xmlTextWriterEndElement(writer
) == -1)
169 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterEndElement() failed.");
177 jack_controller_settings_write_drivers(
178 struct jack_controller
* controller_ptr
,
179 xmlTextWriterPtr writer
,
180 void *dbus_call_context_ptr
)
182 const JSList
* node_ptr
;
183 jackctl_driver driver
;
185 if (xmlTextWriterStartElement(writer
, BAD_CAST
"drivers") == -1)
187 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterStartElement() failed.");
191 node_ptr
= jackctl_server_get_drivers_list(controller_ptr
->server
);
193 while (node_ptr
!= NULL
)
195 driver
= (jackctl_driver
)node_ptr
->data
;
197 if (!jack_controller_settings_write_driver(
201 dbus_call_context_ptr
))
206 node_ptr
= jack_slist_next(node_ptr
);
209 if (xmlTextWriterEndElement(writer
) == -1)
211 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterEndElement() failed.");
219 jack_controller_settings_write_internal(
220 struct jack_controller
* controller_ptr
,
221 xmlTextWriterPtr writer
,
222 jackctl_internal internal
,
223 void *dbus_call_context_ptr
)
225 /* if (xmlTextWriterWriteComment(writer, BAD_CAST "driver parameters") == -1) */
227 /* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */
231 if (xmlTextWriterStartElement(writer
, BAD_CAST
"internal") == -1)
233 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterStartElement() failed.");
237 if (xmlTextWriterWriteAttribute(writer
, BAD_CAST
"name", BAD_CAST
jackctl_internal_get_name(driver
)) == -1)
239 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterWriteAttribute() failed.");
243 if (!jack_controller_settings_save_internal_options(writer
, internal
, dbus_call_context_ptr
))
248 if (xmlTextWriterEndElement(writer
) == -1)
250 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterEndElement() failed.");
258 jack_controller_settings_write_internals(
259 struct jack_controller
* controller_ptr
,
260 xmlTextWriterPtr writer
,
261 void *dbus_call_context_ptr
)
263 const JSList
* node_ptr
;
264 jackctl_driver internal
;
266 if (xmlTextWriterStartElement(writer
, BAD_CAST
"internals") == -1)
268 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterStartElement() failed.");
272 node_ptr
= jackctl_server_get_internals_list(controller_ptr
->server
);
274 while (node_ptr
!= NULL
)
276 internal
= (jackctl_internal
)node_ptr
->data
;
278 if (!jack_controller_settings_write_internal(
282 dbus_call_context_ptr
))
287 node_ptr
= jack_slist_next(node_ptr
);
290 if (xmlTextWriterEndElement(writer
) == -1)
292 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterEndElement() failed.");
300 jack_controller_settings_save(
301 struct jack_controller
* controller_ptr
,
302 void *dbus_call_context_ptr
)
304 xmlTextWriterPtr writer
;
309 char timestamp_str
[28];
312 timestamp_str
[0] = ' ';
313 ctime_r(×tamp
, timestamp_str
+ 1);
314 timestamp_str
[25] = ' ';
318 conf_len
= strlen(JACKDBUS_CONF
);
320 filename
= malloc(g_jackdbus_dir_len
+ conf_len
+ 1);
321 if (filename
== NULL
)
323 jack_error("Out of memory.");
327 memcpy(filename
, g_jackdbus_dir
, g_jackdbus_dir_len
);
328 memcpy(filename
+ g_jackdbus_dir_len
, JACKDBUS_CONF
, conf_len
);
329 filename
[g_jackdbus_dir_len
+ conf_len
] = 0;
331 jack_info("saving settings to \"%s\"", filename
);
333 writer
= xmlNewTextWriterFilename(filename
, 0);
336 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "Error creating the xml writer.");
337 goto fail_free_filename
;
340 if (xmlTextWriterSetIndent(writer
, 1) == -1)
342 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterSetIndent() failed.");
343 goto fail_free_writter
;
346 if (xmlTextWriterStartDocument(writer
, NULL
, NULL
, NULL
) == -1)
348 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterStartDocument() failed.");
349 goto fail_free_writter
;
352 if (xmlTextWriterWriteComment(writer
, BAD_CAST
"\n" JACK_CONF_HEADER_TEXT
) == -1)
354 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterWriteComment() failed.");
355 goto fail_free_writter
;
358 if (xmlTextWriterWriteComment(writer
, BAD_CAST timestamp_str
) == -1)
360 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterWriteComment() failed.");
361 goto fail_free_writter
;
364 if (xmlTextWriterStartElement(writer
, BAD_CAST
"jack") == -1)
366 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterStartElement() failed.");
367 goto fail_free_writter
;
370 if (!jack_controller_settings_write_engine(controller_ptr
, writer
, dbus_call_context_ptr
))
372 goto fail_free_writter
;
375 if (!jack_controller_settings_write_drivers(controller_ptr
, writer
, dbus_call_context_ptr
))
377 goto fail_free_writter
;
380 if (!jack_controller_settings_write_internals(controller_ptr
, writer
, dbus_call_context_ptr
))
382 goto fail_free_writter
;
385 if (xmlTextWriterEndElement(writer
) == -1)
387 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterStartElement() failed.");
388 goto fail_free_writter
;
391 if (xmlTextWriterEndDocument(writer
) == -1)
393 jack_dbus_error(dbus_call_context_ptr
, JACK_DBUS_ERROR_GENERIC
, "xmlTextWriterEndDocument() failed.");
394 goto fail_free_writter
;
400 xmlFreeTextWriter(writer
);
410 jack_controller_settings_read_engine(
411 struct jack_controller
* controller_ptr
,
412 xmlXPathContextPtr xpath_ctx_ptr
)
414 xmlXPathObjectPtr xpath_obj_ptr
;
415 xmlBufferPtr content_buffer_ptr
;
417 const char *option_name
;
418 const char *option_value
;
420 /* Evaluate xpath expression */
421 xpath_obj_ptr
= xmlXPathEvalExpression((const xmlChar
*)XPATH_ENGINE_OPTIONS_EXPRESSION
, xpath_ctx_ptr
);
422 if (xpath_obj_ptr
== NULL
)
424 jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_ENGINE_OPTIONS_EXPRESSION
);
428 if (xpath_obj_ptr
->nodesetval
== NULL
|| xpath_obj_ptr
->nodesetval
->nodeNr
== 0)
430 jack_error("XPath \"%s\" evaluation returned no data", XPATH_ENGINE_OPTIONS_EXPRESSION
);
434 content_buffer_ptr
= xmlBufferCreate();
435 if (content_buffer_ptr
== NULL
)
437 jack_error("xmlBufferCreate() failed.");
441 for (i
= 0 ; i
< xpath_obj_ptr
->nodesetval
->nodeNr
; i
++)
443 //jack_info("engine option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i);
445 if (xmlNodeBufGetContent(content_buffer_ptr
, xpath_obj_ptr
->nodesetval
->nodeTab
[i
]) == -1)
447 jack_error("xmlNodeBufGetContent() failed.");
451 option_name
= (const char *)xmlGetProp(xpath_obj_ptr
->nodesetval
->nodeTab
[i
], BAD_CAST
"name");
452 option_value
= (const char *)xmlBufferContent(content_buffer_ptr
);
454 jack_controller_settings_set_engine_option(controller_ptr
, option_name
, option_value
);
457 xmlBufferEmpty(content_buffer_ptr
);
461 xmlBufferFree(content_buffer_ptr
);
464 xmlXPathFreeObject(xpath_obj_ptr
);
471 jack_controller_settings_read_driver(
472 struct jack_controller
* controller_ptr
,
473 xmlXPathContextPtr xpath_ctx_ptr
,
474 jackctl_driver driver
)
478 xmlXPathObjectPtr xpath_obj_ptr
;
479 xmlBufferPtr content_buffer_ptr
;
481 const char *option_name
;
482 const char *option_value
;
483 const char *driver_name
;
485 driver_name
= jackctl_driver_get_name(driver
);
487 jack_info("reading options for driver \"%s\"", driver_name
);
489 xpath_len
= snprintf(NULL
, 0, XPATH_DRIVER_OPTIONS_EXPRESSION
, driver_name
);
491 xpath
= malloc(xpath_len
);
494 jack_error("Out of memory.");
498 snprintf(xpath
, xpath_len
, XPATH_DRIVER_OPTIONS_EXPRESSION
, driver_name
);
500 //jack_info("xpath = \"%s\"", xpath);
502 /* Evaluate xpath expression */
503 xpath_obj_ptr
= xmlXPathEvalExpression((const xmlChar
*)xpath
, xpath_ctx_ptr
);
504 if (xpath_obj_ptr
== NULL
)
506 jack_error("Unable to evaluate XPath expression \"%s\"", xpath
);
510 if (xpath_obj_ptr
->nodesetval
== NULL
|| xpath_obj_ptr
->nodesetval
->nodeNr
== 0)
512 //jack_info("XPath \"%s\" evaluation returned no data", xpath);
516 content_buffer_ptr
= xmlBufferCreate();
517 if (content_buffer_ptr
== NULL
)
519 jack_error("xmlBufferCreate() failed.");
523 for (i
= 0 ; i
< xpath_obj_ptr
->nodesetval
->nodeNr
; i
++)
525 //jack_info("driver option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i);
527 if (xmlNodeBufGetContent(content_buffer_ptr
, xpath_obj_ptr
->nodesetval
->nodeTab
[i
]) == -1)
529 jack_error("xmlNodeBufGetContent() failed.");
533 option_name
= (const char *)xmlGetProp(xpath_obj_ptr
->nodesetval
->nodeTab
[i
], BAD_CAST
"name");
534 option_value
= (const char *)xmlBufferContent(content_buffer_ptr
);
536 jack_controller_settings_set_driver_option(driver
, option_name
, option_value
);
539 xmlBufferEmpty(content_buffer_ptr
);
543 xmlBufferFree(content_buffer_ptr
);
546 xmlXPathFreeObject(xpath_obj_ptr
);
556 jack_controller_settings_read_internal(
557 struct jack_controller
* controller_ptr
,
558 xmlXPathContextPtr xpath_ctx_ptr
,
559 jackctl_internal internal
)
563 xmlXPathObjectPtr xpath_obj_ptr
;
564 xmlBufferPtr content_buffer_ptr
;
566 const char *option_name
;
567 const char *option_value
;
568 const char *internal_name
;
570 internal_name
= jackctl_internal_get_name(internal
);
572 jack_info("reading options for internal \"%s\"", internal_name
);
574 xpath_len
= snprintf(NULL
, 0, XPATH_DRIVER_OPTIONS_EXPRESSION
, internal_name
);
576 xpath
= malloc(xpath_len
);
579 jack_error("Out of memory.");
583 snprintf(xpath
, xpath_len
, XPATH_DRIVER_OPTIONS_EXPRESSION
, internal_name
);
585 //jack_info("xpath = \"%s\"", xpath);
587 /* Evaluate xpath expression */
588 xpath_obj_ptr
= xmlXPathEvalExpression((const xmlChar
*)xpath
, xpath_ctx_ptr
);
589 if (xpath_obj_ptr
== NULL
)
591 jack_error("Unable to evaluate XPath expression \"%s\"", xpath
);
595 if (xpath_obj_ptr
->nodesetval
== NULL
|| xpath_obj_ptr
->nodesetval
->nodeNr
== 0)
597 //jack_info("XPath \"%s\" evaluation returned no data", xpath);
601 content_buffer_ptr
= xmlBufferCreate();
602 if (content_buffer_ptr
== NULL
)
604 jack_error("xmlBufferCreate() failed.");
608 for (i
= 0 ; i
< xpath_obj_ptr
->nodesetval
->nodeNr
; i
++)
610 //jack_info("driver option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i);
612 if (xmlNodeBufGetContent(content_buffer_ptr
, xpath_obj_ptr
->nodesetval
->nodeTab
[i
]) == -1)
614 jack_error("xmlNodeBufGetContent() failed.");
618 option_name
= (const char *)xmlGetProp(xpath_obj_ptr
->nodesetval
->nodeTab
[i
], BAD_CAST
"name");
619 option_value
= (const char *)xmlBufferContent(content_buffer_ptr
);
621 jack_controller_settings_set_internal_option(internal
, option_name
, option_value
);
624 xmlBufferEmpty(content_buffer_ptr
);
628 xmlBufferFree(content_buffer_ptr
);
631 xmlXPathFreeObject(xpath_obj_ptr
);
641 jack_controller_settings_read_drivers(
642 struct jack_controller
* controller_ptr
,
643 xmlXPathContextPtr xpath_ctx_ptr
)
645 xmlXPathObjectPtr xpath_obj_ptr
;
647 const char *driver_name
;
648 jackctl_driver driver
;
650 /* Evaluate xpath expression */
651 xpath_obj_ptr
= xmlXPathEvalExpression((const xmlChar
*)XPATH_DRIVERS_EXPRESSION
, xpath_ctx_ptr
);
652 if (xpath_obj_ptr
== NULL
)
654 jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_DRIVERS_EXPRESSION
);
658 if (xpath_obj_ptr
->nodesetval
== NULL
|| xpath_obj_ptr
->nodesetval
->nodeNr
== 0)
660 jack_error("XPath \"%s\" evaluation returned no data", XPATH_DRIVERS_EXPRESSION
);
664 for (i
= 0 ; i
< xpath_obj_ptr
->nodesetval
->nodeNr
; i
++)
666 driver_name
= (const char *)xmlGetProp(xpath_obj_ptr
->nodesetval
->nodeTab
[i
], BAD_CAST
"name");
668 driver
= jack_controller_find_driver(controller_ptr
->server
, driver_name
);
671 jack_error("ignoring settings for unknown driver \"%s\"", driver_name
);
675 jack_info("setting for driver \"%s\" found", driver_name
);
677 jack_controller_settings_read_driver(controller_ptr
, xpath_ctx_ptr
, driver
);
682 xmlXPathFreeObject(xpath_obj_ptr
);
689 jack_controller_settings_read_internals(
690 struct jack_controller
* controller_ptr
,
691 xmlXPathContextPtr xpath_ctx_ptr
)
693 xmlXPathObjectPtr xpath_obj_ptr
;
695 const char *internal_name
;
696 jackctl_internal internal
;
698 /* Evaluate xpath expression */
699 xpath_obj_ptr
= xmlXPathEvalExpression((const xmlChar
*)XPATH_DRIVERS_EXPRESSION
, xpath_ctx_ptr
);
700 if (xpath_obj_ptr
== NULL
)
702 jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_DRIVERS_EXPRESSION
);
706 if (xpath_obj_ptr
->nodesetval
== NULL
|| xpath_obj_ptr
->nodesetval
->nodeNr
== 0)
708 jack_error("XPath \"%s\" evaluation returned no data", XPATH_DRIVERS_EXPRESSION
);
712 for (i
= 0 ; i
< xpath_obj_ptr
->nodesetval
->nodeNr
; i
++)
714 internal_name
= (const char *)xmlGetProp(xpath_obj_ptr
->nodesetval
->nodeTab
[i
], BAD_CAST
"name");
716 driver
= jack_controller_find_internal(controller_ptr
->server
, driver_name
);
719 jack_error("ignoring settings for unknown internal \"%s\"", internal_name
);
723 jack_info("setting for internal \"%s\" found", internal_name
);
725 jack_controller_settings_read_internal(controller_ptr
, xpath_ctx_ptr
, driver
);
730 xmlXPathFreeObject(xpath_obj_ptr
);
738 jack_controller_settings_load(
739 struct jack_controller
* controller_ptr
)
744 xmlXPathContextPtr xpath_ctx_ptr
;
746 conf_len
= strlen(JACKDBUS_CONF
);
748 filename
= malloc(g_jackdbus_dir_len
+ conf_len
+ 1);
749 if (filename
== NULL
)
751 jack_error("Out of memory.");
755 memcpy(filename
, g_jackdbus_dir
, g_jackdbus_dir_len
);
756 memcpy(filename
+ g_jackdbus_dir_len
, JACKDBUS_CONF
, conf_len
);
757 filename
[g_jackdbus_dir_len
+ conf_len
] = 0;
759 jack_info("loading settings from \"%s\"", filename
);
761 doc_ptr
= xmlParseFile(filename
);
764 jack_error("Failed to parse \"%s\"", filename
);
768 /* Create xpath evaluation context */
769 xpath_ctx_ptr
= xmlXPathNewContext(doc_ptr
);
770 if (xpath_ctx_ptr
== NULL
)
772 jack_error("Unable to create new XPath context");
776 jack_controller_settings_read_engine(controller_ptr
, xpath_ctx_ptr
);
777 jack_controller_settings_read_drivers(controller_ptr
, xpath_ctx_ptr
);
778 jack_controller_settings_read_internals(controller_ptr
, xpath_ctx_ptr
);
780 xmlXPathFreeContext(xpath_ctx_ptr
);
793 jack_controller_settings_save_auto(
794 struct jack_controller
* controller_ptr
)
796 jack_controller_settings_save(controller_ptr
, NULL
);