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.

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