jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2289 lines
63KB

  1. /* -*- Mode: C ; c-basic-offset: 4 -*- */
  2. /*
  3. Copyright (C) 2007,2008 Nedko Arnaudov
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #include <stdbool.h>
  16. #include <string.h>
  17. #include <dbus/dbus.h>
  18. #include <libxml/xmlwriter.h>
  19. #include <libxml/parser.h>
  20. #include <libxml/xpath.h>
  21. #include <jack/driver.h>
  22. #include <jack/engine.h>
  23. #include "controller_internal.h"
  24. #include "dbus.h"
  25. /* XPath expression used for engine options selection */
  26. #define XPATH_ENGINE_OPTIONS_EXPRESSION "/jack/engine/option"
  27. /* XPath expression used for drivers selection */
  28. #define XPATH_DRIVERS_EXPRESSION "/jack/drivers/driver"
  29. /* XPath expression used for driver options selection */
  30. #define XPATH_DRIVER_OPTIONS_EXPRESSION "/jack/drivers/driver[@name = '%s']/option"
  31. bool
  32. jack_controller_settings_init()
  33. {
  34. /*
  35. * this initialize the library and check potential ABI mismatches
  36. * between the version it was compiled for and the actual shared
  37. * library used.
  38. */
  39. LIBXML_TEST_VERSION;
  40. return true;
  41. }
  42. void
  43. jack_controller_settings_uninit()
  44. {
  45. }
  46. #define writer ((xmlTextWriterPtr)context)
  47. bool
  48. jack_controller_settings_write_option(
  49. void *context,
  50. const char *name,
  51. const char *content,
  52. void *dbus_call_context_ptr)
  53. {
  54. if (xmlTextWriterStartElement(writer, BAD_CAST "option") == -1)
  55. {
  56. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  57. return false;
  58. }
  59. if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST name) == -1)
  60. {
  61. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed.");
  62. return false;
  63. }
  64. if (xmlTextWriterWriteString(writer, BAD_CAST content) == -1)
  65. {
  66. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteString() failed.");
  67. return false;
  68. }
  69. if (xmlTextWriterEndElement(writer) == -1)
  70. {
  71. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  72. return false;
  73. }
  74. return true;
  75. }
  76. #undef writer
  77. bool
  78. jack_controller_settings_write_engine(
  79. struct jack_controller * controller_ptr,
  80. xmlTextWriterPtr writer,
  81. void *dbus_call_context_ptr)
  82. {
  83. /* jack_info("engine settings begin"); */
  84. /* if (xmlTextWriterWriteComment(writer, BAD_CAST "engine parameters") == -1) */
  85. /* { */
  86. /* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */
  87. /* return false; */
  88. /* } */
  89. if (xmlTextWriterStartElement(writer, BAD_CAST "engine") == -1)
  90. {
  91. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  92. return false;
  93. }
  94. if (!jack_controller_settings_save_engine_options(writer, controller_ptr, dbus_call_context_ptr))
  95. {
  96. return false;
  97. }
  98. if (xmlTextWriterEndElement(writer) == -1)
  99. {
  100. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  101. return false;
  102. }
  103. /* jack_info("engine settings end"); */
  104. return true;
  105. }
  106. bool
  107. jack_controller_settings_write_driver(
  108. struct jack_controller * controller_ptr,
  109. xmlTextWriterPtr writer,
  110. jackctl_driver driver,
  111. void *dbus_call_context_ptr)
  112. {
  113. /* if (xmlTextWriterWriteComment(writer, BAD_CAST "driver parameters") == -1) */
  114. /* { */
  115. /* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */
  116. /* return false; */
  117. /* } */
  118. if (xmlTextWriterStartElement(writer, BAD_CAST "driver") == -1)
  119. {
  120. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  121. return false;
  122. }
  123. if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST jackctl_driver_get_name(driver)) == -1)
  124. {
  125. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed.");
  126. return false;
  127. }
  128. if (!jack_controller_settings_save_driver_options(writer, driver, dbus_call_context_ptr))
  129. {
  130. return false;
  131. }
  132. if (xmlTextWriterEndElement(writer) == -1)
  133. {
  134. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  135. return false;
  136. }
  137. return true;
  138. }
  139. bool
  140. jack_controller_settings_write_drivers(
  141. struct jack_controller * controller_ptr,
  142. xmlTextWriterPtr writer,
  143. void *dbus_call_context_ptr)
  144. {
  145. const JSList * node_ptr;
  146. jackctl_driver driver;
  147. if (xmlTextWriterStartElement(writer, BAD_CAST "drivers") == -1)
  148. {
  149. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  150. return false;
  151. }
  152. node_ptr = jackctl_server_get_drivers_list(controller_ptr->server);
  153. while (node_ptr != NULL)
  154. {
  155. driver = (jackctl_driver)node_ptr->data;
  156. if (!jack_controller_settings_write_driver(
  157. controller_ptr,
  158. writer,
  159. driver,
  160. dbus_call_context_ptr))
  161. {
  162. return false;
  163. }
  164. node_ptr = jack_slist_next(node_ptr);
  165. }
  166. if (xmlTextWriterEndElement(writer) == -1)
  167. {
  168. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  169. return false;
  170. }
  171. return true;
  172. }
  173. bool
  174. jack_controller_settings_save(
  175. struct jack_controller * controller_ptr,
  176. void *dbus_call_context_ptr)
  177. {
  178. xmlTextWriterPtr writer;
  179. char *filename;
  180. size_t conf_len;
  181. bool ret;
  182. time_t timestamp;
  183. char timestamp_str[28];
  184. time(&timestamp);
  185. timestamp_str[0] = ' ';
  186. ctime_r(&timestamp, timestamp_str + 1);
  187. timestamp_str[25] = ' ';
  188. ret = false;
  189. conf_len = strlen(JACKDBUS_CONF);
  190. filename = malloc(g_jackdbus_dir_len + conf_len + 1);
  191. if (filename == NULL)
  192. {
  193. jack_error("Out of memory.");
  194. goto fail;
  195. }
  196. memcpy(filename, g_jackdbus_dir, g_jackdbus_dir_len);
  197. memcpy(filename + g_jackdbus_dir_len, JACKDBUS_CONF, conf_len);
  198. filename[g_jackdbus_dir_len + conf_len] = 0;
  199. jack_info("saving settings to \"%s\"", filename);
  200. writer = xmlNewTextWriterFilename(filename, 0);
  201. if (writer == NULL)
  202. {
  203. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Error creating the xml writer.");
  204. goto fail_free_filename;
  205. }
  206. if (xmlTextWriterSetIndent(writer, 1) == -1)
  207. {
  208. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterSetIndent() failed.");
  209. goto fail_free_writter;
  210. }
  211. if (xmlTextWriterStartDocument(writer, NULL, NULL, NULL) == -1)
  212. {
  213. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartDocument() failed.");
  214. goto fail_free_writter;
  215. }
  216. if (xmlTextWriterWriteComment(writer, BAD_CAST "\n" JACK_CONF_HEADER_TEXT) == -1)
  217. {
  218. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed.");
  219. goto fail_free_writter;
  220. }
  221. if (xmlTextWriterWriteComment(writer, BAD_CAST timestamp_str) == -1)
  222. {
  223. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed.");
  224. goto fail_free_writter;
  225. }
  226. if (xmlTextWriterStartElement(writer, BAD_CAST "jack") == -1)
  227. {
  228. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  229. goto fail_free_writter;
  230. }
  231. if (!jack_controller_settings_write_engine(controller_ptr, writer, dbus_call_context_ptr))
  232. {
  233. goto fail_free_writter;
  234. }
  235. if (!jack_controller_settings_write_drivers(controller_ptr, writer, dbus_call_context_ptr))
  236. {
  237. goto fail_free_writter;
  238. }
  239. if (xmlTextWriterEndElement(writer) == -1)
  240. {
  241. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  242. goto fail_free_writter;
  243. }
  244. if (xmlTextWriterEndDocument(writer) == -1)
  245. {
  246. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndDocument() failed.");
  247. goto fail_free_writter;
  248. }
  249. ret = true;
  250. fail_free_writter:
  251. xmlFreeTextWriter(writer);
  252. fail_free_filename:
  253. free(filename);
  254. fail:
  255. return ret;
  256. }
  257. void
  258. jack_controller_settings_read_engine(
  259. struct jack_controller * controller_ptr,
  260. xmlXPathContextPtr xpath_ctx_ptr)
  261. {
  262. xmlXPathObjectPtr xpath_obj_ptr;
  263. xmlBufferPtr content_buffer_ptr;
  264. int i;
  265. const char *option_name;
  266. const char *option_value;
  267. /* Evaluate xpath expression */
  268. xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_ENGINE_OPTIONS_EXPRESSION, xpath_ctx_ptr);
  269. if (xpath_obj_ptr == NULL)
  270. {
  271. jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_ENGINE_OPTIONS_EXPRESSION);
  272. goto exit;
  273. }
  274. if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
  275. {
  276. jack_error("XPath \"%s\" evaluation returned no data", XPATH_ENGINE_OPTIONS_EXPRESSION);
  277. goto free_xpath_obj;
  278. }
  279. content_buffer_ptr = xmlBufferCreate();
  280. if (content_buffer_ptr == NULL)
  281. {
  282. jack_error("xmlBufferCreate() failed.");
  283. goto free_xpath_obj;
  284. }
  285. for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
  286. {
  287. //jack_info("engine option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i);
  288. if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1)
  289. {
  290. jack_error("xmlNodeBufGetContent() failed.");
  291. goto next_option;
  292. }
  293. option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
  294. option_value = (const char *)xmlBufferContent(content_buffer_ptr);
  295. jack_controller_settings_set_engine_option(controller_ptr, option_name, option_value);
  296. next_option:
  297. xmlBufferEmpty(content_buffer_ptr);
  298. }
  299. //free_buffer:
  300. xmlBufferFree(content_buffer_ptr);
  301. free_xpath_obj:
  302. xmlXPathFreeObject(xpath_obj_ptr);
  303. exit:
  304. return;
  305. }
  306. void
  307. jack_controller_settings_read_driver(
  308. struct jack_controller * controller_ptr,
  309. xmlXPathContextPtr xpath_ctx_ptr,
  310. jackctl_driver driver)
  311. {
  312. char *xpath;
  313. size_t xpath_len;
  314. xmlXPathObjectPtr xpath_obj_ptr;
  315. xmlBufferPtr content_buffer_ptr;
  316. int i;
  317. const char *option_name;
  318. const char *option_value;
  319. const char *driver_name;
  320. driver_name = jackctl_driver_get_name(driver);
  321. jack_info("reading options for driver \"%s\"", driver_name);
  322. xpath_len = snprintf(NULL, 0, XPATH_DRIVER_OPTIONS_EXPRESSION, driver_name);
  323. xpath = malloc(xpath_len);
  324. if (xpath == NULL)
  325. {
  326. jack_error("Out of memory.");
  327. goto exit;
  328. }
  329. snprintf(xpath, xpath_len, XPATH_DRIVER_OPTIONS_EXPRESSION, driver_name);
  330. //jack_info("xpath = \"%s\"", xpath);
  331. /* Evaluate xpath expression */
  332. xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)xpath, xpath_ctx_ptr);
  333. if (xpath_obj_ptr == NULL)
  334. {
  335. jack_error("Unable to evaluate XPath expression \"%s\"", xpath);
  336. goto free_xpath;
  337. }
  338. if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
  339. {
  340. //jack_info("XPath \"%s\" evaluation returned no data", xpath);
  341. goto free_xpath_obj;
  342. }
  343. content_buffer_ptr = xmlBufferCreate();
  344. if (content_buffer_ptr == NULL)
  345. {
  346. jack_error("xmlBufferCreate() failed.");
  347. goto free_xpath_obj;
  348. }
  349. for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
  350. {
  351. //jack_info("driver option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i);
  352. if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1)
  353. {
  354. jack_error("xmlNodeBufGetContent() failed.");
  355. goto next_option;
  356. }
  357. option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
  358. option_value = (const char *)xmlBufferContent(content_buffer_ptr);
  359. jack_controller_settings_set_driver_option(driver, option_name, option_value);
  360. next_option:
  361. xmlBufferEmpty(content_buffer_ptr);
  362. }
  363. //free_buffer:
  364. xmlBufferFree(content_buffer_ptr);
  365. free_xpath_obj:
  366. xmlXPathFreeObject(xpath_obj_ptr);
  367. free_xpath:
  368. free(xpath);
  369. exit:
  370. return;
  371. }
  372. void
  373. jack_controller_settings_read_drivers(
  374. struct jack_controller * controller_ptr,
  375. xmlXPathContextPtr xpath_ctx_ptr)
  376. {
  377. xmlXPathObjectPtr xpath_obj_ptr;
  378. int i;
  379. const char *driver_name;
  380. jackctl_driver driver;
  381. /* Evaluate xpath expression */
  382. xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_DRIVERS_EXPRESSION, xpath_ctx_ptr);
  383. if (xpath_obj_ptr == NULL)
  384. {
  385. jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_DRIVERS_EXPRESSION);
  386. goto exit;
  387. }
  388. if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
  389. {
  390. jack_error("XPath \"%s\" evaluation returned no data", XPATH_DRIVERS_EXPRESSION);
  391. goto free_xpath_obj;
  392. }
  393. for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
  394. {
  395. driver_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
  396. driver = jack_controller_find_driver(controller_ptr->server, driver_name);
  397. if (driver == NULL)
  398. {
  399. jack_error("ignoring settings for unknown driver \"%s\"", driver_name);
  400. }
  401. else
  402. {
  403. jack_info("setting for driver \"%s\" found", driver_name);
  404. jack_controller_settings_read_driver(controller_ptr, xpath_ctx_ptr, driver);
  405. }
  406. }
  407. free_xpath_obj:
  408. xmlXPathFreeObject(xpath_obj_ptr);
  409. exit:
  410. return;
  411. }
  412. void
  413. jack_controller_settings_load(
  414. struct jack_controller * controller_ptr)
  415. {
  416. char *filename;
  417. size_t conf_len;
  418. xmlDocPtr doc_ptr;
  419. xmlXPathContextPtr xpath_ctx_ptr;
  420. conf_len = strlen(JACKDBUS_CONF);
  421. filename = malloc(g_jackdbus_dir_len + conf_len + 1);
  422. if (filename == NULL)
  423. {
  424. jack_error("Out of memory.");
  425. goto exit;
  426. }
  427. memcpy(filename, g_jackdbus_dir, g_jackdbus_dir_len);
  428. memcpy(filename + g_jackdbus_dir_len, JACKDBUS_CONF, conf_len);
  429. filename[g_jackdbus_dir_len + conf_len] = 0;
  430. jack_info("loading settings from \"%s\"", filename);
  431. doc_ptr = xmlParseFile(filename);
  432. if (doc_ptr == NULL)
  433. {
  434. jack_error("Failed to parse \"%s\"", filename);
  435. goto free_filename;
  436. }
  437. /* Create xpath evaluation context */
  438. xpath_ctx_ptr = xmlXPathNewContext(doc_ptr);
  439. if (xpath_ctx_ptr == NULL)
  440. {
  441. jack_error("Unable to create new XPath context");
  442. goto free_doc;
  443. }
  444. jack_controller_settings_read_engine(controller_ptr, xpath_ctx_ptr);
  445. jack_controller_settings_read_drivers(controller_ptr, xpath_ctx_ptr);
  446. xmlXPathFreeContext(xpath_ctx_ptr);
  447. free_doc:
  448. xmlFreeDoc(doc_ptr);
  449. free_filename:
  450. free(filename);
  451. exit:
  452. return;
  453. }
  454. void
  455. jack_controller_settings_save_auto(
  456. struct jack_controller * controller_ptr)
  457. {
  458. jack_controller_settings_save(controller_ptr, NULL);
  459. }
  460. /* -*- Mode: C ; c-basic-offset: 4 -*- */
  461. /*
  462. Copyright (C) 2007,2008 Nedko Arnaudov
  463. This program is free software; you can redistribute it and/or modify
  464. it under the terms of the GNU General Public License as published by
  465. the Free Software Foundation; either version 2 of the License.
  466. This program is distributed in the hope that it will be useful,
  467. but WITHOUT ANY WARRANTY; without even the implied warranty of
  468. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  469. GNU General Public License for more details.
  470. You should have received a copy of the GNU General Public License
  471. along with this program; if not, write to the Free Software
  472. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  473. */
  474. #include <stdbool.h>
  475. #include <string.h>
  476. #include <dbus/dbus.h>
  477. #include <libxml/xmlwriter.h>
  478. #include <libxml/parser.h>
  479. #include <libxml/xpath.h>
  480. #include <jack/driver.h>
  481. #include <jack/engine.h>
  482. #include "controller_internal.h"
  483. #include "dbus.h"
  484. /* XPath expression used for engine options selection */
  485. #define XPATH_ENGINE_OPTIONS_EXPRESSION "/jack/engine/option"
  486. /* XPath expression used for drivers selection */
  487. #define XPATH_DRIVERS_EXPRESSION "/jack/drivers/driver"
  488. /* XPath expression used for driver options selection */
  489. #define XPATH_DRIVER_OPTIONS_EXPRESSION "/jack/drivers/driver[@name = '%s']/option"
  490. bool
  491. jack_controller_settings_init()
  492. {
  493. /*
  494. * this initialize the library and check potential ABI mismatches
  495. * between the version it was compiled for and the actual shared
  496. * library used.
  497. */
  498. LIBXML_TEST_VERSION;
  499. return true;
  500. }
  501. void
  502. jack_controller_settings_uninit()
  503. {
  504. }
  505. #define writer ((xmlTextWriterPtr)context)
  506. bool
  507. jack_controller_settings_write_option(
  508. void *context,
  509. const char *name,
  510. const char *content,
  511. void *dbus_call_context_ptr)
  512. {
  513. if (xmlTextWriterStartElement(writer, BAD_CAST "option") == -1)
  514. {
  515. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  516. return false;
  517. }
  518. if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST name) == -1)
  519. {
  520. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed.");
  521. return false;
  522. }
  523. if (xmlTextWriterWriteString(writer, BAD_CAST content) == -1)
  524. {
  525. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteString() failed.");
  526. return false;
  527. }
  528. if (xmlTextWriterEndElement(writer) == -1)
  529. {
  530. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  531. return false;
  532. }
  533. return true;
  534. }
  535. #undef writer
  536. bool
  537. jack_controller_settings_write_engine(
  538. struct jack_controller * controller_ptr,
  539. xmlTextWriterPtr writer,
  540. void *dbus_call_context_ptr)
  541. {
  542. /* jack_info("engine settings begin"); */
  543. /* if (xmlTextWriterWriteComment(writer, BAD_CAST "engine parameters") == -1) */
  544. /* { */
  545. /* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */
  546. /* return false; */
  547. /* } */
  548. if (xmlTextWriterStartElement(writer, BAD_CAST "engine") == -1)
  549. {
  550. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  551. return false;
  552. }
  553. if (!jack_controller_settings_save_engine_options(writer, controller_ptr, dbus_call_context_ptr))
  554. {
  555. return false;
  556. }
  557. if (xmlTextWriterEndElement(writer) == -1)
  558. {
  559. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  560. return false;
  561. }
  562. /* jack_info("engine settings end"); */
  563. return true;
  564. }
  565. bool
  566. jack_controller_settings_write_driver(
  567. struct jack_controller * controller_ptr,
  568. xmlTextWriterPtr writer,
  569. jackctl_driver driver,
  570. void *dbus_call_context_ptr)
  571. {
  572. /* if (xmlTextWriterWriteComment(writer, BAD_CAST "driver parameters") == -1) */
  573. /* { */
  574. /* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */
  575. /* return false; */
  576. /* } */
  577. if (xmlTextWriterStartElement(writer, BAD_CAST "driver") == -1)
  578. {
  579. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  580. return false;
  581. }
  582. if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST jackctl_driver_get_name(driver)) == -1)
  583. {
  584. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed.");
  585. return false;
  586. }
  587. if (!jack_controller_settings_save_driver_options(writer, driver, dbus_call_context_ptr))
  588. {
  589. return false;
  590. }
  591. if (xmlTextWriterEndElement(writer) == -1)
  592. {
  593. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  594. return false;
  595. }
  596. return true;
  597. }
  598. bool
  599. jack_controller_settings_write_drivers(
  600. struct jack_controller * controller_ptr,
  601. xmlTextWriterPtr writer,
  602. void *dbus_call_context_ptr)
  603. {
  604. const JSList * node_ptr;
  605. jackctl_driver driver;
  606. if (xmlTextWriterStartElement(writer, BAD_CAST "drivers") == -1)
  607. {
  608. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  609. return false;
  610. }
  611. node_ptr = jackctl_server_get_drivers_list(controller_ptr->server);
  612. while (node_ptr != NULL)
  613. {
  614. driver = (jackctl_driver)node_ptr->data;
  615. if (!jack_controller_settings_write_driver(
  616. controller_ptr,
  617. writer,
  618. driver,
  619. dbus_call_context_ptr))
  620. {
  621. return false;
  622. }
  623. node_ptr = jack_slist_next(node_ptr);
  624. }
  625. if (xmlTextWriterEndElement(writer) == -1)
  626. {
  627. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  628. return false;
  629. }
  630. return true;
  631. }
  632. bool
  633. jack_controller_settings_save(
  634. struct jack_controller * controller_ptr,
  635. void *dbus_call_context_ptr)
  636. {
  637. xmlTextWriterPtr writer;
  638. char *filename;
  639. size_t conf_len;
  640. bool ret;
  641. time_t timestamp;
  642. char timestamp_str[28];
  643. time(&timestamp);
  644. timestamp_str[0] = ' ';
  645. ctime_r(&timestamp, timestamp_str + 1);
  646. timestamp_str[25] = ' ';
  647. ret = false;
  648. conf_len = strlen(JACKDBUS_CONF);
  649. filename = malloc(g_jackdbus_dir_len + conf_len + 1);
  650. if (filename == NULL)
  651. {
  652. jack_error("Out of memory.");
  653. goto fail;
  654. }
  655. memcpy(filename, g_jackdbus_dir, g_jackdbus_dir_len);
  656. memcpy(filename + g_jackdbus_dir_len, JACKDBUS_CONF, conf_len);
  657. filename[g_jackdbus_dir_len + conf_len] = 0;
  658. jack_info("saving settings to \"%s\"", filename);
  659. writer = xmlNewTextWriterFilename(filename, 0);
  660. if (writer == NULL)
  661. {
  662. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Error creating the xml writer.");
  663. goto fail_free_filename;
  664. }
  665. if (xmlTextWriterSetIndent(writer, 1) == -1)
  666. {
  667. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterSetIndent() failed.");
  668. goto fail_free_writter;
  669. }
  670. if (xmlTextWriterStartDocument(writer, NULL, NULL, NULL) == -1)
  671. {
  672. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartDocument() failed.");
  673. goto fail_free_writter;
  674. }
  675. if (xmlTextWriterWriteComment(writer, BAD_CAST "\n" JACK_CONF_HEADER_TEXT) == -1)
  676. {
  677. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed.");
  678. goto fail_free_writter;
  679. }
  680. if (xmlTextWriterWriteComment(writer, BAD_CAST timestamp_str) == -1)
  681. {
  682. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed.");
  683. goto fail_free_writter;
  684. }
  685. if (xmlTextWriterStartElement(writer, BAD_CAST "jack") == -1)
  686. {
  687. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  688. goto fail_free_writter;
  689. }
  690. if (!jack_controller_settings_write_engine(controller_ptr, writer, dbus_call_context_ptr))
  691. {
  692. goto fail_free_writter;
  693. }
  694. if (!jack_controller_settings_write_drivers(controller_ptr, writer, dbus_call_context_ptr))
  695. {
  696. goto fail_free_writter;
  697. }
  698. if (xmlTextWriterEndElement(writer) == -1)
  699. {
  700. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  701. goto fail_free_writter;
  702. }
  703. if (xmlTextWriterEndDocument(writer) == -1)
  704. {
  705. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndDocument() failed.");
  706. goto fail_free_writter;
  707. }
  708. ret = true;
  709. fail_free_writter:
  710. xmlFreeTextWriter(writer);
  711. fail_free_filename:
  712. free(filename);
  713. fail:
  714. return ret;
  715. }
  716. void
  717. jack_controller_settings_read_engine(
  718. struct jack_controller * controller_ptr,
  719. xmlXPathContextPtr xpath_ctx_ptr)
  720. {
  721. xmlXPathObjectPtr xpath_obj_ptr;
  722. xmlBufferPtr content_buffer_ptr;
  723. int i;
  724. const char *option_name;
  725. const char *option_value;
  726. /* Evaluate xpath expression */
  727. xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_ENGINE_OPTIONS_EXPRESSION, xpath_ctx_ptr);
  728. if (xpath_obj_ptr == NULL)
  729. {
  730. jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_ENGINE_OPTIONS_EXPRESSION);
  731. goto exit;
  732. }
  733. if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
  734. {
  735. jack_error("XPath \"%s\" evaluation returned no data", XPATH_ENGINE_OPTIONS_EXPRESSION);
  736. goto free_xpath_obj;
  737. }
  738. content_buffer_ptr = xmlBufferCreate();
  739. if (content_buffer_ptr == NULL)
  740. {
  741. jack_error("xmlBufferCreate() failed.");
  742. goto free_xpath_obj;
  743. }
  744. for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
  745. {
  746. //jack_info("engine option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i);
  747. if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1)
  748. {
  749. jack_error("xmlNodeBufGetContent() failed.");
  750. goto next_option;
  751. }
  752. option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
  753. option_value = (const char *)xmlBufferContent(content_buffer_ptr);
  754. jack_controller_settings_set_engine_option(controller_ptr, option_name, option_value);
  755. next_option:
  756. xmlBufferEmpty(content_buffer_ptr);
  757. }
  758. //free_buffer:
  759. xmlBufferFree(content_buffer_ptr);
  760. free_xpath_obj:
  761. xmlXPathFreeObject(xpath_obj_ptr);
  762. exit:
  763. return;
  764. }
  765. void
  766. jack_controller_settings_read_driver(
  767. struct jack_controller * controller_ptr,
  768. xmlXPathContextPtr xpath_ctx_ptr,
  769. jackctl_driver driver)
  770. {
  771. char *xpath;
  772. size_t xpath_len;
  773. xmlXPathObjectPtr xpath_obj_ptr;
  774. xmlBufferPtr content_buffer_ptr;
  775. int i;
  776. const char *option_name;
  777. const char *option_value;
  778. const char *driver_name;
  779. driver_name = jackctl_driver_get_name(driver);
  780. jack_info("reading options for driver \"%s\"", driver_name);
  781. xpath_len = snprintf(NULL, 0, XPATH_DRIVER_OPTIONS_EXPRESSION, driver_name);
  782. xpath = malloc(xpath_len);
  783. if (xpath == NULL)
  784. {
  785. jack_error("Out of memory.");
  786. goto exit;
  787. }
  788. snprintf(xpath, xpath_len, XPATH_DRIVER_OPTIONS_EXPRESSION, driver_name);
  789. //jack_info("xpath = \"%s\"", xpath);
  790. /* Evaluate xpath expression */
  791. xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)xpath, xpath_ctx_ptr);
  792. if (xpath_obj_ptr == NULL)
  793. {
  794. jack_error("Unable to evaluate XPath expression \"%s\"", xpath);
  795. goto free_xpath;
  796. }
  797. if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
  798. {
  799. //jack_info("XPath \"%s\" evaluation returned no data", xpath);
  800. goto free_xpath_obj;
  801. }
  802. content_buffer_ptr = xmlBufferCreate();
  803. if (content_buffer_ptr == NULL)
  804. {
  805. jack_error("xmlBufferCreate() failed.");
  806. goto free_xpath_obj;
  807. }
  808. for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
  809. {
  810. //jack_info("driver option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i);
  811. if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1)
  812. {
  813. jack_error("xmlNodeBufGetContent() failed.");
  814. goto next_option;
  815. }
  816. option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
  817. option_value = (const char *)xmlBufferContent(content_buffer_ptr);
  818. jack_controller_settings_set_driver_option(driver, option_name, option_value);
  819. next_option:
  820. xmlBufferEmpty(content_buffer_ptr);
  821. }
  822. //free_buffer:
  823. xmlBufferFree(content_buffer_ptr);
  824. free_xpath_obj:
  825. xmlXPathFreeObject(xpath_obj_ptr);
  826. free_xpath:
  827. free(xpath);
  828. exit:
  829. return;
  830. }
  831. void
  832. jack_controller_settings_read_drivers(
  833. struct jack_controller * controller_ptr,
  834. xmlXPathContextPtr xpath_ctx_ptr)
  835. {
  836. xmlXPathObjectPtr xpath_obj_ptr;
  837. int i;
  838. const char *driver_name;
  839. jackctl_driver driver;
  840. /* Evaluate xpath expression */
  841. xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_DRIVERS_EXPRESSION, xpath_ctx_ptr);
  842. if (xpath_obj_ptr == NULL)
  843. {
  844. jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_DRIVERS_EXPRESSION);
  845. goto exit;
  846. }
  847. if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
  848. {
  849. jack_error("XPath \"%s\" evaluation returned no data", XPATH_DRIVERS_EXPRESSION);
  850. goto free_xpath_obj;
  851. }
  852. for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
  853. {
  854. driver_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
  855. driver = jack_controller_find_driver(controller_ptr->server, driver_name);
  856. if (driver == NULL)
  857. {
  858. jack_error("ignoring settings for unknown driver \"%s\"", driver_name);
  859. }
  860. else
  861. {
  862. jack_info("setting for driver \"%s\" found", driver_name);
  863. jack_controller_settings_read_driver(controller_ptr, xpath_ctx_ptr, driver);
  864. }
  865. }
  866. free_xpath_obj:
  867. xmlXPathFreeObject(xpath_obj_ptr);
  868. exit:
  869. return;
  870. }
  871. void
  872. jack_controller_settings_load(
  873. struct jack_controller * controller_ptr)
  874. {
  875. char *filename;
  876. size_t conf_len;
  877. xmlDocPtr doc_ptr;
  878. xmlXPathContextPtr xpath_ctx_ptr;
  879. conf_len = strlen(JACKDBUS_CONF);
  880. filename = malloc(g_jackdbus_dir_len + conf_len + 1);
  881. if (filename == NULL)
  882. {
  883. jack_error("Out of memory.");
  884. goto exit;
  885. }
  886. memcpy(filename, g_jackdbus_dir, g_jackdbus_dir_len);
  887. memcpy(filename + g_jackdbus_dir_len, JACKDBUS_CONF, conf_len);
  888. filename[g_jackdbus_dir_len + conf_len] = 0;
  889. jack_info("loading settings from \"%s\"", filename);
  890. doc_ptr = xmlParseFile(filename);
  891. if (doc_ptr == NULL)
  892. {
  893. jack_error("Failed to parse \"%s\"", filename);
  894. goto free_filename;
  895. }
  896. /* Create xpath evaluation context */
  897. xpath_ctx_ptr = xmlXPathNewContext(doc_ptr);
  898. if (xpath_ctx_ptr == NULL)
  899. {
  900. jack_error("Unable to create new XPath context");
  901. goto free_doc;
  902. }
  903. jack_controller_settings_read_engine(controller_ptr, xpath_ctx_ptr);
  904. jack_controller_settings_read_drivers(controller_ptr, xpath_ctx_ptr);
  905. xmlXPathFreeContext(xpath_ctx_ptr);
  906. free_doc:
  907. xmlFreeDoc(doc_ptr);
  908. free_filename:
  909. free(filename);
  910. exit:
  911. return;
  912. }
  913. void
  914. jack_controller_settings_save_auto(
  915. struct jack_controller * controller_ptr)
  916. {
  917. jack_controller_settings_save(controller_ptr, NULL);
  918. }
  919. /* -*- Mode: C ; c-basic-offset: 4 -*- */
  920. /*
  921. Copyright (C) 2007,2008 Nedko Arnaudov
  922. This program is free software; you can redistribute it and/or modify
  923. it under the terms of the GNU General Public License as published by
  924. the Free Software Foundation; either version 2 of the License.
  925. This program is distributed in the hope that it will be useful,
  926. but WITHOUT ANY WARRANTY; without even the implied warranty of
  927. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  928. GNU General Public License for more details.
  929. You should have received a copy of the GNU General Public License
  930. along with this program; if not, write to the Free Software
  931. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  932. */
  933. #include <stdbool.h>
  934. #include <string.h>
  935. #include <dbus/dbus.h>
  936. #include <libxml/xmlwriter.h>
  937. #include <libxml/parser.h>
  938. #include <libxml/xpath.h>
  939. #include <jack/driver.h>
  940. #include <jack/engine.h>
  941. #include "controller_internal.h"
  942. #include "dbus.h"
  943. /* XPath expression used for engine options selection */
  944. #define XPATH_ENGINE_OPTIONS_EXPRESSION "/jack/engine/option"
  945. /* XPath expression used for drivers selection */
  946. #define XPATH_DRIVERS_EXPRESSION "/jack/drivers/driver"
  947. /* XPath expression used for driver options selection */
  948. #define XPATH_DRIVER_OPTIONS_EXPRESSION "/jack/drivers/driver[@name = '%s']/option"
  949. bool
  950. jack_controller_settings_init()
  951. {
  952. /*
  953. * this initialize the library and check potential ABI mismatches
  954. * between the version it was compiled for and the actual shared
  955. * library used.
  956. */
  957. LIBXML_TEST_VERSION;
  958. return true;
  959. }
  960. void
  961. jack_controller_settings_uninit()
  962. {
  963. }
  964. #define writer ((xmlTextWriterPtr)context)
  965. bool
  966. jack_controller_settings_write_option(
  967. void *context,
  968. const char *name,
  969. const char *content,
  970. void *dbus_call_context_ptr)
  971. {
  972. if (xmlTextWriterStartElement(writer, BAD_CAST "option") == -1)
  973. {
  974. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  975. return false;
  976. }
  977. if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST name) == -1)
  978. {
  979. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed.");
  980. return false;
  981. }
  982. if (xmlTextWriterWriteString(writer, BAD_CAST content) == -1)
  983. {
  984. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteString() failed.");
  985. return false;
  986. }
  987. if (xmlTextWriterEndElement(writer) == -1)
  988. {
  989. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  990. return false;
  991. }
  992. return true;
  993. }
  994. #undef writer
  995. bool
  996. jack_controller_settings_write_engine(
  997. struct jack_controller * controller_ptr,
  998. xmlTextWriterPtr writer,
  999. void *dbus_call_context_ptr)
  1000. {
  1001. /* jack_info("engine settings begin"); */
  1002. /* if (xmlTextWriterWriteComment(writer, BAD_CAST "engine parameters") == -1) */
  1003. /* { */
  1004. /* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */
  1005. /* return false; */
  1006. /* } */
  1007. if (xmlTextWriterStartElement(writer, BAD_CAST "engine") == -1)
  1008. {
  1009. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  1010. return false;
  1011. }
  1012. if (!jack_controller_settings_save_engine_options(writer, controller_ptr, dbus_call_context_ptr))
  1013. {
  1014. return false;
  1015. }
  1016. if (xmlTextWriterEndElement(writer) == -1)
  1017. {
  1018. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  1019. return false;
  1020. }
  1021. /* jack_info("engine settings end"); */
  1022. return true;
  1023. }
  1024. bool
  1025. jack_controller_settings_write_driver(
  1026. struct jack_controller * controller_ptr,
  1027. xmlTextWriterPtr writer,
  1028. jackctl_driver driver,
  1029. void *dbus_call_context_ptr)
  1030. {
  1031. /* if (xmlTextWriterWriteComment(writer, BAD_CAST "driver parameters") == -1) */
  1032. /* { */
  1033. /* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */
  1034. /* return false; */
  1035. /* } */
  1036. if (xmlTextWriterStartElement(writer, BAD_CAST "driver") == -1)
  1037. {
  1038. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  1039. return false;
  1040. }
  1041. if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST jackctl_driver_get_name(driver)) == -1)
  1042. {
  1043. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed.");
  1044. return false;
  1045. }
  1046. if (!jack_controller_settings_save_driver_options(writer, driver, dbus_call_context_ptr))
  1047. {
  1048. return false;
  1049. }
  1050. if (xmlTextWriterEndElement(writer) == -1)
  1051. {
  1052. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  1053. return false;
  1054. }
  1055. return true;
  1056. }
  1057. bool
  1058. jack_controller_settings_write_drivers(
  1059. struct jack_controller * controller_ptr,
  1060. xmlTextWriterPtr writer,
  1061. void *dbus_call_context_ptr)
  1062. {
  1063. const JSList * node_ptr;
  1064. jackctl_driver driver;
  1065. if (xmlTextWriterStartElement(writer, BAD_CAST "drivers") == -1)
  1066. {
  1067. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  1068. return false;
  1069. }
  1070. node_ptr = jackctl_server_get_drivers_list(controller_ptr->server);
  1071. while (node_ptr != NULL)
  1072. {
  1073. driver = (jackctl_driver)node_ptr->data;
  1074. if (!jack_controller_settings_write_driver(
  1075. controller_ptr,
  1076. writer,
  1077. driver,
  1078. dbus_call_context_ptr))
  1079. {
  1080. return false;
  1081. }
  1082. node_ptr = jack_slist_next(node_ptr);
  1083. }
  1084. if (xmlTextWriterEndElement(writer) == -1)
  1085. {
  1086. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  1087. return false;
  1088. }
  1089. return true;
  1090. }
  1091. bool
  1092. jack_controller_settings_save(
  1093. struct jack_controller * controller_ptr,
  1094. void *dbus_call_context_ptr)
  1095. {
  1096. xmlTextWriterPtr writer;
  1097. char *filename;
  1098. size_t conf_len;
  1099. bool ret;
  1100. time_t timestamp;
  1101. char timestamp_str[28];
  1102. time(&timestamp);
  1103. timestamp_str[0] = ' ';
  1104. ctime_r(&timestamp, timestamp_str + 1);
  1105. timestamp_str[25] = ' ';
  1106. ret = false;
  1107. conf_len = strlen(JACKDBUS_CONF);
  1108. filename = malloc(g_jackdbus_dir_len + conf_len + 1);
  1109. if (filename == NULL)
  1110. {
  1111. jack_error("Out of memory.");
  1112. goto fail;
  1113. }
  1114. memcpy(filename, g_jackdbus_dir, g_jackdbus_dir_len);
  1115. memcpy(filename + g_jackdbus_dir_len, JACKDBUS_CONF, conf_len);
  1116. filename[g_jackdbus_dir_len + conf_len] = 0;
  1117. jack_info("saving settings to \"%s\"", filename);
  1118. writer = xmlNewTextWriterFilename(filename, 0);
  1119. if (writer == NULL)
  1120. {
  1121. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Error creating the xml writer.");
  1122. goto fail_free_filename;
  1123. }
  1124. if (xmlTextWriterSetIndent(writer, 1) == -1)
  1125. {
  1126. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterSetIndent() failed.");
  1127. goto fail_free_writter;
  1128. }
  1129. if (xmlTextWriterStartDocument(writer, NULL, NULL, NULL) == -1)
  1130. {
  1131. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartDocument() failed.");
  1132. goto fail_free_writter;
  1133. }
  1134. if (xmlTextWriterWriteComment(writer, BAD_CAST "\n" JACK_CONF_HEADER_TEXT) == -1)
  1135. {
  1136. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed.");
  1137. goto fail_free_writter;
  1138. }
  1139. if (xmlTextWriterWriteComment(writer, BAD_CAST timestamp_str) == -1)
  1140. {
  1141. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed.");
  1142. goto fail_free_writter;
  1143. }
  1144. if (xmlTextWriterStartElement(writer, BAD_CAST "jack") == -1)
  1145. {
  1146. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  1147. goto fail_free_writter;
  1148. }
  1149. if (!jack_controller_settings_write_engine(controller_ptr, writer, dbus_call_context_ptr))
  1150. {
  1151. goto fail_free_writter;
  1152. }
  1153. if (!jack_controller_settings_write_drivers(controller_ptr, writer, dbus_call_context_ptr))
  1154. {
  1155. goto fail_free_writter;
  1156. }
  1157. if (xmlTextWriterEndElement(writer) == -1)
  1158. {
  1159. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  1160. goto fail_free_writter;
  1161. }
  1162. if (xmlTextWriterEndDocument(writer) == -1)
  1163. {
  1164. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndDocument() failed.");
  1165. goto fail_free_writter;
  1166. }
  1167. ret = true;
  1168. fail_free_writter:
  1169. xmlFreeTextWriter(writer);
  1170. fail_free_filename:
  1171. free(filename);
  1172. fail:
  1173. return ret;
  1174. }
  1175. void
  1176. jack_controller_settings_read_engine(
  1177. struct jack_controller * controller_ptr,
  1178. xmlXPathContextPtr xpath_ctx_ptr)
  1179. {
  1180. xmlXPathObjectPtr xpath_obj_ptr;
  1181. xmlBufferPtr content_buffer_ptr;
  1182. int i;
  1183. const char *option_name;
  1184. const char *option_value;
  1185. /* Evaluate xpath expression */
  1186. xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_ENGINE_OPTIONS_EXPRESSION, xpath_ctx_ptr);
  1187. if (xpath_obj_ptr == NULL)
  1188. {
  1189. jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_ENGINE_OPTIONS_EXPRESSION);
  1190. goto exit;
  1191. }
  1192. if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
  1193. {
  1194. jack_error("XPath \"%s\" evaluation returned no data", XPATH_ENGINE_OPTIONS_EXPRESSION);
  1195. goto free_xpath_obj;
  1196. }
  1197. content_buffer_ptr = xmlBufferCreate();
  1198. if (content_buffer_ptr == NULL)
  1199. {
  1200. jack_error("xmlBufferCreate() failed.");
  1201. goto free_xpath_obj;
  1202. }
  1203. for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
  1204. {
  1205. //jack_info("engine option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i);
  1206. if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1)
  1207. {
  1208. jack_error("xmlNodeBufGetContent() failed.");
  1209. goto next_option;
  1210. }
  1211. option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
  1212. option_value = (const char *)xmlBufferContent(content_buffer_ptr);
  1213. jack_controller_settings_set_engine_option(controller_ptr, option_name, option_value);
  1214. next_option:
  1215. xmlBufferEmpty(content_buffer_ptr);
  1216. }
  1217. //free_buffer:
  1218. xmlBufferFree(content_buffer_ptr);
  1219. free_xpath_obj:
  1220. xmlXPathFreeObject(xpath_obj_ptr);
  1221. exit:
  1222. return;
  1223. }
  1224. void
  1225. jack_controller_settings_read_driver(
  1226. struct jack_controller * controller_ptr,
  1227. xmlXPathContextPtr xpath_ctx_ptr,
  1228. jackctl_driver driver)
  1229. {
  1230. char *xpath;
  1231. size_t xpath_len;
  1232. xmlXPathObjectPtr xpath_obj_ptr;
  1233. xmlBufferPtr content_buffer_ptr;
  1234. int i;
  1235. const char *option_name;
  1236. const char *option_value;
  1237. const char *driver_name;
  1238. driver_name = jackctl_driver_get_name(driver);
  1239. jack_info("reading options for driver \"%s\"", driver_name);
  1240. xpath_len = snprintf(NULL, 0, XPATH_DRIVER_OPTIONS_EXPRESSION, driver_name);
  1241. xpath = malloc(xpath_len);
  1242. if (xpath == NULL)
  1243. {
  1244. jack_error("Out of memory.");
  1245. goto exit;
  1246. }
  1247. snprintf(xpath, xpath_len, XPATH_DRIVER_OPTIONS_EXPRESSION, driver_name);
  1248. //jack_info("xpath = \"%s\"", xpath);
  1249. /* Evaluate xpath expression */
  1250. xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)xpath, xpath_ctx_ptr);
  1251. if (xpath_obj_ptr == NULL)
  1252. {
  1253. jack_error("Unable to evaluate XPath expression \"%s\"", xpath);
  1254. goto free_xpath;
  1255. }
  1256. if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
  1257. {
  1258. //jack_info("XPath \"%s\" evaluation returned no data", xpath);
  1259. goto free_xpath_obj;
  1260. }
  1261. content_buffer_ptr = xmlBufferCreate();
  1262. if (content_buffer_ptr == NULL)
  1263. {
  1264. jack_error("xmlBufferCreate() failed.");
  1265. goto free_xpath_obj;
  1266. }
  1267. for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
  1268. {
  1269. //jack_info("driver option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i);
  1270. if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1)
  1271. {
  1272. jack_error("xmlNodeBufGetContent() failed.");
  1273. goto next_option;
  1274. }
  1275. option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
  1276. option_value = (const char *)xmlBufferContent(content_buffer_ptr);
  1277. jack_controller_settings_set_driver_option(driver, option_name, option_value);
  1278. next_option:
  1279. xmlBufferEmpty(content_buffer_ptr);
  1280. }
  1281. //free_buffer:
  1282. xmlBufferFree(content_buffer_ptr);
  1283. free_xpath_obj:
  1284. xmlXPathFreeObject(xpath_obj_ptr);
  1285. free_xpath:
  1286. free(xpath);
  1287. exit:
  1288. return;
  1289. }
  1290. void
  1291. jack_controller_settings_read_drivers(
  1292. struct jack_controller * controller_ptr,
  1293. xmlXPathContextPtr xpath_ctx_ptr)
  1294. {
  1295. xmlXPathObjectPtr xpath_obj_ptr;
  1296. int i;
  1297. const char *driver_name;
  1298. jackctl_driver driver;
  1299. /* Evaluate xpath expression */
  1300. xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_DRIVERS_EXPRESSION, xpath_ctx_ptr);
  1301. if (xpath_obj_ptr == NULL)
  1302. {
  1303. jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_DRIVERS_EXPRESSION);
  1304. goto exit;
  1305. }
  1306. if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
  1307. {
  1308. jack_error("XPath \"%s\" evaluation returned no data", XPATH_DRIVERS_EXPRESSION);
  1309. goto free_xpath_obj;
  1310. }
  1311. for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
  1312. {
  1313. driver_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
  1314. driver = jack_controller_find_driver(controller_ptr->server, driver_name);
  1315. if (driver == NULL)
  1316. {
  1317. jack_error("ignoring settings for unknown driver \"%s\"", driver_name);
  1318. }
  1319. else
  1320. {
  1321. jack_info("setting for driver \"%s\" found", driver_name);
  1322. jack_controller_settings_read_driver(controller_ptr, xpath_ctx_ptr, driver);
  1323. }
  1324. }
  1325. free_xpath_obj:
  1326. xmlXPathFreeObject(xpath_obj_ptr);
  1327. exit:
  1328. return;
  1329. }
  1330. void
  1331. jack_controller_settings_load(
  1332. struct jack_controller * controller_ptr)
  1333. {
  1334. char *filename;
  1335. size_t conf_len;
  1336. xmlDocPtr doc_ptr;
  1337. xmlXPathContextPtr xpath_ctx_ptr;
  1338. conf_len = strlen(JACKDBUS_CONF);
  1339. filename = malloc(g_jackdbus_dir_len + conf_len + 1);
  1340. if (filename == NULL)
  1341. {
  1342. jack_error("Out of memory.");
  1343. goto exit;
  1344. }
  1345. memcpy(filename, g_jackdbus_dir, g_jackdbus_dir_len);
  1346. memcpy(filename + g_jackdbus_dir_len, JACKDBUS_CONF, conf_len);
  1347. filename[g_jackdbus_dir_len + conf_len] = 0;
  1348. jack_info("loading settings from \"%s\"", filename);
  1349. doc_ptr = xmlParseFile(filename);
  1350. if (doc_ptr == NULL)
  1351. {
  1352. jack_error("Failed to parse \"%s\"", filename);
  1353. goto free_filename;
  1354. }
  1355. /* Create xpath evaluation context */
  1356. xpath_ctx_ptr = xmlXPathNewContext(doc_ptr);
  1357. if (xpath_ctx_ptr == NULL)
  1358. {
  1359. jack_error("Unable to create new XPath context");
  1360. goto free_doc;
  1361. }
  1362. jack_controller_settings_read_engine(controller_ptr, xpath_ctx_ptr);
  1363. jack_controller_settings_read_drivers(controller_ptr, xpath_ctx_ptr);
  1364. xmlXPathFreeContext(xpath_ctx_ptr);
  1365. free_doc:
  1366. xmlFreeDoc(doc_ptr);
  1367. free_filename:
  1368. free(filename);
  1369. exit:
  1370. return;
  1371. }
  1372. void
  1373. jack_controller_settings_save_auto(
  1374. struct jack_controller * controller_ptr)
  1375. {
  1376. jack_controller_settings_save(controller_ptr, NULL);
  1377. }
  1378. /* -*- Mode: C ; c-basic-offset: 4 -*- */
  1379. /*
  1380. Copyright (C) 2007,2008 Nedko Arnaudov
  1381. This program is free software; you can redistribute it and/or modify
  1382. it under the terms of the GNU General Public License as published by
  1383. the Free Software Foundation; either version 2 of the License.
  1384. This program is distributed in the hope that it will be useful,
  1385. but WITHOUT ANY WARRANTY; without even the implied warranty of
  1386. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1387. GNU General Public License for more details.
  1388. You should have received a copy of the GNU General Public License
  1389. along with this program; if not, write to the Free Software
  1390. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  1391. */
  1392. #include <stdbool.h>
  1393. #include <string.h>
  1394. #include <dbus/dbus.h>
  1395. #include <libxml/xmlwriter.h>
  1396. #include <libxml/parser.h>
  1397. #include <libxml/xpath.h>
  1398. #include <jack/driver.h>
  1399. #include <jack/engine.h>
  1400. #include "controller_internal.h"
  1401. #include "dbus.h"
  1402. /* XPath expression used for engine options selection */
  1403. #define XPATH_ENGINE_OPTIONS_EXPRESSION "/jack/engine/option"
  1404. /* XPath expression used for drivers selection */
  1405. #define XPATH_DRIVERS_EXPRESSION "/jack/drivers/driver"
  1406. /* XPath expression used for driver options selection */
  1407. #define XPATH_DRIVER_OPTIONS_EXPRESSION "/jack/drivers/driver[@name = '%s']/option"
  1408. bool
  1409. jack_controller_settings_init()
  1410. {
  1411. /*
  1412. * this initialize the library and check potential ABI mismatches
  1413. * between the version it was compiled for and the actual shared
  1414. * library used.
  1415. */
  1416. LIBXML_TEST_VERSION;
  1417. return true;
  1418. }
  1419. void
  1420. jack_controller_settings_uninit()
  1421. {
  1422. }
  1423. #define writer ((xmlTextWriterPtr)context)
  1424. bool
  1425. jack_controller_settings_write_option(
  1426. void *context,
  1427. const char *name,
  1428. const char *content,
  1429. void *dbus_call_context_ptr)
  1430. {
  1431. if (xmlTextWriterStartElement(writer, BAD_CAST "option") == -1)
  1432. {
  1433. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  1434. return false;
  1435. }
  1436. if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST name) == -1)
  1437. {
  1438. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed.");
  1439. return false;
  1440. }
  1441. if (xmlTextWriterWriteString(writer, BAD_CAST content) == -1)
  1442. {
  1443. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteString() failed.");
  1444. return false;
  1445. }
  1446. if (xmlTextWriterEndElement(writer) == -1)
  1447. {
  1448. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  1449. return false;
  1450. }
  1451. return true;
  1452. }
  1453. #undef writer
  1454. bool
  1455. jack_controller_settings_write_engine(
  1456. struct jack_controller * controller_ptr,
  1457. xmlTextWriterPtr writer,
  1458. void *dbus_call_context_ptr)
  1459. {
  1460. /* jack_info("engine settings begin"); */
  1461. /* if (xmlTextWriterWriteComment(writer, BAD_CAST "engine parameters") == -1) */
  1462. /* { */
  1463. /* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */
  1464. /* return false; */
  1465. /* } */
  1466. if (xmlTextWriterStartElement(writer, BAD_CAST "engine") == -1)
  1467. {
  1468. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  1469. return false;
  1470. }
  1471. if (!jack_controller_settings_save_engine_options(writer, controller_ptr, dbus_call_context_ptr))
  1472. {
  1473. return false;
  1474. }
  1475. if (xmlTextWriterEndElement(writer) == -1)
  1476. {
  1477. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  1478. return false;
  1479. }
  1480. /* jack_info("engine settings end"); */
  1481. return true;
  1482. }
  1483. bool
  1484. jack_controller_settings_write_driver(
  1485. struct jack_controller * controller_ptr,
  1486. xmlTextWriterPtr writer,
  1487. jackctl_driver driver,
  1488. void *dbus_call_context_ptr)
  1489. {
  1490. /* if (xmlTextWriterWriteComment(writer, BAD_CAST "driver parameters") == -1) */
  1491. /* { */
  1492. /* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */
  1493. /* return false; */
  1494. /* } */
  1495. if (xmlTextWriterStartElement(writer, BAD_CAST "driver") == -1)
  1496. {
  1497. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  1498. return false;
  1499. }
  1500. if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST jackctl_driver_get_name(driver)) == -1)
  1501. {
  1502. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed.");
  1503. return false;
  1504. }
  1505. if (!jack_controller_settings_save_driver_options(writer, driver, dbus_call_context_ptr))
  1506. {
  1507. return false;
  1508. }
  1509. if (xmlTextWriterEndElement(writer) == -1)
  1510. {
  1511. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  1512. return false;
  1513. }
  1514. return true;
  1515. }
  1516. bool
  1517. jack_controller_settings_write_drivers(
  1518. struct jack_controller * controller_ptr,
  1519. xmlTextWriterPtr writer,
  1520. void *dbus_call_context_ptr)
  1521. {
  1522. const JSList * node_ptr;
  1523. jackctl_driver driver;
  1524. if (xmlTextWriterStartElement(writer, BAD_CAST "drivers") == -1)
  1525. {
  1526. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  1527. return false;
  1528. }
  1529. node_ptr = jackctl_server_get_drivers_list(controller_ptr->server);
  1530. while (node_ptr != NULL)
  1531. {
  1532. driver = (jackctl_driver)node_ptr->data;
  1533. if (!jack_controller_settings_write_driver(
  1534. controller_ptr,
  1535. writer,
  1536. driver,
  1537. dbus_call_context_ptr))
  1538. {
  1539. return false;
  1540. }
  1541. node_ptr = jack_slist_next(node_ptr);
  1542. }
  1543. if (xmlTextWriterEndElement(writer) == -1)
  1544. {
  1545. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  1546. return false;
  1547. }
  1548. return true;
  1549. }
  1550. bool
  1551. jack_controller_settings_save(
  1552. struct jack_controller * controller_ptr,
  1553. void *dbus_call_context_ptr)
  1554. {
  1555. xmlTextWriterPtr writer;
  1556. char *filename;
  1557. size_t conf_len;
  1558. bool ret;
  1559. time_t timestamp;
  1560. char timestamp_str[28];
  1561. time(&timestamp);
  1562. timestamp_str[0] = ' ';
  1563. ctime_r(&timestamp, timestamp_str + 1);
  1564. timestamp_str[25] = ' ';
  1565. ret = false;
  1566. conf_len = strlen(JACKDBUS_CONF);
  1567. filename = malloc(g_jackdbus_dir_len + conf_len + 1);
  1568. if (filename == NULL)
  1569. {
  1570. jack_error("Out of memory.");
  1571. goto fail;
  1572. }
  1573. memcpy(filename, g_jackdbus_dir, g_jackdbus_dir_len);
  1574. memcpy(filename + g_jackdbus_dir_len, JACKDBUS_CONF, conf_len);
  1575. filename[g_jackdbus_dir_len + conf_len] = 0;
  1576. jack_info("saving settings to \"%s\"", filename);
  1577. writer = xmlNewTextWriterFilename(filename, 0);
  1578. if (writer == NULL)
  1579. {
  1580. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Error creating the xml writer.");
  1581. goto fail_free_filename;
  1582. }
  1583. if (xmlTextWriterSetIndent(writer, 1) == -1)
  1584. {
  1585. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterSetIndent() failed.");
  1586. goto fail_free_writter;
  1587. }
  1588. if (xmlTextWriterStartDocument(writer, NULL, NULL, NULL) == -1)
  1589. {
  1590. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartDocument() failed.");
  1591. goto fail_free_writter;
  1592. }
  1593. if (xmlTextWriterWriteComment(writer, BAD_CAST "\n" JACK_CONF_HEADER_TEXT) == -1)
  1594. {
  1595. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed.");
  1596. goto fail_free_writter;
  1597. }
  1598. if (xmlTextWriterWriteComment(writer, BAD_CAST timestamp_str) == -1)
  1599. {
  1600. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed.");
  1601. goto fail_free_writter;
  1602. }
  1603. if (xmlTextWriterStartElement(writer, BAD_CAST "jack") == -1)
  1604. {
  1605. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  1606. goto fail_free_writter;
  1607. }
  1608. if (!jack_controller_settings_write_engine(controller_ptr, writer, dbus_call_context_ptr))
  1609. {
  1610. goto fail_free_writter;
  1611. }
  1612. if (!jack_controller_settings_write_drivers(controller_ptr, writer, dbus_call_context_ptr))
  1613. {
  1614. goto fail_free_writter;
  1615. }
  1616. if (xmlTextWriterEndElement(writer) == -1)
  1617. {
  1618. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  1619. goto fail_free_writter;
  1620. }
  1621. if (xmlTextWriterEndDocument(writer) == -1)
  1622. {
  1623. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndDocument() failed.");
  1624. goto fail_free_writter;
  1625. }
  1626. ret = true;
  1627. fail_free_writter:
  1628. xmlFreeTextWriter(writer);
  1629. fail_free_filename:
  1630. free(filename);
  1631. fail:
  1632. return ret;
  1633. }
  1634. void
  1635. jack_controller_settings_read_engine(
  1636. struct jack_controller * controller_ptr,
  1637. xmlXPathContextPtr xpath_ctx_ptr)
  1638. {
  1639. xmlXPathObjectPtr xpath_obj_ptr;
  1640. xmlBufferPtr content_buffer_ptr;
  1641. int i;
  1642. const char *option_name;
  1643. const char *option_value;
  1644. /* Evaluate xpath expression */
  1645. xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_ENGINE_OPTIONS_EXPRESSION, xpath_ctx_ptr);
  1646. if (xpath_obj_ptr == NULL)
  1647. {
  1648. jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_ENGINE_OPTIONS_EXPRESSION);
  1649. goto exit;
  1650. }
  1651. if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
  1652. {
  1653. jack_error("XPath \"%s\" evaluation returned no data", XPATH_ENGINE_OPTIONS_EXPRESSION);
  1654. goto free_xpath_obj;
  1655. }
  1656. content_buffer_ptr = xmlBufferCreate();
  1657. if (content_buffer_ptr == NULL)
  1658. {
  1659. jack_error("xmlBufferCreate() failed.");
  1660. goto free_xpath_obj;
  1661. }
  1662. for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
  1663. {
  1664. //jack_info("engine option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i);
  1665. if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1)
  1666. {
  1667. jack_error("xmlNodeBufGetContent() failed.");
  1668. goto next_option;
  1669. }
  1670. option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
  1671. option_value = (const char *)xmlBufferContent(content_buffer_ptr);
  1672. jack_controller_settings_set_engine_option(controller_ptr, option_name, option_value);
  1673. next_option:
  1674. xmlBufferEmpty(content_buffer_ptr);
  1675. }
  1676. //free_buffer:
  1677. xmlBufferFree(content_buffer_ptr);
  1678. free_xpath_obj:
  1679. xmlXPathFreeObject(xpath_obj_ptr);
  1680. exit:
  1681. return;
  1682. }
  1683. void
  1684. jack_controller_settings_read_driver(
  1685. struct jack_controller * controller_ptr,
  1686. xmlXPathContextPtr xpath_ctx_ptr,
  1687. jackctl_driver driver)
  1688. {
  1689. char *xpath;
  1690. size_t xpath_len;
  1691. xmlXPathObjectPtr xpath_obj_ptr;
  1692. xmlBufferPtr content_buffer_ptr;
  1693. int i;
  1694. const char *option_name;
  1695. const char *option_value;
  1696. const char *driver_name;
  1697. driver_name = jackctl_driver_get_name(driver);
  1698. jack_info("reading options for driver \"%s\"", driver_name);
  1699. xpath_len = snprintf(NULL, 0, XPATH_DRIVER_OPTIONS_EXPRESSION, driver_name);
  1700. xpath = malloc(xpath_len);
  1701. if (xpath == NULL)
  1702. {
  1703. jack_error("Out of memory.");
  1704. goto exit;
  1705. }
  1706. snprintf(xpath, xpath_len, XPATH_DRIVER_OPTIONS_EXPRESSION, driver_name);
  1707. //jack_info("xpath = \"%s\"", xpath);
  1708. /* Evaluate xpath expression */
  1709. xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)xpath, xpath_ctx_ptr);
  1710. if (xpath_obj_ptr == NULL)
  1711. {
  1712. jack_error("Unable to evaluate XPath expression \"%s\"", xpath);
  1713. goto free_xpath;
  1714. }
  1715. if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
  1716. {
  1717. //jack_info("XPath \"%s\" evaluation returned no data", xpath);
  1718. goto free_xpath_obj;
  1719. }
  1720. content_buffer_ptr = xmlBufferCreate();
  1721. if (content_buffer_ptr == NULL)
  1722. {
  1723. jack_error("xmlBufferCreate() failed.");
  1724. goto free_xpath_obj;
  1725. }
  1726. for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
  1727. {
  1728. //jack_info("driver option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i);
  1729. if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1)
  1730. {
  1731. jack_error("xmlNodeBufGetContent() failed.");
  1732. goto next_option;
  1733. }
  1734. option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
  1735. option_value = (const char *)xmlBufferContent(content_buffer_ptr);
  1736. jack_controller_settings_set_driver_option(driver, option_name, option_value);
  1737. next_option:
  1738. xmlBufferEmpty(content_buffer_ptr);
  1739. }
  1740. //free_buffer:
  1741. xmlBufferFree(content_buffer_ptr);
  1742. free_xpath_obj:
  1743. xmlXPathFreeObject(xpath_obj_ptr);
  1744. free_xpath:
  1745. free(xpath);
  1746. exit:
  1747. return;
  1748. }
  1749. void
  1750. jack_controller_settings_read_drivers(
  1751. struct jack_controller * controller_ptr,
  1752. xmlXPathContextPtr xpath_ctx_ptr)
  1753. {
  1754. xmlXPathObjectPtr xpath_obj_ptr;
  1755. int i;
  1756. const char *driver_name;
  1757. jackctl_driver driver;
  1758. /* Evaluate xpath expression */
  1759. xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_DRIVERS_EXPRESSION, xpath_ctx_ptr);
  1760. if (xpath_obj_ptr == NULL)
  1761. {
  1762. jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_DRIVERS_EXPRESSION);
  1763. goto exit;
  1764. }
  1765. if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
  1766. {
  1767. jack_error("XPath \"%s\" evaluation returned no data", XPATH_DRIVERS_EXPRESSION);
  1768. goto free_xpath_obj;
  1769. }
  1770. for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
  1771. {
  1772. driver_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
  1773. driver = jack_controller_find_driver(controller_ptr->server, driver_name);
  1774. if (driver == NULL)
  1775. {
  1776. jack_error("ignoring settings for unknown driver \"%s\"", driver_name);
  1777. }
  1778. else
  1779. {
  1780. jack_info("setting for driver \"%s\" found", driver_name);
  1781. jack_controller_settings_read_driver(controller_ptr, xpath_ctx_ptr, driver);
  1782. }
  1783. }
  1784. free_xpath_obj:
  1785. xmlXPathFreeObject(xpath_obj_ptr);
  1786. exit:
  1787. return;
  1788. }
  1789. void
  1790. jack_controller_settings_load(
  1791. struct jack_controller * controller_ptr)
  1792. {
  1793. char *filename;
  1794. size_t conf_len;
  1795. xmlDocPtr doc_ptr;
  1796. xmlXPathContextPtr xpath_ctx_ptr;
  1797. conf_len = strlen(JACKDBUS_CONF);
  1798. filename = malloc(g_jackdbus_dir_len + conf_len + 1);
  1799. if (filename == NULL)
  1800. {
  1801. jack_error("Out of memory.");
  1802. goto exit;
  1803. }
  1804. memcpy(filename, g_jackdbus_dir, g_jackdbus_dir_len);
  1805. memcpy(filename + g_jackdbus_dir_len, JACKDBUS_CONF, conf_len);
  1806. filename[g_jackdbus_dir_len + conf_len] = 0;
  1807. jack_info("loading settings from \"%s\"", filename);
  1808. doc_ptr = xmlParseFile(filename);
  1809. if (doc_ptr == NULL)
  1810. {
  1811. jack_error("Failed to parse \"%s\"", filename);
  1812. goto free_filename;
  1813. }
  1814. /* Create xpath evaluation context */
  1815. xpath_ctx_ptr = xmlXPathNewContext(doc_ptr);
  1816. if (xpath_ctx_ptr == NULL)
  1817. {
  1818. jack_error("Unable to create new XPath context");
  1819. goto free_doc;
  1820. }
  1821. jack_controller_settings_read_engine(controller_ptr, xpath_ctx_ptr);
  1822. jack_controller_settings_read_drivers(controller_ptr, xpath_ctx_ptr);
  1823. xmlXPathFreeContext(xpath_ctx_ptr);
  1824. free_doc:
  1825. xmlFreeDoc(doc_ptr);
  1826. free_filename:
  1827. free(filename);
  1828. exit:
  1829. return;
  1830. }
  1831. void
  1832. jack_controller_settings_save_auto(
  1833. struct jack_controller * controller_ptr)
  1834. {
  1835. jack_controller_settings_save(controller_ptr, NULL);
  1836. }