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.

1852 lines
55KB

  1. /* -*- Mode: C ; c-basic-offset: 4 -*- */
  2. /*
  3. Copyright (C) 2008 Nedko Arnaudov
  4. Copyright (C) 2008 Juuso Alasuutari
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. */
  16. #if defined(HAVE_CONFIG_H)
  17. #include "config.h"
  18. #endif
  19. #define _GNU_SOURCE /* PTHREAD_MUTEX_RECURSIVE */
  20. #include <stdint.h>
  21. #include <inttypes.h>
  22. #include <string.h>
  23. #include <stdio.h>
  24. #include <assert.h>
  25. #include <dbus/dbus.h>
  26. #include <pthread.h>
  27. #include "jackdbus.h"
  28. #include "controller_internal.h"
  29. #include "list.h"
  30. #define JACK_DBUS_IFACE_NAME "org.jackaudio.JackPatchbay"
  31. /* FIXME: these need to be retrieved from common headers */
  32. #define JACK_CLIENT_NAME_SIZE 64
  33. #define JACK_PORT_NAME_SIZE 256
  34. struct jack_graph
  35. {
  36. uint64_t version;
  37. struct list_head clients;
  38. struct list_head ports;
  39. struct list_head connections;
  40. };
  41. struct jack_graph_client
  42. {
  43. uint64_t id;
  44. char * name;
  45. int pid;
  46. struct list_head siblings;
  47. struct list_head ports;
  48. };
  49. struct jack_graph_port
  50. {
  51. uint64_t id;
  52. char * name;
  53. uint32_t flags;
  54. uint32_t type;
  55. struct list_head siblings_graph;
  56. struct list_head siblings_client;
  57. struct jack_graph_client * client;
  58. };
  59. struct jack_graph_connection
  60. {
  61. uint64_t id;
  62. struct jack_graph_port * port1;
  63. struct jack_graph_port * port2;
  64. struct list_head siblings;
  65. };
  66. struct jack_controller_patchbay
  67. {
  68. pthread_mutex_t lock;
  69. struct jack_graph graph;
  70. uint64_t next_client_id;
  71. uint64_t next_port_id;
  72. uint64_t next_connection_id;
  73. };
  74. void
  75. jack_controller_patchbay_send_signal_graph_changed(
  76. dbus_uint64_t new_graph_version)
  77. {
  78. jack_dbus_send_signal(
  79. JACK_CONTROLLER_OBJECT_PATH,
  80. JACK_DBUS_IFACE_NAME,
  81. "GraphChanged",
  82. DBUS_TYPE_UINT64,
  83. &new_graph_version,
  84. DBUS_TYPE_INVALID);
  85. }
  86. void
  87. jack_controller_patchbay_send_signal_client_appeared(
  88. dbus_uint64_t new_graph_version,
  89. dbus_uint64_t client_id,
  90. const char * client_name)
  91. {
  92. jack_dbus_send_signal(
  93. JACK_CONTROLLER_OBJECT_PATH,
  94. JACK_DBUS_IFACE_NAME,
  95. "ClientAppeared",
  96. DBUS_TYPE_UINT64,
  97. &new_graph_version,
  98. DBUS_TYPE_UINT64,
  99. &client_id,
  100. DBUS_TYPE_STRING,
  101. &client_name,
  102. DBUS_TYPE_INVALID);
  103. }
  104. void
  105. jack_controller_patchbay_send_signal_client_disappeared(
  106. dbus_uint64_t new_graph_version,
  107. dbus_uint64_t client_id,
  108. const char * client_name)
  109. {
  110. jack_dbus_send_signal(
  111. JACK_CONTROLLER_OBJECT_PATH,
  112. JACK_DBUS_IFACE_NAME,
  113. "ClientDisappeared",
  114. DBUS_TYPE_UINT64,
  115. &new_graph_version,
  116. DBUS_TYPE_UINT64,
  117. &client_id,
  118. DBUS_TYPE_STRING,
  119. &client_name,
  120. DBUS_TYPE_INVALID);
  121. }
  122. void
  123. jack_controller_patchbay_send_signal_port_appeared(
  124. dbus_uint64_t new_graph_version,
  125. dbus_uint64_t client_id,
  126. const char * client_name,
  127. dbus_uint64_t port_id,
  128. const char * port_name,
  129. dbus_uint32_t port_flags,
  130. dbus_uint32_t port_type)
  131. {
  132. jack_dbus_send_signal(
  133. JACK_CONTROLLER_OBJECT_PATH,
  134. JACK_DBUS_IFACE_NAME,
  135. "PortAppeared",
  136. DBUS_TYPE_UINT64,
  137. &new_graph_version,
  138. DBUS_TYPE_UINT64,
  139. &client_id,
  140. DBUS_TYPE_STRING,
  141. &client_name,
  142. DBUS_TYPE_UINT64,
  143. &port_id,
  144. DBUS_TYPE_STRING,
  145. &port_name,
  146. DBUS_TYPE_UINT32,
  147. &port_flags,
  148. DBUS_TYPE_UINT32,
  149. &port_type,
  150. DBUS_TYPE_INVALID);
  151. }
  152. void
  153. jack_controller_patchbay_send_signal_port_disappeared(
  154. dbus_uint64_t new_graph_version,
  155. dbus_uint64_t client_id,
  156. const char * client_name,
  157. dbus_uint64_t port_id,
  158. const char * port_name)
  159. {
  160. jack_dbus_send_signal(
  161. JACK_CONTROLLER_OBJECT_PATH,
  162. JACK_DBUS_IFACE_NAME,
  163. "PortDisappeared",
  164. DBUS_TYPE_UINT64,
  165. &new_graph_version,
  166. DBUS_TYPE_UINT64,
  167. &client_id,
  168. DBUS_TYPE_STRING,
  169. &client_name,
  170. DBUS_TYPE_UINT64,
  171. &port_id,
  172. DBUS_TYPE_STRING,
  173. &port_name,
  174. DBUS_TYPE_INVALID);
  175. }
  176. void
  177. jack_controller_patchbay_send_signal_ports_connected(
  178. dbus_uint64_t new_graph_version,
  179. dbus_uint64_t client1_id,
  180. const char * client1_name,
  181. dbus_uint64_t port1_id,
  182. const char * port1_name,
  183. dbus_uint64_t client2_id,
  184. const char * client2_name,
  185. dbus_uint64_t port2_id,
  186. const char * port2_name,
  187. dbus_uint64_t connection_id)
  188. {
  189. jack_dbus_send_signal(
  190. JACK_CONTROLLER_OBJECT_PATH,
  191. JACK_DBUS_IFACE_NAME,
  192. "PortsConnected",
  193. DBUS_TYPE_UINT64,
  194. &new_graph_version,
  195. DBUS_TYPE_UINT64,
  196. &client1_id,
  197. DBUS_TYPE_STRING,
  198. &client1_name,
  199. DBUS_TYPE_UINT64,
  200. &port1_id,
  201. DBUS_TYPE_STRING,
  202. &port1_name,
  203. DBUS_TYPE_UINT64,
  204. &client2_id,
  205. DBUS_TYPE_STRING,
  206. &client2_name,
  207. DBUS_TYPE_UINT64,
  208. &port2_id,
  209. DBUS_TYPE_STRING,
  210. &port2_name,
  211. DBUS_TYPE_UINT64,
  212. &connection_id,
  213. DBUS_TYPE_INVALID);
  214. }
  215. void
  216. jack_controller_patchbay_send_signal_ports_disconnected(
  217. dbus_uint64_t new_graph_version,
  218. dbus_uint64_t client1_id,
  219. const char * client1_name,
  220. dbus_uint64_t port1_id,
  221. const char * port1_name,
  222. dbus_uint64_t client2_id,
  223. const char * client2_name,
  224. dbus_uint64_t port2_id,
  225. const char * port2_name,
  226. dbus_uint64_t connection_id)
  227. {
  228. jack_dbus_send_signal(
  229. JACK_CONTROLLER_OBJECT_PATH,
  230. JACK_DBUS_IFACE_NAME,
  231. "PortsDisconnected",
  232. DBUS_TYPE_UINT64,
  233. &new_graph_version,
  234. DBUS_TYPE_UINT64,
  235. &client1_id,
  236. DBUS_TYPE_STRING,
  237. &client1_name,
  238. DBUS_TYPE_UINT64,
  239. &port1_id,
  240. DBUS_TYPE_STRING,
  241. &port1_name,
  242. DBUS_TYPE_UINT64,
  243. &client2_id,
  244. DBUS_TYPE_STRING,
  245. &client2_name,
  246. DBUS_TYPE_UINT64,
  247. &port2_id,
  248. DBUS_TYPE_STRING,
  249. &port2_name,
  250. DBUS_TYPE_UINT64,
  251. &connection_id,
  252. DBUS_TYPE_INVALID);
  253. }
  254. static
  255. struct jack_graph_client *
  256. jack_controller_patchbay_find_client(
  257. struct jack_controller_patchbay *patchbay_ptr,
  258. const char *client_name, /* not '\0' terminated */
  259. size_t client_name_len) /* without terminating '\0' */
  260. {
  261. struct list_head *node_ptr;
  262. struct jack_graph_client *client_ptr;
  263. list_for_each(node_ptr, &patchbay_ptr->graph.clients)
  264. {
  265. client_ptr = list_entry(node_ptr, struct jack_graph_client, siblings);
  266. if (strncmp(client_ptr->name, client_name, client_name_len) == 0)
  267. {
  268. return client_ptr;
  269. }
  270. }
  271. return NULL;
  272. }
  273. static
  274. struct jack_graph_client *
  275. jack_controller_patchbay_find_client_by_id(
  276. struct jack_controller_patchbay *patchbay_ptr,
  277. uint64_t id)
  278. {
  279. struct list_head *node_ptr;
  280. struct jack_graph_client *client_ptr;
  281. list_for_each(node_ptr, &patchbay_ptr->graph.clients)
  282. {
  283. client_ptr = list_entry(node_ptr, struct jack_graph_client, siblings);
  284. if (client_ptr->id == id)
  285. {
  286. return client_ptr;
  287. }
  288. }
  289. return NULL;
  290. }
  291. static
  292. struct jack_graph_client *
  293. jack_controller_patchbay_create_client(
  294. struct jack_controller_patchbay *patchbay_ptr,
  295. const char *client_name, /* not '\0' terminated */
  296. size_t client_name_len) /* without terminating '\0' */
  297. {
  298. struct jack_graph_client * client_ptr;
  299. client_ptr = malloc(sizeof(struct jack_graph_client));
  300. if (client_ptr == NULL)
  301. {
  302. jack_error("Memory allocation of jack_graph_client structure failed.");
  303. goto fail;
  304. }
  305. client_ptr->name = malloc(client_name_len + 1);
  306. if (client_ptr->name == NULL)
  307. {
  308. jack_error("malloc() failed to allocate memory for client name.");
  309. goto fail_free_client;
  310. }
  311. memcpy(client_ptr->name, client_name, client_name_len);
  312. client_ptr->name[client_name_len] = 0;
  313. client_ptr->pid = jack_get_client_pid(client_ptr->name);
  314. jack_info("New client '%s' with PID %d", client_ptr->name, client_ptr->pid);
  315. client_ptr->id = patchbay_ptr->next_client_id++;
  316. INIT_LIST_HEAD(&client_ptr->ports);
  317. pthread_mutex_lock(&patchbay_ptr->lock);
  318. list_add_tail(&client_ptr->siblings, &patchbay_ptr->graph.clients);
  319. patchbay_ptr->graph.version++;
  320. jack_controller_patchbay_send_signal_client_appeared(patchbay_ptr->graph.version, client_ptr->id, client_ptr->name);
  321. jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version);
  322. pthread_mutex_unlock(&patchbay_ptr->lock);
  323. return client_ptr;
  324. fail_free_client:
  325. free(client_ptr);
  326. fail:
  327. return NULL;
  328. }
  329. static
  330. void
  331. jack_controller_patchbay_destroy_client(
  332. struct jack_controller_patchbay *patchbay_ptr,
  333. struct jack_graph_client *client_ptr)
  334. {
  335. jack_info("Client '%s' with PID %d is out", client_ptr->name, client_ptr->pid);
  336. pthread_mutex_lock(&patchbay_ptr->lock);
  337. list_del(&client_ptr->siblings);
  338. patchbay_ptr->graph.version++;
  339. jack_controller_patchbay_send_signal_client_disappeared(patchbay_ptr->graph.version, client_ptr->id, client_ptr->name);
  340. jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version);
  341. pthread_mutex_unlock(&patchbay_ptr->lock);
  342. free(client_ptr->name);
  343. free(client_ptr);
  344. }
  345. static
  346. void
  347. jack_controller_patchbay_destroy_client_by_name(
  348. struct jack_controller_patchbay *patchbay_ptr,
  349. const char *client_name) /* '\0' terminated */
  350. {
  351. struct jack_graph_client *client_ptr;
  352. client_ptr = jack_controller_patchbay_find_client(patchbay_ptr, client_name, strlen(client_name));
  353. if (client_ptr == NULL)
  354. {
  355. jack_error("Cannot destroy unknown client '%s'", client_name);
  356. return;
  357. }
  358. jack_controller_patchbay_destroy_client(patchbay_ptr, client_ptr);
  359. }
  360. static
  361. void
  362. jack_controller_patchbay_new_port(
  363. struct jack_controller_patchbay *patchbay_ptr,
  364. const char *port_full_name,
  365. uint32_t port_flags,
  366. uint32_t port_type)
  367. {
  368. struct jack_graph_client *client_ptr;
  369. struct jack_graph_port *port_ptr;
  370. const char *port_short_name;
  371. size_t client_name_len;
  372. //jack_info("name: %s", port_full_name);
  373. port_short_name = strchr(port_full_name, ':');
  374. if (port_short_name == NULL)
  375. {
  376. jack_error("port name '%s' does not contain ':' separator char", port_full_name);
  377. return;
  378. }
  379. port_short_name++; /* skip ':' separator char */
  380. client_name_len = port_short_name - port_full_name - 1; /* without terminating '\0' */
  381. client_ptr = jack_controller_patchbay_find_client(patchbay_ptr, port_full_name, client_name_len);
  382. if (client_ptr == NULL)
  383. {
  384. client_ptr = jack_controller_patchbay_create_client(patchbay_ptr, port_full_name, client_name_len);
  385. if (client_ptr == NULL)
  386. {
  387. jack_error("Creation of new jack_graph client failed.");
  388. return;
  389. }
  390. }
  391. port_ptr = malloc(sizeof(struct jack_graph_port));
  392. if (port_ptr == NULL)
  393. {
  394. jack_error("Memory allocation of jack_graph_port structure failed.");
  395. return;
  396. }
  397. port_ptr->name = strdup(port_short_name);
  398. if (port_ptr->name == NULL)
  399. {
  400. jack_error("strdup() call for port name '%s' failed.", port_short_name);
  401. free(port_ptr);
  402. return;
  403. }
  404. port_ptr->id = patchbay_ptr->next_port_id++;
  405. port_ptr->flags = port_flags;
  406. port_ptr->type = port_type;
  407. port_ptr->client = client_ptr;
  408. pthread_mutex_lock(&patchbay_ptr->lock);
  409. list_add_tail(&port_ptr->siblings_client, &client_ptr->ports);
  410. list_add_tail(&port_ptr->siblings_graph, &patchbay_ptr->graph.ports);
  411. patchbay_ptr->graph.version++;
  412. jack_controller_patchbay_send_signal_port_appeared(
  413. patchbay_ptr->graph.version,
  414. client_ptr->id,
  415. client_ptr->name,
  416. port_ptr->id,
  417. port_ptr->name,
  418. port_ptr->flags,
  419. port_ptr->type);
  420. jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version);
  421. pthread_mutex_unlock(&patchbay_ptr->lock);
  422. }
  423. static
  424. void
  425. jack_controller_patchbay_remove_port(
  426. struct jack_controller_patchbay *patchbay_ptr,
  427. struct jack_graph_port *port_ptr)
  428. {
  429. pthread_mutex_lock(&patchbay_ptr->lock);
  430. list_del(&port_ptr->siblings_client);
  431. list_del(&port_ptr->siblings_graph);
  432. patchbay_ptr->graph.version++;
  433. jack_controller_patchbay_send_signal_port_disappeared(patchbay_ptr->graph.version, port_ptr->client->id, port_ptr->client->name, port_ptr->id, port_ptr->name);
  434. jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version);
  435. pthread_mutex_unlock(&patchbay_ptr->lock);
  436. free(port_ptr->name);
  437. free(port_ptr);
  438. }
  439. static
  440. struct jack_graph_port *
  441. jack_controller_patchbay_find_port_by_id(
  442. struct jack_controller_patchbay *patchbay_ptr,
  443. uint64_t port_id)
  444. {
  445. struct list_head *node_ptr;
  446. struct jack_graph_port *port_ptr;
  447. list_for_each(node_ptr, &patchbay_ptr->graph.ports)
  448. {
  449. port_ptr = list_entry(node_ptr, struct jack_graph_port, siblings_graph);
  450. if (port_ptr->id == port_id)
  451. {
  452. return port_ptr;
  453. }
  454. }
  455. return NULL;
  456. }
  457. static
  458. struct jack_graph_port *
  459. jack_controller_patchbay_find_client_port_by_name(
  460. struct jack_controller_patchbay *patchbay_ptr,
  461. struct jack_graph_client *client_ptr,
  462. const char *port_name)
  463. {
  464. struct list_head *node_ptr;
  465. struct jack_graph_port *port_ptr;
  466. list_for_each(node_ptr, &client_ptr->ports)
  467. {
  468. port_ptr = list_entry(node_ptr, struct jack_graph_port, siblings_client);
  469. if (strcmp(port_ptr->name, port_name) == 0)
  470. {
  471. return port_ptr;
  472. }
  473. }
  474. return NULL;
  475. }
  476. static
  477. struct jack_graph_port *
  478. jack_controller_patchbay_find_port_by_full_name(
  479. struct jack_controller_patchbay *patchbay_ptr,
  480. const char *port_full_name)
  481. {
  482. const char *port_short_name;
  483. size_t client_name_len;
  484. struct jack_graph_client *client_ptr;
  485. //jack_info("name: %s", port_full_name);
  486. port_short_name = strchr(port_full_name, ':');
  487. if (port_short_name == NULL)
  488. {
  489. jack_error("port name '%s' does not contain ':' separator char", port_full_name);
  490. return NULL;
  491. }
  492. port_short_name++; /* skip ':' separator char */
  493. client_name_len = port_short_name - port_full_name - 1; /* without terminating '\0' */
  494. client_ptr = jack_controller_patchbay_find_client(patchbay_ptr, port_full_name, client_name_len);
  495. if (client_ptr == NULL)
  496. {
  497. jack_error("cannot find client of port '%s'", port_full_name);
  498. return NULL;
  499. }
  500. return jack_controller_patchbay_find_client_port_by_name(patchbay_ptr, client_ptr, port_short_name);
  501. }
  502. static
  503. struct jack_graph_port *
  504. jack_controller_patchbay_find_port_by_names(
  505. struct jack_controller_patchbay *patchbay_ptr,
  506. const char *client_name,
  507. const char *port_name)
  508. {
  509. struct jack_graph_client *client_ptr;
  510. client_ptr = jack_controller_patchbay_find_client(patchbay_ptr, client_name, strlen(client_name));
  511. if (client_ptr == NULL)
  512. {
  513. jack_error("cannot find client '%s'", client_name);
  514. return NULL;
  515. }
  516. return jack_controller_patchbay_find_client_port_by_name(patchbay_ptr, client_ptr, port_name);
  517. }
  518. static
  519. struct jack_graph_connection *
  520. jack_controller_patchbay_create_connection(
  521. struct jack_controller_patchbay *patchbay_ptr,
  522. struct jack_graph_port *port1_ptr,
  523. struct jack_graph_port *port2_ptr)
  524. {
  525. struct jack_graph_connection * connection_ptr;
  526. connection_ptr = malloc(sizeof(struct jack_graph_connection));
  527. if (connection_ptr == NULL)
  528. {
  529. jack_error("Memory allocation of jack_graph_connection structure failed.");
  530. return NULL;
  531. }
  532. connection_ptr->id = patchbay_ptr->next_connection_id++;
  533. connection_ptr->port1 = port1_ptr;
  534. connection_ptr->port2 = port2_ptr;
  535. pthread_mutex_lock(&patchbay_ptr->lock);
  536. list_add_tail(&connection_ptr->siblings, &patchbay_ptr->graph.connections);
  537. patchbay_ptr->graph.version++;
  538. jack_controller_patchbay_send_signal_ports_connected(
  539. patchbay_ptr->graph.version,
  540. port1_ptr->client->id,
  541. port1_ptr->client->name,
  542. port1_ptr->id,
  543. port1_ptr->name,
  544. port2_ptr->client->id,
  545. port2_ptr->client->name,
  546. port2_ptr->id,
  547. port2_ptr->name,
  548. connection_ptr->id);
  549. jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version);
  550. pthread_mutex_unlock(&patchbay_ptr->lock);
  551. return connection_ptr;
  552. }
  553. static
  554. void
  555. jack_controller_patchbay_destroy_connection(
  556. struct jack_controller_patchbay *patchbay_ptr,
  557. struct jack_graph_connection *connection_ptr)
  558. {
  559. pthread_mutex_lock(&patchbay_ptr->lock);
  560. list_del(&connection_ptr->siblings);
  561. patchbay_ptr->graph.version++;
  562. jack_controller_patchbay_send_signal_ports_disconnected(
  563. patchbay_ptr->graph.version,
  564. connection_ptr->port1->client->id,
  565. connection_ptr->port1->client->name,
  566. connection_ptr->port1->id,
  567. connection_ptr->port1->name,
  568. connection_ptr->port2->client->id,
  569. connection_ptr->port2->client->name,
  570. connection_ptr->port2->id,
  571. connection_ptr->port2->name,
  572. connection_ptr->id);
  573. jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version);
  574. pthread_mutex_unlock(&patchbay_ptr->lock);
  575. free(connection_ptr);
  576. }
  577. static
  578. struct jack_graph_connection *
  579. jack_controller_patchbay_find_connection(
  580. struct jack_controller_patchbay *patchbay_ptr,
  581. struct jack_graph_port *port1_ptr,
  582. struct jack_graph_port *port2_ptr)
  583. {
  584. struct list_head *node_ptr;
  585. struct jack_graph_connection *connection_ptr;
  586. list_for_each(node_ptr, &patchbay_ptr->graph.connections)
  587. {
  588. connection_ptr = list_entry(node_ptr, struct jack_graph_connection, siblings);
  589. if ((connection_ptr->port1 == port1_ptr &&
  590. connection_ptr->port2 == port2_ptr) ||
  591. (connection_ptr->port1 == port2_ptr &&
  592. connection_ptr->port2 == port1_ptr))
  593. {
  594. return connection_ptr;
  595. }
  596. }
  597. return NULL;
  598. }
  599. static
  600. struct jack_graph_connection *
  601. jack_controller_patchbay_find_connection_by_id(
  602. struct jack_controller_patchbay *patchbay_ptr,
  603. uint64_t connection_id)
  604. {
  605. struct list_head *node_ptr;
  606. struct jack_graph_connection *connection_ptr;
  607. list_for_each(node_ptr, &patchbay_ptr->graph.connections)
  608. {
  609. connection_ptr = list_entry(node_ptr, struct jack_graph_connection, siblings);
  610. if (connection_ptr->id == connection_id)
  611. {
  612. return connection_ptr;
  613. }
  614. }
  615. return NULL;
  616. }
  617. static
  618. bool
  619. jack_controller_patchbay_connect(
  620. struct jack_dbus_method_call *dbus_call_ptr,
  621. struct jack_controller *controller_ptr,
  622. struct jack_graph_port *port1_ptr,
  623. struct jack_graph_port *port2_ptr)
  624. {
  625. int ret;
  626. char port1_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
  627. char port2_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
  628. sprintf(port1_name, "%s:%s", port1_ptr->client->name, port1_ptr->name);
  629. sprintf(port2_name, "%s:%s", port2_ptr->client->name, port2_ptr->name);
  630. ret = jack_connect(controller_ptr->client, port1_name, port2_name);
  631. if (ret != 0)
  632. {
  633. jack_dbus_error(dbus_call_ptr, JACK_DBUS_ERROR_GENERIC, "jack_connect() failed with %d", ret);
  634. return false;
  635. }
  636. return true;
  637. }
  638. static
  639. bool
  640. jack_controller_patchbay_disconnect(
  641. struct jack_dbus_method_call *dbus_call_ptr,
  642. struct jack_controller *controller_ptr,
  643. struct jack_graph_port *port1_ptr,
  644. struct jack_graph_port *port2_ptr)
  645. {
  646. int ret;
  647. char port1_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
  648. char port2_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
  649. sprintf(port1_name, "%s:%s", port1_ptr->client->name, port1_ptr->name);
  650. sprintf(port2_name, "%s:%s", port2_ptr->client->name, port2_ptr->name);
  651. ret = jack_disconnect(controller_ptr->client, port1_name, port2_name);
  652. if (ret != 0)
  653. {
  654. jack_dbus_error(dbus_call_ptr, JACK_DBUS_ERROR_GENERIC, "jack_connect() failed with %d", ret);
  655. return false;
  656. }
  657. return true;
  658. }
  659. #define controller_ptr ((struct jack_controller *)call->context)
  660. #define patchbay_ptr ((struct jack_controller_patchbay *)controller_ptr->patchbay_context)
  661. static
  662. void
  663. jack_controller_dbus_get_all_ports(
  664. struct jack_dbus_method_call * call)
  665. {
  666. struct list_head * client_node_ptr;
  667. struct list_head * port_node_ptr;
  668. struct jack_graph_client * client_ptr;
  669. struct jack_graph_port * port_ptr;
  670. DBusMessageIter iter, sub_iter;
  671. char fullname[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
  672. char *fullname_var = fullname;
  673. if (!controller_ptr->started)
  674. {
  675. jack_dbus_error(
  676. call,
  677. JACK_DBUS_ERROR_SERVER_NOT_RUNNING,
  678. "Can't execute this method with stopped JACK server");
  679. return;
  680. }
  681. call->reply = dbus_message_new_method_return (call->message);
  682. if (!call->reply)
  683. {
  684. goto fail;
  685. }
  686. dbus_message_iter_init_append (call->reply, &iter);
  687. if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s", &sub_iter))
  688. {
  689. goto fail_unref;
  690. }
  691. pthread_mutex_lock(&patchbay_ptr->lock);
  692. list_for_each(client_node_ptr, &patchbay_ptr->graph.clients)
  693. {
  694. client_ptr = list_entry(client_node_ptr, struct jack_graph_client, siblings);
  695. list_for_each(port_node_ptr, &client_ptr->ports)
  696. {
  697. port_ptr = list_entry(port_node_ptr, struct jack_graph_port, siblings_client);
  698. jack_info("%s:%s", client_ptr->name, port_ptr->name);
  699. sprintf(fullname, "%s:%s", client_ptr->name, port_ptr->name);
  700. if (!dbus_message_iter_append_basic (&sub_iter, DBUS_TYPE_STRING, &fullname_var))
  701. {
  702. pthread_mutex_unlock(&patchbay_ptr->lock);
  703. dbus_message_iter_close_container (&iter, &sub_iter);
  704. goto fail_unref;
  705. }
  706. }
  707. }
  708. pthread_mutex_unlock(&patchbay_ptr->lock);
  709. if (!dbus_message_iter_close_container (&iter, &sub_iter))
  710. {
  711. goto fail_unref;
  712. }
  713. return;
  714. fail_unref:
  715. dbus_message_unref (call->reply);
  716. call->reply = NULL;
  717. fail:
  718. jack_error ("Ran out of memory trying to construct method return");
  719. }
  720. static
  721. void
  722. jack_controller_dbus_get_graph(
  723. struct jack_dbus_method_call * call)
  724. {
  725. struct list_head * client_node_ptr;
  726. struct list_head * port_node_ptr;
  727. struct list_head * connection_node_ptr;
  728. struct jack_graph_client * client_ptr;
  729. struct jack_graph_port * port_ptr;
  730. struct jack_graph_connection * connection_ptr;
  731. DBusMessageIter iter;
  732. DBusMessageIter clients_array_iter;
  733. DBusMessageIter client_struct_iter;
  734. DBusMessageIter ports_array_iter;
  735. DBusMessageIter port_struct_iter;
  736. dbus_uint64_t version;
  737. DBusMessageIter connections_array_iter;
  738. DBusMessageIter connection_struct_iter;
  739. if (!controller_ptr->started)
  740. {
  741. jack_dbus_error(
  742. call,
  743. JACK_DBUS_ERROR_SERVER_NOT_RUNNING,
  744. "Can't execute this method with stopped JACK server");
  745. return;
  746. }
  747. if (!jack_dbus_get_method_args(call, DBUS_TYPE_UINT64, &version, DBUS_TYPE_INVALID))
  748. {
  749. /* The method call had invalid arguments meaning that
  750. * jack_dbus_get_method_args() has constructed an error for us.
  751. */
  752. goto exit;
  753. }
  754. //jack_info("Getting graph, know version is %" PRIu32, version);
  755. call->reply = dbus_message_new_method_return(call->message);
  756. if (!call->reply)
  757. {
  758. jack_error("Ran out of memory trying to construct method return");
  759. goto exit;
  760. }
  761. dbus_message_iter_init_append (call->reply, &iter);
  762. pthread_mutex_lock(&patchbay_ptr->lock);
  763. if (version > patchbay_ptr->graph.version)
  764. {
  765. jack_dbus_error(
  766. call,
  767. JACK_DBUS_ERROR_INVALID_ARGS,
  768. "known graph version %" PRIu64 " is newer than actual version %" PRIu64,
  769. version,
  770. patchbay_ptr->graph.version);
  771. pthread_mutex_unlock(&patchbay_ptr->lock);
  772. goto exit;
  773. }
  774. if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT64, &patchbay_ptr->graph.version))
  775. {
  776. goto nomem_unlock;
  777. }
  778. if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(tsa(tsuu))", &clients_array_iter))
  779. {
  780. goto nomem_unlock;
  781. }
  782. if (version < patchbay_ptr->graph.version)
  783. {
  784. list_for_each(client_node_ptr, &patchbay_ptr->graph.clients)
  785. {
  786. client_ptr = list_entry(client_node_ptr, struct jack_graph_client, siblings);
  787. if (!dbus_message_iter_open_container (&clients_array_iter, DBUS_TYPE_STRUCT, NULL, &client_struct_iter))
  788. {
  789. goto nomem_close_clients_array;
  790. }
  791. if (!dbus_message_iter_append_basic(&client_struct_iter, DBUS_TYPE_UINT64, &client_ptr->id))
  792. {
  793. goto nomem_close_client_struct;
  794. }
  795. if (!dbus_message_iter_append_basic(&client_struct_iter, DBUS_TYPE_STRING, &client_ptr->name))
  796. {
  797. goto nomem_close_client_struct;
  798. }
  799. if (!dbus_message_iter_open_container(&client_struct_iter, DBUS_TYPE_ARRAY, "(tsuu)", &ports_array_iter))
  800. {
  801. goto nomem_close_client_struct;
  802. }
  803. list_for_each(port_node_ptr, &client_ptr->ports)
  804. {
  805. port_ptr = list_entry(port_node_ptr, struct jack_graph_port, siblings_client);
  806. if (!dbus_message_iter_open_container(&ports_array_iter, DBUS_TYPE_STRUCT, NULL, &port_struct_iter))
  807. {
  808. goto nomem_close_ports_array;
  809. }
  810. if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT64, &port_ptr->id))
  811. {
  812. goto nomem_close_port_struct;
  813. }
  814. if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_STRING, &port_ptr->name))
  815. {
  816. goto nomem_close_port_struct;
  817. }
  818. if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT32, &port_ptr->flags))
  819. {
  820. goto nomem_close_port_struct;
  821. }
  822. if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT32, &port_ptr->type))
  823. {
  824. goto nomem_close_port_struct;
  825. }
  826. if (!dbus_message_iter_close_container(&ports_array_iter, &port_struct_iter))
  827. {
  828. goto nomem_close_ports_array;
  829. }
  830. }
  831. if (!dbus_message_iter_close_container(&client_struct_iter, &ports_array_iter))
  832. {
  833. goto nomem_close_client_struct;
  834. }
  835. if (!dbus_message_iter_close_container(&clients_array_iter, &client_struct_iter))
  836. {
  837. goto nomem_close_clients_array;
  838. }
  839. }
  840. }
  841. if (!dbus_message_iter_close_container(&iter, &clients_array_iter))
  842. {
  843. goto nomem_unlock;
  844. }
  845. if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(tstststst)", &connections_array_iter))
  846. {
  847. goto nomem_unlock;
  848. }
  849. if (version < patchbay_ptr->graph.version)
  850. {
  851. list_for_each(connection_node_ptr, &patchbay_ptr->graph.connections)
  852. {
  853. connection_ptr = list_entry(connection_node_ptr, struct jack_graph_connection, siblings);
  854. if (!dbus_message_iter_open_container(&connections_array_iter, DBUS_TYPE_STRUCT, NULL, &connection_struct_iter))
  855. {
  856. goto nomem_close_connections_array;
  857. }
  858. if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port1->client->id))
  859. {
  860. goto nomem_close_connection_struct;
  861. }
  862. if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port1->client->name))
  863. {
  864. goto nomem_close_connection_struct;
  865. }
  866. if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port1->id))
  867. {
  868. goto nomem_close_connection_struct;
  869. }
  870. if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port1->name))
  871. {
  872. goto nomem_close_connection_struct;
  873. }
  874. if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port2->client->id))
  875. {
  876. goto nomem_close_connection_struct;
  877. }
  878. if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port2->client->name))
  879. {
  880. goto nomem_close_connection_struct;
  881. }
  882. if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port2->id))
  883. {
  884. goto nomem_close_connection_struct;
  885. }
  886. if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port2->name))
  887. {
  888. goto nomem_close_connection_struct;
  889. }
  890. if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->id))
  891. {
  892. goto nomem_close_connection_struct;
  893. }
  894. if (!dbus_message_iter_close_container(&connections_array_iter, &connection_struct_iter))
  895. {
  896. goto nomem_close_connections_array;
  897. }
  898. }
  899. }
  900. if (!dbus_message_iter_close_container(&iter, &connections_array_iter))
  901. {
  902. goto nomem_unlock;
  903. }
  904. pthread_mutex_unlock(&patchbay_ptr->lock);
  905. return;
  906. nomem_close_connection_struct:
  907. dbus_message_iter_close_container(&connections_array_iter, &connection_struct_iter);
  908. nomem_close_connections_array:
  909. dbus_message_iter_close_container(&iter, &connections_array_iter);
  910. goto nomem_unlock;
  911. nomem_close_port_struct:
  912. dbus_message_iter_close_container(&ports_array_iter, &port_struct_iter);
  913. nomem_close_ports_array:
  914. dbus_message_iter_close_container(&client_struct_iter, &ports_array_iter);
  915. nomem_close_client_struct:
  916. dbus_message_iter_close_container(&clients_array_iter, &client_struct_iter);
  917. nomem_close_clients_array:
  918. dbus_message_iter_close_container(&iter, &clients_array_iter);
  919. nomem_unlock:
  920. pthread_mutex_unlock(&patchbay_ptr->lock);
  921. //nomem:
  922. dbus_message_unref(call->reply);
  923. call->reply = NULL;
  924. jack_error("Ran out of memory trying to construct method return");
  925. exit:
  926. return;
  927. }
  928. static
  929. void
  930. jack_controller_dbus_connect_ports_by_name(
  931. struct jack_dbus_method_call * call)
  932. {
  933. const char * client1_name;
  934. const char * port1_name;
  935. const char * client2_name;
  936. const char * port2_name;
  937. struct jack_graph_port *port1_ptr;
  938. struct jack_graph_port *port2_ptr;
  939. /* jack_info("jack_controller_dbus_connect_ports_by_name() called."); */
  940. if (!controller_ptr->started)
  941. {
  942. jack_dbus_error(
  943. call,
  944. JACK_DBUS_ERROR_SERVER_NOT_RUNNING,
  945. "Can't execute this method with stopped JACK server");
  946. return;
  947. }
  948. if (!jack_dbus_get_method_args(
  949. call,
  950. DBUS_TYPE_STRING,
  951. &client1_name,
  952. DBUS_TYPE_STRING,
  953. &port1_name,
  954. DBUS_TYPE_STRING,
  955. &client2_name,
  956. DBUS_TYPE_STRING,
  957. &port2_name,
  958. DBUS_TYPE_INVALID))
  959. {
  960. /* The method call had invalid arguments meaning that
  961. * jack_dbus_get_method_args() has constructed an error for us.
  962. */
  963. return;
  964. }
  965. /* jack_info("connecting %s:%s and %s:%s", client1_name, port1_name, client2_name, port2_name); */
  966. pthread_mutex_lock(&patchbay_ptr->lock);
  967. port1_ptr = jack_controller_patchbay_find_port_by_names(patchbay_ptr, client1_name, port1_name);
  968. if (port1_ptr == NULL)
  969. {
  970. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port '%s':'%s'", client1_name, port1_name);
  971. goto unlock;
  972. }
  973. port2_ptr = jack_controller_patchbay_find_port_by_names(patchbay_ptr, client2_name, port2_name);
  974. if (port2_ptr == NULL)
  975. {
  976. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port '%s':'%s'", client2_name, port2_name);
  977. goto unlock;
  978. }
  979. if (!jack_controller_patchbay_connect(
  980. call,
  981. controller_ptr,
  982. port1_ptr,
  983. port2_ptr))
  984. {
  985. /* jack_controller_patchbay_connect() constructed error reply */
  986. goto unlock;
  987. }
  988. jack_dbus_construct_method_return_empty(call);
  989. unlock:
  990. pthread_mutex_unlock(&patchbay_ptr->lock);
  991. }
  992. static
  993. void
  994. jack_controller_dbus_connect_ports_by_id(
  995. struct jack_dbus_method_call * call)
  996. {
  997. dbus_uint64_t port1_id;
  998. dbus_uint64_t port2_id;
  999. struct jack_graph_port *port1_ptr;
  1000. struct jack_graph_port *port2_ptr;
  1001. /* jack_info("jack_controller_dbus_connect_ports_by_id() called."); */
  1002. if (!controller_ptr->started)
  1003. {
  1004. jack_dbus_error(
  1005. call,
  1006. JACK_DBUS_ERROR_SERVER_NOT_RUNNING,
  1007. "Can't execute this method with stopped JACK server");
  1008. return;
  1009. }
  1010. if (!jack_dbus_get_method_args(
  1011. call,
  1012. DBUS_TYPE_UINT64,
  1013. &port1_id,
  1014. DBUS_TYPE_UINT64,
  1015. &port2_id,
  1016. DBUS_TYPE_INVALID))
  1017. {
  1018. /* The method call had invalid arguments meaning that
  1019. * jack_dbus_get_method_args() has constructed an error for us.
  1020. */
  1021. return;
  1022. }
  1023. pthread_mutex_lock(&patchbay_ptr->lock);
  1024. port1_ptr = jack_controller_patchbay_find_port_by_id(patchbay_ptr, port1_id);
  1025. if (port1_ptr == NULL)
  1026. {
  1027. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port %" PRIu64, port1_id);
  1028. goto unlock;
  1029. }
  1030. port2_ptr = jack_controller_patchbay_find_port_by_id(patchbay_ptr, port2_id);
  1031. if (port2_ptr == NULL)
  1032. {
  1033. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port %" PRIu64, port2_id);
  1034. goto unlock;
  1035. }
  1036. if (!jack_controller_patchbay_connect(
  1037. call,
  1038. controller_ptr,
  1039. port1_ptr,
  1040. port2_ptr))
  1041. {
  1042. /* jack_controller_patchbay_connect() constructed error reply */
  1043. goto unlock;
  1044. }
  1045. jack_dbus_construct_method_return_empty(call);
  1046. unlock:
  1047. pthread_mutex_unlock(&patchbay_ptr->lock);
  1048. }
  1049. static
  1050. void
  1051. jack_controller_dbus_disconnect_ports_by_name(
  1052. struct jack_dbus_method_call * call)
  1053. {
  1054. const char * client1_name;
  1055. const char * port1_name;
  1056. const char * client2_name;
  1057. const char * port2_name;
  1058. struct jack_graph_port *port1_ptr;
  1059. struct jack_graph_port *port2_ptr;
  1060. /* jack_info("jack_controller_dbus_disconnect_ports_by_name() called."); */
  1061. if (!controller_ptr->started)
  1062. {
  1063. jack_dbus_error(
  1064. call,
  1065. JACK_DBUS_ERROR_SERVER_NOT_RUNNING,
  1066. "Can't execute this method with stopped JACK server");
  1067. return;
  1068. }
  1069. if (!jack_dbus_get_method_args(
  1070. call,
  1071. DBUS_TYPE_STRING,
  1072. &client1_name,
  1073. DBUS_TYPE_STRING,
  1074. &port1_name,
  1075. DBUS_TYPE_STRING,
  1076. &client2_name,
  1077. DBUS_TYPE_STRING,
  1078. &port2_name,
  1079. DBUS_TYPE_INVALID))
  1080. {
  1081. /* The method call had invalid arguments meaning that
  1082. * jack_dbus_get_method_args() has constructed an error for us.
  1083. */
  1084. return;
  1085. }
  1086. /* jack_info("disconnecting %s:%s and %s:%s", client1_name, port1_name, client2_name, port2_name); */
  1087. pthread_mutex_lock(&patchbay_ptr->lock);
  1088. port1_ptr = jack_controller_patchbay_find_port_by_names(patchbay_ptr, client1_name, port1_name);
  1089. if (port1_ptr == NULL)
  1090. {
  1091. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port '%s':'%s'", client1_name, port1_name);
  1092. goto unlock;
  1093. }
  1094. port2_ptr = jack_controller_patchbay_find_port_by_names(patchbay_ptr, client2_name, port2_name);
  1095. if (port2_ptr == NULL)
  1096. {
  1097. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port '%s':'%s'", client2_name, port2_name);
  1098. goto unlock;
  1099. }
  1100. if (!jack_controller_patchbay_disconnect(
  1101. call,
  1102. controller_ptr,
  1103. port1_ptr,
  1104. port2_ptr))
  1105. {
  1106. /* jack_controller_patchbay_connect() constructed error reply */
  1107. goto unlock;
  1108. }
  1109. jack_dbus_construct_method_return_empty(call);
  1110. unlock:
  1111. pthread_mutex_unlock(&patchbay_ptr->lock);
  1112. }
  1113. static
  1114. void
  1115. jack_controller_dbus_disconnect_ports_by_id(
  1116. struct jack_dbus_method_call * call)
  1117. {
  1118. dbus_uint64_t port1_id;
  1119. dbus_uint64_t port2_id;
  1120. struct jack_graph_port *port1_ptr;
  1121. struct jack_graph_port *port2_ptr;
  1122. /* jack_info("jack_controller_dbus_disconnect_ports_by_id() called."); */
  1123. if (!controller_ptr->started)
  1124. {
  1125. jack_dbus_error(
  1126. call,
  1127. JACK_DBUS_ERROR_SERVER_NOT_RUNNING,
  1128. "Can't execute this method with stopped JACK server");
  1129. return;
  1130. }
  1131. if (!jack_dbus_get_method_args(
  1132. call,
  1133. DBUS_TYPE_UINT64,
  1134. &port1_id,
  1135. DBUS_TYPE_UINT64,
  1136. &port2_id,
  1137. DBUS_TYPE_INVALID))
  1138. {
  1139. /* The method call had invalid arguments meaning that
  1140. * jack_dbus_get_method_args() has constructed an error for us.
  1141. */
  1142. return;
  1143. }
  1144. pthread_mutex_lock(&patchbay_ptr->lock);
  1145. port1_ptr = jack_controller_patchbay_find_port_by_id(patchbay_ptr, port1_id);
  1146. if (port1_ptr == NULL)
  1147. {
  1148. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port %" PRIu64, port1_id);
  1149. return;
  1150. }
  1151. port2_ptr = jack_controller_patchbay_find_port_by_id(patchbay_ptr, port2_id);
  1152. if (port2_ptr == NULL)
  1153. {
  1154. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port %" PRIu64, port2_id);
  1155. return;
  1156. }
  1157. if (!jack_controller_patchbay_disconnect(
  1158. call,
  1159. controller_ptr,
  1160. port1_ptr,
  1161. port2_ptr))
  1162. {
  1163. /* jack_controller_patchbay_connect() constructed error reply */
  1164. goto unlock;
  1165. }
  1166. jack_dbus_construct_method_return_empty(call);
  1167. unlock:
  1168. pthread_mutex_unlock(&patchbay_ptr->lock);
  1169. }
  1170. static
  1171. void
  1172. jack_controller_dbus_disconnect_ports_by_connection_id(
  1173. struct jack_dbus_method_call * call)
  1174. {
  1175. dbus_uint64_t connection_id;
  1176. struct jack_graph_connection *connection_ptr;
  1177. /* jack_info("jack_controller_dbus_disconnect_ports_by_id() called."); */
  1178. if (!jack_dbus_get_method_args(
  1179. call,
  1180. DBUS_TYPE_UINT64,
  1181. &connection_id,
  1182. DBUS_TYPE_INVALID))
  1183. {
  1184. /* The method call had invalid arguments meaning that
  1185. * jack_dbus_get_method_args() has constructed an error for us.
  1186. */
  1187. return;
  1188. }
  1189. pthread_mutex_lock(&patchbay_ptr->lock);
  1190. connection_ptr = jack_controller_patchbay_find_connection_by_id(patchbay_ptr, connection_id);
  1191. if (connection_ptr == NULL)
  1192. {
  1193. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find connection %" PRIu64, connection_id);
  1194. goto unlock;
  1195. }
  1196. if (!jack_controller_patchbay_disconnect(
  1197. call,
  1198. controller_ptr,
  1199. connection_ptr->port1,
  1200. connection_ptr->port2))
  1201. {
  1202. /* jack_controller_patchbay_connect() constructed error reply */
  1203. goto unlock;
  1204. }
  1205. jack_dbus_construct_method_return_empty(call);
  1206. unlock:
  1207. pthread_mutex_unlock(&patchbay_ptr->lock);
  1208. }
  1209. static
  1210. void
  1211. jack_controller_dbus_get_client_pid(
  1212. struct jack_dbus_method_call * call)
  1213. {
  1214. dbus_uint64_t client_id;
  1215. struct jack_graph_client *client_ptr;
  1216. message_arg_t arg;
  1217. /* jack_info("jack_controller_dbus_get_client_pid() called."); */
  1218. if (!jack_dbus_get_method_args(
  1219. call,
  1220. DBUS_TYPE_UINT64,
  1221. &client_id,
  1222. DBUS_TYPE_INVALID))
  1223. {
  1224. /* The method call had invalid arguments meaning that
  1225. * jack_dbus_get_method_args() has constructed an error for us.
  1226. */
  1227. return;
  1228. }
  1229. pthread_mutex_lock(&patchbay_ptr->lock);
  1230. client_ptr = jack_controller_patchbay_find_client_by_id(patchbay_ptr, client_id);
  1231. if (client_ptr == NULL)
  1232. {
  1233. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find client %" PRIu64, client_id);
  1234. goto unlock;
  1235. }
  1236. arg.int64 = client_ptr->pid;
  1237. jack_dbus_construct_method_return_single(call, DBUS_TYPE_INT64, arg);
  1238. unlock:
  1239. pthread_mutex_unlock(&patchbay_ptr->lock);
  1240. }
  1241. #undef controller_ptr
  1242. #define controller_ptr ((struct jack_controller *)context)
  1243. static
  1244. int
  1245. jack_controller_graph_order_callback(
  1246. void *context)
  1247. {
  1248. const char **ports;
  1249. int i;
  1250. jack_port_t *port_ptr;
  1251. if (patchbay_ptr->graph.version > 1)
  1252. {
  1253. /* we use this only for initial catchup */
  1254. return 0;
  1255. }
  1256. ports = jack_get_ports(controller_ptr->client, NULL, NULL, 0);
  1257. if (ports)
  1258. {
  1259. for (i = 0; ports[i]; ++i)
  1260. {
  1261. jack_info("graph reorder: new port '%s'", ports[i]);
  1262. port_ptr = jack_port_by_name(controller_ptr->client, ports[i]);;
  1263. jack_controller_patchbay_new_port(patchbay_ptr, ports[i], jack_port_flags(port_ptr), jack_port_type_id(port_ptr));
  1264. }
  1265. free(ports);
  1266. }
  1267. if (patchbay_ptr->graph.version == 1)
  1268. {
  1269. /* we have empty initial graph, increment graph version,
  1270. so we dont do jack_get_ports() again,
  1271. on next next graph change */
  1272. patchbay_ptr->graph.version++;
  1273. }
  1274. return 0;
  1275. }
  1276. void
  1277. jack_controller_client_registration_callback(
  1278. const char *client_name,
  1279. int created,
  1280. void *context)
  1281. {
  1282. if (created)
  1283. {
  1284. jack_log("client '%s' created", client_name);
  1285. jack_controller_patchbay_create_client(patchbay_ptr, client_name, strlen(client_name));
  1286. }
  1287. else
  1288. {
  1289. jack_log("client '%s' destroyed", client_name);
  1290. jack_controller_patchbay_destroy_client_by_name(patchbay_ptr, client_name);
  1291. }
  1292. }
  1293. void
  1294. jack_controller_port_registration_callback(
  1295. jack_port_id_t port_id,
  1296. int created,
  1297. void *context)
  1298. {
  1299. jack_port_t *port_ptr;
  1300. struct jack_graph_port *graph_port_ptr;
  1301. const char *port_name;
  1302. port_ptr = jack_port_by_id(controller_ptr->client, port_id);
  1303. port_name = jack_port_name(port_ptr);
  1304. if (created)
  1305. {
  1306. jack_log("port '%s' created", port_name);
  1307. jack_controller_patchbay_new_port(patchbay_ptr, port_name, jack_port_flags(port_ptr), jack_port_type_id(port_ptr));
  1308. }
  1309. else
  1310. {
  1311. jack_log("port '%s' destroyed", port_name);
  1312. graph_port_ptr = jack_controller_patchbay_find_port_by_full_name(patchbay_ptr, port_name);
  1313. if (graph_port_ptr == NULL)
  1314. {
  1315. jack_error("Failed to find port '%s' to destroy", port_name);
  1316. return;
  1317. }
  1318. jack_controller_patchbay_remove_port(patchbay_ptr, graph_port_ptr);
  1319. }
  1320. }
  1321. void
  1322. jack_controller_port_connect_callback(
  1323. jack_port_id_t port1_id,
  1324. jack_port_id_t port2_id,
  1325. int connect,
  1326. void *context)
  1327. {
  1328. jack_port_t *port1;
  1329. jack_port_t *port2;
  1330. const char *port1_name;
  1331. const char *port2_name;
  1332. struct jack_graph_port *port1_ptr;
  1333. struct jack_graph_port *port2_ptr;
  1334. struct jack_graph_connection *connection_ptr;
  1335. port1 = jack_port_by_id(controller_ptr->client, port1_id);
  1336. port2 = jack_port_by_id(controller_ptr->client, port2_id);
  1337. port1_name = jack_port_name(port1);
  1338. port2_name = jack_port_name(port2);
  1339. port1_ptr = jack_controller_patchbay_find_port_by_full_name(patchbay_ptr, port1_name);
  1340. if (port1_ptr == NULL)
  1341. {
  1342. jack_error("Failed to find port '%s' to [dis]connect", port1_name);
  1343. return;
  1344. }
  1345. port2_ptr = jack_controller_patchbay_find_port_by_full_name(patchbay_ptr, port2_name);
  1346. if (port2_ptr == NULL)
  1347. {
  1348. jack_error("Failed to find port '%s' to [dis]connect", port2_name);
  1349. return;
  1350. }
  1351. if (connect)
  1352. {
  1353. jack_info("Connecting '%s' to '%s'", port1_name, port2_name);
  1354. connection_ptr = jack_controller_patchbay_find_connection(patchbay_ptr, port1_ptr, port2_ptr);
  1355. if (connection_ptr != NULL)
  1356. {
  1357. jack_error("'%s' and '%s' are already connected", port1_name, port2_name);
  1358. return;
  1359. }
  1360. jack_controller_patchbay_create_connection(patchbay_ptr, port1_ptr, port2_ptr);
  1361. }
  1362. else
  1363. {
  1364. jack_info("Disonnecting '%s' from '%s'", port1_name, port2_name);
  1365. connection_ptr = jack_controller_patchbay_find_connection(patchbay_ptr, port1_ptr, port2_ptr);
  1366. if (connection_ptr == NULL)
  1367. {
  1368. jack_error("Cannot find connection being removed");
  1369. return;
  1370. }
  1371. jack_controller_patchbay_destroy_connection(patchbay_ptr, connection_ptr);
  1372. }
  1373. }
  1374. #undef controller_ptr
  1375. void
  1376. jack_controller_patchbay_uninit(
  1377. struct jack_controller * controller_ptr)
  1378. {
  1379. struct jack_graph_client *client_ptr;
  1380. struct jack_graph_port *port_ptr;
  1381. /* jack_info("jack_controller_patchbay_uninit() called"); */
  1382. while (!list_empty(&patchbay_ptr->graph.ports))
  1383. {
  1384. port_ptr = list_entry(patchbay_ptr->graph.ports.next, struct jack_graph_port, siblings_graph);
  1385. jack_controller_patchbay_remove_port(patchbay_ptr, port_ptr);
  1386. }
  1387. while (!list_empty(&patchbay_ptr->graph.clients))
  1388. {
  1389. client_ptr = list_entry(patchbay_ptr->graph.clients.next, struct jack_graph_client, siblings);
  1390. jack_controller_patchbay_destroy_client(patchbay_ptr, client_ptr);
  1391. }
  1392. pthread_mutex_destroy(&patchbay_ptr->lock);
  1393. }
  1394. #undef patchbay_ptr
  1395. bool
  1396. jack_controller_patchbay_init(
  1397. struct jack_controller * controller_ptr)
  1398. {
  1399. int ret;
  1400. struct jack_controller_patchbay * patchbay_ptr;
  1401. pthread_mutexattr_t attr;
  1402. /* jack_info("jack_controller_patchbay_init() called"); */
  1403. patchbay_ptr = malloc(sizeof(struct jack_controller_patchbay));
  1404. if (patchbay_ptr == NULL)
  1405. {
  1406. jack_error("Memory allocation of jack_controller_patchbay structure failed.");
  1407. goto fail;
  1408. }
  1409. ret = pthread_mutexattr_init(&attr);
  1410. if (ret != 0)
  1411. {
  1412. goto fail;
  1413. }
  1414. ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
  1415. if (ret != 0)
  1416. {
  1417. goto fail;
  1418. }
  1419. pthread_mutex_init(&patchbay_ptr->lock, &attr);
  1420. INIT_LIST_HEAD(&patchbay_ptr->graph.clients);
  1421. INIT_LIST_HEAD(&patchbay_ptr->graph.ports);
  1422. INIT_LIST_HEAD(&patchbay_ptr->graph.connections);
  1423. patchbay_ptr->graph.version = 1;
  1424. patchbay_ptr->next_client_id = 1;
  1425. patchbay_ptr->next_port_id = 1;
  1426. patchbay_ptr->next_connection_id = 1;
  1427. controller_ptr->patchbay_context = patchbay_ptr;
  1428. ret = jack_set_graph_order_callback(controller_ptr->client, jack_controller_graph_order_callback, controller_ptr);
  1429. if (ret != 0)
  1430. {
  1431. jack_error("jack_set_graph_order_callback() failed with error %d", ret);
  1432. goto fail_uninit_mutex;
  1433. }
  1434. ret = jack_set_client_registration_callback(controller_ptr->client, jack_controller_client_registration_callback, controller_ptr);
  1435. if (ret != 0)
  1436. {
  1437. jack_error("jack_set_client_registration_callback() failed with error %d", ret);
  1438. goto fail_uninit_mutex;
  1439. }
  1440. ret = jack_set_port_registration_callback(controller_ptr->client, jack_controller_port_registration_callback, controller_ptr);
  1441. if (ret != 0)
  1442. {
  1443. jack_error("jack_set_port_registration_callback() failed with error %d", ret);
  1444. goto fail_uninit_mutex;
  1445. }
  1446. ret = jack_set_port_connect_callback(controller_ptr->client, jack_controller_port_connect_callback, controller_ptr);
  1447. if (ret != 0)
  1448. {
  1449. jack_error("jack_set_port_connect_callback() failed with error %d", ret);
  1450. goto fail_uninit_mutex;
  1451. }
  1452. return true;
  1453. fail_uninit_mutex:
  1454. pthread_mutex_destroy(&patchbay_ptr->lock);
  1455. fail:
  1456. return false;
  1457. }
  1458. JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetAllPorts)
  1459. JACK_DBUS_METHOD_ARGUMENT("ports_list", "as", true)
  1460. JACK_DBUS_METHOD_ARGUMENTS_END
  1461. JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetGraph)
  1462. JACK_DBUS_METHOD_ARGUMENT("known_graph_version", DBUS_TYPE_UINT64_AS_STRING, false)
  1463. JACK_DBUS_METHOD_ARGUMENT("current_graph_version", DBUS_TYPE_UINT64_AS_STRING, true)
  1464. JACK_DBUS_METHOD_ARGUMENT("clients_and_ports", "a(tsa(tsuu))", true)
  1465. JACK_DBUS_METHOD_ARGUMENT("connections", "a(tstststst)", true)
  1466. JACK_DBUS_METHOD_ARGUMENTS_END
  1467. JACK_DBUS_METHOD_ARGUMENTS_BEGIN(ConnectPortsByName)
  1468. JACK_DBUS_METHOD_ARGUMENT("client1_name", DBUS_TYPE_STRING_AS_STRING, false)
  1469. JACK_DBUS_METHOD_ARGUMENT("port1_name", DBUS_TYPE_STRING_AS_STRING, false)
  1470. JACK_DBUS_METHOD_ARGUMENT("client2_name", DBUS_TYPE_STRING_AS_STRING, false)
  1471. JACK_DBUS_METHOD_ARGUMENT("port2_name", DBUS_TYPE_STRING_AS_STRING, false)
  1472. JACK_DBUS_METHOD_ARGUMENTS_END
  1473. JACK_DBUS_METHOD_ARGUMENTS_BEGIN(ConnectPortsByID)
  1474. JACK_DBUS_METHOD_ARGUMENT("port1_id", DBUS_TYPE_UINT64_AS_STRING, false)
  1475. JACK_DBUS_METHOD_ARGUMENT("port2_id", DBUS_TYPE_UINT64_AS_STRING, false)
  1476. JACK_DBUS_METHOD_ARGUMENTS_END
  1477. JACK_DBUS_METHOD_ARGUMENTS_BEGIN(DisconnectPortsByName)
  1478. JACK_DBUS_METHOD_ARGUMENT("client1_name", DBUS_TYPE_STRING_AS_STRING, false)
  1479. JACK_DBUS_METHOD_ARGUMENT("port1_name", DBUS_TYPE_STRING_AS_STRING, false)
  1480. JACK_DBUS_METHOD_ARGUMENT("client2_name", DBUS_TYPE_STRING_AS_STRING, false)
  1481. JACK_DBUS_METHOD_ARGUMENT("port2_name", DBUS_TYPE_STRING_AS_STRING, false)
  1482. JACK_DBUS_METHOD_ARGUMENTS_END
  1483. JACK_DBUS_METHOD_ARGUMENTS_BEGIN(DisconnectPortsByID)
  1484. JACK_DBUS_METHOD_ARGUMENT("port1_id", DBUS_TYPE_UINT64_AS_STRING, false)
  1485. JACK_DBUS_METHOD_ARGUMENT("port2_id", DBUS_TYPE_UINT64_AS_STRING, false)
  1486. JACK_DBUS_METHOD_ARGUMENTS_END
  1487. JACK_DBUS_METHOD_ARGUMENTS_BEGIN(DisconnectPortsByConnectionID)
  1488. JACK_DBUS_METHOD_ARGUMENT("connection_id", DBUS_TYPE_UINT64_AS_STRING, false)
  1489. JACK_DBUS_METHOD_ARGUMENTS_END
  1490. JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetClientPID)
  1491. JACK_DBUS_METHOD_ARGUMENT("client_id", DBUS_TYPE_INT64_AS_STRING, false)
  1492. JACK_DBUS_METHOD_ARGUMENTS_END
  1493. JACK_DBUS_METHODS_BEGIN
  1494. JACK_DBUS_METHOD_DESCRIBE(GetAllPorts, jack_controller_dbus_get_all_ports)
  1495. JACK_DBUS_METHOD_DESCRIBE(GetGraph, jack_controller_dbus_get_graph)
  1496. JACK_DBUS_METHOD_DESCRIBE(ConnectPortsByName, jack_controller_dbus_connect_ports_by_name)
  1497. JACK_DBUS_METHOD_DESCRIBE(ConnectPortsByID, jack_controller_dbus_connect_ports_by_id)
  1498. JACK_DBUS_METHOD_DESCRIBE(DisconnectPortsByName, jack_controller_dbus_disconnect_ports_by_name)
  1499. JACK_DBUS_METHOD_DESCRIBE(DisconnectPortsByID, jack_controller_dbus_disconnect_ports_by_id)
  1500. JACK_DBUS_METHOD_DESCRIBE(DisconnectPortsByConnectionID, jack_controller_dbus_disconnect_ports_by_connection_id)
  1501. JACK_DBUS_METHOD_DESCRIBE(GetClientPID, jack_controller_dbus_get_client_pid)
  1502. JACK_DBUS_METHODS_END
  1503. JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(GraphChanged)
  1504. JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
  1505. JACK_DBUS_SIGNAL_ARGUMENTS_END
  1506. JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(ClientAppeared)
  1507. JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
  1508. JACK_DBUS_SIGNAL_ARGUMENT("client_id", DBUS_TYPE_UINT64_AS_STRING)
  1509. JACK_DBUS_SIGNAL_ARGUMENT("client_name", DBUS_TYPE_STRING_AS_STRING)
  1510. JACK_DBUS_SIGNAL_ARGUMENTS_END
  1511. JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(ClientDisappeared)
  1512. JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
  1513. JACK_DBUS_SIGNAL_ARGUMENT("client_id", DBUS_TYPE_UINT64_AS_STRING)
  1514. JACK_DBUS_SIGNAL_ARGUMENT("client_name", DBUS_TYPE_STRING_AS_STRING)
  1515. JACK_DBUS_SIGNAL_ARGUMENTS_END
  1516. JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(PortAppeared)
  1517. JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
  1518. JACK_DBUS_SIGNAL_ARGUMENT("client_id", DBUS_TYPE_UINT64_AS_STRING)
  1519. JACK_DBUS_SIGNAL_ARGUMENT("client_name", DBUS_TYPE_STRING_AS_STRING)
  1520. JACK_DBUS_SIGNAL_ARGUMENT("port_id", DBUS_TYPE_UINT64_AS_STRING)
  1521. JACK_DBUS_SIGNAL_ARGUMENT("port_name", DBUS_TYPE_STRING_AS_STRING)
  1522. JACK_DBUS_SIGNAL_ARGUMENT("port_flags", DBUS_TYPE_UINT32_AS_STRING)
  1523. JACK_DBUS_SIGNAL_ARGUMENT("port_type", DBUS_TYPE_UINT32_AS_STRING)
  1524. JACK_DBUS_SIGNAL_ARGUMENTS_END
  1525. JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(PortDisappeared)
  1526. JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
  1527. JACK_DBUS_SIGNAL_ARGUMENT("client_id", DBUS_TYPE_UINT64_AS_STRING)
  1528. JACK_DBUS_SIGNAL_ARGUMENT("client_name", DBUS_TYPE_STRING_AS_STRING)
  1529. JACK_DBUS_SIGNAL_ARGUMENT("port_id", DBUS_TYPE_UINT64_AS_STRING)
  1530. JACK_DBUS_SIGNAL_ARGUMENT("port_name", DBUS_TYPE_STRING_AS_STRING)
  1531. JACK_DBUS_SIGNAL_ARGUMENTS_END
  1532. JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(PortsConnected)
  1533. JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
  1534. JACK_DBUS_SIGNAL_ARGUMENT("client1_id", DBUS_TYPE_UINT64_AS_STRING)
  1535. JACK_DBUS_SIGNAL_ARGUMENT("client1_name", DBUS_TYPE_STRING_AS_STRING)
  1536. JACK_DBUS_SIGNAL_ARGUMENT("port1_id", DBUS_TYPE_UINT64_AS_STRING)
  1537. JACK_DBUS_SIGNAL_ARGUMENT("port1_name", DBUS_TYPE_STRING_AS_STRING)
  1538. JACK_DBUS_SIGNAL_ARGUMENT("client2_id", DBUS_TYPE_UINT64_AS_STRING)
  1539. JACK_DBUS_SIGNAL_ARGUMENT("client2_name", DBUS_TYPE_STRING_AS_STRING)
  1540. JACK_DBUS_SIGNAL_ARGUMENT("port2_id", DBUS_TYPE_UINT64_AS_STRING)
  1541. JACK_DBUS_SIGNAL_ARGUMENT("port2_name", DBUS_TYPE_STRING_AS_STRING)
  1542. JACK_DBUS_SIGNAL_ARGUMENT("connection_id", DBUS_TYPE_UINT64_AS_STRING)
  1543. JACK_DBUS_SIGNAL_ARGUMENTS_END
  1544. JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(PortsDisconnected)
  1545. JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
  1546. JACK_DBUS_SIGNAL_ARGUMENT("client1_id", DBUS_TYPE_UINT64_AS_STRING)
  1547. JACK_DBUS_SIGNAL_ARGUMENT("client1_name", DBUS_TYPE_STRING_AS_STRING)
  1548. JACK_DBUS_SIGNAL_ARGUMENT("port1_id", DBUS_TYPE_UINT64_AS_STRING)
  1549. JACK_DBUS_SIGNAL_ARGUMENT("port1_name", DBUS_TYPE_STRING_AS_STRING)
  1550. JACK_DBUS_SIGNAL_ARGUMENT("client2_id", DBUS_TYPE_UINT64_AS_STRING)
  1551. JACK_DBUS_SIGNAL_ARGUMENT("client2_name", DBUS_TYPE_STRING_AS_STRING)
  1552. JACK_DBUS_SIGNAL_ARGUMENT("port2_id", DBUS_TYPE_UINT64_AS_STRING)
  1553. JACK_DBUS_SIGNAL_ARGUMENT("port2_name", DBUS_TYPE_STRING_AS_STRING)
  1554. JACK_DBUS_SIGNAL_ARGUMENT("connection_id", DBUS_TYPE_UINT64_AS_STRING)
  1555. JACK_DBUS_SIGNAL_ARGUMENTS_END
  1556. JACK_DBUS_SIGNALS_BEGIN
  1557. JACK_DBUS_SIGNAL_DESCRIBE(GraphChanged)
  1558. JACK_DBUS_SIGNAL_DESCRIBE(ClientAppeared)
  1559. JACK_DBUS_SIGNAL_DESCRIBE(ClientDisappeared)
  1560. JACK_DBUS_SIGNAL_DESCRIBE(PortAppeared)
  1561. JACK_DBUS_SIGNAL_DESCRIBE(PortDisappeared)
  1562. JACK_DBUS_SIGNAL_DESCRIBE(PortsConnected)
  1563. JACK_DBUS_SIGNAL_DESCRIBE(PortsDisconnected)
  1564. JACK_DBUS_SIGNALS_END
  1565. JACK_DBUS_IFACE_BEGIN(g_jack_controller_iface_patchbay, JACK_DBUS_IFACE_NAME)
  1566. JACK_DBUS_IFACE_EXPOSE_METHODS
  1567. JACK_DBUS_IFACE_EXPOSE_SIGNALS
  1568. JACK_DBUS_IFACE_END