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 AssertBufferSize(jack_nframes_t buffer_size
)
34 if (buffer_size
> BUFFER_SIZE_MAX
) {
35 jack_log("JackGraphManager::AssertBufferSize frames = %ld", buffer_size
);
36 assert(buffer_size
<= BUFFER_SIZE_MAX
);
40 void JackGraphManager::AssertPort(jack_port_id_t port_index
)
42 if (port_index
>= fPortMax
) {
43 jack_log("JackGraphManager::AssertPort port_index = %ld", port_index
);
44 assert(port_index
< fPortMax
);
48 JackGraphManager
* JackGraphManager::Allocate(int port_max
)
50 // Using "Placement" new
51 void* shared_ptr
= JackShmMem::operator new(sizeof(JackGraphManager
) + port_max
* sizeof(JackPort
));
52 return new(shared_ptr
) JackGraphManager(port_max
);
55 void JackGraphManager::Destroy(JackGraphManager
* manager
)
57 // "Placement" new was used
58 manager
->~JackGraphManager();
59 JackShmMem::operator delete(manager
);
62 JackGraphManager::JackGraphManager(int port_max
)
64 assert(port_max
<= PORT_NUM_MAX
);
66 for (int i
= 0; i
< port_max
; i
++) {
67 fPortArray
[i
].Release();
73 JackPort
* JackGraphManager::GetPort(jack_port_id_t port_index
)
75 AssertPort(port_index
);
76 return &fPortArray
[port_index
];
79 jack_default_audio_sample_t
* JackGraphManager::GetBuffer(jack_port_id_t port_index
)
81 return fPortArray
[port_index
].GetBuffer();
85 void JackGraphManager::InitRefNum(int refnum
)
87 JackConnectionManager
* manager
= WriteNextStateStart();
88 manager
->InitRefNum(refnum
);
93 void JackGraphManager::RunCurrentGraph()
95 JackConnectionManager
* manager
= ReadCurrentState();
96 manager
->ResetGraph(fClientTiming
);
100 bool JackGraphManager::RunNextGraph()
103 JackConnectionManager
* manager
= TrySwitchState(&res
);
104 manager
->ResetGraph(fClientTiming
);
109 bool JackGraphManager::IsFinishedGraph()
111 JackConnectionManager
* manager
= ReadCurrentState();
112 return (manager
->GetActivation(FREEWHEEL_DRIVER_REFNUM
) == 0);
116 int JackGraphManager::ResumeRefNum(JackClientControl
* control
, JackSynchro
* table
)
118 JackConnectionManager
* manager
= ReadCurrentState();
119 return manager
->ResumeRefNum(control
, table
, fClientTiming
);
123 int JackGraphManager::SuspendRefNum(JackClientControl
* control
, JackSynchro
* table
, long usec
)
125 JackConnectionManager
* manager
= ReadCurrentState();
126 return manager
->SuspendRefNum(control
, table
, fClientTiming
, usec
);
129 void JackGraphManager::TopologicalSort(std::vector
<jack_int_t
>& sorted
)
135 cur_index
= GetCurrentIndex();
137 ReadCurrentState()->TopologicalSort(sorted
);
138 next_index
= GetCurrentIndex();
139 } while (cur_index
!= next_index
); // Until a coherent state has been read
143 void JackGraphManager::DirectConnect(int ref1
, int ref2
)
145 JackConnectionManager
* manager
= WriteNextStateStart();
146 manager
->DirectConnect(ref1
, ref2
);
147 jack_log("JackGraphManager::ConnectRefNum cur_index = %ld ref1 = %ld ref2 = %ld", CurIndex(fCounter
), ref1
, ref2
);
148 WriteNextStateStop();
152 void JackGraphManager::DirectDisconnect(int ref1
, int ref2
)
154 JackConnectionManager
* manager
= WriteNextStateStart();
155 manager
->DirectDisconnect(ref1
, ref2
);
156 jack_log("JackGraphManager::DisconnectRefNum cur_index = %ld ref1 = %ld ref2 = %ld", CurIndex(fCounter
), ref1
, ref2
);
157 WriteNextStateStop();
161 bool JackGraphManager::IsDirectConnection(int ref1
, int ref2
)
163 JackConnectionManager
* manager
= ReadCurrentState();
164 return manager
->IsDirectConnection(ref1
, ref2
);
168 void* JackGraphManager::GetBuffer(jack_port_id_t port_index
, jack_nframes_t buffer_size
)
170 AssertPort(port_index
);
171 AssertBufferSize(buffer_size
);
173 JackConnectionManager
* manager
= ReadCurrentState();
174 JackPort
* port
= GetPort(port_index
);
176 // This happens when a port has just been unregistered and is still used by the RT code
177 if (!port
->IsUsed()) {
178 jack_log("JackGraphManager::GetBuffer : port = %ld is released state", port_index
);
179 return GetBuffer(0); // port_index 0 is not used
182 jack_int_t len
= manager
->Connections(port_index
);
185 if (port
->fFlags
& JackPortIsOutput
) {
186 return (port
->fTied
!= NO_PORT
) ? GetBuffer(port
->fTied
, buffer_size
) : GetBuffer(port_index
);
189 // No connections : return a zero-filled buffer
191 port
->ClearBuffer(buffer_size
);
192 return port
->GetBuffer();
195 } else if (len
== 1) {
196 jack_port_id_t src_index
= manager
->GetPort(port_index
, 0);
198 // Ports in same client : copy the buffer
199 if (GetPort(src_index
)->GetRefNum() == port
->GetRefNum()) {
201 buffers
[0] = GetBuffer(src_index
, buffer_size
);
202 port
->MixBuffers(buffers
, 1, buffer_size
);
203 return port
->GetBuffer();
204 // Otherwise, use zero-copy mode, just pass the buffer of the connected (output) port.
206 return GetBuffer(src_index
, buffer_size
);
209 // Multiple connections : mix all buffers
212 const jack_int_t
* connections
= manager
->GetConnections(port_index
);
213 void* buffers
[CONNECTION_NUM_FOR_PORT
];
214 jack_port_id_t src_index
;
217 for (i
= 0; (i
< CONNECTION_NUM_FOR_PORT
) && ((src_index
= connections
[i
]) != EMPTY
); i
++) {
218 AssertPort(src_index
);
219 buffers
[i
] = GetBuffer(src_index
, buffer_size
);
222 port
->MixBuffers(buffers
, i
, buffer_size
);
223 return port
->GetBuffer();
228 int JackGraphManager::RequestMonitor(jack_port_id_t port_index
, bool onoff
) // Client
230 AssertPort(port_index
);
231 JackPort
* port
= GetPort(port_index
);
235 * If @ref JackPortCanMonitor is set for this @a port, turn input
236 * monitoring on or off. Otherwise, do nothing.
238 if (!(fFlags & JackPortCanMonitor))
242 port
->RequestMonitor(onoff
);
244 const jack_int_t
* connections
= ReadCurrentState()->GetConnections(port_index
);
245 if ((port
->fFlags
& JackPortIsOutput
) == 0) { // ?? Taken from jack, why not (port->fFlags & JackPortIsInput) ?
246 jack_port_id_t src_index
;
247 for (int i
= 0; (i
< CONNECTION_NUM_FOR_PORT
) && ((src_index
= connections
[i
]) != EMPTY
); i
++) {
248 // XXX much worse things will happen if there is a feedback loop !!!
249 RequestMonitor(src_index
, onoff
);
257 jack_nframes_t
JackGraphManager::ComputeTotalLatencyAux(jack_port_id_t port_index
, jack_port_id_t src_port_index
, JackConnectionManager
* manager
, int hop_count
)
259 const jack_int_t
* connections
= ReadCurrentState()->GetConnections(port_index
);
260 jack_nframes_t max_latency
= 0;
261 jack_port_id_t dst_index
;
264 return GetPort(port_index
)->GetLatency();
266 for (int i
= 0; (i
< CONNECTION_NUM_FOR_PORT
) && ((dst_index
= connections
[i
]) != EMPTY
); i
++) {
267 if (src_port_index
!= dst_index
) {
268 AssertPort(dst_index
);
269 JackPort
* dst_port
= GetPort(dst_index
);
270 jack_nframes_t this_latency
= (dst_port
->fFlags
& JackPortIsTerminal
)
271 ? dst_port
->GetLatency()
272 : ComputeTotalLatencyAux(dst_index
, port_index
, manager
, hop_count
+ 1);
273 max_latency
= ((max_latency
> this_latency
) ? max_latency
: this_latency
);
277 return max_latency
+ GetPort(port_index
)->GetLatency();
281 int JackGraphManager::ComputeTotalLatency(jack_port_id_t port_index
)
285 JackPort
* port
= GetPort(port_index
);
286 AssertPort(port_index
);
289 cur_index
= GetCurrentIndex();
290 port
->fTotalLatency
= ComputeTotalLatencyAux(port_index
, port_index
, ReadCurrentState(), 0);
291 next_index
= GetCurrentIndex();
292 } while (cur_index
!= next_index
); // Until a coherent state has been read
294 jack_log("JackGraphManager::GetTotalLatency port_index = %ld total latency = %ld", port_index
, port
->fTotalLatency
);
299 int JackGraphManager::ComputeTotalLatencies()
301 jack_port_id_t port_index
;
302 for (port_index
= FIRST_AVAILABLE_PORT
; port_index
< fPortMax
; port_index
++) {
303 JackPort
* port
= GetPort(port_index
);
304 if (port
->IsUsed()) {
305 ComputeTotalLatency(port_index
);
311 void JackGraphManager::RecalculateLatencyAux(jack_port_id_t port_index
, jack_latency_callback_mode_t mode
)
313 const jack_int_t
* connections
= ReadCurrentState()->GetConnections(port_index
);
314 JackPort
* port
= GetPort(port_index
);
315 jack_latency_range_t latency
= { UINT32_MAX
, 0 };
316 jack_port_id_t dst_index
;
318 for (int i
= 0; (i
< CONNECTION_NUM_FOR_PORT
) && ((dst_index
= connections
[i
]) != EMPTY
); i
++) {
319 AssertPort(dst_index
);
320 JackPort
* dst_port
= GetPort(dst_index
);
321 jack_latency_range_t other_latency
;
323 dst_port
->GetLatencyRange(mode
, &other_latency
);
325 if (other_latency
.max
> latency
.max
) {
326 latency
.max
= other_latency
.max
;
328 if (other_latency
.min
< latency
.min
) {
329 latency
.min
= other_latency
.min
;
333 if (latency
.min
== UINT32_MAX
) {
337 port
->SetLatencyRange(mode
, &latency
);
340 void JackGraphManager::RecalculateLatency(jack_port_id_t port_index
, jack_latency_callback_mode_t mode
)
346 cur_index
= GetCurrentIndex();
347 RecalculateLatencyAux(port_index
, mode
);
348 next_index
= GetCurrentIndex();
349 } while (cur_index
!= next_index
); // Until a coherent state has been read
351 //jack_log("JackGraphManager::RecalculateLatency port_index = %ld", port_index);
355 void JackGraphManager::SetBufferSize(jack_nframes_t buffer_size
)
357 jack_log("JackGraphManager::SetBufferSize size = %ld", buffer_size
);
359 jack_port_id_t port_index
;
360 for (port_index
= FIRST_AVAILABLE_PORT
; port_index
< fPortMax
; port_index
++) {
361 JackPort
* port
= GetPort(port_index
);
362 if (port
->IsUsed()) {
363 port
->ClearBuffer(buffer_size
);
369 jack_port_id_t
JackGraphManager::AllocatePortAux(int refnum
, const char* port_name
, const char* port_type
, JackPortFlags flags
)
371 jack_port_id_t port_index
;
373 // Available ports start at FIRST_AVAILABLE_PORT (= 1), otherwise a port_index of 0 is "seen" as a NULL port by the external API...
374 for (port_index
= FIRST_AVAILABLE_PORT
; port_index
< fPortMax
; port_index
++) {
375 JackPort
* port
= GetPort(port_index
);
376 if (!port
->IsUsed()) {
377 jack_log("JackGraphManager::AllocatePortAux port_index = %ld name = %s type = %s", port_index
, port_name
, port_type
);
378 if (!port
->Allocate(refnum
, port_name
, port_type
, flags
)) {
385 return (port_index
< fPortMax
) ? port_index
: NO_PORT
;
389 jack_port_id_t
JackGraphManager::AllocatePort(int refnum
, const char* port_name
, const char* port_type
, JackPortFlags flags
, jack_nframes_t buffer_size
)
391 JackConnectionManager
* manager
= WriteNextStateStart();
392 jack_port_id_t port_index
= AllocatePortAux(refnum
, port_name
, port_type
, flags
);
394 if (port_index
!= NO_PORT
) {
395 JackPort
* port
= GetPort(port_index
);
397 port
->ClearBuffer(buffer_size
);
400 if (flags
& JackPortIsOutput
) {
401 res
= manager
->AddOutputPort(refnum
, port_index
);
403 res
= manager
->AddInputPort(refnum
, port_index
);
408 port_index
= NO_PORT
;
412 WriteNextStateStop();
417 int JackGraphManager::ReleasePort(int refnum
, jack_port_id_t port_index
)
419 JackConnectionManager
* manager
= WriteNextStateStart();
420 JackPort
* port
= GetPort(port_index
);
423 if (port
->fFlags
& JackPortIsOutput
) {
424 DisconnectAllOutput(port_index
);
425 res
= manager
->RemoveOutputPort(refnum
, port_index
);
427 DisconnectAllInput(port_index
);
428 res
= manager
->RemoveInputPort(refnum
, port_index
);
432 WriteNextStateStop();
436 void JackGraphManager::GetInputPorts(int refnum
, jack_int_t
* res
)
438 JackConnectionManager
* manager
= WriteNextStateStart();
439 const jack_int_t
* input
= manager
->GetInputPorts(refnum
);
440 memcpy(res
, input
, sizeof(jack_int_t
) * PORT_NUM_FOR_CLIENT
);
441 WriteNextStateStop();
444 void JackGraphManager::GetOutputPorts(int refnum
, jack_int_t
* res
)
446 JackConnectionManager
* manager
= WriteNextStateStart();
447 const jack_int_t
* output
= manager
->GetOutputPorts(refnum
);
448 memcpy(res
, output
, sizeof(jack_int_t
) * PORT_NUM_FOR_CLIENT
);
449 WriteNextStateStop();
453 void JackGraphManager::RemoveAllPorts(int refnum
)
455 jack_log("JackGraphManager::RemoveAllPorts ref = %ld", refnum
);
456 JackConnectionManager
* manager
= WriteNextStateStart();
457 jack_port_id_t port_index
;
459 // Warning : ReleasePort shift port to left, thus we always remove the first port until the "input" table is empty
460 const jack_int_t
* input
= manager
->GetInputPorts(refnum
);
461 while ((port_index
= input
[0]) != EMPTY
) {
462 int res
= ReleasePort(refnum
, port_index
);
464 jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum
, port_index
);
470 // Warning : ReleasePort shift port to left, thus we always remove the first port until the "output" table is empty
471 const jack_int_t
* output
= manager
->GetOutputPorts(refnum
);
472 while ((port_index
= output
[0]) != EMPTY
) {
473 int res
= ReleasePort(refnum
, port_index
);
475 jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum
, port_index
);
481 WriteNextStateStop();
485 void JackGraphManager::DisconnectAllPorts(int refnum
)
488 jack_log("JackGraphManager::DisconnectAllPorts ref = %ld", refnum
);
489 JackConnectionManager
* manager
= WriteNextStateStart();
491 const jack_int_t
* input
= manager
->GetInputPorts(refnum
);
492 for (i
= 0; i
< PORT_NUM_FOR_CLIENT
&& input
[i
] != EMPTY
; i
++) {
493 DisconnectAllInput(input
[i
]);
496 const jack_int_t
* output
= manager
->GetOutputPorts(refnum
);
497 for (i
= 0; i
< PORT_NUM_FOR_CLIENT
&& output
[i
] != EMPTY
; i
++) {
498 DisconnectAllOutput(output
[i
]);
501 WriteNextStateStop();
505 void JackGraphManager::DisconnectAllInput(jack_port_id_t port_index
)
507 jack_log("JackGraphManager::DisconnectAllInput port_index = %ld", port_index
);
508 JackConnectionManager
* manager
= WriteNextStateStart();
510 for (unsigned int i
= 0; i
< fPortMax
; i
++) {
511 if (manager
->IsConnected(i
, port_index
)) {
512 jack_log("JackGraphManager::Disconnect i = %ld port_index = %ld", i
, port_index
);
513 Disconnect(i
, port_index
);
516 WriteNextStateStop();
520 void JackGraphManager::DisconnectAllOutput(jack_port_id_t port_index
)
522 jack_log("JackGraphManager::DisconnectAllOutput port_index = %ld ", port_index
);
523 JackConnectionManager
* manager
= WriteNextStateStart();
525 const jack_int_t
* connections
= manager
->GetConnections(port_index
);
526 while (connections
[0] != EMPTY
) {
527 Disconnect(port_index
, connections
[0]); // Warning : Disconnect shift port to left
529 WriteNextStateStop();
533 int JackGraphManager::DisconnectAll(jack_port_id_t port_index
)
535 AssertPort(port_index
);
537 JackPort
* port
= GetPort(port_index
);
538 if (port
->fFlags
& JackPortIsOutput
) {
539 DisconnectAllOutput(port_index
);
541 DisconnectAllInput(port_index
);
547 void JackGraphManager::GetConnections(jack_port_id_t port_index
, jack_int_t
* res
)
549 JackConnectionManager
* manager
= WriteNextStateStart();
550 const jack_int_t
* connections
= manager
->GetConnections(port_index
);
551 memcpy(res
, connections
, sizeof(jack_int_t
) * CONNECTION_NUM_FOR_PORT
);
552 WriteNextStateStop();
556 void JackGraphManager::Activate(int refnum
)
558 DirectConnect(FREEWHEEL_DRIVER_REFNUM
, refnum
);
559 DirectConnect(refnum
, FREEWHEEL_DRIVER_REFNUM
);
563 Disconnection from the FW must be done in last otherwise an intermediate "unconnected"
564 (thus unactivated) state may happen where the client is still checked for its end.
568 void JackGraphManager::Deactivate(int refnum
)
570 // Disconnect only when needed
571 if (IsDirectConnection(refnum
, FREEWHEEL_DRIVER_REFNUM
)) {
572 DirectDisconnect(refnum
, FREEWHEEL_DRIVER_REFNUM
);
574 jack_log("JackServer::Deactivate client = %ld was not activated", refnum
);
577 // Disconnect only when needed
578 if (IsDirectConnection(FREEWHEEL_DRIVER_REFNUM
, refnum
)) {
579 DirectDisconnect(FREEWHEEL_DRIVER_REFNUM
, refnum
);
581 jack_log("JackServer::Deactivate client = %ld was not activated", refnum
);
586 int JackGraphManager::GetInputRefNum(jack_port_id_t port_index
)
588 AssertPort(port_index
);
589 JackConnectionManager
* manager
= WriteNextStateStart();
590 int res
= manager
->GetInputRefNum(port_index
);
591 WriteNextStateStop();
596 int JackGraphManager::GetOutputRefNum(jack_port_id_t port_index
)
598 AssertPort(port_index
);
599 JackConnectionManager
* manager
= WriteNextStateStart();
600 int res
= manager
->GetOutputRefNum(port_index
);
601 WriteNextStateStop();
605 int JackGraphManager::Connect(jack_port_id_t port_src
, jack_port_id_t port_dst
)
607 JackConnectionManager
* manager
= WriteNextStateStart();
608 jack_log("JackGraphManager::Connect port_src = %ld port_dst = %ld", port_src
, port_dst
);
609 JackPort
* src
= GetPort(port_src
);
610 JackPort
* dst
= GetPort(port_dst
);
613 if (!src
->fInUse
|| !dst
->fInUse
) {
615 jack_error("JackGraphManager::Connect port_src = %ld not used name = %s", port_src
, GetPort(port_src
)->fName
);
617 jack_error("JackGraphManager::Connect port_dst = %ld not used name = %s", port_dst
, GetPort(port_dst
)->fName
);
621 if (src
->fTypeId
!= dst
->fTypeId
) {
622 jack_error("JackGraphManager::Connect different port types port_src = %ld port_dst = %ld", port_src
, port_dst
);
626 if (manager
->IsConnected(port_src
, port_dst
)) {
627 jack_error("JackGraphManager::Connect already connected port_src = %ld port_dst = %ld", port_src
, port_dst
);
632 res
= manager
->Connect(port_src
, port_dst
);
634 jack_error("JackGraphManager::Connect failed port_src = %ld port_dst = %ld", port_src
, port_dst
);
637 res
= manager
->Connect(port_dst
, port_src
);
639 jack_error("JackGraphManager::Connect failed port_dst = %ld port_src = %ld", port_dst
, port_src
);
643 if (manager
->IsLoopPath(port_src
, port_dst
)) {
644 jack_log("JackGraphManager::Connect: LOOP detected");
645 manager
->IncFeedbackConnection(port_src
, port_dst
);
647 manager
->IncDirectConnection(port_src
, port_dst
);
651 WriteNextStateStop();
656 int JackGraphManager::Disconnect(jack_port_id_t port_src
, jack_port_id_t port_dst
)
658 JackConnectionManager
* manager
= WriteNextStateStart();
659 jack_log("JackGraphManager::Disconnect port_src = %ld port_dst = %ld", port_src
, port_dst
);
660 bool in_use_src
= GetPort(port_src
)->fInUse
;
661 bool in_use_dst
= GetPort(port_dst
)->fInUse
;
664 if (!in_use_src
|| !in_use_dst
) {
666 jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_src
, GetPort(port_src
)->fName
);
668 jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_dst
, GetPort(port_dst
)->fName
);
672 if (!manager
->IsConnected(port_src
, port_dst
)) {
673 jack_error("JackGraphManager::Disconnect not connected port_src = %ld port_dst = %ld", port_src
, port_dst
);
678 res
= manager
->Disconnect(port_src
, port_dst
);
680 jack_error("JackGraphManager::Disconnect failed port_src = %ld port_dst = %ld", port_src
, port_dst
);
683 res
= manager
->Disconnect(port_dst
, port_src
);
685 jack_error("JackGraphManager::Disconnect failed port_dst = %ld port_src = %ld", port_dst
, port_src
);
689 if (manager
->IsFeedbackConnection(port_src
, port_dst
)) {
690 jack_log("JackGraphManager::Disconnect: FEEDBACK removed");
691 manager
->DecFeedbackConnection(port_src
, port_dst
);
693 manager
->DecDirectConnection(port_src
, port_dst
);
697 WriteNextStateStop();
702 int JackGraphManager::IsConnected(jack_port_id_t port_src
, jack_port_id_t port_dst
)
704 JackConnectionManager
* manager
= ReadCurrentState();
705 return manager
->IsConnected(port_src
, port_dst
);
709 int JackGraphManager::CheckPorts(jack_port_id_t port_src
, jack_port_id_t port_dst
)
711 JackPort
* src
= GetPort(port_src
);
712 JackPort
* dst
= GetPort(port_dst
);
714 if ((dst
->fFlags
& JackPortIsInput
) == 0) {
715 jack_error("Destination port in attempted (dis)connection of %s and %s is not an input port", src
->fName
, dst
->fName
);
719 if ((src
->fFlags
& JackPortIsOutput
) == 0) {
720 jack_error("Source port in attempted (dis)connection of %s and %s is not an output port", src
->fName
, dst
->fName
);
727 int JackGraphManager::GetTwoPorts(const char* src_name
, const char* dst_name
, jack_port_id_t
* port_src
, jack_port_id_t
* port_dst
)
729 jack_log("JackGraphManager::CheckConnect src_name = %s dst_name = %s", src_name
, dst_name
);
731 if ((*port_src
= GetPort(src_name
)) == NO_PORT
) {
732 jack_error("Unknown source port in attempted (dis)connection src_name [%s] dst_name [%s]", src_name
, dst_name
);
736 if ((*port_dst
= GetPort(dst_name
)) == NO_PORT
) {
737 jack_error("Unknown destination port in attempted (dis)connection src_name [%s] dst_name [%s]", src_name
, dst_name
);
744 // Client : port array
745 jack_port_id_t
JackGraphManager::GetPort(const char* name
)
747 for (unsigned int i
= 0; i
< fPortMax
; i
++) {
748 JackPort
* port
= GetPort(i
);
749 if (port
->IsUsed() && port
->NameEquals(name
)) {
757 \brief Get the connection port name array.
761 void JackGraphManager::GetConnectionsAux(JackConnectionManager
* manager
, const char** res
, jack_port_id_t port_index
)
763 const jack_int_t
* connections
= manager
->GetConnections(port_index
);
767 // Cleanup connection array
768 memset(res
, 0, sizeof(char*) * CONNECTION_NUM_FOR_PORT
);
770 for (i
= 0; (i
< CONNECTION_NUM_FOR_PORT
) && ((index
= connections
[i
]) != EMPTY
); i
++) {
771 JackPort
* port
= GetPort(index
);
772 res
[i
] = port
->fName
;
779 Use the state returned by ReadCurrentState and check that the state was not changed during the read operation.
780 The operation is lock-free since there is no intermediate state in the write operation that could cause the
781 read to loop forever.
785 const char** JackGraphManager::GetConnections(jack_port_id_t port_index
)
787 const char** res
= (const char**)malloc(sizeof(char*) * CONNECTION_NUM_FOR_PORT
);
788 UInt16 cur_index
, next_index
;
794 cur_index
= GetCurrentIndex();
795 GetConnectionsAux(ReadCurrentState(), res
, port_index
);
796 next_index
= GetCurrentIndex();
797 } while (cur_index
!= next_index
); // Until a coherent state has been read
799 if (res
[0]) { // At least one connection
801 } else { // Empty array, should return NULL
808 void JackGraphManager::GetPortsAux(const char** matching_ports
, const char* port_name_pattern
, const char* type_name_pattern
, unsigned long flags
)
810 // Cleanup port array
811 memset(matching_ports
, 0, sizeof(char*) * fPortMax
);
814 regex_t port_regex
, type_regex
;
816 if (port_name_pattern
&& port_name_pattern
[0]) {
817 if (regcomp(&port_regex
, port_name_pattern
, REG_EXTENDED
| REG_NOSUB
)!=0) {
818 jack_log("JackGraphManager::GetPortsAux could not compile regex for port_name_pattern '%s'", port_name_pattern
);
822 if (type_name_pattern
&& type_name_pattern
[0]) {
823 if (regcomp(&type_regex
, type_name_pattern
, REG_EXTENDED
| REG_NOSUB
)!=0) {
824 jack_log("JackGraphManager::GetPortsAux could not compile regex for type_name_pattern '%s'", type_name_pattern
);
829 for (unsigned int i
= 0; i
< fPortMax
; i
++) {
830 bool matching
= true;
831 JackPort
* port
= GetPort(i
);
833 if (port
->IsUsed()) {
836 if ((port
->fFlags
& flags
) != flags
) {
841 if (matching
&& port_name_pattern
&& port_name_pattern
[0]) {
842 if (regexec(&port_regex
, port
->GetName(), 0, NULL
, 0)) {
846 if (matching
&& type_name_pattern
&& type_name_pattern
[0]) {
847 if (regexec(&type_regex
, port
->GetType(), 0, NULL
, 0)) {
853 matching_ports
[match_cnt
++] = port
->fName
;
858 matching_ports
[match_cnt
] = 0;
860 if (port_name_pattern
&& port_name_pattern
[0]) {
861 regfree(&port_regex
);
863 if (type_name_pattern
&& type_name_pattern
[0]) {
864 regfree(&type_regex
);
870 Check that the state was not changed during the read operation.
871 The operation is lock-free since there is no intermediate state in the write operation that could cause the
872 read to loop forever.
874 const char** JackGraphManager::GetPorts(const char* port_name_pattern
, const char* type_name_pattern
, unsigned long flags
)
876 const char** res
= (const char**)malloc(sizeof(char*) * fPortMax
);
877 UInt16 cur_index
, next_index
;
883 cur_index
= GetCurrentIndex();
884 GetPortsAux(res
, port_name_pattern
, type_name_pattern
, flags
);
885 next_index
= GetCurrentIndex();
886 } while (cur_index
!= next_index
); // Until a coherent state has been read
888 if (res
[0]) { // At least one port
891 free(res
); // Empty array, should return NULL
897 void JackGraphManager::Save(JackConnectionManager
* dst
)
899 JackConnectionManager
* manager
= WriteNextStateStart();
900 memcpy(dst
, manager
, sizeof(JackConnectionManager
));
901 WriteNextStateStop();
905 void JackGraphManager::Restore(JackConnectionManager
* src
)
907 JackConnectionManager
* manager
= WriteNextStateStart();
908 memcpy(manager
, src
, sizeof(JackConnectionManager
));
909 WriteNextStateStop();
912 } // end of namespace