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"
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();
60 void JackGraphManager::InitRefNum(int refnum
)
62 JackConnectionManager
* manager
= WriteNextStateStart();
63 manager
->InitRefNum(refnum
);
68 void JackGraphManager::RunCurrentGraph()
70 JackConnectionManager
* manager
= ReadCurrentState();
71 manager
->ResetGraph(fClientTiming
);
75 bool JackGraphManager::RunNextGraph()
78 JackConnectionManager
* manager
= TrySwitchState(&res
);
79 manager
->ResetGraph(fClientTiming
);
84 bool JackGraphManager::IsFinishedGraph()
86 JackConnectionManager
* manager
= ReadCurrentState();
87 return (manager
->GetActivation(FREEWHEEL_DRIVER_REFNUM
) == 0);
91 int JackGraphManager::ResumeRefNum(JackClientControl
* control
, JackSynchro
* table
)
93 JackConnectionManager
* manager
= ReadCurrentState();
94 return manager
->ResumeRefNum(control
, table
, fClientTiming
);
98 int JackGraphManager::SuspendRefNum(JackClientControl
* control
, JackSynchro
* table
, long usec
)
100 JackConnectionManager
* manager
= ReadCurrentState();
101 return manager
->SuspendRefNum(control
, table
, fClientTiming
, usec
);
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();
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();
123 bool JackGraphManager::IsDirectConnection(int ref1
, int ref2
)
125 JackConnectionManager
* manager
= ReadCurrentState();
126 return manager
->IsDirectConnection(ref1
, ref2
);
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
145 if (port
->fFlags
& JackPortIsOutput
) {
146 return (port
->fTied
!= NO_PORT
) ? GetBuffer(port
->fTied
, buffer_size
) : GetBuffer(port_index
);
150 jack_int_t len
= manager
->Connections(port_index
);
152 // No connections : return a zero-filled buffer
154 port
->ClearBuffer(buffer_size
);
155 return port
->GetBuffer();
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()) {
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.
169 return GetBuffer(src_index
, buffer_size
);
172 // Multiple connections : mix all buffers
175 const jack_int_t
* connections
= manager
->GetConnections(port_index
);
176 void* buffers
[CONNECTION_NUM_FOR_PORT
];
177 jack_port_id_t src_index
;
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();
191 int JackGraphManager::RequestMonitor(jack_port_id_t port_index
, bool onoff
) // Client
193 AssertPort(port_index
);
194 JackPort
* port
= GetPort(port_index
);
198 * If @ref JackPortCanMonitor is set for this @a port, turn input
199 * monitoring on or off. Otherwise, do nothing.
201 if (!(fFlags & JackPortCanMonitor))
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
);
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
;
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();
244 int JackGraphManager::ComputeTotalLatency(jack_port_id_t port_index
)
248 JackPort
* port
= GetPort(port_index
);
249 AssertPort(port_index
);
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
);
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
);
268 ComputeTotalLatency(port_index
);
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
);
282 port
->ClearBuffer(buffer_size
);
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
))
302 return (port_index
< PORT_NUM
) ? port_index
: NO_PORT
;
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
);
314 port
->ClearBuffer(buffer_size
);
317 if (flags
& JackPortIsOutput
) {
318 res
= manager
->AddOutputPort(refnum
, port_index
);
320 res
= manager
->AddInputPort(refnum
, port_index
);
325 port_index
= NO_PORT
;
329 WriteNextStateStop();
334 int JackGraphManager::ReleasePort(int refnum
, jack_port_id_t port_index
)
336 JackConnectionManager
* manager
= WriteNextStateStart();
337 JackPort
* port
= GetPort(port_index
);
340 if (port
->fFlags
& JackPortIsOutput
) {
341 DisconnectAllOutput(port_index
);
342 res
= manager
->RemoveOutputPort(refnum
, port_index
);
344 DisconnectAllInput(port_index
);
345 res
= manager
->RemoveInputPort(refnum
, port_index
);
349 WriteNextStateStop();
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();
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
);
381 jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum
, port_index
);
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
);
392 jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum
, port_index
);
398 WriteNextStateStop();
402 void JackGraphManager::DisconnectAllPorts(int refnum
)
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();
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();
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();
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
);
458 DisconnectAllInput(port_index
);
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();
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.
485 void JackGraphManager::Deactivate(int refnum
)
487 // Disconnect only when needed
488 if (IsDirectConnection(refnum
, FREEWHEEL_DRIVER_REFNUM
)) {
489 DirectDisconnect(refnum
, FREEWHEEL_DRIVER_REFNUM
);
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
);
498 jack_log("JackServer::Deactivate client = %ld was not activated", refnum
);
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();
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();
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
);
530 if (!src
->fInUse
|| !dst
->fInUse
) {
532 jack_error("JackGraphManager::Connect port_src = %ld not used name = %s", port_src
, GetPort(port_src
)->fName
);
534 jack_error("JackGraphManager::Connect port_dst = %ld not used name = %s", port_dst
, GetPort(port_dst
)->fName
);
538 if (src
->fTypeId
!= dst
->fTypeId
) {
539 jack_error("JackGraphManager::Connect different port types port_src = %ld port_dst = %ld", port_src
, port_dst
);
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
);
549 res
= manager
->Connect(port_src
, port_dst
);
551 jack_error("JackGraphManager::Connect failed port_src = %ld port_dst = %ld", port_src
, port_dst
);
554 res
= manager
->Connect(port_dst
, port_src
);
556 jack_error("JackGraphManager::Connect failed port_dst = %ld port_src = %ld", port_dst
, port_src
);
560 if (manager
->IsLoopPath(port_src
, port_dst
)) {
561 jack_log("JackGraphManager::Connect: LOOP detected");
562 manager
->IncFeedbackConnection(port_src
, port_dst
);
564 manager
->IncDirectConnection(port_src
, port_dst
);
568 WriteNextStateStop();
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
;
581 if (!in_use_src
|| !in_use_dst
) {
583 jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_src
, GetPort(port_src
)->fName
);
585 jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_dst
, GetPort(port_dst
)->fName
);
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
);
595 res
= manager
->Disconnect(port_src
, port_dst
);
597 jack_error("JackGraphManager::Disconnect failed port_src = %ld port_dst = %ld", port_src
, port_dst
);
600 res
= manager
->Disconnect(port_dst
, port_src
);
602 jack_error("JackGraphManager::Disconnect failed port_dst = %ld port_src = %ld", port_dst
, port_src
);
606 if (manager
->IsFeedbackConnection(port_src
, port_dst
)) {
607 jack_log("JackGraphManager::Disconnect: FEEDBACK removed");
608 manager
->DecFeedbackConnection(port_src
, port_dst
);
610 manager
->DecDirectConnection(port_src
, port_dst
);
614 WriteNextStateStop();
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
);
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
);
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
);
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
);
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
);
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
))
673 \brief Get the connection port name array.
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
);
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
;
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.
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
;
707 cur_index
= GetCurrentIndex();
708 GetConnectionsAux(ReadCurrentState(), res
, port_index
);
709 next_index
= GetCurrentIndex();
710 } while (cur_index
!= next_index
); // Until a coherent state has been read
712 if (res
[0]) { // at least one connection
714 } else { // empty array, should return NULL
721 void JackGraphManager::GetPortsAux(const char** matching_ports
, const char* port_name_pattern
, const char* type_name_pattern
, unsigned long flags
)
724 regex_t port_regex
, type_regex
;
726 if (port_name_pattern
&& port_name_pattern
[0]) {
727 regcomp(&port_regex
, port_name_pattern
, REG_EXTENDED
| REG_NOSUB
);
729 if (type_name_pattern
&& type_name_pattern
[0]) {
730 regcomp(&type_regex
, type_name_pattern
, REG_EXTENDED
| REG_NOSUB
);
733 // Cleanup port array
734 memset(matching_ports
, 0, sizeof(char*) * PORT_NUM
);
736 for (int i
= 0; i
< PORT_NUM
; i
++) {
737 bool matching
= true;
738 JackPort
* port
= GetPort(i
);
740 if (port
->IsUsed()) {
743 if ((port
->fFlags
& flags
) != flags
) {
748 if (matching
&& port_name_pattern
&& port_name_pattern
[0]) {
749 if (regexec(&port_regex
, port
->GetName(), 0, NULL
, 0)) {
753 if (matching
&& type_name_pattern
&& type_name_pattern
[0]) {
754 if (regexec(&type_regex
, port
->GetType(), 0, NULL
, 0)) {
760 matching_ports
[match_cnt
++] = port
->fName
;
765 matching_ports
[match_cnt
] = 0;
767 if (port_name_pattern
&& port_name_pattern
[0]) {
768 regfree(&port_regex
);
770 if (type_name_pattern
&& type_name_pattern
[0]) {
771 regfree(&type_regex
);
777 Check that the state was not changed during the read operation.
778 The operation is lock-free since there is no intermediate state in the write operation that could cause the
779 read to loop forever.
781 const char** JackGraphManager::GetPorts(const char* port_name_pattern
, const char* type_name_pattern
, unsigned long flags
)
783 const char** res
= (const char**)malloc(sizeof(char*) * PORT_NUM
);
784 UInt16 cur_index
, next_index
;
787 cur_index
= GetCurrentIndex();
788 GetPortsAux(res
, port_name_pattern
, type_name_pattern
, flags
);
789 next_index
= GetCurrentIndex();
790 } while (cur_index
!= next_index
); // Until a coherent state has been read
792 if (res
[0]) { // at least one port
795 free(res
); // empty array, should return NULL
801 void JackGraphManager::Save(JackConnectionManager
* dst
)
803 JackConnectionManager
* manager
= WriteNextStateStart();
804 memcpy(dst
, manager
, sizeof(JackConnectionManager
));
805 WriteNextStateStop();
809 void JackGraphManager::Restore(JackConnectionManager
* src
)
811 JackConnectionManager
* manager
= WriteNextStateStart();
812 memcpy(manager
, src
, sizeof(JackConnectionManager
));
813 WriteNextStateStop();
816 } // end of namespace