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.

718 lines
19KB

  1. /* -*- Mode: C ; c-basic-offset: 4 -*- */
  2. /*
  3. Copyright (C) 2011 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. /*
  16. * Parameter addresses:
  17. *
  18. * "engine"
  19. * "engine", "driver"
  20. * "engine", "realtime"
  21. * "engine", ...more engine parameters
  22. *
  23. * "driver", "device"
  24. * "driver", ...more driver parameters
  25. *
  26. * "drivers", "alsa", "device"
  27. * "drivers", "alsa", ...more alsa driver parameters
  28. *
  29. * "drivers", ...more drivers
  30. *
  31. * "internals", "netmanager", "multicast_ip"
  32. * "internals", "netmanager", ...more netmanager parameters
  33. *
  34. * "internals", ...more internals
  35. *
  36. */
  37. #include <stdbool.h>
  38. #include <string.h>
  39. #include <assert.h>
  40. #include <dbus/dbus.h>
  41. #include "params.h"
  42. #include "controller_internal.h"
  43. #define PTNODE_ENGINE "engine"
  44. #define PTNODE_DRIVER "driver"
  45. #define PTNODE_DRIVERS "drivers"
  46. #define PTNODE_INTERNALS "internals"
  47. struct jack_parameter_container
  48. {
  49. struct list_head siblings;
  50. char * name;
  51. struct jack_parameter_container * symlink;
  52. bool leaf;
  53. struct list_head children;
  54. void * obj;
  55. };
  56. struct jack_params
  57. {
  58. jackctl_server_t * server;
  59. struct jack_parameter_container root;
  60. struct list_head * drivers_ptr;
  61. uint32_t drivers_count;
  62. struct jack_parameter_container * driver_ptr;
  63. bool driver_set; /* whether driver is manually set, if false - DEFAULT_DRIVER is auto set */
  64. };
  65. static bool controlapi_parameter_is_set(void * obj)
  66. {
  67. return jackctl_parameter_is_set((jackctl_parameter_t *)obj);
  68. }
  69. static bool controlapi_parameter_reset(void * obj)
  70. {
  71. return jackctl_parameter_reset((jackctl_parameter_t *)obj);
  72. }
  73. union jackctl_parameter_value controlapi_parameter_get_value(void * obj)
  74. {
  75. return jackctl_parameter_get_value((jackctl_parameter_t *)obj);
  76. }
  77. bool controlapi_parameter_set_value(void * obj, const union jackctl_parameter_value * value_ptr)
  78. {
  79. return jackctl_parameter_set_value((jackctl_parameter_t *)obj, value_ptr);
  80. }
  81. union jackctl_parameter_value controlapi_parameter_get_default_value(void * obj)
  82. {
  83. return jackctl_parameter_get_default_value((jackctl_parameter_t *)obj);
  84. }
  85. static struct jack_parameter_container * create_container(struct list_head * parent_list_ptr, const char * name)
  86. {
  87. struct jack_parameter_container * container_ptr;
  88. container_ptr = malloc(sizeof(struct jack_parameter_container));
  89. if (container_ptr == NULL)
  90. {
  91. jack_error("Ran out of memory trying to allocate struct jack_parameter_container");
  92. goto fail;
  93. }
  94. container_ptr->name = strdup(name);
  95. if (container_ptr->name == NULL)
  96. {
  97. jack_error("Ran out of memory trying to strdup parameter container name");
  98. goto free;
  99. }
  100. container_ptr->leaf = false;
  101. container_ptr->symlink = NULL;
  102. container_ptr->obj = NULL;
  103. INIT_LIST_HEAD(&container_ptr->children);
  104. list_add_tail(&container_ptr->siblings, parent_list_ptr);
  105. return container_ptr;
  106. free:
  107. free(container_ptr);
  108. fail:
  109. return NULL;
  110. }
  111. static bool add_controlapi_param(struct list_head * parent_list_ptr, jackctl_parameter_t * param)
  112. {
  113. struct jack_parameter * param_ptr;
  114. uint32_t i;
  115. param_ptr = malloc(sizeof(struct jack_parameter));
  116. if (param_ptr == NULL)
  117. {
  118. jack_error("Ran out of memory trying to allocate struct jack_parameter");
  119. goto fail;
  120. }
  121. param_ptr->obj = param;
  122. param_ptr->vtable.is_set = controlapi_parameter_is_set;
  123. param_ptr->vtable.reset = controlapi_parameter_reset;
  124. param_ptr->vtable.get_value = controlapi_parameter_get_value;
  125. param_ptr->vtable.set_value = controlapi_parameter_set_value;
  126. param_ptr->vtable.get_default_value = controlapi_parameter_get_default_value;
  127. param_ptr->type = jackctl_parameter_get_type(param);
  128. param_ptr->name = jackctl_parameter_get_name(param);
  129. param_ptr->short_decr = jackctl_parameter_get_short_description(param);
  130. param_ptr->long_descr = jackctl_parameter_get_long_description(param);
  131. if (jackctl_parameter_has_range_constraint(param))
  132. {
  133. param_ptr->constraint_flags = JACK_CONSTRAINT_FLAG_VALID;
  134. param_ptr->constraint_range = true;
  135. jackctl_parameter_get_range_constraint(param, &param_ptr->constraint.range.min, &param_ptr->constraint.range.max);
  136. }
  137. else if (jackctl_parameter_has_enum_constraint(param))
  138. {
  139. param_ptr->constraint_flags = JACK_CONSTRAINT_FLAG_VALID;
  140. param_ptr->constraint_range = false;
  141. param_ptr->constraint.enumeration.count = jackctl_parameter_get_enum_constraints_count(param);
  142. param_ptr->constraint.enumeration.possible_values_array = malloc(sizeof(struct jack_parameter_enum) * param_ptr->constraint.enumeration.count);
  143. if (param_ptr->constraint.enumeration.possible_values_array == NULL)
  144. {
  145. goto free;
  146. }
  147. for (i = 0; i < param_ptr->constraint.enumeration.count; i++)
  148. {
  149. param_ptr->constraint.enumeration.possible_values_array[i].value = jackctl_parameter_get_enum_constraint_value(param, i);
  150. param_ptr->constraint.enumeration.possible_values_array[i].short_desc = jackctl_parameter_get_enum_constraint_description(param, i);
  151. }
  152. }
  153. else
  154. {
  155. param_ptr->constraint_flags = 0;
  156. goto add;
  157. }
  158. if (jackctl_parameter_constraint_is_strict(param))
  159. {
  160. param_ptr->constraint_flags |= JACK_CONSTRAINT_FLAG_STRICT;
  161. }
  162. if (jackctl_parameter_constraint_is_fake_value(param))
  163. {
  164. param_ptr->constraint_flags |= JACK_CONSTRAINT_FLAG_FAKE_VALUE;
  165. }
  166. add:
  167. list_add_tail(&param_ptr->siblings, parent_list_ptr);
  168. return true;
  169. free:
  170. free(param_ptr);
  171. fail:
  172. return false;
  173. }
  174. static void free_params(struct list_head * parent_list_ptr)
  175. {
  176. struct jack_parameter * param_ptr;
  177. while (!list_empty(parent_list_ptr))
  178. {
  179. param_ptr = list_entry(parent_list_ptr->next, struct jack_parameter, siblings);
  180. list_del(&param_ptr->siblings);
  181. if ((param_ptr->constraint_flags & JACK_CONSTRAINT_FLAG_VALID) != 0 &&
  182. !param_ptr->constraint_range &&
  183. param_ptr->constraint.enumeration.possible_values_array != NULL)
  184. {
  185. free(param_ptr->constraint.enumeration.possible_values_array);
  186. }
  187. free(param_ptr);
  188. }
  189. }
  190. static void free_containers(struct list_head * parent_list_ptr)
  191. {
  192. struct jack_parameter_container * container_ptr;
  193. while (!list_empty(parent_list_ptr))
  194. {
  195. container_ptr = list_entry(parent_list_ptr->next, struct jack_parameter_container, siblings);
  196. list_del(&container_ptr->siblings);
  197. if (container_ptr->leaf)
  198. {
  199. free_params(&container_ptr->children);
  200. }
  201. else
  202. {
  203. free_containers(&container_ptr->children);
  204. }
  205. free(container_ptr->name);
  206. free(container_ptr);
  207. }
  208. }
  209. static struct jack_parameter_container * find_container(struct jack_parameter_container * parent_ptr, const char * const * address, int max_depth)
  210. {
  211. struct list_head * node_ptr;
  212. struct jack_parameter_container * container_ptr;
  213. if (max_depth == 0 || *address == NULL)
  214. {
  215. return parent_ptr;
  216. }
  217. if (parent_ptr->leaf)
  218. {
  219. return NULL;
  220. }
  221. if (max_depth > 0)
  222. {
  223. max_depth--;
  224. }
  225. list_for_each(node_ptr, &parent_ptr->children)
  226. {
  227. container_ptr = list_entry(node_ptr, struct jack_parameter_container, siblings);
  228. if (strcmp(container_ptr->name, *address) == 0)
  229. {
  230. if (container_ptr->symlink != NULL)
  231. {
  232. container_ptr = container_ptr->symlink;
  233. }
  234. return find_container(container_ptr, address + 1, max_depth);
  235. }
  236. }
  237. return NULL;
  238. }
  239. static bool init_leaf(struct list_head * parent_list_ptr, const char * name, const JSList * params_list, void * obj)
  240. {
  241. struct jack_parameter_container * container_ptr;
  242. container_ptr = create_container(parent_list_ptr, name);
  243. if (container_ptr == NULL)
  244. {
  245. return false;
  246. }
  247. container_ptr->leaf = true;
  248. container_ptr->obj = obj;
  249. while (params_list)
  250. {
  251. if (!add_controlapi_param(&container_ptr->children, params_list->data))
  252. {
  253. return false;
  254. }
  255. params_list = jack_slist_next(params_list);
  256. }
  257. return true;
  258. }
  259. static bool init_engine(struct jack_params * params_ptr)
  260. {
  261. return init_leaf(&params_ptr->root.children, PTNODE_ENGINE, jackctl_server_get_parameters(params_ptr->server), NULL);
  262. }
  263. static bool init_drivers(struct jack_params * params_ptr)
  264. {
  265. const JSList * list;
  266. struct jack_parameter_container * container_ptr;
  267. container_ptr = create_container(&params_ptr->root.children, PTNODE_DRIVERS);
  268. if (container_ptr == NULL)
  269. {
  270. return false;
  271. }
  272. params_ptr->drivers_ptr = &container_ptr->children;
  273. params_ptr->drivers_count = 0;
  274. list = jackctl_server_get_drivers_list(params_ptr->server);
  275. while (list)
  276. {
  277. if (!init_leaf(&container_ptr->children, jackctl_driver_get_name(list->data), jackctl_driver_get_parameters(list->data), list->data))
  278. {
  279. return false;
  280. }
  281. params_ptr->drivers_count++;
  282. list = jack_slist_next(list);
  283. }
  284. return true;
  285. }
  286. static bool init_internals(struct jack_params * params_ptr)
  287. {
  288. const JSList * list;
  289. struct jack_parameter_container * container_ptr;
  290. container_ptr = create_container(&params_ptr->root.children, PTNODE_INTERNALS);
  291. if (container_ptr == NULL)
  292. {
  293. return false;
  294. }
  295. list = jackctl_server_get_internals_list(params_ptr->server);
  296. while (list)
  297. {
  298. if (!init_leaf(&container_ptr->children, jackctl_internal_get_name(list->data), jackctl_internal_get_parameters(list->data), NULL))
  299. {
  300. return false;
  301. }
  302. list = jack_slist_next(list);
  303. }
  304. return true;
  305. }
  306. static bool init_driver(struct jack_params * params_ptr)
  307. {
  308. struct jack_parameter_container * container_ptr;
  309. container_ptr = create_container(&params_ptr->root.children, PTNODE_DRIVER);
  310. if (container_ptr == NULL)
  311. {
  312. return false;
  313. }
  314. params_ptr->driver_ptr = container_ptr;
  315. return true;
  316. }
  317. #define params_ptr ((struct jack_params *)obj)
  318. static bool engine_driver_parameter_is_set(void * obj)
  319. {
  320. return params_ptr->driver_set;
  321. }
  322. static bool engine_driver_parameter_reset(void * obj)
  323. {
  324. if (!jack_params_set_driver(obj, DEFAULT_DRIVER))
  325. {
  326. return false;
  327. }
  328. params_ptr->driver_set = false;
  329. return true;
  330. }
  331. union jackctl_parameter_value engine_driver_parameter_get_value(void * obj)
  332. {
  333. union jackctl_parameter_value value;
  334. strcpy(value.str, params_ptr->driver_ptr->symlink->name);
  335. return value;
  336. }
  337. bool engine_driver_parameter_set_value(void * obj, const union jackctl_parameter_value * value_ptr)
  338. {
  339. return jack_params_set_driver(obj, value_ptr->str);
  340. }
  341. union jackctl_parameter_value engine_driver_parameter_get_default_value(void * obj)
  342. {
  343. union jackctl_parameter_value value;
  344. strcpy(value.str, DEFAULT_DRIVER);
  345. return value;
  346. }
  347. #undef params_ptr
  348. static bool add_engine_driver_enum_constraint(void * context, const char * name)
  349. {
  350. strcpy((*((struct jack_parameter_enum **)context))->value.str, name);
  351. (*((struct jack_parameter_enum **)context))->short_desc = name;
  352. (*((struct jack_parameter_enum **)context))++;
  353. return true;
  354. }
  355. static bool init_engine_driver_parameter(struct jack_params * params_ptr)
  356. {
  357. struct jack_parameter * param_ptr;
  358. const char * address[PARAM_ADDRESS_SIZE] = {PTNODE_ENGINE, NULL};
  359. struct jack_parameter_container * engine_ptr;
  360. struct jack_parameter_enum * possible_value;
  361. engine_ptr = find_container(&params_ptr->root, address, PARAM_ADDRESS_SIZE);
  362. if (engine_ptr == NULL)
  363. {
  364. return false;
  365. }
  366. param_ptr = malloc(sizeof(struct jack_parameter));
  367. if (param_ptr == NULL)
  368. {
  369. jack_error("Ran out of memory trying to allocate struct jack_parameter");
  370. goto fail;
  371. }
  372. param_ptr->obj = params_ptr;
  373. param_ptr->vtable.is_set = engine_driver_parameter_is_set;
  374. param_ptr->vtable.reset = engine_driver_parameter_reset;
  375. param_ptr->vtable.get_value = engine_driver_parameter_get_value;
  376. param_ptr->vtable.set_value = engine_driver_parameter_set_value;
  377. param_ptr->vtable.get_default_value = engine_driver_parameter_get_default_value;
  378. param_ptr->type = JackParamString;
  379. param_ptr->name = "driver";
  380. param_ptr->short_decr = "Driver to use";
  381. param_ptr->long_descr = "";
  382. param_ptr->constraint_flags = JACK_CONSTRAINT_FLAG_VALID | JACK_CONSTRAINT_FLAG_STRICT | JACK_CONSTRAINT_FLAG_FAKE_VALUE;
  383. param_ptr->constraint_range = false;
  384. param_ptr->constraint.enumeration.count = params_ptr->drivers_count;
  385. param_ptr->constraint.enumeration.possible_values_array = malloc(sizeof(struct jack_parameter_enum) * params_ptr->drivers_count);
  386. if (param_ptr->constraint.enumeration.possible_values_array == NULL)
  387. {
  388. goto free;
  389. }
  390. address[0] = PTNODE_DRIVERS;
  391. possible_value = param_ptr->constraint.enumeration.possible_values_array;
  392. jack_params_iterate_container((jack_params_handle)params_ptr, address, add_engine_driver_enum_constraint, &possible_value);
  393. list_add(&param_ptr->siblings, &engine_ptr->children);
  394. return true;
  395. free:
  396. free(param_ptr);
  397. fail:
  398. return false;
  399. }
  400. jack_params_handle jack_params_create(jackctl_server_t * server)
  401. {
  402. struct jack_params * params_ptr;
  403. params_ptr = malloc(sizeof(struct jack_params));
  404. if (params_ptr == NULL)
  405. {
  406. jack_error("Ran out of memory trying to allocate struct jack_params");
  407. return NULL;
  408. }
  409. params_ptr->server = server;
  410. INIT_LIST_HEAD(&params_ptr->root.children);
  411. params_ptr->root.leaf = false;
  412. params_ptr->root.name = NULL;
  413. if (!init_engine(params_ptr) ||
  414. !init_drivers(params_ptr) ||
  415. !init_driver(params_ptr) ||
  416. !init_engine_driver_parameter(params_ptr) ||
  417. !jack_params_set_driver((jack_params_handle)params_ptr, DEFAULT_DRIVER) ||
  418. !init_internals(params_ptr))
  419. {
  420. jack_params_destroy((jack_params_handle)params_ptr);
  421. return NULL;
  422. }
  423. params_ptr->driver_set = false;
  424. assert(strcmp(params_ptr->driver_ptr->symlink->name, DEFAULT_DRIVER) == 0);
  425. return (jack_params_handle)params_ptr;
  426. }
  427. #define params_ptr ((struct jack_params *)params)
  428. void jack_params_destroy(jack_params_handle params)
  429. {
  430. free_containers(&params_ptr->root.children);
  431. free(params);
  432. }
  433. bool jack_params_set_driver(jack_params_handle params, const char * name)
  434. {
  435. struct list_head * node_ptr;
  436. struct jack_parameter_container * container_ptr;
  437. list_for_each(node_ptr, params_ptr->drivers_ptr)
  438. {
  439. container_ptr = list_entry(node_ptr, struct jack_parameter_container, siblings);
  440. if (strcmp(container_ptr->name, name) == 0)
  441. {
  442. params_ptr->driver_ptr->symlink = container_ptr;
  443. params_ptr->driver_set = true;
  444. return true;
  445. }
  446. }
  447. return false;
  448. }
  449. jackctl_driver_t * jack_params_get_driver(jack_params_handle params)
  450. {
  451. return params_ptr->driver_ptr->symlink->obj;
  452. }
  453. bool jack_params_check_address(jack_params_handle params, const char * const * address, bool want_leaf)
  454. {
  455. struct jack_parameter_container * container_ptr;
  456. container_ptr = find_container(&params_ptr->root, address, PARAM_ADDRESS_SIZE);
  457. if (container_ptr == NULL)
  458. {
  459. return false;
  460. }
  461. if (want_leaf && !container_ptr->leaf)
  462. {
  463. return false;
  464. }
  465. return true;
  466. }
  467. bool jack_params_is_leaf_container(jack_params_handle params, const char * const * address)
  468. {
  469. struct jack_parameter_container * container_ptr;
  470. container_ptr = find_container(&params_ptr->root, address, PARAM_ADDRESS_SIZE);
  471. if (container_ptr == NULL)
  472. {
  473. assert(false);
  474. return false;
  475. }
  476. return container_ptr->leaf;
  477. }
  478. bool
  479. jack_params_iterate_container(
  480. jack_params_handle params,
  481. const char * const * address,
  482. bool (* callback)(void * context, const char * name),
  483. void * context)
  484. {
  485. struct jack_parameter_container * container_ptr;
  486. struct list_head * node_ptr;
  487. const char * name;
  488. container_ptr = find_container(&params_ptr->root, address, PARAM_ADDRESS_SIZE);
  489. if (container_ptr == NULL)
  490. {
  491. assert(false);
  492. return true;
  493. }
  494. list_for_each(node_ptr, &container_ptr->children)
  495. {
  496. if (container_ptr->leaf)
  497. {
  498. name = list_entry(node_ptr, struct jack_parameter, siblings)->name;
  499. }
  500. else
  501. {
  502. name = list_entry(node_ptr, struct jack_parameter_container, siblings)->name;
  503. }
  504. if (!callback(context, name))
  505. {
  506. return false;
  507. }
  508. }
  509. return true;
  510. }
  511. bool
  512. jack_params_iterate_params(
  513. jack_params_handle params,
  514. const char * const * address,
  515. bool (* callback)(void * context, const struct jack_parameter * param_ptr),
  516. void * context)
  517. {
  518. struct jack_parameter_container * container_ptr;
  519. struct list_head * node_ptr;
  520. struct jack_parameter * param_ptr;
  521. container_ptr = find_container(&params_ptr->root, address, PARAM_ADDRESS_SIZE);
  522. if (container_ptr == NULL || !container_ptr->leaf)
  523. {
  524. assert(false);
  525. return true;
  526. }
  527. list_for_each(node_ptr, &container_ptr->children)
  528. {
  529. param_ptr = list_entry(node_ptr, struct jack_parameter, siblings);
  530. if (!callback(context, param_ptr))
  531. {
  532. return false;
  533. }
  534. }
  535. return true;
  536. }
  537. const struct jack_parameter * jack_params_get_parameter(jack_params_handle params, const char * const * address)
  538. {
  539. int depth;
  540. struct jack_parameter_container * container_ptr;
  541. struct list_head * node_ptr;
  542. struct jack_parameter * param_ptr;
  543. for (depth = 0; depth < PARAM_ADDRESS_SIZE; depth++)
  544. {
  545. if (address[depth] == NULL)
  546. {
  547. break;
  548. }
  549. }
  550. depth--;
  551. container_ptr = find_container(&params_ptr->root, address, depth);
  552. if (container_ptr == NULL || !container_ptr->leaf)
  553. {
  554. return NULL;
  555. }
  556. list_for_each(node_ptr, &container_ptr->children)
  557. {
  558. param_ptr = list_entry(node_ptr, struct jack_parameter, siblings);
  559. if (strcmp(param_ptr->name, address[depth]) == 0)
  560. {
  561. return param_ptr;
  562. }
  563. }
  564. return NULL;
  565. }
  566. bool jack_params_add_parameter(jack_params_handle params, const char * const * address, bool end, struct jack_parameter * param_ptr)
  567. {
  568. struct jack_parameter_container * container_ptr;
  569. container_ptr = find_container(&params_ptr->root, address, PARAM_ADDRESS_SIZE);
  570. if (container_ptr == NULL || !container_ptr->leaf)
  571. {
  572. assert(false);
  573. return false;
  574. }
  575. if (end)
  576. {
  577. list_add_tail(&param_ptr->siblings, &container_ptr->children);
  578. }
  579. else
  580. {
  581. list_add(&param_ptr->siblings, &container_ptr->children);
  582. }
  583. return true;
  584. }
  585. #undef params_ptr