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.

727 lines
20KB

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