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.

809 lines
25KB

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