Fix XCode project.
[jack2.git] / common / JackGraphManager.cpp
blobd16becd6c32804fe9d48db723b1b64132ee6a1fb
1 /*
2 Copyright (C) 2001 Paul Davis
3 Copyright (C) 2004-2008 Grame
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #include "JackGraphManager.h"
22 #include "JackConstants.h"
23 #include "JackError.h"
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <algorithm>
27 #include <regex.h>
29 namespace Jack
32 static void AssertPort(jack_port_id_t port_index)
34 if (port_index >= PORT_NUM) {
35 jack_log("JackGraphManager::AssertPort port_index = %ld", port_index);
36 assert(port_index < PORT_NUM);
40 static void AssertBufferSize(jack_nframes_t buffer_size)
42 if (buffer_size > BUFFER_SIZE_MAX) {
43 jack_log("JackGraphManager::AssertBufferSize frames = %ld", buffer_size);
44 assert(buffer_size <= BUFFER_SIZE_MAX);
48 JackPort* JackGraphManager::GetPort(jack_port_id_t port_index)
50 AssertPort(port_index);
51 return &fPortArray[port_index];
54 float* JackGraphManager::GetBuffer(jack_port_id_t port_index)
56 return fPortArray[port_index].GetBuffer();
59 // Server
60 void JackGraphManager::InitRefNum(int refnum)
62 JackConnectionManager* manager = WriteNextStateStart();
63 manager->InitRefNum(refnum);
64 WriteNextStateStop();
67 // RT
68 void JackGraphManager::RunCurrentGraph()
70 JackConnectionManager* manager = ReadCurrentState();
71 manager->ResetGraph(fClientTiming);
74 // RT
75 bool JackGraphManager::RunNextGraph()
77 bool res;
78 JackConnectionManager* manager = TrySwitchState(&res);
79 manager->ResetGraph(fClientTiming);
80 return res;
83 // RT
84 bool JackGraphManager::IsFinishedGraph()
86 JackConnectionManager* manager = ReadCurrentState();
87 return (manager->GetActivation(FREEWHEEL_DRIVER_REFNUM) == 0);
90 // RT
91 int JackGraphManager::ResumeRefNum(JackClientControl* control, JackSynchro* table)
93 JackConnectionManager* manager = ReadCurrentState();
94 return manager->ResumeRefNum(control, table, fClientTiming);
97 // RT
98 int JackGraphManager::SuspendRefNum(JackClientControl* control, JackSynchro* table, long usec)
100 JackConnectionManager* manager = ReadCurrentState();
101 return manager->SuspendRefNum(control, table, fClientTiming, usec);
104 // Server
105 void JackGraphManager::DirectConnect(int ref1, int ref2)
107 JackConnectionManager* manager = WriteNextStateStart();
108 manager->DirectConnect(ref1, ref2);
109 jack_log("JackGraphManager::ConnectRefNum cur_index = %ld ref1 = %ld ref2 = %ld", CurIndex(fCounter), ref1, ref2);
110 WriteNextStateStop();
113 // Server
114 void JackGraphManager::DirectDisconnect(int ref1, int ref2)
116 JackConnectionManager* manager = WriteNextStateStart();
117 manager->DirectDisconnect(ref1, ref2);
118 jack_log("JackGraphManager::DisconnectRefNum cur_index = %ld ref1 = %ld ref2 = %ld", CurIndex(fCounter), ref1, ref2);
119 WriteNextStateStop();
122 // Server
123 bool JackGraphManager::IsDirectConnection(int ref1, int ref2)
125 JackConnectionManager* manager = ReadCurrentState();
126 return manager->IsDirectConnection(ref1, ref2);
129 // RT
130 void* JackGraphManager::GetBuffer(jack_port_id_t port_index, jack_nframes_t buffer_size)
132 AssertPort(port_index);
133 AssertBufferSize(buffer_size);
135 JackConnectionManager* manager = ReadCurrentState();
136 JackPort* port = GetPort(port_index);
138 // This happens when a port has just been unregistered and is still used by the RT code
139 if (!port->IsUsed()) {
140 jack_log("JackGraphManager::GetBuffer : port = %ld is released state", port_index);
141 return GetBuffer(0); // port_index 0 is not used
144 // Output port
145 if (port->fFlags & JackPortIsOutput) {
146 return (port->fTied != NO_PORT) ? GetBuffer(port->fTied, buffer_size) : GetBuffer(port_index);
149 // Input port
150 jack_int_t len = manager->Connections(port_index);
152 // No connections : return a zero-filled buffer
153 if (len == 0) {
154 port->ClearBuffer(buffer_size);
155 return port->GetBuffer();
157 // One connection
158 } else if (len == 1) {
159 jack_port_id_t src_index = manager->GetPort(port_index, 0);
161 // Ports in same client : copy the buffer
162 if (GetPort(src_index)->GetRefNum() == port->GetRefNum()) {
163 void* buffers[1];
164 buffers[0] = GetBuffer(src_index, buffer_size);
165 port->MixBuffers(buffers, 1, buffer_size);
166 return port->GetBuffer();
167 // Otherwise, use zero-copy mode, just pass the buffer of the connected (output) port.
168 } else {
169 return GetBuffer(src_index, buffer_size);
172 // Multiple connections : mix all buffers
173 } else {
175 const jack_int_t* connections = manager->GetConnections(port_index);
176 void* buffers[CONNECTION_NUM_FOR_PORT];
177 jack_port_id_t src_index;
178 int i;
180 for (i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((src_index = connections[i]) != EMPTY); i++) {
181 AssertPort(src_index);
182 buffers[i] = GetBuffer(src_index, buffer_size);
185 port->MixBuffers(buffers, i, buffer_size);
186 return port->GetBuffer();
190 // Server
191 int JackGraphManager::RequestMonitor(jack_port_id_t port_index, bool onoff) // Client
193 AssertPort(port_index);
194 JackPort* port = GetPort(port_index);
197 jackd.h
198 * If @ref JackPortCanMonitor is set for this @a port, turn input
199 * monitoring on or off. Otherwise, do nothing.
201 if (!(fFlags & JackPortCanMonitor))
202 return -1;
205 port->RequestMonitor(onoff);
207 const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index);
208 if ((port->fFlags & JackPortIsOutput) == 0) { // ?? Taken from jack, why not (port->fFlags & JackPortIsInput) ?
209 jack_port_id_t src_index;
210 for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((src_index = connections[i]) != EMPTY); i++) {
211 // XXX much worse things will happen if there is a feedback loop !!!
212 RequestMonitor(src_index, onoff);
216 return 0;
219 // Client
220 jack_nframes_t JackGraphManager::ComputeTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count)
222 const jack_int_t* connections = manager->GetConnections(port_index);
223 jack_nframes_t max_latency = 0;
224 jack_port_id_t dst_index;
226 if (hop_count > 8)
227 return GetPort(port_index)->GetLatency();
229 for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((dst_index = connections[i]) != EMPTY); i++) {
230 if (src_port_index != dst_index) {
231 AssertPort(dst_index);
232 JackPort* dst_port = GetPort(dst_index);
233 jack_nframes_t this_latency = (dst_port->fFlags & JackPortIsTerminal)
234 ? dst_port->GetLatency()
235 : ComputeTotalLatencyAux(dst_index, port_index, manager, hop_count + 1);
236 max_latency = ((max_latency > this_latency) ? max_latency : this_latency);
240 return max_latency + GetPort(port_index)->GetLatency();
243 // Client
244 int JackGraphManager::ComputeTotalLatency(jack_port_id_t port_index)
246 UInt16 cur_index;
247 UInt16 next_index;
248 JackPort* port = GetPort(port_index);
249 AssertPort(port_index);
251 do {
252 cur_index = GetCurrentIndex();
253 port->fTotalLatency = ComputeTotalLatencyAux(port_index, port_index, ReadCurrentState(), 0);
254 next_index = GetCurrentIndex();
255 } while (cur_index != next_index); // Until a coherent state has been read
257 jack_log("JackGraphManager::GetTotalLatency port_index = %ld total latency = %ld", port_index, port->fTotalLatency);
258 return 0;
261 // Client
262 int JackGraphManager::ComputeTotalLatencies()
264 jack_port_id_t port_index;
265 for (port_index = FIRST_AVAILABLE_PORT; port_index < PORT_NUM; port_index++) {
266 JackPort* port = GetPort(port_index);
267 if (port->IsUsed())
268 ComputeTotalLatency(port_index);
270 return 0;
273 // Server
274 void JackGraphManager::SetBufferSize(jack_nframes_t buffer_size)
276 jack_log("JackGraphManager::SetBufferSize size = %ld", buffer_size);
278 jack_port_id_t port_index;
279 for (port_index = FIRST_AVAILABLE_PORT; port_index < PORT_NUM; port_index++) {
280 JackPort* port = GetPort(port_index);
281 if (port->IsUsed())
282 port->ClearBuffer(buffer_size);
286 // Server
287 jack_port_id_t JackGraphManager::AllocatePortAux(int refnum, const char* port_name, const char* port_type, JackPortFlags flags)
289 jack_port_id_t port_index;
291 // Available ports start at FIRST_AVAILABLE_PORT (= 1), otherwise a port_index of 0 is "seen" as a NULL port by the external API...
292 for (port_index = FIRST_AVAILABLE_PORT; port_index < PORT_NUM; port_index++) {
293 JackPort* port = GetPort(port_index);
294 if (!port->IsUsed()) {
295 jack_log("JackGraphManager::AllocatePortAux port_index = %ld name = %s type = %s", port_index, port_name, port_type);
296 if (!port->Allocate(refnum, port_name, port_type, flags))
297 return NO_PORT;
298 break;
302 return (port_index < PORT_NUM) ? port_index : NO_PORT;
305 // Server
306 jack_port_id_t JackGraphManager::AllocatePort(int refnum, const char* port_name, const char* port_type, JackPortFlags flags, jack_nframes_t buffer_size)
308 JackConnectionManager* manager = WriteNextStateStart();
309 jack_port_id_t port_index = AllocatePortAux(refnum, port_name, port_type, flags);
311 if (port_index != NO_PORT) {
312 JackPort* port = GetPort(port_index);
313 assert(port);
314 port->ClearBuffer(buffer_size);
316 int res;
317 if (flags & JackPortIsOutput) {
318 res = manager->AddOutputPort(refnum, port_index);
319 } else {
320 res = manager->AddInputPort(refnum, port_index);
322 // Insertion failure
323 if (res < 0) {
324 port->Release();
325 port_index = NO_PORT;
329 WriteNextStateStop();
330 return port_index;
333 // Server
334 int JackGraphManager::ReleasePort(int refnum, jack_port_id_t port_index)
336 JackConnectionManager* manager = WriteNextStateStart();
337 JackPort* port = GetPort(port_index);
338 int res;
340 if (port->fFlags & JackPortIsOutput) {
341 DisconnectAllOutput(port_index);
342 res = manager->RemoveOutputPort(refnum, port_index);
343 } else {
344 DisconnectAllInput(port_index);
345 res = manager->RemoveInputPort(refnum, port_index);
348 port->Release();
349 WriteNextStateStop();
350 return res;
353 void JackGraphManager::GetInputPorts(int refnum, jack_int_t* res)
355 JackConnectionManager* manager = WriteNextStateStart();
356 const jack_int_t* input = manager->GetInputPorts(refnum);
357 memcpy(res, input, sizeof(jack_int_t) * PORT_NUM_FOR_CLIENT);
358 WriteNextStateStop();
361 void JackGraphManager::GetOutputPorts(int refnum, jack_int_t* res)
363 JackConnectionManager* manager = WriteNextStateStart();
364 const jack_int_t* output = manager->GetOutputPorts(refnum);
365 memcpy(res, output, sizeof(jack_int_t) * PORT_NUM_FOR_CLIENT);
366 WriteNextStateStop();
369 // Server
370 void JackGraphManager::RemoveAllPorts(int refnum)
372 jack_log("JackGraphManager::RemoveAllPorts ref = %ld", refnum);
373 JackConnectionManager* manager = WriteNextStateStart();
374 jack_port_id_t port_index;
376 // Warning : ReleasePort shift port to left, thus we always remove the first port until the "input" table is empty
377 const jack_int_t* input = manager->GetInputPorts(refnum);
378 while ((port_index = input[0]) != EMPTY) {
379 int res = ReleasePort(refnum, port_index);
380 if (res < 0) {
381 jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum, port_index);
382 assert(true);
383 break;
387 // Warning : ReleasePort shift port to left, thus we always remove the first port until the "output" table is empty
388 const jack_int_t* output = manager->GetOutputPorts(refnum);
389 while ((port_index = output[0]) != EMPTY) {
390 int res = ReleasePort(refnum, port_index);
391 if (res < 0) {
392 jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum, port_index);
393 assert(true);
394 break;
398 WriteNextStateStop();
401 // Server
402 void JackGraphManager::DisconnectAllPorts(int refnum)
404 int i;
405 jack_log("JackGraphManager::DisconnectAllPorts ref = %ld", refnum);
406 JackConnectionManager* manager = WriteNextStateStart();
408 const jack_int_t* input = manager->GetInputPorts(refnum);
409 for (i = 0; i < PORT_NUM_FOR_CLIENT && input[i] != EMPTY ; i++) {
410 DisconnectAllInput(input[i]);
413 const jack_int_t* output = manager->GetOutputPorts(refnum);
414 for (i = 0; i < PORT_NUM_FOR_CLIENT && output[i] != EMPTY; i++) {
415 DisconnectAllOutput(output[i]);
418 WriteNextStateStop();
421 // Server
422 void JackGraphManager::DisconnectAllInput(jack_port_id_t port_index)
424 jack_log("JackGraphManager::DisconnectAllInput port_index = %ld", port_index);
425 JackConnectionManager* manager = WriteNextStateStart();
427 for (int i = 0; i < PORT_NUM; i++) {
428 if (manager->IsConnected(i, port_index)) {
429 jack_log("JackGraphManager::Disconnect i = %ld port_index = %ld", i, port_index);
430 Disconnect(i, port_index);
433 WriteNextStateStop();
436 // Server
437 void JackGraphManager::DisconnectAllOutput(jack_port_id_t port_index)
439 jack_log("JackGraphManager::DisconnectAllOutput port_index = %ld ", port_index);
440 JackConnectionManager* manager = WriteNextStateStart();
442 const jack_int_t* connections = manager->GetConnections(port_index);
443 while (connections[0] != EMPTY) {
444 Disconnect(port_index, connections[0]); // Warning : Disconnect shift port to left
446 WriteNextStateStop();
449 // Server
450 int JackGraphManager::DisconnectAll(jack_port_id_t port_index)
452 AssertPort(port_index);
454 JackPort* port = GetPort(port_index);
455 if (port->fFlags & JackPortIsOutput) {
456 DisconnectAllOutput(port_index);
457 } else {
458 DisconnectAllInput(port_index);
460 return 0;
463 // Server
464 void JackGraphManager::GetConnections(jack_port_id_t port_index, jack_int_t* res)
466 JackConnectionManager* manager = WriteNextStateStart();
467 const jack_int_t* connections = manager->GetConnections(port_index);
468 memcpy(res, connections, sizeof(jack_int_t) * CONNECTION_NUM_FOR_PORT);
469 WriteNextStateStop();
472 // Server
473 void JackGraphManager::Activate(int refnum)
475 DirectConnect(FREEWHEEL_DRIVER_REFNUM, refnum);
476 DirectConnect(refnum, FREEWHEEL_DRIVER_REFNUM);
480 Disconnection from the FW must be done in last otherwise an intermediate "unconnected"
481 (thus unactivated) state may happen where the client is still checked for its end.
484 // Server
485 void JackGraphManager::Deactivate(int refnum)
487 // Disconnect only when needed
488 if (IsDirectConnection(refnum, FREEWHEEL_DRIVER_REFNUM)) {
489 DirectDisconnect(refnum, FREEWHEEL_DRIVER_REFNUM);
490 } else {
491 jack_log("JackServer::Deactivate client = %ld was not activated", refnum);
494 // Disconnect only when needed
495 if (IsDirectConnection(FREEWHEEL_DRIVER_REFNUM, refnum)) {
496 DirectDisconnect(FREEWHEEL_DRIVER_REFNUM, refnum);
497 } else {
498 jack_log("JackServer::Deactivate client = %ld was not activated", refnum);
502 // Server
503 int JackGraphManager::GetInputRefNum(jack_port_id_t port_index)
505 AssertPort(port_index);
506 JackConnectionManager* manager = WriteNextStateStart();
507 int res = manager->GetInputRefNum(port_index);
508 WriteNextStateStop();
509 return res;
512 // Server
513 int JackGraphManager::GetOutputRefNum(jack_port_id_t port_index)
515 AssertPort(port_index);
516 JackConnectionManager* manager = WriteNextStateStart();
517 int res = manager->GetOutputRefNum(port_index);
518 WriteNextStateStop();
519 return res;
522 int JackGraphManager::Connect(jack_port_id_t port_src, jack_port_id_t port_dst)
524 JackConnectionManager* manager = WriteNextStateStart();
525 jack_log("JackGraphManager::Connect port_src = %ld port_dst = %ld", port_src, port_dst);
526 JackPort* src = GetPort(port_src);
527 JackPort* dst = GetPort(port_dst);
528 int res = 0;
530 if (!src->fInUse || !dst->fInUse) {
531 if (!src->fInUse)
532 jack_error("JackGraphManager::Connect port_src = %ld not used name = %s", port_src, GetPort(port_src)->fName);
533 if (!dst->fInUse)
534 jack_error("JackGraphManager::Connect port_dst = %ld not used name = %s", port_dst, GetPort(port_dst)->fName);
535 res = -1;
536 goto end;
538 if (src->fTypeId != dst->fTypeId) {
539 jack_error("JackGraphManager::Connect different port types port_src = %ld port_dst = %ld", port_src, port_dst);
540 res = -1;
541 goto end;
543 if (manager->IsConnected(port_src, port_dst)) {
544 jack_error("JackGraphManager::Connect already connected port_src = %ld port_dst = %ld", port_src, port_dst);
545 res = EEXIST;
546 goto end;
549 res = manager->Connect(port_src, port_dst);
550 if (res < 0) {
551 jack_error("JackGraphManager::Connect failed port_src = %ld port_dst = %ld", port_src, port_dst);
552 goto end;
554 res = manager->Connect(port_dst, port_src);
555 if (res < 0) {
556 jack_error("JackGraphManager::Connect failed port_dst = %ld port_src = %ld", port_dst, port_src);
557 goto end;
560 if (manager->IsLoopPath(port_src, port_dst)) {
561 jack_log("JackGraphManager::Connect: LOOP detected");
562 manager->IncFeedbackConnection(port_src, port_dst);
563 } else {
564 manager->IncDirectConnection(port_src, port_dst);
567 end:
568 WriteNextStateStop();
569 return res;
572 // Server
573 int JackGraphManager::Disconnect(jack_port_id_t port_src, jack_port_id_t port_dst)
575 JackConnectionManager* manager = WriteNextStateStart();
576 jack_log("JackGraphManager::Disconnect port_src = %ld port_dst = %ld", port_src, port_dst);
577 bool in_use_src = GetPort(port_src)->fInUse;
578 bool in_use_dst = GetPort(port_dst)->fInUse;
579 int res = 0;
581 if (!in_use_src || !in_use_dst) {
582 if (!in_use_src)
583 jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_src, GetPort(port_src)->fName);
584 if (!in_use_dst)
585 jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_dst, GetPort(port_dst)->fName);
586 res = -1;
587 goto end;
589 if (!manager->IsConnected(port_src, port_dst)) {
590 jack_error("JackGraphManager::Disconnect not connected port_src = %ld port_dst = %ld", port_src, port_dst);
591 res = -1;
592 goto end;
595 res = manager->Disconnect(port_src, port_dst);
596 if (res < 0) {
597 jack_error("JackGraphManager::Disconnect failed port_src = %ld port_dst = %ld", port_src, port_dst);
598 goto end;
600 res = manager->Disconnect(port_dst, port_src);
601 if (res < 0) {
602 jack_error("JackGraphManager::Disconnect failed port_dst = %ld port_src = %ld", port_dst, port_src);
603 goto end;
606 if (manager->IsFeedbackConnection(port_src, port_dst)) {
607 jack_log("JackGraphManager::Disconnect: FEEDBACK removed");
608 manager->DecFeedbackConnection(port_src, port_dst);
609 } else {
610 manager->DecDirectConnection(port_src, port_dst);
613 end:
614 WriteNextStateStop();
615 return res;
618 // Client
619 int JackGraphManager::IsConnected(jack_port_id_t port_src, jack_port_id_t port_dst)
621 JackConnectionManager* manager = ReadCurrentState();
622 return manager->IsConnected(port_src, port_dst);
625 // Server
626 int JackGraphManager::CheckPorts(jack_port_id_t port_src, jack_port_id_t port_dst)
628 JackPort* src = GetPort(port_src);
629 JackPort* dst = GetPort(port_dst);
631 if ((dst->fFlags & JackPortIsInput) == 0) {
632 jack_error("Destination port in attempted (dis)connection of %s and %s is not an input port", src->fName, dst->fName);
633 return -1;
636 if ((src->fFlags & JackPortIsOutput) == 0) {
637 jack_error("Source port in attempted (dis)connection of %s and %s is not an output port", src->fName, dst->fName);
638 return -1;
641 return 0;
644 int JackGraphManager::GetTwoPorts(const char* src_name, const char* dst_name, jack_port_id_t* port_src, jack_port_id_t* port_dst)
646 jack_log("JackGraphManager::CheckConnect src_name = %s dst_name = %s", src_name, dst_name);
648 if ((*port_src = GetPort(src_name)) == NO_PORT) {
649 jack_error("Unknown source port in attempted (dis)connection src_name [%s] dst_name [%s]", src_name, dst_name);
650 return -1;
653 if ((*port_dst = GetPort(dst_name)) == NO_PORT) {
654 jack_error("Unknown destination port in attempted (dis)connection src_name [%s] dst_name [%s]", src_name, dst_name);
655 return -1;
658 return 0;
661 // Client : port array
662 jack_port_id_t JackGraphManager::GetPort(const char* name)
664 for (int i = 0; i < PORT_NUM; i++) {
665 JackPort* port = GetPort(i);
666 if (port->IsUsed() && port->NameEquals(name))
667 return i;
669 return NO_PORT;
673 \brief Get the connection port name array.
676 // Client
677 void JackGraphManager::GetConnectionsAux(JackConnectionManager* manager, const char** res, jack_port_id_t port_index)
679 const jack_int_t* connections = manager->GetConnections(port_index);
680 jack_int_t index;
681 int i;
683 // Cleanup connection array
684 memset(res, 0, sizeof(char*) * CONNECTION_NUM_FOR_PORT);
686 for (i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((index = connections[i]) != EMPTY); i++) {
687 JackPort* port = GetPort(index);
688 res[i] = port->fName;
691 res[i] = NULL;
695 Use the state returned by ReadCurrentState and check that the state was not changed during the read operation.
696 The operation is lock-free since there is no intermediate state in the write operation that could cause the
697 read to loop forever.
700 // Client
701 const char** JackGraphManager::GetConnections(jack_port_id_t port_index)
703 const char** res = (const char**)malloc(sizeof(char*) * CONNECTION_NUM_FOR_PORT);
704 UInt16 cur_index, next_index;
706 if (!res)
707 return NULL;
709 do {
710 cur_index = GetCurrentIndex();
711 GetConnectionsAux(ReadCurrentState(), res, port_index);
712 next_index = GetCurrentIndex();
713 } while (cur_index != next_index); // Until a coherent state has been read
715 if (res[0]) { // at least one connection
716 return res;
717 } else { // empty array, should return NULL
718 free(res);
719 return NULL;
723 // Client
724 void JackGraphManager::GetPortsAux(const char** matching_ports, const char* port_name_pattern, const char* type_name_pattern, unsigned long flags)
726 int match_cnt = 0;
727 regex_t port_regex, type_regex;
729 if (port_name_pattern && port_name_pattern[0]) {
730 regcomp(&port_regex, port_name_pattern, REG_EXTENDED | REG_NOSUB);
732 if (type_name_pattern && type_name_pattern[0]) {
733 regcomp(&type_regex, type_name_pattern, REG_EXTENDED | REG_NOSUB);
736 // Cleanup port array
737 memset(matching_ports, 0, sizeof(char*) * PORT_NUM);
739 for (int i = 0; i < PORT_NUM; i++) {
740 bool matching = true;
741 JackPort* port = GetPort(i);
743 if (port->IsUsed()) {
745 if (flags) {
746 if ((port->fFlags & flags) != flags) {
747 matching = false;
751 if (matching && port_name_pattern && port_name_pattern[0]) {
752 if (regexec(&port_regex, port->GetName(), 0, NULL, 0)) {
753 matching = false;
756 if (matching && type_name_pattern && type_name_pattern[0]) {
757 if (regexec(&type_regex, port->GetType(), 0, NULL, 0)) {
758 matching = false;
762 if (matching) {
763 matching_ports[match_cnt++] = port->fName;
768 matching_ports[match_cnt] = 0;
770 if (port_name_pattern && port_name_pattern[0]) {
771 regfree(&port_regex);
773 if (type_name_pattern && type_name_pattern[0]) {
774 regfree(&type_regex);
778 // Client
780 Check that the state was not changed during the read operation.
781 The operation is lock-free since there is no intermediate state in the write operation that could cause the
782 read to loop forever.
784 const char** JackGraphManager::GetPorts(const char* port_name_pattern, const char* type_name_pattern, unsigned long flags)
786 const char** res = (const char**)malloc(sizeof(char*) * PORT_NUM);
787 UInt16 cur_index, next_index;
789 if (!res)
790 return NULL;
792 do {
793 cur_index = GetCurrentIndex();
794 GetPortsAux(res, port_name_pattern, type_name_pattern, flags);
795 next_index = GetCurrentIndex();
796 } while (cur_index != next_index); // Until a coherent state has been read
798 if (res[0]) { // at least one port
799 return res;
800 } else {
801 free(res); // empty array, should return NULL
802 return NULL;
806 // Server
807 void JackGraphManager::Save(JackConnectionManager* dst)
809 JackConnectionManager* manager = WriteNextStateStart();
810 memcpy(dst, manager, sizeof(JackConnectionManager));
811 WriteNextStateStop();
814 // Server
815 void JackGraphManager::Restore(JackConnectionManager* src)
817 JackConnectionManager* manager = WriteNextStateStart();
818 memcpy(manager, src, sizeof(JackConnectionManager));
819 WriteNextStateStop();
822 } // end of namespace