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.

778 lines
24KB

  1. /*
  2. Copyright (C) 2001 Paul Davis
  3. Copyright (C) 2004-2006 Grame
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  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. #include "JackGraphManager.h"
  17. #include "JackConstants.h"
  18. #include <assert.h>
  19. #include <stdlib.h>
  20. #include <algorithm>
  21. #include <regex.h>
  22. namespace Jack
  23. {
  24. static inline jack_nframes_t MAX(jack_nframes_t a, jack_nframes_t b)
  25. {
  26. return (a < b) ? b : a;
  27. }
  28. static void AssertPort(jack_port_id_t port_index)
  29. {
  30. if (port_index >= PORT_NUM) {
  31. JackLog("JackGraphManager::AssertPort port_index = %ld\n", port_index);
  32. assert(port_index < PORT_NUM);
  33. }
  34. }
  35. static void AssertBufferSize(jack_nframes_t frames)
  36. {
  37. if (frames > BUFFER_SIZE_MAX) {
  38. JackLog("JackGraphManager::AssertBufferSize frames = %ld\n", frames);
  39. assert(frames <= BUFFER_SIZE_MAX);
  40. }
  41. }
  42. JackPort* JackGraphManager::GetPort(jack_port_id_t port_index)
  43. {
  44. AssertPort(port_index);
  45. return &fPortArray[port_index];
  46. }
  47. float* JackGraphManager::GetBuffer(jack_port_id_t port_index)
  48. {
  49. return fPortArray[port_index].GetBuffer();
  50. }
  51. // RT, client
  52. int JackGraphManager::GetConnectionsNum(jack_port_id_t port_index)
  53. {
  54. JackConnectionManager* manager = ReadCurrentState();
  55. return manager->Connections(port_index);
  56. }
  57. // Server
  58. int JackGraphManager::AllocateRefNum()
  59. {
  60. JackConnectionManager* manager = WriteNextStateStart();
  61. int res = manager->AllocateRefNum();
  62. WriteNextStateStop();
  63. return res;
  64. }
  65. // Server
  66. void JackGraphManager::ReleaseRefNum(int refnum)
  67. {
  68. JackConnectionManager* manager = WriteNextStateStart();
  69. manager->ReleaseRefNum(refnum);
  70. WriteNextStateStop();
  71. }
  72. // RT
  73. void JackGraphManager::RunCurrentGraph()
  74. {
  75. JackConnectionManager* manager = ReadCurrentState();
  76. manager->ResetGraph(fClientTiming);
  77. }
  78. // RT
  79. bool JackGraphManager::RunNextGraph()
  80. {
  81. bool res;
  82. JackConnectionManager* manager = TrySwitchState(&res);
  83. manager->ResetGraph(fClientTiming);
  84. return res;
  85. }
  86. // RT
  87. bool JackGraphManager::IsFinishedGraph()
  88. {
  89. JackConnectionManager* manager = ReadCurrentState();
  90. return (manager->GetActivation(FREEWHEEL_DRIVER_REFNUM) == 0);
  91. }
  92. // RT
  93. int JackGraphManager::ResumeRefNum(JackClientControl* control, JackSynchro** table)
  94. {
  95. JackConnectionManager* manager = ReadCurrentState();
  96. return manager->ResumeRefNum(control, table, fClientTiming);
  97. }
  98. // RT
  99. int JackGraphManager::SuspendRefNum(JackClientControl* control, JackSynchro** table, long usec)
  100. {
  101. JackConnectionManager* manager = ReadCurrentState();
  102. return manager->SuspendRefNum(control, table, fClientTiming, usec);
  103. }
  104. JackClientTiming* JackGraphManager::GetClientTiming(int ref)
  105. {
  106. return &fClientTiming[ref];
  107. }
  108. // Server
  109. void JackGraphManager::DirectConnect(int ref1, int ref2)
  110. {
  111. JackConnectionManager* manager = WriteNextStateStart();
  112. manager->DirectConnect(ref1, ref2);
  113. JackLog("JackGraphManager::ConnectRefNum cur_index = %ld ref1 = %ld ref2 = %ld\n", CurIndex(fCounter), ref1, ref2);
  114. WriteNextStateStop();
  115. }
  116. // Server
  117. void JackGraphManager::DirectDisconnect(int ref1, int ref2)
  118. {
  119. JackConnectionManager* manager = WriteNextStateStart();
  120. manager->DirectDisconnect(ref1, ref2);
  121. JackLog("JackGraphManager::DisconnectRefNum cur_index = %ld ref1 = %ld ref2 = %ld\n", CurIndex(fCounter), ref1, ref2);
  122. WriteNextStateStop();
  123. }
  124. // Server
  125. bool JackGraphManager::IsDirectConnection(int ref1, int ref2)
  126. {
  127. JackConnectionManager* manager = ReadCurrentState();
  128. return manager->IsDirectConnection(ref1, ref2);
  129. }
  130. // RT
  131. void* JackGraphManager::GetBuffer(jack_port_id_t port_index, jack_nframes_t frames)
  132. {
  133. AssertPort(port_index);
  134. AssertBufferSize(frames);
  135. JackConnectionManager* manager = ReadCurrentState();
  136. JackPort* port = GetPort(port_index);
  137. if (!port->IsUsed()) {
  138. // This happens when a port has just been unregistered and is still used by the RT code.
  139. JackLog("JackGraphManager::GetBuffer : port = %ld is released state\n", port_index);
  140. return GetBuffer(0); // port_index 0 is not used
  141. }
  142. // Output port
  143. if (port->fFlags & JackPortIsOutput) {
  144. return (port->fTied != NO_PORT) ? GetBuffer(port->fTied, frames) : GetBuffer(port_index);
  145. }
  146. // Input port
  147. jack_int_t len = manager->Connections(port_index);
  148. if (len == 0) { // No connections: return a zero-filled buffer
  149. float* buffer = GetBuffer(port_index);
  150. memset(buffer, 0, frames * sizeof(float)); // Clear buffer
  151. return buffer;
  152. } else if (len == 1) { // One connection: use zero-copy mode - just pass the buffer of the connected (output) port.
  153. assert(manager->GetPort(port_index, 0) != port_index); // Check recursion
  154. return GetBuffer(manager->GetPort(port_index, 0), frames);
  155. } else { // Multiple connections
  156. const jack_int_t* connections = manager->GetConnections(port_index);
  157. float* mixbuffer = GetBuffer(port_index);
  158. jack_port_id_t src_index;
  159. float* buffer;
  160. // Copy first buffer
  161. src_index = connections[0];
  162. AssertPort(src_index);
  163. buffer = (float*)GetBuffer(src_index, frames);
  164. memcpy(mixbuffer, buffer, frames * sizeof(float));
  165. // Mix remaining buffers
  166. for (int i = 1; (i < CONNECTION_NUM) && ((src_index = connections[i]) != EMPTY); i++) {
  167. AssertPort(src_index);
  168. buffer = (float*)GetBuffer(src_index, frames);
  169. JackPort::MixBuffer(mixbuffer, buffer, frames);
  170. }
  171. return mixbuffer;
  172. }
  173. }
  174. int JackGraphManager::RequestMonitor(jack_port_id_t port_index, bool onoff) // Client
  175. {
  176. AssertPort(port_index);
  177. JackPort* port = GetPort(port_index);
  178. /**
  179. jackd.h
  180. * If @ref JackPortCanMonitor is set for this @a port, turn input
  181. * monitoring on or off. Otherwise, do nothing.
  182. if (!(fFlags & JackPortCanMonitor))
  183. return -1;
  184. */
  185. port->RequestMonitor(onoff);
  186. const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index);
  187. if ((port->fFlags & JackPortIsOutput) == 0) { // ?? Taken from jack, why not (port->fFlags & JackPortIsInput) ?
  188. jack_port_id_t src_index;
  189. for (int i = 0; (i < CONNECTION_NUM) && ((src_index = connections[i]) != EMPTY); i++) {
  190. // XXX much worse things will happen if there is a feedback loop !!!
  191. RequestMonitor(src_index, onoff);
  192. }
  193. }
  194. return 0;
  195. }
  196. jack_nframes_t JackGraphManager::GetTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count)
  197. {
  198. const jack_int_t* connections = manager->GetConnections(port_index);
  199. jack_nframes_t latency = GetPort(port_index)->GetLatency();
  200. jack_nframes_t max_latency = 0;
  201. jack_port_id_t dst_index;
  202. if (hop_count > 8)
  203. return latency;
  204. for (int i = 0; (i < CONNECTION_NUM) && ((dst_index = connections[i]) != EMPTY); i++) {
  205. if (src_port_index != dst_index) {
  206. AssertPort(dst_index);
  207. JackPort* dst_port = GetPort(dst_index);
  208. jack_nframes_t this_latency = (dst_port->fFlags & JackPortIsTerminal)
  209. ? dst_port->GetLatency()
  210. : GetTotalLatencyAux(dst_index, port_index, manager, hop_count + 1);
  211. max_latency = MAX(max_latency, this_latency);
  212. }
  213. }
  214. return max_latency + latency;
  215. }
  216. jack_nframes_t JackGraphManager::GetTotalLatency(jack_port_id_t port_index)
  217. {
  218. UInt16 cur_index;
  219. UInt16 next_index;
  220. jack_nframes_t total_latency;
  221. AssertPort(port_index);
  222. JackLog("JackGraphManager::GetTotalLatency port_index = %ld\n", port_index);
  223. do {
  224. cur_index = GetCurrentIndex();
  225. total_latency = GetTotalLatencyAux(port_index, port_index, ReadCurrentState(), 0);
  226. next_index = GetCurrentIndex();
  227. } while (cur_index != next_index); // Until a coherent state has been read
  228. return total_latency;
  229. }
  230. // Server
  231. jack_port_id_t JackGraphManager::AllocatePortAux(int refnum, const char* port_name, JackPortFlags flags)
  232. {
  233. jack_port_id_t port_index;
  234. // Look for first available port Port index start at 1, otherwise a port_index of 0 is "seen" as a NULL port by the external API...
  235. for (port_index = 1; port_index < PORT_NUM; port_index++) {
  236. JackPort* port = GetPort(port_index);
  237. if (!port->IsUsed()) {
  238. JackLog("JackGraphManager::AllocatePortAux port_index = %ld name = %s\n", port_index, port_name);
  239. port->Allocate(refnum, port_name, flags);
  240. break;
  241. }
  242. }
  243. return (port_index < PORT_NUM) ? port_index : NO_PORT;
  244. }
  245. // Server
  246. jack_port_id_t JackGraphManager::AllocatePort(int refnum, const char* port_name, JackPortFlags flags)
  247. {
  248. JackConnectionManager* manager = WriteNextStateStart();
  249. jack_port_id_t port_index = AllocatePortAux(refnum, port_name, flags);
  250. if (port_index != NO_PORT) {
  251. int res;
  252. if (flags & JackPortIsOutput) {
  253. res = manager->AddOutputPort(refnum, port_index);
  254. } else {
  255. res = manager->AddInputPort(refnum, port_index);
  256. }
  257. if (res < 0) {
  258. JackPort* port = GetPort(port_index);
  259. assert(port);
  260. port->Release();
  261. port_index = NO_PORT;
  262. }
  263. }
  264. WriteNextStateStop();
  265. return port_index;
  266. }
  267. // Server
  268. void JackGraphManager::ReleasePort(jack_port_id_t port_index)
  269. {
  270. JackPort* port = GetPort(port_index);
  271. port->Release();
  272. }
  273. // Server
  274. int JackGraphManager::RemovePort(int refnum, jack_port_id_t port_index)
  275. {
  276. JackConnectionManager* manager = WriteNextStateStart();
  277. JackPort* port = GetPort(port_index);
  278. int res;
  279. if (port->fFlags & JackPortIsOutput) {
  280. DisconnectAllOutput(port_index);
  281. res = manager->RemoveOutputPort(refnum, port_index);
  282. } else {
  283. DisconnectAllInput(port_index);
  284. res = manager->RemoveInputPort(refnum, port_index);
  285. }
  286. WriteNextStateStop();
  287. return res;
  288. }
  289. // Server
  290. void JackGraphManager::RemoveAllPorts(int refnum)
  291. {
  292. JackLog("JackGraphManager::RemoveAllPorts ref = %ld\n", refnum);
  293. JackConnectionManager* manager = WriteNextStateStart();
  294. jack_port_id_t port_index;
  295. // Warning : RemovePort shift port to left, thus we always remove the first port until the "input" table is empty
  296. const jack_int_t* input = manager->GetInputPorts(refnum);
  297. while ((port_index = input[0]) != EMPTY) {
  298. RemovePort(refnum, port_index);
  299. ReleasePort(port_index);
  300. }
  301. // Warning : RemovePort shift port to left, thus we always remove the first port until the "output" table is empty
  302. const jack_int_t* output = manager->GetOutputPorts(refnum);
  303. while ((port_index = output[0]) != EMPTY) {
  304. RemovePort(refnum, port_index);
  305. ReleasePort(port_index);
  306. }
  307. WriteNextStateStop();
  308. }
  309. // Server
  310. void JackGraphManager::DisconnectAllPorts(int refnum)
  311. {
  312. int i;
  313. JackLog("JackGraphManager::DisconnectAllPorts ref = %ld\n", refnum);
  314. JackConnectionManager* manager = WriteNextStateStart();
  315. const jack_int_t* input = manager->GetInputPorts(refnum);
  316. for (i = 0; i < PORT_NUM_FOR_CLIENT && input[i] != EMPTY ; i++) {
  317. DisconnectAllInput(input[i]);
  318. }
  319. const jack_int_t* output = manager->GetOutputPorts(refnum);
  320. for (i = 0; i < PORT_NUM_FOR_CLIENT && output[i] != EMPTY; i++) {
  321. DisconnectAllOutput(output[i]);
  322. }
  323. WriteNextStateStop();
  324. }
  325. // Server
  326. void JackGraphManager::DisconnectAllInput(jack_port_id_t port_index)
  327. {
  328. JackLog("JackGraphManager::DisconnectAllInput port_index = %ld \n", port_index);
  329. JackConnectionManager* manager = WriteNextStateStart();
  330. for (int i = 0; i < PORT_NUM; i++) {
  331. if (manager->IsConnected(i, port_index)) {
  332. JackLog("JackGraphManager::Disconnect i = %ld port_index = %ld\n", i, port_index);
  333. Disconnect(i, port_index);
  334. }
  335. }
  336. WriteNextStateStop();
  337. }
  338. // Server
  339. void JackGraphManager::DisconnectAllOutput(jack_port_id_t port_index)
  340. {
  341. JackLog("JackGraphManager::DisconnectAllOutput port_index = %ld \n", port_index);
  342. JackConnectionManager* manager = WriteNextStateStart();
  343. const jack_int_t* connections = manager->GetConnections(port_index);
  344. while (connections[0] != EMPTY) {
  345. Disconnect(port_index, connections[0]); // Warning : Disconnect shift port to left
  346. }
  347. WriteNextStateStop();
  348. }
  349. // Server
  350. int JackGraphManager::DisconnectAll(jack_port_id_t port_index)
  351. {
  352. AssertPort(port_index);
  353. JackPort* port = GetPort(port_index);
  354. if (port->fFlags & JackPortIsOutput) {
  355. DisconnectAllOutput(port_index);
  356. } else {
  357. DisconnectAllInput(port_index);
  358. }
  359. return 0;
  360. }
  361. // Server
  362. int JackGraphManager::GetInputRefNum(jack_port_id_t port_index)
  363. {
  364. AssertPort(port_index);
  365. JackConnectionManager* manager = WriteNextStateStart();
  366. int res = manager->GetInputRefNum(port_index);
  367. WriteNextStateStop();
  368. return res;
  369. }
  370. // Server
  371. int JackGraphManager::GetOutputRefNum(jack_port_id_t port_index)
  372. {
  373. AssertPort(port_index);
  374. JackConnectionManager* manager = WriteNextStateStart();
  375. int res = manager->GetOutputRefNum(port_index);
  376. WriteNextStateStop();
  377. return res;
  378. }
  379. int JackGraphManager::Connect(jack_port_id_t port_src, jack_port_id_t port_dst)
  380. {
  381. JackConnectionManager* manager = WriteNextStateStart();
  382. JackLog("JackGraphManager::Connect port_src = %ld port_dst = %ld\n", port_src, port_dst);
  383. bool in_use_src = GetPort(port_src)->fInUse;
  384. bool in_use_dst = GetPort(port_src)->fInUse;
  385. int res = 0;
  386. if (!in_use_src || !in_use_dst) {
  387. if (!in_use_src)
  388. jack_error("JackGraphManager::Connect: port_src not %ld used name = %s", port_src, GetPort(port_src)->fName);
  389. if (!in_use_dst)
  390. jack_error("JackGraphManager::Connect: port_dst not %ld used name = %s", port_dst, GetPort(port_dst)->fName);
  391. res = -1;
  392. goto end;
  393. }
  394. if (manager->IsConnected(port_src, port_dst)) {
  395. jack_error("JackGraphManager::Connect already connected port_src = %ld port_dst = %ld", port_src, port_dst);
  396. res = EEXIST;
  397. goto end;
  398. }
  399. res = manager->Connect(port_src, port_dst);
  400. if (res < 0) {
  401. jack_error("JackGraphManager::Connect failed port_src = %ld port_dst = %ld", port_src, port_dst);
  402. goto end;
  403. }
  404. manager->Connect(port_dst, port_src);
  405. if (res < 0) {
  406. jack_error("JackGraphManager::Connect failed port_src = %ld port_dst = %ld", port_dst, port_src);
  407. goto end;
  408. }
  409. if (manager->IsLoopPath(port_src, port_dst)) {
  410. JackLog("JackGraphManager::Connect: LOOP detected\n");
  411. manager->IncFeedbackConnection(port_src, port_dst);
  412. } else {
  413. manager->IncDirectConnection(port_src, port_dst);
  414. }
  415. end:
  416. WriteNextStateStop();
  417. if (res < 0)
  418. jack_error("JackGraphManager::Connect failed port_src = %ld port_dst = %ld", port_dst, port_src);
  419. return res;
  420. }
  421. // Server
  422. int JackGraphManager::Disconnect(jack_port_id_t port_src, jack_port_id_t port_dst)
  423. {
  424. JackConnectionManager* manager = WriteNextStateStart();
  425. JackLog("JackGraphManager::Disconnect port_src = %ld port_dst = %ld\n", port_src, port_dst);
  426. bool in_use_src = GetPort(port_src)->fInUse;
  427. bool in_use_dst = GetPort(port_src)->fInUse;
  428. int res = 0;
  429. if (!in_use_src || !in_use_dst) {
  430. if (!in_use_src)
  431. jack_error("JackGraphManager::Disconnect: port_src not %ld used name = %s", port_src, GetPort(port_src)->fName);
  432. if (!in_use_dst)
  433. jack_error("JackGraphManager::Disconnect: port_src not %ld used name = %s", port_dst, GetPort(port_dst)->fName);
  434. res = -1;
  435. goto end;
  436. }
  437. if (!manager->IsConnected(port_src, port_dst)) {
  438. jack_error("JackGraphManager::Disconnect not connected port_src = %ld port_dst = %ld", port_src, port_dst);
  439. res = -1;
  440. goto end;
  441. }
  442. manager->Disconnect(port_src, port_dst);
  443. if (res < 0) {
  444. jack_error("JackGraphManager::Disconnect failed port_src = %ld port_dst = %ld", port_src, port_dst);
  445. goto end;
  446. }
  447. manager->Disconnect(port_dst, port_src);
  448. if (res < 0) {
  449. jack_error("JackGraphManager::Disconnect failed port_src = %ld port_dst = %ld", port_dst, port_src);
  450. goto end;
  451. }
  452. if (manager->IsFeedbackConnection(port_src, port_dst)) {
  453. JackLog("JackGraphManager::Disconnect: FEEDBACK removed\n");
  454. manager->DecFeedbackConnection(port_src, port_dst);
  455. } else {
  456. manager->DecDirectConnection(port_src, port_dst);
  457. }
  458. end:
  459. WriteNextStateStop();
  460. return res;
  461. }
  462. // Client
  463. int JackGraphManager::ConnectedTo(jack_port_id_t port_src, const char* port_name)
  464. {
  465. JackLog("JackGraphManager::ConnectedTo port_src = %ld port_name = %s\n", port_src, port_name);
  466. JackConnectionManager* manager = ReadCurrentState();
  467. jack_port_id_t port_dst;
  468. if ((port_dst = GetPort(port_name)) == NO_PORT) {
  469. jack_error("Unknown destination port port_name = %s", port_name);
  470. return 0;
  471. } else {
  472. return manager->IsConnected(port_src, port_dst);
  473. }
  474. }
  475. // Server
  476. int JackGraphManager::CheckPort(jack_port_id_t port_index)
  477. {
  478. JackPort* port = GetPort(port_index);
  479. if (port->fLocked) {
  480. jack_error("Port %s is locked against connection changes", port->fName);
  481. return -1;
  482. } else {
  483. return 0;
  484. }
  485. }
  486. int JackGraphManager::CheckPorts(jack_port_id_t port_src, jack_port_id_t port_dst)
  487. {
  488. JackPort* src = GetPort(port_src);
  489. JackPort* dst = GetPort(port_dst);
  490. if ((dst->Flags() & JackPortIsInput) == 0) {
  491. jack_error("Destination port in attempted (dis)connection of %s and %s is not an input port", src->fName, dst->fName);
  492. return -1;
  493. }
  494. if ((src->Flags() & JackPortIsOutput) == 0) {
  495. jack_error("Source port in attempted (dis)connection of %s and %s is not an output port", src->fName, dst->fName);
  496. return -1;
  497. }
  498. if (src->fLocked) {
  499. jack_error("Source port %s is locked against connection changes", src->fName);
  500. return -1;
  501. }
  502. if (dst->fLocked) {
  503. jack_error("Destination port %s is locked against connection changes", dst->fName);
  504. return -1;
  505. }
  506. return 0;
  507. }
  508. int JackGraphManager::CheckPorts(const char* src_name, const char* dst_name, jack_port_id_t* port_src, jack_port_id_t* port_dst)
  509. {
  510. JackLog("JackGraphManager::CheckConnect src_name = %s dst_name = %s\n", src_name, dst_name);
  511. if ((*port_src = GetPort(src_name)) == NO_PORT) {
  512. jack_error("Unknown source port in attempted (dis)connection src_name [%s] dst_name [%s]", src_name, dst_name);
  513. return -1;
  514. }
  515. if ((*port_dst = GetPort(dst_name)) == NO_PORT) {
  516. jack_error("Unknown destination port in attempted (dis)connection src_name [%s] dst_name [%s]", src_name, dst_name);
  517. return -1;
  518. }
  519. return CheckPorts(*port_src, *port_dst);
  520. }
  521. // Client : port array
  522. jack_port_id_t JackGraphManager::GetPort(const char* name)
  523. {
  524. for (int i = 0; i < PORT_NUM; i++) {
  525. JackPort* port = GetPort(i);
  526. if (port->IsUsed() && strcmp(port->fName, name) == 0)
  527. return i;
  528. }
  529. return NO_PORT;
  530. }
  531. /*!
  532. \brief Get the connection port name array.
  533. */
  534. // Client
  535. void JackGraphManager::GetConnectionsAux(JackConnectionManager* manager, const char** res, jack_port_id_t port_index)
  536. {
  537. const jack_int_t* connections = manager->GetConnections(port_index);
  538. jack_int_t index;
  539. int i;
  540. for (i = 0; (i < CONNECTION_NUM) && ((index = connections[i]) != EMPTY) ; i++) {
  541. JackPort* port = GetPort(index);
  542. res[i] = port->fName;
  543. }
  544. res[i] = NULL;
  545. }
  546. // Client
  547. /*
  548. Use the state returned by ReadCurrentState and check that the state was not changed during the read operation.
  549. The operation is lock-free since there is no intermediate state in the write operation that could cause the
  550. read to loop forever.
  551. */
  552. const char** JackGraphManager::GetConnections(jack_port_id_t port_index)
  553. {
  554. const char** res = (const char**)malloc(sizeof(char*) * (CONNECTION_NUM + 1));
  555. UInt16 cur_index;
  556. UInt16 next_index;
  557. AssertPort(port_index);
  558. do {
  559. cur_index = GetCurrentIndex();
  560. GetConnectionsAux(ReadCurrentState(), res, port_index);
  561. next_index = GetCurrentIndex();
  562. } while (cur_index != next_index); // Until a coherent state has been read
  563. return res;
  564. }
  565. // Client
  566. const char** JackGraphManager::GetPortsAux(const char* port_name_pattern, const char* type_name_pattern, unsigned long flags)
  567. {
  568. const char** matching_ports;
  569. unsigned long match_cnt = 0;
  570. regex_t port_regex;
  571. regex_t type_regex;
  572. bool matching;
  573. if (port_name_pattern && port_name_pattern[0]) {
  574. regcomp(&port_regex, port_name_pattern, REG_EXTENDED | REG_NOSUB);
  575. }
  576. if (type_name_pattern && type_name_pattern[0]) {
  577. regcomp(&type_regex, type_name_pattern, REG_EXTENDED | REG_NOSUB);
  578. }
  579. matching_ports = (const char**)malloc(sizeof(char*) * PORT_NUM);
  580. for (int i = 0; i < PORT_NUM; i++) {
  581. matching = true;
  582. JackPort* port = GetPort(i);
  583. if (port->IsUsed()) {
  584. if (flags) {
  585. if ((port->fFlags & flags) != flags) {
  586. matching = false;
  587. }
  588. }
  589. if (matching && port_name_pattern && port_name_pattern[0]) {
  590. if (regexec(&port_regex, port->fName, 0, NULL, 0)) {
  591. matching = false;
  592. }
  593. }
  594. /*
  595. if (matching && type_name_pattern && type_name_pattern[0]) {
  596. jack_port_type_id_t ptid = psp[i].ptype_id;
  597. if (regexec (&type_regex,engine->port_types[ptid].type_name,0, NULL, 0)) {
  598. matching = false;
  599. }
  600. }
  601. */
  602. // TO BE IMPROVED
  603. if (matching && type_name_pattern && type_name_pattern[0]) {
  604. if (regexec(&type_regex, JACK_DEFAULT_AUDIO_TYPE, 0, NULL, 0)) {
  605. matching = false;
  606. }
  607. }
  608. if (matching) {
  609. matching_ports[match_cnt++] = port->fName;
  610. }
  611. }
  612. }
  613. matching_ports[match_cnt] = 0;
  614. if (match_cnt == 0) {
  615. free(matching_ports);
  616. matching_ports = NULL;
  617. }
  618. return matching_ports;
  619. }
  620. // Client
  621. /*
  622. Check that the state was not changed during the read operation.
  623. The operation is lock-free since there is no intermediate state in the write operation that could cause the
  624. read to loop forever.
  625. */
  626. const char** JackGraphManager::GetPorts(const char* port_name_pattern, const char* type_name_pattern, unsigned long flags)
  627. {
  628. const char** matching_ports = NULL;
  629. UInt16 cur_index;
  630. UInt16 next_index;
  631. do {
  632. cur_index = GetCurrentIndex();
  633. if (matching_ports)
  634. free(matching_ports);
  635. matching_ports = GetPortsAux(port_name_pattern, type_name_pattern, flags);
  636. next_index = GetCurrentIndex();
  637. } while (cur_index != next_index); // Until a coherent state has been read
  638. return matching_ports;
  639. }
  640. // Server
  641. void JackGraphManager::Save(JackConnectionManager* dst)
  642. {
  643. JackConnectionManager* manager = WriteNextStateStart();
  644. memcpy(dst, manager, sizeof(JackConnectionManager));
  645. WriteNextStateStop();
  646. }
  647. // Server
  648. void JackGraphManager::Restore(JackConnectionManager* src)
  649. {
  650. JackConnectionManager* manager = WriteNextStateStart();
  651. memcpy(manager, src, sizeof(JackConnectionManager));
  652. WriteNextStateStop();
  653. }
  654. } // end of namespace