Merge branch 'master' into newer-midi-with-winmme-driver
[jack2.git] / common / JackGraphManager.cpp
blob1366316a137b44efeea359c48302084311a63e58
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
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();
71 fPortMax = port_max;
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();
85 // Server
86 void JackGraphManager::InitRefNum(int refnum)
88 JackConnectionManager* manager = WriteNextStateStart();
89 manager->InitRefNum(refnum);
90 WriteNextStateStop();
93 // RT
94 void JackGraphManager::RunCurrentGraph()
96 JackConnectionManager* manager = ReadCurrentState();
97 manager->ResetGraph(fClientTiming);
100 // RT
101 bool JackGraphManager::RunNextGraph()
103 bool res;
104 JackConnectionManager* manager = TrySwitchState(&res);
105 manager->ResetGraph(fClientTiming);
106 return res;
109 // RT
110 bool JackGraphManager::IsFinishedGraph()
112 JackConnectionManager* manager = ReadCurrentState();
113 return (manager->GetActivation(FREEWHEEL_DRIVER_REFNUM) == 0);
116 // RT
117 int JackGraphManager::ResumeRefNum(JackClientControl* control, JackSynchro* table)
119 JackConnectionManager* manager = ReadCurrentState();
120 return manager->ResumeRefNum(control, table, fClientTiming);
123 // RT
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)
132 UInt16 cur_index;
133 UInt16 next_index;
135 do {
136 cur_index = GetCurrentIndex();
137 sorted.clear();
138 ReadCurrentState()->TopologicalSort(sorted);
139 next_index = GetCurrentIndex();
140 } while (cur_index != next_index); // Until a coherent state has been read
143 // Server
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();
152 // Server
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();
161 // Server
162 bool JackGraphManager::IsDirectConnection(int ref1, int ref2)
164 JackConnectionManager* manager = ReadCurrentState();
165 return manager->IsDirectConnection(ref1, ref2);
168 // RT
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
183 // Output port
184 if (port->fFlags & JackPortIsOutput) {
185 return (port->fTied != NO_PORT) ? GetBuffer(port->fTied, buffer_size) : GetBuffer(port_index);
188 // Input port
189 jack_int_t len = manager->Connections(port_index);
191 // No connections : return a zero-filled buffer
192 if (len == 0) {
193 port->ClearBuffer(buffer_size);
194 return port->GetBuffer();
196 // One connection
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()) {
202 void* buffers[1];
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.
207 } else {
208 return GetBuffer(src_index, buffer_size);
211 // Multiple connections : mix all buffers
212 } else {
214 const jack_int_t* connections = manager->GetConnections(port_index);
215 void* buffers[CONNECTION_NUM_FOR_PORT];
216 jack_port_id_t src_index;
217 int i;
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();
229 // Server
230 int JackGraphManager::RequestMonitor(jack_port_id_t port_index, bool onoff) // Client
232 AssertPort(port_index);
233 JackPort* port = GetPort(port_index);
236 jackd.h
237 * If @ref JackPortCanMonitor is set for this @a port, turn input
238 * monitoring on or off. Otherwise, do nothing.
240 if (!(fFlags & JackPortCanMonitor))
241 return -1;
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);
255 return 0;
258 // Client
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;
265 if (hop_count > 8)
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();
282 // Client
283 int JackGraphManager::ComputeTotalLatency(jack_port_id_t port_index)
285 UInt16 cur_index;
286 UInt16 next_index;
287 JackPort* port = GetPort(port_index);
288 AssertPort(port_index);
290 do {
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);
297 return 0;
300 // Client
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);
306 if (port->IsUsed())
307 ComputeTotalLatency(port_index);
309 return 0;
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)
333 latency.min = 0;
335 port->SetLatencyRange(mode, &latency);
338 void JackGraphManager::RecalculateLatency(jack_port_id_t port_index, jack_latency_callback_mode_t mode)
340 UInt16 cur_index;
341 UInt16 next_index;
343 do {
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);
352 // Server
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);
360 if (port->IsUsed())
361 port->ClearBuffer(buffer_size);
365 // Server
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))
376 return NO_PORT;
377 break;
381 return (port_index < fPortMax) ? port_index : NO_PORT;
384 // Server
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);
392 assert(port);
393 port->ClearBuffer(buffer_size);
395 int res;
396 if (flags & JackPortIsOutput) {
397 res = manager->AddOutputPort(refnum, port_index);
398 } else {
399 res = manager->AddInputPort(refnum, port_index);
401 // Insertion failure
402 if (res < 0) {
403 port->Release();
404 port_index = NO_PORT;
408 WriteNextStateStop();
409 return port_index;
412 // Server
413 int JackGraphManager::ReleasePort(int refnum, jack_port_id_t port_index)
415 JackConnectionManager* manager = WriteNextStateStart();
416 JackPort* port = GetPort(port_index);
417 int res;
419 if (port->fFlags & JackPortIsOutput) {
420 DisconnectAllOutput(port_index);
421 res = manager->RemoveOutputPort(refnum, port_index);
422 } else {
423 DisconnectAllInput(port_index);
424 res = manager->RemoveInputPort(refnum, port_index);
427 port->Release();
428 WriteNextStateStop();
429 return res;
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();
448 // Server
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);
459 if (res < 0) {
460 jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum, port_index);
461 assert(true);
462 break;
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);
470 if (res < 0) {
471 jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum, port_index);
472 assert(true);
473 break;
477 WriteNextStateStop();
480 // Server
481 void JackGraphManager::DisconnectAllPorts(int refnum)
483 int i;
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();
500 // Server
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();
515 // Server
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();
528 // Server
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);
536 } else {
537 DisconnectAllInput(port_index);
539 return 0;
542 // Server
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();
551 // Server
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.
563 // Server
564 void JackGraphManager::Deactivate(int refnum)
566 // Disconnect only when needed
567 if (IsDirectConnection(refnum, FREEWHEEL_DRIVER_REFNUM)) {
568 DirectDisconnect(refnum, FREEWHEEL_DRIVER_REFNUM);
569 } else {
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);
576 } else {
577 jack_log("JackServer::Deactivate client = %ld was not activated", refnum);
581 // Server
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();
588 return res;
591 // Server
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();
598 return res;
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);
607 int res = 0;
609 if (!src->fInUse || !dst->fInUse) {
610 if (!src->fInUse)
611 jack_error("JackGraphManager::Connect port_src = %ld not used name = %s", port_src, GetPort(port_src)->fName);
612 if (!dst->fInUse)
613 jack_error("JackGraphManager::Connect port_dst = %ld not used name = %s", port_dst, GetPort(port_dst)->fName);
614 res = -1;
615 goto end;
617 if (src->fTypeId != dst->fTypeId) {
618 jack_error("JackGraphManager::Connect different port types port_src = %ld port_dst = %ld", port_src, port_dst);
619 res = -1;
620 goto end;
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);
624 res = EEXIST;
625 goto end;
628 res = manager->Connect(port_src, port_dst);
629 if (res < 0) {
630 jack_error("JackGraphManager::Connect failed port_src = %ld port_dst = %ld", port_src, port_dst);
631 goto end;
633 res = manager->Connect(port_dst, port_src);
634 if (res < 0) {
635 jack_error("JackGraphManager::Connect failed port_dst = %ld port_src = %ld", port_dst, port_src);
636 goto end;
639 if (manager->IsLoopPath(port_src, port_dst)) {
640 jack_log("JackGraphManager::Connect: LOOP detected");
641 manager->IncFeedbackConnection(port_src, port_dst);
642 } else {
643 manager->IncDirectConnection(port_src, port_dst);
646 end:
647 WriteNextStateStop();
648 return res;
651 // Server
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;
658 int res = 0;
660 if (!in_use_src || !in_use_dst) {
661 if (!in_use_src)
662 jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_src, GetPort(port_src)->fName);
663 if (!in_use_dst)
664 jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_dst, GetPort(port_dst)->fName);
665 res = -1;
666 goto end;
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);
670 res = -1;
671 goto end;
674 res = manager->Disconnect(port_src, port_dst);
675 if (res < 0) {
676 jack_error("JackGraphManager::Disconnect failed port_src = %ld port_dst = %ld", port_src, port_dst);
677 goto end;
679 res = manager->Disconnect(port_dst, port_src);
680 if (res < 0) {
681 jack_error("JackGraphManager::Disconnect failed port_dst = %ld port_src = %ld", port_dst, port_src);
682 goto end;
685 if (manager->IsFeedbackConnection(port_src, port_dst)) {
686 jack_log("JackGraphManager::Disconnect: FEEDBACK removed");
687 manager->DecFeedbackConnection(port_src, port_dst);
688 } else {
689 manager->DecDirectConnection(port_src, port_dst);
692 end:
693 WriteNextStateStop();
694 return res;
697 // Client
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);
704 // Server
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);
712 return -1;
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);
717 return -1;
720 return 0;
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);
729 return -1;
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);
734 return -1;
737 return 0;
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))
746 return i;
748 return NO_PORT;
752 \brief Get the connection port name array.
755 // Client
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);
759 jack_int_t index;
760 int i;
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;
770 res[i] = NULL;
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.
779 // Client
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;
785 if (!res)
786 return NULL;
788 do {
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
795 return res;
796 } else { // empty array, should return NULL
797 free(res);
798 return NULL;
802 // Client
803 void JackGraphManager::GetPortsAux(const char** matching_ports, const char* port_name_pattern, const char* type_name_pattern, unsigned long flags)
805 int match_cnt = 0;
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()) {
824 if (flags) {
825 if ((port->fFlags & flags) != flags) {
826 matching = false;
830 if (matching && port_name_pattern && port_name_pattern[0]) {
831 if (regexec(&port_regex, port->GetName(), 0, NULL, 0)) {
832 matching = false;
835 if (matching && type_name_pattern && type_name_pattern[0]) {
836 if (regexec(&type_regex, port->GetType(), 0, NULL, 0)) {
837 matching = false;
841 if (matching) {
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);
857 // Client
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;
868 if (!res)
869 return NULL;
871 do {
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
878 return res;
879 } else {
880 free(res); // empty array, should return NULL
881 return NULL;
885 // Server
886 void JackGraphManager::Save(JackConnectionManager* dst)
888 JackConnectionManager* manager = WriteNextStateStart();
889 memcpy(dst, manager, sizeof(JackConnectionManager));
890 WriteNextStateStop();
893 // Server
894 void JackGraphManager::Restore(JackConnectionManager* src)
896 JackConnectionManager* manager = WriteNextStateStart();
897 memcpy(manager, src, sizeof(JackConnectionManager));
898 WriteNextStateStop();
901 } // end of namespace