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.

798 lines
22KB

  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. #if defined(HAVE_CONFIG_H)
  16. #include "config.h"
  17. #endif
  18. #include <stdbool.h>
  19. #include <string.h>
  20. #include <dbus/dbus.h>
  21. #include <libxml/xmlwriter.h>
  22. #include <libxml/parser.h>
  23. #include <libxml/xpath.h>
  24. #include <jack/driver.h>
  25. #include <jack/engine.h>
  26. #include "controller_internal.h"
  27. #include "dbus.h"
  28. /* XPath expression used for engine options selection */
  29. #define XPATH_ENGINE_OPTIONS_EXPRESSION "/jack/engine/option"
  30. /* XPath expression used for drivers selection */
  31. #define XPATH_DRIVERS_EXPRESSION "/jack/drivers/driver"
  32. /* XPath expression used for driver options selection */
  33. #define XPATH_DRIVER_OPTIONS_EXPRESSION "/jack/drivers/driver[@name = '%s']/option"
  34. bool
  35. jack_controller_settings_init()
  36. {
  37. /*
  38. * this initialize the library and check potential ABI mismatches
  39. * between the version it was compiled for and the actual shared
  40. * library used.
  41. */
  42. LIBXML_TEST_VERSION;
  43. return true;
  44. }
  45. void
  46. jack_controller_settings_uninit()
  47. {
  48. }
  49. #define writer ((xmlTextWriterPtr)context)
  50. bool
  51. jack_controller_settings_write_option(
  52. void *context,
  53. const char *name,
  54. const char *content,
  55. void *dbus_call_context_ptr)
  56. {
  57. if (xmlTextWriterStartElement(writer, BAD_CAST "option") == -1)
  58. {
  59. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  60. return false;
  61. }
  62. if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST name) == -1)
  63. {
  64. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed.");
  65. return false;
  66. }
  67. if (xmlTextWriterWriteString(writer, BAD_CAST content) == -1)
  68. {
  69. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteString() failed.");
  70. return false;
  71. }
  72. if (xmlTextWriterEndElement(writer) == -1)
  73. {
  74. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  75. return false;
  76. }
  77. return true;
  78. }
  79. #undef writer
  80. bool
  81. jack_controller_settings_write_engine(
  82. struct jack_controller * controller_ptr,
  83. xmlTextWriterPtr writer,
  84. void *dbus_call_context_ptr)
  85. {
  86. /* jack_info("engine settings begin"); */
  87. /* if (xmlTextWriterWriteComment(writer, BAD_CAST "engine parameters") == -1) */
  88. /* { */
  89. /* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */
  90. /* return false; */
  91. /* } */
  92. if (xmlTextWriterStartElement(writer, BAD_CAST "engine") == -1)
  93. {
  94. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  95. return false;
  96. }
  97. if (!jack_controller_settings_save_engine_options(writer, controller_ptr, dbus_call_context_ptr))
  98. {
  99. return false;
  100. }
  101. if (xmlTextWriterEndElement(writer) == -1)
  102. {
  103. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  104. return false;
  105. }
  106. /* jack_info("engine settings end"); */
  107. return true;
  108. }
  109. bool
  110. jack_controller_settings_write_driver(
  111. struct jack_controller * controller_ptr,
  112. xmlTextWriterPtr writer,
  113. jackctl_driver driver,
  114. void *dbus_call_context_ptr)
  115. {
  116. /* if (xmlTextWriterWriteComment(writer, BAD_CAST "driver parameters") == -1) */
  117. /* { */
  118. /* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */
  119. /* return false; */
  120. /* } */
  121. if (xmlTextWriterStartElement(writer, BAD_CAST "driver") == -1)
  122. {
  123. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  124. return false;
  125. }
  126. if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST jackctl_driver_get_name(driver)) == -1)
  127. {
  128. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed.");
  129. return false;
  130. }
  131. if (!jack_controller_settings_save_driver_options(writer, driver, dbus_call_context_ptr))
  132. {
  133. return false;
  134. }
  135. if (xmlTextWriterEndElement(writer) == -1)
  136. {
  137. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  138. return false;
  139. }
  140. return true;
  141. }
  142. bool
  143. jack_controller_settings_write_drivers(
  144. struct jack_controller * controller_ptr,
  145. xmlTextWriterPtr writer,
  146. void *dbus_call_context_ptr)
  147. {
  148. const JSList * node_ptr;
  149. jackctl_driver driver;
  150. if (xmlTextWriterStartElement(writer, BAD_CAST "drivers") == -1)
  151. {
  152. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  153. return false;
  154. }
  155. node_ptr = jackctl_server_get_drivers_list(controller_ptr->server);
  156. while (node_ptr != NULL)
  157. {
  158. driver = (jackctl_driver)node_ptr->data;
  159. if (!jack_controller_settings_write_driver(
  160. controller_ptr,
  161. writer,
  162. driver,
  163. dbus_call_context_ptr))
  164. {
  165. return false;
  166. }
  167. node_ptr = jack_slist_next(node_ptr);
  168. }
  169. if (xmlTextWriterEndElement(writer) == -1)
  170. {
  171. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  172. return false;
  173. }
  174. return true;
  175. }
  176. bool
  177. jack_controller_settings_write_internal(
  178. struct jack_controller * controller_ptr,
  179. xmlTextWriterPtr writer,
  180. jackctl_internal internal,
  181. void *dbus_call_context_ptr)
  182. {
  183. /* if (xmlTextWriterWriteComment(writer, BAD_CAST "driver parameters") == -1) */
  184. /* { */
  185. /* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */
  186. /* return false; */
  187. /* } */
  188. if (xmlTextWriterStartElement(writer, BAD_CAST "internal") == -1)
  189. {
  190. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  191. return false;
  192. }
  193. if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST jackctl_internal_get_name(driver)) == -1)
  194. {
  195. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed.");
  196. return false;
  197. }
  198. if (!jack_controller_settings_save_internal_options(writer, internal, dbus_call_context_ptr))
  199. {
  200. return false;
  201. }
  202. if (xmlTextWriterEndElement(writer) == -1)
  203. {
  204. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  205. return false;
  206. }
  207. return true;
  208. }
  209. bool
  210. jack_controller_settings_write_internals(
  211. struct jack_controller * controller_ptr,
  212. xmlTextWriterPtr writer,
  213. void *dbus_call_context_ptr)
  214. {
  215. const JSList * node_ptr;
  216. jackctl_driver internal;
  217. if (xmlTextWriterStartElement(writer, BAD_CAST "internals") == -1)
  218. {
  219. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  220. return false;
  221. }
  222. node_ptr = jackctl_server_get_internals_list(controller_ptr->server);
  223. while (node_ptr != NULL)
  224. {
  225. internal = (jackctl_internal)node_ptr->data;
  226. if (!jack_controller_settings_write_internal(
  227. controller_ptr,
  228. writer,
  229. internal,
  230. dbus_call_context_ptr))
  231. {
  232. return false;
  233. }
  234. node_ptr = jack_slist_next(node_ptr);
  235. }
  236. if (xmlTextWriterEndElement(writer) == -1)
  237. {
  238. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed.");
  239. return false;
  240. }
  241. return true;
  242. }
  243. bool
  244. jack_controller_settings_save(
  245. struct jack_controller * controller_ptr,
  246. void *dbus_call_context_ptr)
  247. {
  248. xmlTextWriterPtr writer;
  249. char *filename;
  250. size_t conf_len;
  251. bool ret;
  252. time_t timestamp;
  253. char timestamp_str[28];
  254. time(&timestamp);
  255. timestamp_str[0] = ' ';
  256. ctime_r(&timestamp, timestamp_str + 1);
  257. timestamp_str[25] = ' ';
  258. ret = false;
  259. conf_len = strlen(JACKDBUS_CONF);
  260. filename = malloc(g_jackdbus_dir_len + conf_len + 1);
  261. if (filename == NULL)
  262. {
  263. jack_error("Out of memory.");
  264. goto fail;
  265. }
  266. memcpy(filename, g_jackdbus_dir, g_jackdbus_dir_len);
  267. memcpy(filename + g_jackdbus_dir_len, JACKDBUS_CONF, conf_len);
  268. filename[g_jackdbus_dir_len + conf_len] = 0;
  269. jack_info("saving settings to \"%s\"", filename);
  270. writer = xmlNewTextWriterFilename(filename, 0);
  271. if (writer == NULL)
  272. {
  273. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Error creating the xml writer.");
  274. goto fail_free_filename;
  275. }
  276. if (xmlTextWriterSetIndent(writer, 1) == -1)
  277. {
  278. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterSetIndent() failed.");
  279. goto fail_free_writter;
  280. }
  281. if (xmlTextWriterStartDocument(writer, NULL, NULL, NULL) == -1)
  282. {
  283. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartDocument() failed.");
  284. goto fail_free_writter;
  285. }
  286. if (xmlTextWriterWriteComment(writer, BAD_CAST "\n" JACK_CONF_HEADER_TEXT) == -1)
  287. {
  288. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed.");
  289. goto fail_free_writter;
  290. }
  291. if (xmlTextWriterWriteComment(writer, BAD_CAST timestamp_str) == -1)
  292. {
  293. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed.");
  294. goto fail_free_writter;
  295. }
  296. if (xmlTextWriterStartElement(writer, BAD_CAST "jack") == -1)
  297. {
  298. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  299. goto fail_free_writter;
  300. }
  301. if (!jack_controller_settings_write_engine(controller_ptr, writer, dbus_call_context_ptr))
  302. {
  303. goto fail_free_writter;
  304. }
  305. if (!jack_controller_settings_write_drivers(controller_ptr, writer, dbus_call_context_ptr))
  306. {
  307. goto fail_free_writter;
  308. }
  309. if (!jack_controller_settings_write_internals(controller_ptr, writer, dbus_call_context_ptr))
  310. {
  311. goto fail_free_writter;
  312. }
  313. if (xmlTextWriterEndElement(writer) == -1)
  314. {
  315. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed.");
  316. goto fail_free_writter;
  317. }
  318. if (xmlTextWriterEndDocument(writer) == -1)
  319. {
  320. jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndDocument() failed.");
  321. goto fail_free_writter;
  322. }
  323. ret = true;
  324. fail_free_writter:
  325. xmlFreeTextWriter(writer);
  326. fail_free_filename:
  327. free(filename);
  328. fail:
  329. return ret;
  330. }
  331. void
  332. jack_controller_settings_read_engine(
  333. struct jack_controller * controller_ptr,
  334. xmlXPathContextPtr xpath_ctx_ptr)
  335. {
  336. xmlXPathObjectPtr xpath_obj_ptr;
  337. xmlBufferPtr content_buffer_ptr;
  338. int i;
  339. const char *option_name;
  340. const char *option_value;
  341. /* Evaluate xpath expression */
  342. xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_ENGINE_OPTIONS_EXPRESSION, xpath_ctx_ptr);
  343. if (xpath_obj_ptr == NULL)
  344. {
  345. jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_ENGINE_OPTIONS_EXPRESSION);
  346. goto exit;
  347. }
  348. if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
  349. {
  350. jack_error("XPath \"%s\" evaluation returned no data", XPATH_ENGINE_OPTIONS_EXPRESSION);
  351. goto free_xpath_obj;
  352. }
  353. content_buffer_ptr = xmlBufferCreate();
  354. if (content_buffer_ptr == NULL)
  355. {
  356. jack_error("xmlBufferCreate() failed.");
  357. goto free_xpath_obj;
  358. }
  359. for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
  360. {
  361. //jack_info("engine option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i);
  362. if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1)
  363. {
  364. jack_error("xmlNodeBufGetContent() failed.");
  365. goto next_option;
  366. }
  367. option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
  368. option_value = (const char *)xmlBufferContent(content_buffer_ptr);
  369. jack_controller_settings_set_engine_option(controller_ptr, option_name, option_value);
  370. next_option:
  371. xmlBufferEmpty(content_buffer_ptr);
  372. }
  373. //free_buffer:
  374. xmlBufferFree(content_buffer_ptr);
  375. free_xpath_obj:
  376. xmlXPathFreeObject(xpath_obj_ptr);
  377. exit:
  378. return;
  379. }
  380. void
  381. jack_controller_settings_read_driver(
  382. struct jack_controller * controller_ptr,
  383. xmlXPathContextPtr xpath_ctx_ptr,
  384. jackctl_driver driver)
  385. {
  386. char *xpath;
  387. size_t xpath_len;
  388. xmlXPathObjectPtr xpath_obj_ptr;
  389. xmlBufferPtr content_buffer_ptr;
  390. int i;
  391. const char *option_name;
  392. const char *option_value;
  393. const char *driver_name;
  394. driver_name = jackctl_driver_get_name(driver);
  395. jack_info("reading options for driver \"%s\"", driver_name);
  396. xpath_len = snprintf(NULL, 0, XPATH_DRIVER_OPTIONS_EXPRESSION, driver_name);
  397. xpath = malloc(xpath_len);
  398. if (xpath == NULL)
  399. {
  400. jack_error("Out of memory.");
  401. goto exit;
  402. }
  403. snprintf(xpath, xpath_len, XPATH_DRIVER_OPTIONS_EXPRESSION, driver_name);
  404. //jack_info("xpath = \"%s\"", xpath);
  405. /* Evaluate xpath expression */
  406. xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)xpath, xpath_ctx_ptr);
  407. if (xpath_obj_ptr == NULL)
  408. {
  409. jack_error("Unable to evaluate XPath expression \"%s\"", xpath);
  410. goto free_xpath;
  411. }
  412. if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
  413. {
  414. //jack_info("XPath \"%s\" evaluation returned no data", xpath);
  415. goto free_xpath_obj;
  416. }
  417. content_buffer_ptr = xmlBufferCreate();
  418. if (content_buffer_ptr == NULL)
  419. {
  420. jack_error("xmlBufferCreate() failed.");
  421. goto free_xpath_obj;
  422. }
  423. for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
  424. {
  425. //jack_info("driver option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i);
  426. if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1)
  427. {
  428. jack_error("xmlNodeBufGetContent() failed.");
  429. goto next_option;
  430. }
  431. option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
  432. option_value = (const char *)xmlBufferContent(content_buffer_ptr);
  433. jack_controller_settings_set_driver_option(driver, option_name, option_value);
  434. next_option:
  435. xmlBufferEmpty(content_buffer_ptr);
  436. }
  437. //free_buffer:
  438. xmlBufferFree(content_buffer_ptr);
  439. free_xpath_obj:
  440. xmlXPathFreeObject(xpath_obj_ptr);
  441. free_xpath:
  442. free(xpath);
  443. exit:
  444. return;
  445. }
  446. void
  447. jack_controller_settings_read_internal(
  448. struct jack_controller * controller_ptr,
  449. xmlXPathContextPtr xpath_ctx_ptr,
  450. jackctl_internal internal)
  451. {
  452. char *xpath;
  453. size_t xpath_len;
  454. xmlXPathObjectPtr xpath_obj_ptr;
  455. xmlBufferPtr content_buffer_ptr;
  456. int i;
  457. const char *option_name;
  458. const char *option_value;
  459. const char *internal_name;
  460. internal_name = jackctl_internal_get_name(internal);
  461. jack_info("reading options for internal \"%s\"", internal_name);
  462. xpath_len = snprintf(NULL, 0, XPATH_DRIVER_OPTIONS_EXPRESSION, internal_name);
  463. xpath = malloc(xpath_len);
  464. if (xpath == NULL)
  465. {
  466. jack_error("Out of memory.");
  467. goto exit;
  468. }
  469. snprintf(xpath, xpath_len, XPATH_DRIVER_OPTIONS_EXPRESSION, internal_name);
  470. //jack_info("xpath = \"%s\"", xpath);
  471. /* Evaluate xpath expression */
  472. xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)xpath, xpath_ctx_ptr);
  473. if (xpath_obj_ptr == NULL)
  474. {
  475. jack_error("Unable to evaluate XPath expression \"%s\"", xpath);
  476. goto free_xpath;
  477. }
  478. if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
  479. {
  480. //jack_info("XPath \"%s\" evaluation returned no data", xpath);
  481. goto free_xpath_obj;
  482. }
  483. content_buffer_ptr = xmlBufferCreate();
  484. if (content_buffer_ptr == NULL)
  485. {
  486. jack_error("xmlBufferCreate() failed.");
  487. goto free_xpath_obj;
  488. }
  489. for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
  490. {
  491. //jack_info("driver option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i);
  492. if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1)
  493. {
  494. jack_error("xmlNodeBufGetContent() failed.");
  495. goto next_option;
  496. }
  497. option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
  498. option_value = (const char *)xmlBufferContent(content_buffer_ptr);
  499. jack_controller_settings_set_internal_option(internal, option_name, option_value);
  500. next_option:
  501. xmlBufferEmpty(content_buffer_ptr);
  502. }
  503. //free_buffer:
  504. xmlBufferFree(content_buffer_ptr);
  505. free_xpath_obj:
  506. xmlXPathFreeObject(xpath_obj_ptr);
  507. free_xpath:
  508. free(xpath);
  509. exit:
  510. return;
  511. }
  512. void
  513. jack_controller_settings_read_drivers(
  514. struct jack_controller * controller_ptr,
  515. xmlXPathContextPtr xpath_ctx_ptr)
  516. {
  517. xmlXPathObjectPtr xpath_obj_ptr;
  518. int i;
  519. const char *driver_name;
  520. jackctl_driver driver;
  521. /* Evaluate xpath expression */
  522. xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_DRIVERS_EXPRESSION, xpath_ctx_ptr);
  523. if (xpath_obj_ptr == NULL)
  524. {
  525. jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_DRIVERS_EXPRESSION);
  526. goto exit;
  527. }
  528. if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
  529. {
  530. jack_error("XPath \"%s\" evaluation returned no data", XPATH_DRIVERS_EXPRESSION);
  531. goto free_xpath_obj;
  532. }
  533. for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
  534. {
  535. driver_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
  536. driver = jack_controller_find_driver(controller_ptr->server, driver_name);
  537. if (driver == NULL)
  538. {
  539. jack_error("ignoring settings for unknown driver \"%s\"", driver_name);
  540. }
  541. else
  542. {
  543. jack_info("setting for driver \"%s\" found", driver_name);
  544. jack_controller_settings_read_driver(controller_ptr, xpath_ctx_ptr, driver);
  545. }
  546. }
  547. free_xpath_obj:
  548. xmlXPathFreeObject(xpath_obj_ptr);
  549. exit:
  550. return;
  551. }
  552. void
  553. jack_controller_settings_read_internals(
  554. struct jack_controller * controller_ptr,
  555. xmlXPathContextPtr xpath_ctx_ptr)
  556. {
  557. xmlXPathObjectPtr xpath_obj_ptr;
  558. int i;
  559. const char *internal_name;
  560. jackctl_internal internal;
  561. /* Evaluate xpath expression */
  562. xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_DRIVERS_EXPRESSION, xpath_ctx_ptr);
  563. if (xpath_obj_ptr == NULL)
  564. {
  565. jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_DRIVERS_EXPRESSION);
  566. goto exit;
  567. }
  568. if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0)
  569. {
  570. jack_error("XPath \"%s\" evaluation returned no data", XPATH_DRIVERS_EXPRESSION);
  571. goto free_xpath_obj;
  572. }
  573. for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++)
  574. {
  575. internal_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name");
  576. driver = jack_controller_find_internal(controller_ptr->server, driver_name);
  577. if (driver == NULL)
  578. {
  579. jack_error("ignoring settings for unknown internal \"%s\"", internal_name);
  580. }
  581. else
  582. {
  583. jack_info("setting for internal \"%s\" found", internal_name);
  584. jack_controller_settings_read_internal(controller_ptr, xpath_ctx_ptr, driver);
  585. }
  586. }
  587. free_xpath_obj:
  588. xmlXPathFreeObject(xpath_obj_ptr);
  589. exit:
  590. return;
  591. }
  592. void
  593. jack_controller_settings_load(
  594. struct jack_controller * controller_ptr)
  595. {
  596. char *filename;
  597. size_t conf_len;
  598. xmlDocPtr doc_ptr;
  599. xmlXPathContextPtr xpath_ctx_ptr;
  600. conf_len = strlen(JACKDBUS_CONF);
  601. filename = malloc(g_jackdbus_dir_len + conf_len + 1);
  602. if (filename == NULL)
  603. {
  604. jack_error("Out of memory.");
  605. goto exit;
  606. }
  607. memcpy(filename, g_jackdbus_dir, g_jackdbus_dir_len);
  608. memcpy(filename + g_jackdbus_dir_len, JACKDBUS_CONF, conf_len);
  609. filename[g_jackdbus_dir_len + conf_len] = 0;
  610. jack_info("loading settings from \"%s\"", filename);
  611. doc_ptr = xmlParseFile(filename);
  612. if (doc_ptr == NULL)
  613. {
  614. jack_error("Failed to parse \"%s\"", filename);
  615. goto free_filename;
  616. }
  617. /* Create xpath evaluation context */
  618. xpath_ctx_ptr = xmlXPathNewContext(doc_ptr);
  619. if (xpath_ctx_ptr == NULL)
  620. {
  621. jack_error("Unable to create new XPath context");
  622. goto free_doc;
  623. }
  624. jack_controller_settings_read_engine(controller_ptr, xpath_ctx_ptr);
  625. jack_controller_settings_read_drivers(controller_ptr, xpath_ctx_ptr);
  626. jack_controller_settings_read_internals(controller_ptr, xpath_ctx_ptr);
  627. xmlXPathFreeContext(xpath_ctx_ptr);
  628. free_doc:
  629. xmlFreeDoc(doc_ptr);
  630. free_filename:
  631. free(filename);
  632. exit:
  633. return;
  634. }
  635. void
  636. jack_controller_settings_save_auto(
  637. struct jack_controller * controller_ptr)
  638. {
  639. jack_controller_settings_save(controller_ptr, NULL);
  640. }