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"
33 static void AssertBufferSize(jack_nframes_t buffer_size
)
35 if (buffer_size
> BUFFER_SIZE_MAX
) {
36 jack_log("JackGraphManager::AssertBufferSize frames = %ld", buffer_size
);
37 assert(buffer_size
<= BUFFER_SIZE_MAX
);
41 void JackGraphManager::AssertPort(jack_port_id_t port_index
)
43 if (port_index
>= fPortMax
) {
44 jack_log("JackGraphManager::AssertPort port_index = %ld", port_index
);
45 assert(port_index
< fPortMax
);
49 JackGraphManager
* JackGraphManager::Allocate(int port_max
)
51 // Using "Placement" new
52 void* shared_ptr
= JackShmMem::operator new(sizeof(JackGraphManager
) + port_max
* sizeof(JackPort
));
53 return new(shared_ptr
) JackGraphManager(port_max
);
56 void JackGraphManager::Destroy(JackGraphManager
* manager
)
58 // "Placement" new was used
59 manager
->~JackGraphManager();
60 JackShmMem::operator delete(manager
);
63 JackGraphManager::JackGraphManager(int port_max
)
65 assert(port_max
<= PORT_NUM_MAX
);
67 for (int i
= 0; i
< port_max
; i
++) {
68 fPortArray
[i
].Release();
74 JackPort
* JackGraphManager::GetPort(jack_port_id_t port_index
)
76 AssertPort(port_index
);
77 return &fPortArray
[port_index
];
80 jack_default_audio_sample_t
* JackGraphManager::GetBuffer(jack_port_id_t port_index
)
82 return fPortArray
[port_index
].GetBuffer();
86 void JackGraphManager::InitRefNum(int refnum
)
88 JackConnectionManager
* manager
= WriteNextStateStart();
89 manager
->InitRefNum(refnum
);
94 void JackGraphManager::RunCurrentGraph()
96 JackConnectionManager
* manager
= ReadCurrentState();
97 manager
->ResetGraph(fClientTiming
);
101 bool JackGraphManager::RunNextGraph()
104 JackConnectionManager
* manager
= TrySwitchState(&res
);
105 manager
->ResetGraph(fClientTiming
);
110 bool JackGraphManager::IsFinishedGraph()
112 JackConnectionManager
* manager
= ReadCurrentState();
113 return (manager
->GetActivation(FREEWHEEL_DRIVER_REFNUM
) == 0);
117 int JackGraphManager::ResumeRefNum(JackClientControl
* control
, JackSynchro
* table
)
119 JackConnectionManager
* manager
= ReadCurrentState();
120 return manager
->ResumeRefNum(control
, table
, fClientTiming
);
124 int JackGraphManager::SuspendRefNum(JackClientControl
* control
, JackSynchro
* table
, long usec
)
126 JackConnectionManager
* manager
= ReadCurrentState();
127 return manager
->SuspendRefNum(control
, table
, fClientTiming
, usec
);
130 void JackGraphManager::TopologicalSort(std::vector
<jack_int_t
>& sorted
)
136 cur_index
= GetCurrentIndex();
138 ReadCurrentState()->TopologicalSort(sorted
);
139 next_index
= GetCurrentIndex();
140 } while (cur_index
!= next_index
); // Until a coherent state has been read
144 void JackGraphManager::DirectConnect(int ref1
, int ref2
)
146 JackConnectionManager
* manager
= WriteNextStateStart();
147 manager
->DirectConnect(ref1
, ref2
);
148 jack_log("JackGraphManager::ConnectRefNum cur_index = %ld ref1 = %ld ref2 = %ld", CurIndex(fCounter
), ref1
, ref2
);
149 WriteNextStateStop();
153 void JackGraphManager::DirectDisconnect(int ref1
, int ref2
)
155 JackConnectionManager
* manager
= WriteNextStateStart();
156 manager
->DirectDisconnect(ref1
, ref2
);
157 jack_log("JackGraphManager::DisconnectRefNum cur_index = %ld ref1 = %ld ref2 = %ld", CurIndex(fCounter
), ref1
, ref2
);
158 WriteNextStateStop();
162 bool JackGraphManager::IsDirectConnection(int ref1
, int ref2
)
164 JackConnectionManager
* manager
= ReadCurrentState();
165 return manager
->IsDirectConnection(ref1
, ref2
);
169 void* JackGraphManager::GetBuffer(jack_port_id_t port_index
, jack_nframes_t buffer_size
)
171 AssertPort(port_index
);
172 AssertBufferSize(buffer_size
);
174 JackConnectionManager
* manager
= ReadCurrentState();
175 JackPort
* port
= GetPort(port_index
);
177 // This happens when a port has just been unregistered and is still used by the RT code
178 if (!port
->IsUsed()) {
179 jack_log("JackGraphManager::GetBuffer : port = %ld is released state", port_index
);
180 return GetBuffer(0); // port_index 0 is not used
184 if (port
->fFlags
& JackPortIsOutput
) {
185 return (port
->fTied
!= NO_PORT
) ? GetBuffer(port
->fTied
, buffer_size
) : GetBuffer(port_index
);
189 jack_int_t len
= manager
->Connections(port_index
);
191 // No connections : return a zero-filled buffer
193 port
->ClearBuffer(buffer_size
);
194 return port
->GetBuffer();
197 } else if (len
== 1) {
198 jack_port_id_t src_index
= manager
->GetPort(port_index
, 0);
200 // Ports in same client : copy the buffer
201 if (GetPort(src_index
)->GetRefNum() == port
->GetRefNum()) {
203 buffers
[0] = GetBuffer(src_index
, buffer_size
);
204 port
->MixBuffers(buffers
, 1, buffer_size
);
205 return port
->GetBuffer();
206 // Otherwise, use zero-copy mode, just pass the buffer of the connected (output) port.
208 return GetBuffer(src_index
, buffer_size
);
211 // Multiple connections : mix all buffers
214 const jack_int_t
* connections
= manager
->GetConnections(port_index
);
215 void* buffers
[CONNECTION_NUM_FOR_PORT
];
216 jack_port_id_t src_index
;
219 for (i
= 0; (i
< CONNECTION_NUM_FOR_PORT
) && ((src_index
= connections
[i
]) != EMPTY
); i
++) {
220 AssertPort(src_index
);
221 buffers
[i
] = GetBuffer(src_index
, buffer_size
);
224 port
->MixBuffers(buffers
, i
, buffer_size
);
225 return port
->GetBuffer();
230 int JackGraphManager::RequestMonitor(jack_port_id_t port_index
, bool onoff
) // Client
232 AssertPort(port_index
);
233 JackPort
* port
= GetPort(port_index
);
237 * If @ref JackPortCanMonitor is set for this @a port, turn input
238 * monitoring on or off. Otherwise, do nothing.
240 if (!(fFlags & JackPortCanMonitor))
244 port
->RequestMonitor(onoff
);
246 const jack_int_t
* connections
= ReadCurrentState()->GetConnections(port_index
);
247 if ((port
->fFlags
& JackPortIsOutput
) == 0) { // ?? Taken from jack, why not (port->fFlags & JackPortIsInput) ?
248 jack_port_id_t src_index
;
249 for (int i
= 0; (i
< CONNECTION_NUM_FOR_PORT
) && ((src_index
= connections
[i
]) != EMPTY
); i
++) {
250 // XXX much worse things will happen if there is a feedback loop !!!
251 RequestMonitor(src_index
, onoff
);
259 jack_nframes_t
JackGraphManager::ComputeTotalLatencyAux(jack_port_id_t port_index
, jack_port_id_t src_port_index
, JackConnectionManager
* manager
, int hop_count
)
261 const jack_int_t
* connections
= ReadCurrentState()->GetConnections(port_index
);
262 jack_nframes_t max_latency
= 0;
263 jack_port_id_t dst_index
;
266 return GetPort(port_index
)->GetLatency();
268 for (int i
= 0; (i
< CONNECTION_NUM_FOR_PORT
) && ((dst_index
= connections
[i
]) != EMPTY
); i
++) {
269 if (src_port_index
!= dst_index
) {
270 AssertPort(dst_index
);
271 JackPort
* dst_port
= GetPort(dst_index
);
272 jack_nframes_t this_latency
= (dst_port
->fFlags
& JackPortIsTerminal
)
273 ? dst_port
->GetLatency()
274 : ComputeTotalLatencyAux(dst_index
, port_index
, manager
, hop_count
+ 1);
275 max_latency
= ((max_latency
> this_latency
) ? max_latency
: this_latency
);
279 return max_latency
+ GetPort(port_index
)->GetLatency();
283 int JackGraphManager::ComputeTotalLatency(jack_port_id_t port_index
)
287 JackPort
* port
= GetPort(port_index
);
288 AssertPort(port_index
);
291 cur_index
= GetCurrentIndex();
292 port
->fTotalLatency
= ComputeTotalLatencyAux(port_index
, port_index
, ReadCurrentState(), 0);
293 next_index
= GetCurrentIndex();
294 } while (cur_index
!= next_index
); // Until a coherent state has been read
296 jack_log("JackGraphManager::GetTotalLatency port_index = %ld total latency = %ld", port_index
, port
->fTotalLatency
);
301 int JackGraphManager::ComputeTotalLatencies()
303 jack_port_id_t port_index
;
304 for (port_index
= FIRST_AVAILABLE_PORT
; port_index
< fPortMax
; port_index
++) {
305 JackPort
* port
= GetPort(port_index
);
307 ComputeTotalLatency(port_index
);
312 void JackGraphManager::RecalculateLatencyAux(jack_port_id_t port_index
, jack_latency_callback_mode_t mode
)
314 const jack_int_t
* connections
= ReadCurrentState()->GetConnections(port_index
);
315 JackPort
* port
= GetPort(port_index
);
316 jack_latency_range_t latency
= { UINT32_MAX
, 0 };
317 jack_port_id_t dst_index
;
319 for (int i
= 0; (i
< CONNECTION_NUM_FOR_PORT
) && ((dst_index
= connections
[i
]) != EMPTY
); i
++) {
320 AssertPort(dst_index
);
321 JackPort
* dst_port
= GetPort(dst_index
);
322 jack_latency_range_t other_latency
;
324 dst_port
->GetLatencyRange(mode
, &other_latency
);
326 if (other_latency
.max
> latency
.max
)
327 latency
.max
= other_latency
.max
;
328 if (other_latency
.min
< latency
.min
)
329 latency
.min
= other_latency
.min
;
332 if (latency
.min
== UINT32_MAX
)
335 port
->SetLatencyRange(mode
, &latency
);
338 void JackGraphManager::RecalculateLatency(jack_port_id_t port_index
, jack_latency_callback_mode_t mode
)
344 cur_index
= GetCurrentIndex();
345 RecalculateLatencyAux(port_index
, mode
);
346 next_index
= GetCurrentIndex();
347 } while (cur_index
!= next_index
); // Until a coherent state has been read
349 jack_log("JackGraphManager::RecalculateLatency port_index = %ld", port_index
);
353 void JackGraphManager::SetBufferSize(jack_nframes_t buffer_size
)
355 jack_log("JackGraphManager::SetBufferSize size = %ld", buffer_size
);
357 jack_port_id_t port_index
;
358 for (port_index
= FIRST_AVAILABLE_PORT
; port_index
< fPortMax
; port_index
++) {
359 JackPort
* port
= GetPort(port_index
);
361 port
->ClearBuffer(buffer_size
);
366 jack_port_id_t
JackGraphManager::AllocatePortAux(int refnum
, const char* port_name
, const char* port_type
, JackPortFlags flags
)
368 jack_port_id_t port_index
;
370 // Available ports start at FIRST_AVAILABLE_PORT (= 1), otherwise a port_index of 0 is "seen" as a NULL port by the external API...
371 for (port_index
= FIRST_AVAILABLE_PORT
; port_index
< fPortMax
; port_index
++) {
372 JackPort
* port
= GetPort(port_index
);
373 if (!port
->IsUsed()) {
374 jack_log("JackGraphManager::AllocatePortAux port_index = %ld name = %s type = %s", port_index
, port_name
, port_type
);
375 if (!port
->Allocate(refnum
, port_name
, port_type
, flags
))
381 return (port_index
< fPortMax
) ? port_index
: NO_PORT
;
385 jack_port_id_t
JackGraphManager::AllocatePort(int refnum
, const char* port_name
, const char* port_type
, JackPortFlags flags
, jack_nframes_t buffer_size
)
387 JackConnectionManager
* manager
= WriteNextStateStart();
388 jack_port_id_t port_index
= AllocatePortAux(refnum
, port_name
, port_type
, flags
);
390 if (port_index
!= NO_PORT
) {
391 JackPort
* port
= GetPort(port_index
);
393 port
->ClearBuffer(buffer_size
);
396 if (flags
& JackPortIsOutput
) {
397 res
= manager
->AddOutputPort(refnum
, port_index
);
399 res
= manager
->AddInputPort(refnum
, port_index
);
404 port_index
= NO_PORT
;
408 WriteNextStateStop();
413 int JackGraphManager::ReleasePort(int refnum
, jack_port_id_t port_index
)
415 JackConnectionManager
* manager
= WriteNextStateStart();
416 JackPort
* port
= GetPort(port_index
);
419 if (port
->fFlags
& JackPortIsOutput
) {
420 DisconnectAllOutput(port_index
);
421 res
= manager
->RemoveOutputPort(refnum
, port_index
);
423 DisconnectAllInput(port_index
);
424 res
= manager
->RemoveInputPort(refnum
, port_index
);
428 WriteNextStateStop();
432 void JackGraphManager::GetInputPorts(int refnum
, jack_int_t
* res
)
434 JackConnectionManager
* manager
= WriteNextStateStart();
435 const jack_int_t
* input
= manager
->GetInputPorts(refnum
);
436 memcpy(res
, input
, sizeof(jack_int_t
) * PORT_NUM_FOR_CLIENT
);
437 WriteNextStateStop();
440 void JackGraphManager::GetOutputPorts(int refnum
, jack_int_t
* res
)
442 JackConnectionManager
* manager
= WriteNextStateStart();
443 const jack_int_t
* output
= manager
->GetOutputPorts(refnum
);
444 memcpy(res
, output
, sizeof(jack_int_t
) * PORT_NUM_FOR_CLIENT
);
445 WriteNextStateStop();
449 void JackGraphManager::RemoveAllPorts(int refnum
)
451 jack_log("JackGraphManager::RemoveAllPorts ref = %ld", refnum
);
452 JackConnectionManager
* manager
= WriteNextStateStart();
453 jack_port_id_t port_index
;
455 // Warning : ReleasePort shift port to left, thus we always remove the first port until the "input" table is empty
456 const jack_int_t
* input
= manager
->GetInputPorts(refnum
);
457 while ((port_index
= input
[0]) != EMPTY
) {
458 int res
= ReleasePort(refnum
, port_index
);
460 jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum
, port_index
);
466 // Warning : ReleasePort shift port to left, thus we always remove the first port until the "output" table is empty
467 const jack_int_t
* output
= manager
->GetOutputPorts(refnum
);
468 while ((port_index
= output
[0]) != EMPTY
) {
469 int res
= ReleasePort(refnum
, port_index
);
471 jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum
, port_index
);
477 WriteNextStateStop();
481 void JackGraphManager::DisconnectAllPorts(int refnum
)
484 jack_log("JackGraphManager::DisconnectAllPorts ref = %ld", refnum
);
485 JackConnectionManager
* manager
= WriteNextStateStart();
487 const jack_int_t
* input
= manager
->GetInputPorts(refnum
);
488 for (i
= 0; i
< PORT_NUM_FOR_CLIENT
&& input
[i
] != EMPTY
; i
++) {
489 DisconnectAllInput(input
[i
]);
492 const jack_int_t
* output
= manager
->GetOutputPorts(refnum
);
493 for (i
= 0; i
< PORT_NUM_FOR_CLIENT
&& output
[i
] != EMPTY
; i
++) {
494 DisconnectAllOutput(output
[i
]);
497 WriteNextStateStop();
501 void JackGraphManager::DisconnectAllInput(jack_port_id_t port_index
)
503 jack_log("JackGraphManager::DisconnectAllInput port_index = %ld", port_index
);
504 JackConnectionManager
* manager
= WriteNextStateStart();
506 for (unsigned int i
= 0; i
< fPortMax
; i
++) {
507 if (manager
->IsConnected(i
, port_index
)) {
508 jack_log("JackGraphManager::Disconnect i = %ld port_index = %ld", i
, port_index
);
509 Disconnect(i
, port_index
);
512 WriteNextStateStop();
516 void JackGraphManager::DisconnectAllOutput(jack_port_id_t port_index
)
518 jack_log("JackGraphManager::DisconnectAllOutput port_index = %ld ", port_index
);
519 JackConnectionManager
* manager
= WriteNextStateStart();
521 const jack_int_t
* connections
= manager
->GetConnections(port_index
);
522 while (connections
[0] != EMPTY
) {
523 Disconnect(port_index
, connections
[0]); // Warning : Disconnect shift port to left
525 WriteNextStateStop();
529 int JackGraphManager::DisconnectAll(jack_port_id_t port_index
)
531 AssertPort(port_index
);
533 JackPort
* port
= GetPort(port_index
);
534 if (port
->fFlags
& JackPortIsOutput
) {
535 DisconnectAllOutput(port_index
);
537 DisconnectAllInput(port_index
);
543 void JackGraphManager::GetConnections(jack_port_id_t port_index
, jack_int_t
* res
)
545 JackConnectionManager
* manager
= WriteNextStateStart();
546 const jack_int_t
* connections
= manager
->GetConnections(port_index
);
547 memcpy(res
, connections
, sizeof(jack_int_t
) * CONNECTION_NUM_FOR_PORT
);
548 WriteNextStateStop();
552 void JackGraphManager::Activate(int refnum
)
554 DirectConnect(FREEWHEEL_DRIVER_REFNUM
, refnum
);
555 DirectConnect(refnum
, FREEWHEEL_DRIVER_REFNUM
);
559 Disconnection from the FW must be done in last otherwise an intermediate "unconnected"
560 (thus unactivated) state may happen where the client is still checked for its end.
564 void JackGraphManager::Deactivate(int refnum
)
566 // Disconnect only when needed
567 if (IsDirectConnection(refnum
, FREEWHEEL_DRIVER_REFNUM
)) {
568 DirectDisconnect(refnum
, FREEWHEEL_DRIVER_REFNUM
);
570 jack_log("JackServer::Deactivate client = %ld was not activated", refnum
);
573 // Disconnect only when needed
574 if (IsDirectConnection(FREEWHEEL_DRIVER_REFNUM
, refnum
)) {
575 DirectDisconnect(FREEWHEEL_DRIVER_REFNUM
, refnum
);
577 jack_log("JackServer::Deactivate client = %ld was not activated", refnum
);
582 int JackGraphManager::GetInputRefNum(jack_port_id_t port_index
)
584 AssertPort(port_index
);
585 JackConnectionManager
* manager
= WriteNextStateStart();
586 int res
= manager
->GetInputRefNum(port_index
);
587 WriteNextStateStop();
592 int JackGraphManager::GetOutputRefNum(jack_port_id_t port_index
)
594 AssertPort(port_index
);
595 JackConnectionManager
* manager
= WriteNextStateStart();
596 int res
= manager
->GetOutputRefNum(port_index
);
597 WriteNextStateStop();
601 int JackGraphManager::Connect(jack_port_id_t port_src
, jack_port_id_t port_dst
)
603 JackConnectionManager
* manager
= WriteNextStateStart();
604 jack_log("JackGraphManager::Connect port_src = %ld port_dst = %ld", port_src
, port_dst
);
605 JackPort
* src
= GetPort(port_src
);
606 JackPort
* dst
= GetPort(port_dst
);
609 if (!src
->fInUse
|| !dst
->fInUse
) {
611 jack_error("JackGraphManager::Connect port_src = %ld not used name = %s", port_src
, GetPort(port_src
)->fName
);
613 jack_error("JackGraphManager::Connect port_dst = %ld not used name = %s", port_dst
, GetPort(port_dst
)->fName
);
617 if (src
->fTypeId
!= dst
->fTypeId
) {
618 jack_error("JackGraphManager::Connect different port types port_src = %ld port_dst = %ld", port_src
, port_dst
);
622 if (manager
->IsConnected(port_src
, port_dst
)) {
623 jack_error("JackGraphManager::Connect already connected port_src = %ld port_dst = %ld", port_src
, port_dst
);
628 res
= manager
->Connect(port_src
, port_dst
);
630 jack_error("JackGraphManager::Connect failed port_src = %ld port_dst = %ld", port_src
, port_dst
);
633 res
= manager
->Connect(port_dst
, port_src
);
635 jack_error("JackGraphManager::Connect failed port_dst = %ld port_src = %ld", port_dst
, port_src
);
639 if (manager
->IsLoopPath(port_src
, port_dst
)) {
640 jack_log("JackGraphManager::Connect: LOOP detected");
641 manager
->IncFeedbackConnection(port_src
, port_dst
);
643 manager
->IncDirectConnection(port_src
, port_dst
);
647 WriteNextStateStop();
652 int JackGraphManager::Disconnect(jack_port_id_t port_src
, jack_port_id_t port_dst
)
654 JackConnectionManager
* manager
= WriteNextStateStart();
655 jack_log("JackGraphManager::Disconnect port_src = %ld port_dst = %ld", port_src
, port_dst
);
656 bool in_use_src
= GetPort(port_src
)->fInUse
;
657 bool in_use_dst
= GetPort(port_dst
)->fInUse
;
660 if (!in_use_src
|| !in_use_dst
) {
662 jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_src
, GetPort(port_src
)->fName
);
664 jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_dst
, GetPort(port_dst
)->fName
);
668 if (!manager
->IsConnected(port_src
, port_dst
)) {
669 jack_error("JackGraphManager::Disconnect not connected port_src = %ld port_dst = %ld", port_src
, port_dst
);
674 res
= manager
->Disconnect(port_src
, port_dst
);
676 jack_error("JackGraphManager::Disconnect failed port_src = %ld port_dst = %ld", port_src
, port_dst
);
679 res
= manager
->Disconnect(port_dst
, port_src
);
681 jack_error("JackGraphManager::Disconnect failed port_dst = %ld port_src = %ld", port_dst
, port_src
);
685 if (manager
->IsFeedbackConnection(port_src
, port_dst
)) {
686 jack_log("JackGraphManager::Disconnect: FEEDBACK removed");
687 manager
->DecFeedbackConnection(port_src
, port_dst
);
689 manager
->DecDirectConnection(port_src
, port_dst
);
693 WriteNextStateStop();
698 int JackGraphManager::IsConnected(jack_port_id_t port_src
, jack_port_id_t port_dst
)
700 JackConnectionManager
* manager
= ReadCurrentState();
701 return manager
->IsConnected(port_src
, port_dst
);
705 int JackGraphManager::CheckPorts(jack_port_id_t port_src
, jack_port_id_t port_dst
)
707 JackPort
* src
= GetPort(port_src
);
708 JackPort
* dst
= GetPort(port_dst
);
710 if ((dst
->fFlags
& JackPortIsInput
) == 0) {
711 jack_error("Destination port in attempted (dis)connection of %s and %s is not an input port", src
->fName
, dst
->fName
);
715 if ((src
->fFlags
& JackPortIsOutput
) == 0) {
716 jack_error("Source port in attempted (dis)connection of %s and %s is not an output port", src
->fName
, dst
->fName
);
723 int JackGraphManager::GetTwoPorts(const char* src_name
, const char* dst_name
, jack_port_id_t
* port_src
, jack_port_id_t
* port_dst
)
725 jack_log("JackGraphManager::CheckConnect src_name = %s dst_name = %s", src_name
, dst_name
);
727 if ((*port_src
= GetPort(src_name
)) == NO_PORT
) {
728 jack_error("Unknown source port in attempted (dis)connection src_name [%s] dst_name [%s]", src_name
, dst_name
);
732 if ((*port_dst
= GetPort(dst_name
)) == NO_PORT
) {
733 jack_error("Unknown destination port in attempted (dis)connection src_name [%s] dst_name [%s]", src_name
, dst_name
);
740 // Client : port array
741 jack_port_id_t
JackGraphManager::GetPort(const char* name
)
743 for (unsigned int i
= 0; i
< fPortMax
; i
++) {
744 JackPort
* port
= GetPort(i
);
745 if (port
->IsUsed() && port
->NameEquals(name
))
752 \brief Get the connection port name array.
756 void JackGraphManager::GetConnectionsAux(JackConnectionManager
* manager
, const char** res
, jack_port_id_t port_index
)
758 const jack_int_t
* connections
= manager
->GetConnections(port_index
);
762 // Cleanup connection array
763 memset(res
, 0, sizeof(char*) * CONNECTION_NUM_FOR_PORT
);
765 for (i
= 0; (i
< CONNECTION_NUM_FOR_PORT
) && ((index
= connections
[i
]) != EMPTY
); i
++) {
766 JackPort
* port
= GetPort(index
);
767 res
[i
] = port
->fName
;
774 Use the state returned by ReadCurrentState and check that the state was not changed during the read operation.
775 The operation is lock-free since there is no intermediate state in the write operation that could cause the
776 read to loop forever.
780 const char** JackGraphManager::GetConnections(jack_port_id_t port_index
)
782 const char** res
= (const char**)malloc(sizeof(char*) * CONNECTION_NUM_FOR_PORT
);
783 UInt16 cur_index
, next_index
;
789 cur_index
= GetCurrentIndex();
790 GetConnectionsAux(ReadCurrentState(), res
, port_index
);
791 next_index
= GetCurrentIndex();
792 } while (cur_index
!= next_index
); // Until a coherent state has been read
794 if (res
[0]) { // at least one connection
796 } else { // empty array, should return NULL
803 void JackGraphManager::GetPortsAux(const char** matching_ports
, const char* port_name_pattern
, const char* type_name_pattern
, unsigned long flags
)
806 regex_t port_regex
, type_regex
;
808 if (port_name_pattern
&& port_name_pattern
[0]) {
809 regcomp(&port_regex
, port_name_pattern
, REG_EXTENDED
| REG_NOSUB
);
811 if (type_name_pattern
&& type_name_pattern
[0]) {
812 regcomp(&type_regex
, type_name_pattern
, REG_EXTENDED
| REG_NOSUB
);
815 // Cleanup port array
816 memset(matching_ports
, 0, sizeof(char*) * fPortMax
);
818 for (unsigned int i
= 0; i
< fPortMax
; i
++) {
819 bool matching
= true;
820 JackPort
* port
= GetPort(i
);
822 if (port
->IsUsed()) {
825 if ((port
->fFlags
& flags
) != flags
) {
830 if (matching
&& port_name_pattern
&& port_name_pattern
[0]) {
831 if (regexec(&port_regex
, port
->GetName(), 0, NULL
, 0)) {
835 if (matching
&& type_name_pattern
&& type_name_pattern
[0]) {
836 if (regexec(&type_regex
, port
->GetType(), 0, NULL
, 0)) {
842 matching_ports
[match_cnt
++] = port
->fName
;
847 matching_ports
[match_cnt
] = 0;
849 if (port_name_pattern
&& port_name_pattern
[0]) {
850 regfree(&port_regex
);
852 if (type_name_pattern
&& type_name_pattern
[0]) {
853 regfree(&type_regex
);
859 Check that the state was not changed during the read operation.
860 The operation is lock-free since there is no intermediate state in the write operation that could cause the
861 read to loop forever.
863 const char** JackGraphManager::GetPorts(const char* port_name_pattern
, const char* type_name_pattern
, unsigned long flags
)
865 const char** res
= (const char**)malloc(sizeof(char*) * fPortMax
);
866 UInt16 cur_index
, next_index
;
872 cur_index
= GetCurrentIndex();
873 GetPortsAux(res
, port_name_pattern
, type_name_pattern
, flags
);
874 next_index
= GetCurrentIndex();
875 } while (cur_index
!= next_index
); // Until a coherent state has been read
877 if (res
[0]) { // at least one port
880 free(res
); // empty array, should return NULL
886 void JackGraphManager::Save(JackConnectionManager
* dst
)
888 JackConnectionManager
* manager
= WriteNextStateStart();
889 memcpy(dst
, manager
, sizeof(JackConnectionManager
));
890 WriteNextStateStop();
894 void JackGraphManager::Restore(JackConnectionManager
* src
)
896 JackConnectionManager
* manager
= WriteNextStateStart();
897 memcpy(manager
, src
, sizeof(JackConnectionManager
));
898 WriteNextStateStop();
901 } // end of namespace