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.

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