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.

822 lines
25KB

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