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.

1850 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. pthread_mutex_lock(&patchbay_ptr->lock);
  336. list_del(&client_ptr->siblings);
  337. patchbay_ptr->graph.version++;
  338. jack_controller_patchbay_send_signal_client_disappeared(patchbay_ptr->graph.version, client_ptr->id, client_ptr->name);
  339. jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version);
  340. pthread_mutex_unlock(&patchbay_ptr->lock);
  341. free(client_ptr->name);
  342. free(client_ptr);
  343. }
  344. static
  345. void
  346. jack_controller_patchbay_destroy_client_by_name(
  347. struct jack_controller_patchbay *patchbay_ptr,
  348. const char *client_name) /* '\0' terminated */
  349. {
  350. struct jack_graph_client *client_ptr;
  351. client_ptr = jack_controller_patchbay_find_client(patchbay_ptr, client_name, strlen(client_name));
  352. if (client_ptr == NULL)
  353. {
  354. jack_error("Cannot destroy unknown client '%s'", client_name);
  355. return;
  356. }
  357. jack_controller_patchbay_destroy_client(patchbay_ptr, client_ptr);
  358. }
  359. static
  360. void
  361. jack_controller_patchbay_new_port(
  362. struct jack_controller_patchbay *patchbay_ptr,
  363. const char *port_full_name,
  364. uint32_t port_flags,
  365. uint32_t port_type)
  366. {
  367. struct jack_graph_client *client_ptr;
  368. struct jack_graph_port *port_ptr;
  369. const char *port_short_name;
  370. size_t client_name_len;
  371. //jack_info("name: %s", port_full_name);
  372. port_short_name = strchr(port_full_name, ':');
  373. if (port_short_name == NULL)
  374. {
  375. jack_error("port name '%s' does not contain ':' separator char", port_full_name);
  376. return;
  377. }
  378. port_short_name++; /* skip ':' separator char */
  379. client_name_len = port_short_name - port_full_name - 1; /* without terminating '\0' */
  380. client_ptr = jack_controller_patchbay_find_client(patchbay_ptr, port_full_name, client_name_len);
  381. if (client_ptr == NULL)
  382. {
  383. client_ptr = jack_controller_patchbay_create_client(patchbay_ptr, port_full_name, client_name_len);
  384. if (client_ptr == NULL)
  385. {
  386. jack_error("Creation of new jack_graph client failed.");
  387. return;
  388. }
  389. }
  390. port_ptr = malloc(sizeof(struct jack_graph_port));
  391. if (port_ptr == NULL)
  392. {
  393. jack_error("Memory allocation of jack_graph_port structure failed.");
  394. return;
  395. }
  396. port_ptr->name = strdup(port_short_name);
  397. if (port_ptr->name == NULL)
  398. {
  399. jack_error("strdup() call for port name '%s' failed.", port_short_name);
  400. free(port_ptr);
  401. return;
  402. }
  403. port_ptr->id = patchbay_ptr->next_port_id++;
  404. port_ptr->flags = port_flags;
  405. port_ptr->type = port_type;
  406. port_ptr->client = client_ptr;
  407. pthread_mutex_lock(&patchbay_ptr->lock);
  408. list_add_tail(&port_ptr->siblings_client, &client_ptr->ports);
  409. list_add_tail(&port_ptr->siblings_graph, &patchbay_ptr->graph.ports);
  410. patchbay_ptr->graph.version++;
  411. jack_controller_patchbay_send_signal_port_appeared(
  412. patchbay_ptr->graph.version,
  413. client_ptr->id,
  414. client_ptr->name,
  415. port_ptr->id,
  416. port_ptr->name,
  417. port_ptr->flags,
  418. port_ptr->type);
  419. jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version);
  420. pthread_mutex_unlock(&patchbay_ptr->lock);
  421. }
  422. static
  423. void
  424. jack_controller_patchbay_remove_port(
  425. struct jack_controller_patchbay *patchbay_ptr,
  426. struct jack_graph_port *port_ptr)
  427. {
  428. pthread_mutex_lock(&patchbay_ptr->lock);
  429. list_del(&port_ptr->siblings_client);
  430. list_del(&port_ptr->siblings_graph);
  431. patchbay_ptr->graph.version++;
  432. 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);
  433. jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version);
  434. pthread_mutex_unlock(&patchbay_ptr->lock);
  435. free(port_ptr->name);
  436. free(port_ptr);
  437. }
  438. static
  439. struct jack_graph_port *
  440. jack_controller_patchbay_find_port_by_id(
  441. struct jack_controller_patchbay *patchbay_ptr,
  442. uint64_t port_id)
  443. {
  444. struct list_head *node_ptr;
  445. struct jack_graph_port *port_ptr;
  446. list_for_each(node_ptr, &patchbay_ptr->graph.ports)
  447. {
  448. port_ptr = list_entry(node_ptr, struct jack_graph_port, siblings_graph);
  449. if (port_ptr->id == port_id)
  450. {
  451. return port_ptr;
  452. }
  453. }
  454. return NULL;
  455. }
  456. static
  457. struct jack_graph_port *
  458. jack_controller_patchbay_find_client_port_by_name(
  459. struct jack_controller_patchbay *patchbay_ptr,
  460. struct jack_graph_client *client_ptr,
  461. const char *port_name)
  462. {
  463. struct list_head *node_ptr;
  464. struct jack_graph_port *port_ptr;
  465. list_for_each(node_ptr, &client_ptr->ports)
  466. {
  467. port_ptr = list_entry(node_ptr, struct jack_graph_port, siblings_client);
  468. if (strcmp(port_ptr->name, port_name) == 0)
  469. {
  470. return port_ptr;
  471. }
  472. }
  473. return NULL;
  474. }
  475. static
  476. struct jack_graph_port *
  477. jack_controller_patchbay_find_port_by_full_name(
  478. struct jack_controller_patchbay *patchbay_ptr,
  479. const char *port_full_name)
  480. {
  481. const char *port_short_name;
  482. size_t client_name_len;
  483. struct jack_graph_client *client_ptr;
  484. //jack_info("name: %s", port_full_name);
  485. port_short_name = strchr(port_full_name, ':');
  486. if (port_short_name == NULL)
  487. {
  488. jack_error("port name '%s' does not contain ':' separator char", port_full_name);
  489. return NULL;
  490. }
  491. port_short_name++; /* skip ':' separator char */
  492. client_name_len = port_short_name - port_full_name - 1; /* without terminating '\0' */
  493. client_ptr = jack_controller_patchbay_find_client(patchbay_ptr, port_full_name, client_name_len);
  494. if (client_ptr == NULL)
  495. {
  496. jack_error("cannot find client of port '%s'", port_full_name);
  497. return NULL;
  498. }
  499. return jack_controller_patchbay_find_client_port_by_name(patchbay_ptr, client_ptr, port_short_name);
  500. }
  501. static
  502. struct jack_graph_port *
  503. jack_controller_patchbay_find_port_by_names(
  504. struct jack_controller_patchbay *patchbay_ptr,
  505. const char *client_name,
  506. const char *port_name)
  507. {
  508. struct jack_graph_client *client_ptr;
  509. client_ptr = jack_controller_patchbay_find_client(patchbay_ptr, client_name, strlen(client_name));
  510. if (client_ptr == NULL)
  511. {
  512. jack_error("cannot find client '%s'", client_name);
  513. return NULL;
  514. }
  515. return jack_controller_patchbay_find_client_port_by_name(patchbay_ptr, client_ptr, port_name);
  516. }
  517. static
  518. struct jack_graph_connection *
  519. jack_controller_patchbay_create_connection(
  520. struct jack_controller_patchbay *patchbay_ptr,
  521. struct jack_graph_port *port1_ptr,
  522. struct jack_graph_port *port2_ptr)
  523. {
  524. struct jack_graph_connection * connection_ptr;
  525. connection_ptr = malloc(sizeof(struct jack_graph_connection));
  526. if (connection_ptr == NULL)
  527. {
  528. jack_error("Memory allocation of jack_graph_connection structure failed.");
  529. return NULL;
  530. }
  531. connection_ptr->id = patchbay_ptr->next_connection_id++;
  532. connection_ptr->port1 = port1_ptr;
  533. connection_ptr->port2 = port2_ptr;
  534. pthread_mutex_lock(&patchbay_ptr->lock);
  535. list_add_tail(&connection_ptr->siblings, &patchbay_ptr->graph.connections);
  536. patchbay_ptr->graph.version++;
  537. jack_controller_patchbay_send_signal_ports_connected(
  538. patchbay_ptr->graph.version,
  539. port1_ptr->client->id,
  540. port1_ptr->client->name,
  541. port1_ptr->id,
  542. port1_ptr->name,
  543. port2_ptr->client->id,
  544. port2_ptr->client->name,
  545. port2_ptr->id,
  546. port2_ptr->name,
  547. connection_ptr->id);
  548. jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version);
  549. pthread_mutex_unlock(&patchbay_ptr->lock);
  550. return connection_ptr;
  551. }
  552. static
  553. void
  554. jack_controller_patchbay_destroy_connection(
  555. struct jack_controller_patchbay *patchbay_ptr,
  556. struct jack_graph_connection *connection_ptr)
  557. {
  558. pthread_mutex_lock(&patchbay_ptr->lock);
  559. list_del(&connection_ptr->siblings);
  560. patchbay_ptr->graph.version++;
  561. jack_controller_patchbay_send_signal_ports_disconnected(
  562. patchbay_ptr->graph.version,
  563. connection_ptr->port1->client->id,
  564. connection_ptr->port1->client->name,
  565. connection_ptr->port1->id,
  566. connection_ptr->port1->name,
  567. connection_ptr->port2->client->id,
  568. connection_ptr->port2->client->name,
  569. connection_ptr->port2->id,
  570. connection_ptr->port2->name,
  571. connection_ptr->id);
  572. jack_controller_patchbay_send_signal_graph_changed(patchbay_ptr->graph.version);
  573. pthread_mutex_unlock(&patchbay_ptr->lock);
  574. free(connection_ptr);
  575. }
  576. static
  577. struct jack_graph_connection *
  578. jack_controller_patchbay_find_connection(
  579. struct jack_controller_patchbay *patchbay_ptr,
  580. struct jack_graph_port *port1_ptr,
  581. struct jack_graph_port *port2_ptr)
  582. {
  583. struct list_head *node_ptr;
  584. struct jack_graph_connection *connection_ptr;
  585. list_for_each(node_ptr, &patchbay_ptr->graph.connections)
  586. {
  587. connection_ptr = list_entry(node_ptr, struct jack_graph_connection, siblings);
  588. if ((connection_ptr->port1 == port1_ptr &&
  589. connection_ptr->port2 == port2_ptr) ||
  590. (connection_ptr->port1 == port2_ptr &&
  591. connection_ptr->port2 == port1_ptr))
  592. {
  593. return connection_ptr;
  594. }
  595. }
  596. return NULL;
  597. }
  598. static
  599. struct jack_graph_connection *
  600. jack_controller_patchbay_find_connection_by_id(
  601. struct jack_controller_patchbay *patchbay_ptr,
  602. uint64_t connection_id)
  603. {
  604. struct list_head *node_ptr;
  605. struct jack_graph_connection *connection_ptr;
  606. list_for_each(node_ptr, &patchbay_ptr->graph.connections)
  607. {
  608. connection_ptr = list_entry(node_ptr, struct jack_graph_connection, siblings);
  609. if (connection_ptr->id == connection_id)
  610. {
  611. return connection_ptr;
  612. }
  613. }
  614. return NULL;
  615. }
  616. static
  617. bool
  618. jack_controller_patchbay_connect(
  619. struct jack_dbus_method_call *dbus_call_ptr,
  620. struct jack_controller *controller_ptr,
  621. struct jack_graph_port *port1_ptr,
  622. struct jack_graph_port *port2_ptr)
  623. {
  624. int ret;
  625. char port1_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
  626. char port2_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
  627. sprintf(port1_name, "%s:%s", port1_ptr->client->name, port1_ptr->name);
  628. sprintf(port2_name, "%s:%s", port2_ptr->client->name, port2_ptr->name);
  629. ret = jack_connect(controller_ptr->client, port1_name, port2_name);
  630. if (ret != 0)
  631. {
  632. jack_dbus_error(dbus_call_ptr, JACK_DBUS_ERROR_GENERIC, "jack_connect() failed with %d", ret);
  633. return false;
  634. }
  635. return true;
  636. }
  637. static
  638. bool
  639. jack_controller_patchbay_disconnect(
  640. struct jack_dbus_method_call *dbus_call_ptr,
  641. struct jack_controller *controller_ptr,
  642. struct jack_graph_port *port1_ptr,
  643. struct jack_graph_port *port2_ptr)
  644. {
  645. int ret;
  646. char port1_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
  647. char port2_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
  648. sprintf(port1_name, "%s:%s", port1_ptr->client->name, port1_ptr->name);
  649. sprintf(port2_name, "%s:%s", port2_ptr->client->name, port2_ptr->name);
  650. ret = jack_disconnect(controller_ptr->client, port1_name, port2_name);
  651. if (ret != 0)
  652. {
  653. jack_dbus_error(dbus_call_ptr, JACK_DBUS_ERROR_GENERIC, "jack_connect() failed with %d", ret);
  654. return false;
  655. }
  656. return true;
  657. }
  658. #define controller_ptr ((struct jack_controller *)call->context)
  659. #define patchbay_ptr ((struct jack_controller_patchbay *)controller_ptr->patchbay_context)
  660. static
  661. void
  662. jack_controller_dbus_get_all_ports(
  663. struct jack_dbus_method_call * call)
  664. {
  665. struct list_head * client_node_ptr;
  666. struct list_head * port_node_ptr;
  667. struct jack_graph_client * client_ptr;
  668. struct jack_graph_port * port_ptr;
  669. DBusMessageIter iter, sub_iter;
  670. char fullname[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
  671. char *fullname_var = fullname;
  672. if (!controller_ptr->started)
  673. {
  674. jack_dbus_error(
  675. call,
  676. JACK_DBUS_ERROR_SERVER_NOT_RUNNING,
  677. "Can't execute this method with stopped JACK server");
  678. return;
  679. }
  680. call->reply = dbus_message_new_method_return (call->message);
  681. if (!call->reply)
  682. {
  683. goto fail;
  684. }
  685. dbus_message_iter_init_append (call->reply, &iter);
  686. if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s", &sub_iter))
  687. {
  688. goto fail_unref;
  689. }
  690. pthread_mutex_lock(&patchbay_ptr->lock);
  691. list_for_each(client_node_ptr, &patchbay_ptr->graph.clients)
  692. {
  693. client_ptr = list_entry(client_node_ptr, struct jack_graph_client, siblings);
  694. list_for_each(port_node_ptr, &client_ptr->ports)
  695. {
  696. port_ptr = list_entry(port_node_ptr, struct jack_graph_port, siblings_client);
  697. jack_info("%s:%s", client_ptr->name, port_ptr->name);
  698. sprintf(fullname, "%s:%s", client_ptr->name, port_ptr->name);
  699. if (!dbus_message_iter_append_basic (&sub_iter, DBUS_TYPE_STRING, &fullname_var))
  700. {
  701. pthread_mutex_unlock(&patchbay_ptr->lock);
  702. dbus_message_iter_close_container (&iter, &sub_iter);
  703. goto fail_unref;
  704. }
  705. }
  706. }
  707. pthread_mutex_unlock(&patchbay_ptr->lock);
  708. if (!dbus_message_iter_close_container (&iter, &sub_iter))
  709. {
  710. goto fail_unref;
  711. }
  712. return;
  713. fail_unref:
  714. dbus_message_unref (call->reply);
  715. call->reply = NULL;
  716. fail:
  717. jack_error ("Ran out of memory trying to construct method return");
  718. }
  719. static
  720. void
  721. jack_controller_dbus_get_graph(
  722. struct jack_dbus_method_call * call)
  723. {
  724. struct list_head * client_node_ptr;
  725. struct list_head * port_node_ptr;
  726. struct list_head * connection_node_ptr;
  727. struct jack_graph_client * client_ptr;
  728. struct jack_graph_port * port_ptr;
  729. struct jack_graph_connection * connection_ptr;
  730. DBusMessageIter iter;
  731. DBusMessageIter clients_array_iter;
  732. DBusMessageIter client_struct_iter;
  733. DBusMessageIter ports_array_iter;
  734. DBusMessageIter port_struct_iter;
  735. dbus_uint64_t version;
  736. DBusMessageIter connections_array_iter;
  737. DBusMessageIter connection_struct_iter;
  738. if (!controller_ptr->started)
  739. {
  740. jack_dbus_error(
  741. call,
  742. JACK_DBUS_ERROR_SERVER_NOT_RUNNING,
  743. "Can't execute this method with stopped JACK server");
  744. return;
  745. }
  746. if (!jack_dbus_get_method_args(call, DBUS_TYPE_UINT64, &version, DBUS_TYPE_INVALID))
  747. {
  748. /* The method call had invalid arguments meaning that
  749. * jack_dbus_get_method_args() has constructed an error for us.
  750. */
  751. goto exit;
  752. }
  753. //jack_info("Getting graph, know version is %" PRIu32, version);
  754. call->reply = dbus_message_new_method_return(call->message);
  755. if (!call->reply)
  756. {
  757. jack_error("Ran out of memory trying to construct method return");
  758. goto exit;
  759. }
  760. dbus_message_iter_init_append (call->reply, &iter);
  761. pthread_mutex_lock(&patchbay_ptr->lock);
  762. if (version > patchbay_ptr->graph.version)
  763. {
  764. jack_dbus_error(
  765. call,
  766. JACK_DBUS_ERROR_INVALID_ARGS,
  767. "known graph version %" PRIu64 " is newer than actual version %" PRIu64,
  768. version,
  769. patchbay_ptr->graph.version);
  770. pthread_mutex_unlock(&patchbay_ptr->lock);
  771. goto exit;
  772. }
  773. if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT64, &patchbay_ptr->graph.version))
  774. {
  775. goto nomem_unlock;
  776. }
  777. if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(tsa(tsuu))", &clients_array_iter))
  778. {
  779. goto nomem_unlock;
  780. }
  781. if (version < patchbay_ptr->graph.version)
  782. {
  783. list_for_each(client_node_ptr, &patchbay_ptr->graph.clients)
  784. {
  785. client_ptr = list_entry(client_node_ptr, struct jack_graph_client, siblings);
  786. if (!dbus_message_iter_open_container (&clients_array_iter, DBUS_TYPE_STRUCT, NULL, &client_struct_iter))
  787. {
  788. goto nomem_close_clients_array;
  789. }
  790. if (!dbus_message_iter_append_basic(&client_struct_iter, DBUS_TYPE_UINT64, &client_ptr->id))
  791. {
  792. goto nomem_close_client_struct;
  793. }
  794. if (!dbus_message_iter_append_basic(&client_struct_iter, DBUS_TYPE_STRING, &client_ptr->name))
  795. {
  796. goto nomem_close_client_struct;
  797. }
  798. if (!dbus_message_iter_open_container(&client_struct_iter, DBUS_TYPE_ARRAY, "(tsuu)", &ports_array_iter))
  799. {
  800. goto nomem_close_client_struct;
  801. }
  802. list_for_each(port_node_ptr, &client_ptr->ports)
  803. {
  804. port_ptr = list_entry(port_node_ptr, struct jack_graph_port, siblings_client);
  805. if (!dbus_message_iter_open_container(&ports_array_iter, DBUS_TYPE_STRUCT, NULL, &port_struct_iter))
  806. {
  807. goto nomem_close_ports_array;
  808. }
  809. if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT64, &port_ptr->id))
  810. {
  811. goto nomem_close_port_struct;
  812. }
  813. if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_STRING, &port_ptr->name))
  814. {
  815. goto nomem_close_port_struct;
  816. }
  817. if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT32, &port_ptr->flags))
  818. {
  819. goto nomem_close_port_struct;
  820. }
  821. if (!dbus_message_iter_append_basic(&port_struct_iter, DBUS_TYPE_UINT32, &port_ptr->type))
  822. {
  823. goto nomem_close_port_struct;
  824. }
  825. if (!dbus_message_iter_close_container(&ports_array_iter, &port_struct_iter))
  826. {
  827. goto nomem_close_ports_array;
  828. }
  829. }
  830. if (!dbus_message_iter_close_container(&client_struct_iter, &ports_array_iter))
  831. {
  832. goto nomem_close_client_struct;
  833. }
  834. if (!dbus_message_iter_close_container(&clients_array_iter, &client_struct_iter))
  835. {
  836. goto nomem_close_clients_array;
  837. }
  838. }
  839. }
  840. if (!dbus_message_iter_close_container(&iter, &clients_array_iter))
  841. {
  842. goto nomem_unlock;
  843. }
  844. if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(tstststst)", &connections_array_iter))
  845. {
  846. goto nomem_unlock;
  847. }
  848. if (version < patchbay_ptr->graph.version)
  849. {
  850. list_for_each(connection_node_ptr, &patchbay_ptr->graph.connections)
  851. {
  852. connection_ptr = list_entry(connection_node_ptr, struct jack_graph_connection, siblings);
  853. if (!dbus_message_iter_open_container(&connections_array_iter, DBUS_TYPE_STRUCT, NULL, &connection_struct_iter))
  854. {
  855. goto nomem_close_connections_array;
  856. }
  857. if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port1->client->id))
  858. {
  859. goto nomem_close_connection_struct;
  860. }
  861. if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port1->client->name))
  862. {
  863. goto nomem_close_connection_struct;
  864. }
  865. if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port1->id))
  866. {
  867. goto nomem_close_connection_struct;
  868. }
  869. if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port1->name))
  870. {
  871. goto nomem_close_connection_struct;
  872. }
  873. if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port2->client->id))
  874. {
  875. goto nomem_close_connection_struct;
  876. }
  877. if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port2->client->name))
  878. {
  879. goto nomem_close_connection_struct;
  880. }
  881. if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->port2->id))
  882. {
  883. goto nomem_close_connection_struct;
  884. }
  885. if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_STRING, &connection_ptr->port2->name))
  886. {
  887. goto nomem_close_connection_struct;
  888. }
  889. if (!dbus_message_iter_append_basic(&connection_struct_iter, DBUS_TYPE_UINT64, &connection_ptr->id))
  890. {
  891. goto nomem_close_connection_struct;
  892. }
  893. if (!dbus_message_iter_close_container(&connections_array_iter, &connection_struct_iter))
  894. {
  895. goto nomem_close_connections_array;
  896. }
  897. }
  898. }
  899. if (!dbus_message_iter_close_container(&iter, &connections_array_iter))
  900. {
  901. goto nomem_unlock;
  902. }
  903. pthread_mutex_unlock(&patchbay_ptr->lock);
  904. return;
  905. nomem_close_connection_struct:
  906. dbus_message_iter_close_container(&connections_array_iter, &connection_struct_iter);
  907. nomem_close_connections_array:
  908. dbus_message_iter_close_container(&iter, &connections_array_iter);
  909. goto nomem_unlock;
  910. nomem_close_port_struct:
  911. dbus_message_iter_close_container(&ports_array_iter, &port_struct_iter);
  912. nomem_close_ports_array:
  913. dbus_message_iter_close_container(&client_struct_iter, &ports_array_iter);
  914. nomem_close_client_struct:
  915. dbus_message_iter_close_container(&clients_array_iter, &client_struct_iter);
  916. nomem_close_clients_array:
  917. dbus_message_iter_close_container(&iter, &clients_array_iter);
  918. nomem_unlock:
  919. pthread_mutex_unlock(&patchbay_ptr->lock);
  920. //nomem:
  921. dbus_message_unref(call->reply);
  922. call->reply = NULL;
  923. jack_error("Ran out of memory trying to construct method return");
  924. exit:
  925. return;
  926. }
  927. static
  928. void
  929. jack_controller_dbus_connect_ports_by_name(
  930. struct jack_dbus_method_call * call)
  931. {
  932. const char * client1_name;
  933. const char * port1_name;
  934. const char * client2_name;
  935. const char * port2_name;
  936. struct jack_graph_port *port1_ptr;
  937. struct jack_graph_port *port2_ptr;
  938. /* jack_info("jack_controller_dbus_connect_ports_by_name() called."); */
  939. if (!controller_ptr->started)
  940. {
  941. jack_dbus_error(
  942. call,
  943. JACK_DBUS_ERROR_SERVER_NOT_RUNNING,
  944. "Can't execute this method with stopped JACK server");
  945. return;
  946. }
  947. if (!jack_dbus_get_method_args(
  948. call,
  949. DBUS_TYPE_STRING,
  950. &client1_name,
  951. DBUS_TYPE_STRING,
  952. &port1_name,
  953. DBUS_TYPE_STRING,
  954. &client2_name,
  955. DBUS_TYPE_STRING,
  956. &port2_name,
  957. DBUS_TYPE_INVALID))
  958. {
  959. /* The method call had invalid arguments meaning that
  960. * jack_dbus_get_method_args() has constructed an error for us.
  961. */
  962. return;
  963. }
  964. /* jack_info("connecting %s:%s and %s:%s", client1_name, port1_name, client2_name, port2_name); */
  965. pthread_mutex_lock(&patchbay_ptr->lock);
  966. port1_ptr = jack_controller_patchbay_find_port_by_names(patchbay_ptr, client1_name, port1_name);
  967. if (port1_ptr == NULL)
  968. {
  969. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port '%s':'%s'", client1_name, port1_name);
  970. goto unlock;
  971. }
  972. port2_ptr = jack_controller_patchbay_find_port_by_names(patchbay_ptr, client2_name, port2_name);
  973. if (port2_ptr == NULL)
  974. {
  975. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port '%s':'%s'", client2_name, port2_name);
  976. goto unlock;
  977. }
  978. if (!jack_controller_patchbay_connect(
  979. call,
  980. controller_ptr,
  981. port1_ptr,
  982. port2_ptr))
  983. {
  984. /* jack_controller_patchbay_connect() constructed error reply */
  985. goto unlock;
  986. }
  987. jack_dbus_construct_method_return_empty(call);
  988. unlock:
  989. pthread_mutex_unlock(&patchbay_ptr->lock);
  990. }
  991. static
  992. void
  993. jack_controller_dbus_connect_ports_by_id(
  994. struct jack_dbus_method_call * call)
  995. {
  996. dbus_uint64_t port1_id;
  997. dbus_uint64_t port2_id;
  998. struct jack_graph_port *port1_ptr;
  999. struct jack_graph_port *port2_ptr;
  1000. /* jack_info("jack_controller_dbus_connect_ports_by_id() called."); */
  1001. if (!controller_ptr->started)
  1002. {
  1003. jack_dbus_error(
  1004. call,
  1005. JACK_DBUS_ERROR_SERVER_NOT_RUNNING,
  1006. "Can't execute this method with stopped JACK server");
  1007. return;
  1008. }
  1009. if (!jack_dbus_get_method_args(
  1010. call,
  1011. DBUS_TYPE_UINT64,
  1012. &port1_id,
  1013. DBUS_TYPE_UINT64,
  1014. &port2_id,
  1015. DBUS_TYPE_INVALID))
  1016. {
  1017. /* The method call had invalid arguments meaning that
  1018. * jack_dbus_get_method_args() has constructed an error for us.
  1019. */
  1020. return;
  1021. }
  1022. pthread_mutex_lock(&patchbay_ptr->lock);
  1023. port1_ptr = jack_controller_patchbay_find_port_by_id(patchbay_ptr, port1_id);
  1024. if (port1_ptr == NULL)
  1025. {
  1026. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port %" PRIu64, port1_id);
  1027. goto unlock;
  1028. }
  1029. port2_ptr = jack_controller_patchbay_find_port_by_id(patchbay_ptr, port2_id);
  1030. if (port2_ptr == NULL)
  1031. {
  1032. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port %" PRIu64, port2_id);
  1033. goto unlock;
  1034. }
  1035. if (!jack_controller_patchbay_connect(
  1036. call,
  1037. controller_ptr,
  1038. port1_ptr,
  1039. port2_ptr))
  1040. {
  1041. /* jack_controller_patchbay_connect() constructed error reply */
  1042. goto unlock;
  1043. }
  1044. jack_dbus_construct_method_return_empty(call);
  1045. unlock:
  1046. pthread_mutex_unlock(&patchbay_ptr->lock);
  1047. }
  1048. static
  1049. void
  1050. jack_controller_dbus_disconnect_ports_by_name(
  1051. struct jack_dbus_method_call * call)
  1052. {
  1053. const char * client1_name;
  1054. const char * port1_name;
  1055. const char * client2_name;
  1056. const char * port2_name;
  1057. struct jack_graph_port *port1_ptr;
  1058. struct jack_graph_port *port2_ptr;
  1059. /* jack_info("jack_controller_dbus_disconnect_ports_by_name() called."); */
  1060. if (!controller_ptr->started)
  1061. {
  1062. jack_dbus_error(
  1063. call,
  1064. JACK_DBUS_ERROR_SERVER_NOT_RUNNING,
  1065. "Can't execute this method with stopped JACK server");
  1066. return;
  1067. }
  1068. if (!jack_dbus_get_method_args(
  1069. call,
  1070. DBUS_TYPE_STRING,
  1071. &client1_name,
  1072. DBUS_TYPE_STRING,
  1073. &port1_name,
  1074. DBUS_TYPE_STRING,
  1075. &client2_name,
  1076. DBUS_TYPE_STRING,
  1077. &port2_name,
  1078. DBUS_TYPE_INVALID))
  1079. {
  1080. /* The method call had invalid arguments meaning that
  1081. * jack_dbus_get_method_args() has constructed an error for us.
  1082. */
  1083. return;
  1084. }
  1085. /* jack_info("disconnecting %s:%s and %s:%s", client1_name, port1_name, client2_name, port2_name); */
  1086. pthread_mutex_lock(&patchbay_ptr->lock);
  1087. port1_ptr = jack_controller_patchbay_find_port_by_names(patchbay_ptr, client1_name, port1_name);
  1088. if (port1_ptr == NULL)
  1089. {
  1090. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port '%s':'%s'", client1_name, port1_name);
  1091. goto unlock;
  1092. }
  1093. port2_ptr = jack_controller_patchbay_find_port_by_names(patchbay_ptr, client2_name, port2_name);
  1094. if (port2_ptr == NULL)
  1095. {
  1096. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port '%s':'%s'", client2_name, port2_name);
  1097. goto unlock;
  1098. }
  1099. if (!jack_controller_patchbay_disconnect(
  1100. call,
  1101. controller_ptr,
  1102. port1_ptr,
  1103. port2_ptr))
  1104. {
  1105. /* jack_controller_patchbay_connect() constructed error reply */
  1106. goto unlock;
  1107. }
  1108. jack_dbus_construct_method_return_empty(call);
  1109. unlock:
  1110. pthread_mutex_unlock(&patchbay_ptr->lock);
  1111. }
  1112. static
  1113. void
  1114. jack_controller_dbus_disconnect_ports_by_id(
  1115. struct jack_dbus_method_call * call)
  1116. {
  1117. dbus_uint64_t port1_id;
  1118. dbus_uint64_t port2_id;
  1119. struct jack_graph_port *port1_ptr;
  1120. struct jack_graph_port *port2_ptr;
  1121. /* jack_info("jack_controller_dbus_disconnect_ports_by_id() called."); */
  1122. if (!controller_ptr->started)
  1123. {
  1124. jack_dbus_error(
  1125. call,
  1126. JACK_DBUS_ERROR_SERVER_NOT_RUNNING,
  1127. "Can't execute this method with stopped JACK server");
  1128. return;
  1129. }
  1130. if (!jack_dbus_get_method_args(
  1131. call,
  1132. DBUS_TYPE_UINT64,
  1133. &port1_id,
  1134. DBUS_TYPE_UINT64,
  1135. &port2_id,
  1136. DBUS_TYPE_INVALID))
  1137. {
  1138. /* The method call had invalid arguments meaning that
  1139. * jack_dbus_get_method_args() has constructed an error for us.
  1140. */
  1141. return;
  1142. }
  1143. pthread_mutex_lock(&patchbay_ptr->lock);
  1144. port1_ptr = jack_controller_patchbay_find_port_by_id(patchbay_ptr, port1_id);
  1145. if (port1_ptr == NULL)
  1146. {
  1147. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port %" PRIu64, port1_id);
  1148. return;
  1149. }
  1150. port2_ptr = jack_controller_patchbay_find_port_by_id(patchbay_ptr, port2_id);
  1151. if (port2_ptr == NULL)
  1152. {
  1153. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find port %" PRIu64, port2_id);
  1154. return;
  1155. }
  1156. if (!jack_controller_patchbay_disconnect(
  1157. call,
  1158. controller_ptr,
  1159. port1_ptr,
  1160. port2_ptr))
  1161. {
  1162. /* jack_controller_patchbay_connect() constructed error reply */
  1163. goto unlock;
  1164. }
  1165. jack_dbus_construct_method_return_empty(call);
  1166. unlock:
  1167. pthread_mutex_unlock(&patchbay_ptr->lock);
  1168. }
  1169. static
  1170. void
  1171. jack_controller_dbus_disconnect_ports_by_connection_id(
  1172. struct jack_dbus_method_call * call)
  1173. {
  1174. dbus_uint64_t connection_id;
  1175. struct jack_graph_connection *connection_ptr;
  1176. /* jack_info("jack_controller_dbus_disconnect_ports_by_id() called."); */
  1177. if (!jack_dbus_get_method_args(
  1178. call,
  1179. DBUS_TYPE_UINT64,
  1180. &connection_id,
  1181. DBUS_TYPE_INVALID))
  1182. {
  1183. /* The method call had invalid arguments meaning that
  1184. * jack_dbus_get_method_args() has constructed an error for us.
  1185. */
  1186. return;
  1187. }
  1188. pthread_mutex_lock(&patchbay_ptr->lock);
  1189. connection_ptr = jack_controller_patchbay_find_connection_by_id(patchbay_ptr, connection_id);
  1190. if (connection_ptr == NULL)
  1191. {
  1192. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find connection %" PRIu64, connection_id);
  1193. goto unlock;
  1194. }
  1195. if (!jack_controller_patchbay_disconnect(
  1196. call,
  1197. controller_ptr,
  1198. connection_ptr->port1,
  1199. connection_ptr->port2))
  1200. {
  1201. /* jack_controller_patchbay_connect() constructed error reply */
  1202. goto unlock;
  1203. }
  1204. jack_dbus_construct_method_return_empty(call);
  1205. unlock:
  1206. pthread_mutex_unlock(&patchbay_ptr->lock);
  1207. }
  1208. static
  1209. void
  1210. jack_controller_dbus_get_client_pid(
  1211. struct jack_dbus_method_call * call)
  1212. {
  1213. dbus_uint64_t client_id;
  1214. struct jack_graph_client *client_ptr;
  1215. message_arg_t arg;
  1216. /* jack_info("jack_controller_dbus_get_client_pid() called."); */
  1217. if (!jack_dbus_get_method_args(
  1218. call,
  1219. DBUS_TYPE_UINT64,
  1220. &client_id,
  1221. DBUS_TYPE_INVALID))
  1222. {
  1223. /* The method call had invalid arguments meaning that
  1224. * jack_dbus_get_method_args() has constructed an error for us.
  1225. */
  1226. return;
  1227. }
  1228. pthread_mutex_lock(&patchbay_ptr->lock);
  1229. client_ptr = jack_controller_patchbay_find_client_by_id(patchbay_ptr, client_id);
  1230. if (client_ptr == NULL)
  1231. {
  1232. jack_dbus_error(call, JACK_DBUS_ERROR_INVALID_ARGS, "cannot find client %" PRIu64, client_id);
  1233. goto unlock;
  1234. }
  1235. arg.int64 = client_ptr->pid;
  1236. jack_dbus_construct_method_return_single(call, DBUS_TYPE_INT64, arg);
  1237. unlock:
  1238. pthread_mutex_unlock(&patchbay_ptr->lock);
  1239. }
  1240. #undef controller_ptr
  1241. #define controller_ptr ((struct jack_controller *)context)
  1242. static
  1243. int
  1244. jack_controller_graph_order_callback(
  1245. void *context)
  1246. {
  1247. const char **ports;
  1248. int i;
  1249. jack_port_t *port_ptr;
  1250. if (patchbay_ptr->graph.version > 1)
  1251. {
  1252. /* we use this only for initial catchup */
  1253. return 0;
  1254. }
  1255. ports = jack_get_ports(controller_ptr->client, NULL, NULL, 0);
  1256. if (ports)
  1257. {
  1258. for (i = 0; ports[i]; ++i)
  1259. {
  1260. jack_info("graph reorder: new port '%s'", ports[i]);
  1261. port_ptr = jack_port_by_name(controller_ptr->client, ports[i]);;
  1262. jack_controller_patchbay_new_port(patchbay_ptr, ports[i], jack_port_flags(port_ptr), jack_port_type_id(port_ptr));
  1263. }
  1264. free(ports);
  1265. }
  1266. if (patchbay_ptr->graph.version == 1)
  1267. {
  1268. /* we have empty initial graph, increment graph version,
  1269. so we dont do jack_get_ports() again,
  1270. on next next graph change */
  1271. patchbay_ptr->graph.version++;
  1272. }
  1273. return 0;
  1274. }
  1275. void
  1276. jack_controller_client_registration_callback(
  1277. const char *client_name,
  1278. int created,
  1279. void *context)
  1280. {
  1281. if (created)
  1282. {
  1283. jack_log("client '%s' created", client_name);
  1284. jack_controller_patchbay_create_client(patchbay_ptr, client_name, strlen(client_name));
  1285. }
  1286. else
  1287. {
  1288. jack_log("client '%s' destroyed", client_name);
  1289. jack_controller_patchbay_destroy_client_by_name(patchbay_ptr, client_name);
  1290. }
  1291. }
  1292. void
  1293. jack_controller_port_registration_callback(
  1294. jack_port_id_t port_id,
  1295. int created,
  1296. void *context)
  1297. {
  1298. jack_port_t *port_ptr;
  1299. struct jack_graph_port *graph_port_ptr;
  1300. const char *port_name;
  1301. port_ptr = jack_port_by_id(controller_ptr->client, port_id);
  1302. port_name = jack_port_name(port_ptr);
  1303. if (created)
  1304. {
  1305. jack_log("port '%s' created", port_name);
  1306. jack_controller_patchbay_new_port(patchbay_ptr, port_name, jack_port_flags(port_ptr), jack_port_type_id(port_ptr));
  1307. }
  1308. else
  1309. {
  1310. jack_log("port '%s' destroyed", port_name);
  1311. graph_port_ptr = jack_controller_patchbay_find_port_by_full_name(patchbay_ptr, port_name);
  1312. if (graph_port_ptr == NULL)
  1313. {
  1314. jack_error("Failed to find port '%s' to destroy", port_name);
  1315. return;
  1316. }
  1317. jack_controller_patchbay_remove_port(patchbay_ptr, graph_port_ptr);
  1318. }
  1319. }
  1320. void
  1321. jack_controller_port_connect_callback(
  1322. jack_port_id_t port1_id,
  1323. jack_port_id_t port2_id,
  1324. int connect,
  1325. void *context)
  1326. {
  1327. jack_port_t *port1;
  1328. jack_port_t *port2;
  1329. const char *port1_name;
  1330. const char *port2_name;
  1331. struct jack_graph_port *port1_ptr;
  1332. struct jack_graph_port *port2_ptr;
  1333. struct jack_graph_connection *connection_ptr;
  1334. port1 = jack_port_by_id(controller_ptr->client, port1_id);
  1335. port2 = jack_port_by_id(controller_ptr->client, port2_id);
  1336. port1_name = jack_port_name(port1);
  1337. port2_name = jack_port_name(port2);
  1338. port1_ptr = jack_controller_patchbay_find_port_by_full_name(patchbay_ptr, port1_name);
  1339. if (port1_ptr == NULL)
  1340. {
  1341. jack_error("Failed to find port '%s' to [dis]connect", port1_name);
  1342. return;
  1343. }
  1344. port2_ptr = jack_controller_patchbay_find_port_by_full_name(patchbay_ptr, port2_name);
  1345. if (port2_ptr == NULL)
  1346. {
  1347. jack_error("Failed to find port '%s' to [dis]connect", port2_name);
  1348. return;
  1349. }
  1350. if (connect)
  1351. {
  1352. jack_info("Connecting '%s' to '%s'", port1_name, port2_name);
  1353. connection_ptr = jack_controller_patchbay_find_connection(patchbay_ptr, port1_ptr, port2_ptr);
  1354. if (connection_ptr != NULL)
  1355. {
  1356. jack_error("'%s' and '%s' are already connected", port1_name, port2_name);
  1357. return;
  1358. }
  1359. jack_controller_patchbay_create_connection(patchbay_ptr, port1_ptr, port2_ptr);
  1360. }
  1361. else
  1362. {
  1363. jack_info("Disonnecting '%s' from '%s'", port1_name, port2_name);
  1364. connection_ptr = jack_controller_patchbay_find_connection(patchbay_ptr, port1_ptr, port2_ptr);
  1365. if (connection_ptr == NULL)
  1366. {
  1367. jack_error("Cannot find connection being removed");
  1368. return;
  1369. }
  1370. jack_controller_patchbay_destroy_connection(patchbay_ptr, connection_ptr);
  1371. }
  1372. }
  1373. #undef controller_ptr
  1374. void
  1375. jack_controller_patchbay_uninit(
  1376. struct jack_controller * controller_ptr)
  1377. {
  1378. struct jack_graph_client *client_ptr;
  1379. struct jack_graph_port *port_ptr;
  1380. /* jack_info("jack_controller_patchbay_uninit() called"); */
  1381. while (!list_empty(&patchbay_ptr->graph.ports))
  1382. {
  1383. port_ptr = list_entry(patchbay_ptr->graph.ports.next, struct jack_graph_port, siblings_graph);
  1384. jack_controller_patchbay_remove_port(patchbay_ptr, port_ptr);
  1385. }
  1386. while (!list_empty(&patchbay_ptr->graph.clients))
  1387. {
  1388. client_ptr = list_entry(patchbay_ptr->graph.clients.next, struct jack_graph_client, siblings);
  1389. jack_controller_patchbay_destroy_client(patchbay_ptr, client_ptr);
  1390. }
  1391. pthread_mutex_destroy(&patchbay_ptr->lock);
  1392. }
  1393. #undef patchbay_ptr
  1394. bool
  1395. jack_controller_patchbay_init(
  1396. struct jack_controller * controller_ptr)
  1397. {
  1398. int ret;
  1399. struct jack_controller_patchbay * patchbay_ptr;
  1400. pthread_mutexattr_t attr;
  1401. /* jack_info("jack_controller_patchbay_init() called"); */
  1402. patchbay_ptr = malloc(sizeof(struct jack_controller_patchbay));
  1403. if (patchbay_ptr == NULL)
  1404. {
  1405. jack_error("Memory allocation of jack_controller_patchbay structure failed.");
  1406. goto fail;
  1407. }
  1408. ret = pthread_mutexattr_init(&attr);
  1409. if (ret != 0)
  1410. {
  1411. goto fail;
  1412. }
  1413. ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
  1414. if (ret != 0)
  1415. {
  1416. goto fail;
  1417. }
  1418. pthread_mutex_init(&patchbay_ptr->lock, &attr);
  1419. INIT_LIST_HEAD(&patchbay_ptr->graph.clients);
  1420. INIT_LIST_HEAD(&patchbay_ptr->graph.ports);
  1421. INIT_LIST_HEAD(&patchbay_ptr->graph.connections);
  1422. patchbay_ptr->graph.version = 1;
  1423. patchbay_ptr->next_client_id = 1;
  1424. patchbay_ptr->next_port_id = 1;
  1425. patchbay_ptr->next_connection_id = 1;
  1426. controller_ptr->patchbay_context = patchbay_ptr;
  1427. ret = jack_set_graph_order_callback(controller_ptr->client, jack_controller_graph_order_callback, controller_ptr);
  1428. if (ret != 0)
  1429. {
  1430. jack_error("jack_set_graph_order_callback() failed with error %d", ret);
  1431. goto fail_uninit_mutex;
  1432. }
  1433. ret = jack_set_client_registration_callback(controller_ptr->client, jack_controller_client_registration_callback, controller_ptr);
  1434. if (ret != 0)
  1435. {
  1436. jack_error("jack_set_client_registration_callback() failed with error %d", ret);
  1437. goto fail_uninit_mutex;
  1438. }
  1439. ret = jack_set_port_registration_callback(controller_ptr->client, jack_controller_port_registration_callback, controller_ptr);
  1440. if (ret != 0)
  1441. {
  1442. jack_error("jack_set_port_registration_callback() failed with error %d", ret);
  1443. goto fail_uninit_mutex;
  1444. }
  1445. ret = jack_set_port_connect_callback(controller_ptr->client, jack_controller_port_connect_callback, controller_ptr);
  1446. if (ret != 0)
  1447. {
  1448. jack_error("jack_set_port_connect_callback() failed with error %d", ret);
  1449. goto fail_uninit_mutex;
  1450. }
  1451. return true;
  1452. fail_uninit_mutex:
  1453. pthread_mutex_destroy(&patchbay_ptr->lock);
  1454. fail:
  1455. return false;
  1456. }
  1457. JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetAllPorts)
  1458. JACK_DBUS_METHOD_ARGUMENT("ports_list", "as", true)
  1459. JACK_DBUS_METHOD_ARGUMENTS_END
  1460. JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetGraph)
  1461. JACK_DBUS_METHOD_ARGUMENT("known_graph_version", DBUS_TYPE_UINT64_AS_STRING, false)
  1462. JACK_DBUS_METHOD_ARGUMENT("current_graph_version", DBUS_TYPE_UINT64_AS_STRING, true)
  1463. JACK_DBUS_METHOD_ARGUMENT("clients_and_ports", "a(tsa(tsuu))", true)
  1464. JACK_DBUS_METHOD_ARGUMENT("connections", "a(tstststst)", true)
  1465. JACK_DBUS_METHOD_ARGUMENTS_END
  1466. JACK_DBUS_METHOD_ARGUMENTS_BEGIN(ConnectPortsByName)
  1467. JACK_DBUS_METHOD_ARGUMENT("client1_name", DBUS_TYPE_STRING_AS_STRING, false)
  1468. JACK_DBUS_METHOD_ARGUMENT("port1_name", DBUS_TYPE_STRING_AS_STRING, false)
  1469. JACK_DBUS_METHOD_ARGUMENT("client2_name", DBUS_TYPE_STRING_AS_STRING, false)
  1470. JACK_DBUS_METHOD_ARGUMENT("port2_name", DBUS_TYPE_STRING_AS_STRING, false)
  1471. JACK_DBUS_METHOD_ARGUMENTS_END
  1472. JACK_DBUS_METHOD_ARGUMENTS_BEGIN(ConnectPortsByID)
  1473. JACK_DBUS_METHOD_ARGUMENT("port1_id", DBUS_TYPE_UINT64_AS_STRING, false)
  1474. JACK_DBUS_METHOD_ARGUMENT("port2_id", DBUS_TYPE_UINT64_AS_STRING, false)
  1475. JACK_DBUS_METHOD_ARGUMENTS_END
  1476. JACK_DBUS_METHOD_ARGUMENTS_BEGIN(DisconnectPortsByName)
  1477. JACK_DBUS_METHOD_ARGUMENT("client1_name", DBUS_TYPE_STRING_AS_STRING, false)
  1478. JACK_DBUS_METHOD_ARGUMENT("port1_name", DBUS_TYPE_STRING_AS_STRING, false)
  1479. JACK_DBUS_METHOD_ARGUMENT("client2_name", DBUS_TYPE_STRING_AS_STRING, false)
  1480. JACK_DBUS_METHOD_ARGUMENT("port2_name", DBUS_TYPE_STRING_AS_STRING, false)
  1481. JACK_DBUS_METHOD_ARGUMENTS_END
  1482. JACK_DBUS_METHOD_ARGUMENTS_BEGIN(DisconnectPortsByID)
  1483. JACK_DBUS_METHOD_ARGUMENT("port1_id", DBUS_TYPE_UINT64_AS_STRING, false)
  1484. JACK_DBUS_METHOD_ARGUMENT("port2_id", DBUS_TYPE_UINT64_AS_STRING, false)
  1485. JACK_DBUS_METHOD_ARGUMENTS_END
  1486. JACK_DBUS_METHOD_ARGUMENTS_BEGIN(DisconnectPortsByConnectionID)
  1487. JACK_DBUS_METHOD_ARGUMENT("connection_id", DBUS_TYPE_UINT64_AS_STRING, false)
  1488. JACK_DBUS_METHOD_ARGUMENTS_END
  1489. JACK_DBUS_METHOD_ARGUMENTS_BEGIN(GetClientPID)
  1490. JACK_DBUS_METHOD_ARGUMENT("client_id", DBUS_TYPE_INT64_AS_STRING, false)
  1491. JACK_DBUS_METHOD_ARGUMENTS_END
  1492. JACK_DBUS_METHODS_BEGIN
  1493. JACK_DBUS_METHOD_DESCRIBE(GetAllPorts, jack_controller_dbus_get_all_ports)
  1494. JACK_DBUS_METHOD_DESCRIBE(GetGraph, jack_controller_dbus_get_graph)
  1495. JACK_DBUS_METHOD_DESCRIBE(ConnectPortsByName, jack_controller_dbus_connect_ports_by_name)
  1496. JACK_DBUS_METHOD_DESCRIBE(ConnectPortsByID, jack_controller_dbus_connect_ports_by_id)
  1497. JACK_DBUS_METHOD_DESCRIBE(DisconnectPortsByName, jack_controller_dbus_disconnect_ports_by_name)
  1498. JACK_DBUS_METHOD_DESCRIBE(DisconnectPortsByID, jack_controller_dbus_disconnect_ports_by_id)
  1499. JACK_DBUS_METHOD_DESCRIBE(DisconnectPortsByConnectionID, jack_controller_dbus_disconnect_ports_by_connection_id)
  1500. JACK_DBUS_METHOD_DESCRIBE(GetClientPID, jack_controller_dbus_get_client_pid)
  1501. JACK_DBUS_METHODS_END
  1502. JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(GraphChanged)
  1503. JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
  1504. JACK_DBUS_SIGNAL_ARGUMENTS_END
  1505. JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(ClientAppeared)
  1506. JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
  1507. JACK_DBUS_SIGNAL_ARGUMENT("client_id", DBUS_TYPE_UINT64_AS_STRING)
  1508. JACK_DBUS_SIGNAL_ARGUMENT("client_name", DBUS_TYPE_STRING_AS_STRING)
  1509. JACK_DBUS_SIGNAL_ARGUMENTS_END
  1510. JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(ClientDisappeared)
  1511. JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
  1512. JACK_DBUS_SIGNAL_ARGUMENT("client_id", DBUS_TYPE_UINT64_AS_STRING)
  1513. JACK_DBUS_SIGNAL_ARGUMENT("client_name", DBUS_TYPE_STRING_AS_STRING)
  1514. JACK_DBUS_SIGNAL_ARGUMENTS_END
  1515. JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(PortAppeared)
  1516. JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
  1517. JACK_DBUS_SIGNAL_ARGUMENT("client_id", DBUS_TYPE_UINT64_AS_STRING)
  1518. JACK_DBUS_SIGNAL_ARGUMENT("client_name", DBUS_TYPE_STRING_AS_STRING)
  1519. JACK_DBUS_SIGNAL_ARGUMENT("port_id", DBUS_TYPE_UINT64_AS_STRING)
  1520. JACK_DBUS_SIGNAL_ARGUMENT("port_name", DBUS_TYPE_STRING_AS_STRING)
  1521. JACK_DBUS_SIGNAL_ARGUMENT("port_flags", DBUS_TYPE_UINT32_AS_STRING)
  1522. JACK_DBUS_SIGNAL_ARGUMENT("port_type", DBUS_TYPE_UINT32_AS_STRING)
  1523. JACK_DBUS_SIGNAL_ARGUMENTS_END
  1524. JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(PortDisappeared)
  1525. JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
  1526. JACK_DBUS_SIGNAL_ARGUMENT("client_id", DBUS_TYPE_UINT64_AS_STRING)
  1527. JACK_DBUS_SIGNAL_ARGUMENT("client_name", DBUS_TYPE_STRING_AS_STRING)
  1528. JACK_DBUS_SIGNAL_ARGUMENT("port_id", DBUS_TYPE_UINT64_AS_STRING)
  1529. JACK_DBUS_SIGNAL_ARGUMENT("port_name", DBUS_TYPE_STRING_AS_STRING)
  1530. JACK_DBUS_SIGNAL_ARGUMENTS_END
  1531. JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(PortsConnected)
  1532. JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
  1533. JACK_DBUS_SIGNAL_ARGUMENT("client1_id", DBUS_TYPE_UINT64_AS_STRING)
  1534. JACK_DBUS_SIGNAL_ARGUMENT("client1_name", DBUS_TYPE_STRING_AS_STRING)
  1535. JACK_DBUS_SIGNAL_ARGUMENT("port1_id", DBUS_TYPE_UINT64_AS_STRING)
  1536. JACK_DBUS_SIGNAL_ARGUMENT("port1_name", DBUS_TYPE_STRING_AS_STRING)
  1537. JACK_DBUS_SIGNAL_ARGUMENT("client2_id", DBUS_TYPE_UINT64_AS_STRING)
  1538. JACK_DBUS_SIGNAL_ARGUMENT("client2_name", DBUS_TYPE_STRING_AS_STRING)
  1539. JACK_DBUS_SIGNAL_ARGUMENT("port2_id", DBUS_TYPE_UINT64_AS_STRING)
  1540. JACK_DBUS_SIGNAL_ARGUMENT("port2_name", DBUS_TYPE_STRING_AS_STRING)
  1541. JACK_DBUS_SIGNAL_ARGUMENT("connection_id", DBUS_TYPE_UINT64_AS_STRING)
  1542. JACK_DBUS_SIGNAL_ARGUMENTS_END
  1543. JACK_DBUS_SIGNAL_ARGUMENTS_BEGIN(PortsDisconnected)
  1544. JACK_DBUS_SIGNAL_ARGUMENT("new_graph_version", DBUS_TYPE_UINT64_AS_STRING)
  1545. JACK_DBUS_SIGNAL_ARGUMENT("client1_id", DBUS_TYPE_UINT64_AS_STRING)
  1546. JACK_DBUS_SIGNAL_ARGUMENT("client1_name", DBUS_TYPE_STRING_AS_STRING)
  1547. JACK_DBUS_SIGNAL_ARGUMENT("port1_id", DBUS_TYPE_UINT64_AS_STRING)
  1548. JACK_DBUS_SIGNAL_ARGUMENT("port1_name", DBUS_TYPE_STRING_AS_STRING)
  1549. JACK_DBUS_SIGNAL_ARGUMENT("client2_id", DBUS_TYPE_UINT64_AS_STRING)
  1550. JACK_DBUS_SIGNAL_ARGUMENT("client2_name", DBUS_TYPE_STRING_AS_STRING)
  1551. JACK_DBUS_SIGNAL_ARGUMENT("port2_id", DBUS_TYPE_UINT64_AS_STRING)
  1552. JACK_DBUS_SIGNAL_ARGUMENT("port2_name", DBUS_TYPE_STRING_AS_STRING)
  1553. JACK_DBUS_SIGNAL_ARGUMENT("connection_id", DBUS_TYPE_UINT64_AS_STRING)
  1554. JACK_DBUS_SIGNAL_ARGUMENTS_END
  1555. JACK_DBUS_SIGNALS_BEGIN
  1556. JACK_DBUS_SIGNAL_DESCRIBE(GraphChanged)
  1557. JACK_DBUS_SIGNAL_DESCRIBE(ClientAppeared)
  1558. JACK_DBUS_SIGNAL_DESCRIBE(ClientDisappeared)
  1559. JACK_DBUS_SIGNAL_DESCRIBE(PortAppeared)
  1560. JACK_DBUS_SIGNAL_DESCRIBE(PortDisappeared)
  1561. JACK_DBUS_SIGNAL_DESCRIBE(PortsConnected)
  1562. JACK_DBUS_SIGNAL_DESCRIBE(PortsDisconnected)
  1563. JACK_DBUS_SIGNALS_END
  1564. JACK_DBUS_IFACE_BEGIN(g_jack_controller_iface_patchbay, JACK_DBUS_IFACE_NAME)
  1565. JACK_DBUS_IFACE_EXPOSE_METHODS
  1566. JACK_DBUS_IFACE_EXPOSE_SIGNALS
  1567. JACK_DBUS_IFACE_END