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.

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