Jack2 1.9.12

JackGraphManager.cpp
1 /*
2 Copyright (C) 2001 Paul Davis
3 Copyright (C) 2004-2008 Grame
4
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.
9
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.
14
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.
18
19 */
20
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>
28
29 namespace Jack
30 {
31
32 static void AssertBufferSize(jack_nframes_t buffer_size)
33 {
34 if (buffer_size > BUFFER_SIZE_MAX) {
35 jack_log("JackGraphManager::AssertBufferSize frames = %ld", buffer_size);
36 assert(buffer_size <= BUFFER_SIZE_MAX);
37 }
38 }
39
40 void JackGraphManager::AssertPort(jack_port_id_t port_index)
41 {
42 if (port_index >= fPortMax) {
43 jack_log("JackGraphManager::AssertPort port_index = %ld", port_index);
44 assert(port_index < fPortMax);
45 }
46 }
47
48 JackGraphManager* JackGraphManager::Allocate(int port_max)
49 {
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);
53 }
54
55 void JackGraphManager::Destroy(JackGraphManager* manager)
56 {
57 // "Placement" new was used
58 manager->~JackGraphManager();
59 JackShmMem::operator delete(manager);
60 }
61
62 JackGraphManager::JackGraphManager(int port_max)
63 {
64 assert(port_max <= PORT_NUM_MAX);
65
66 for (int i = 0; i < port_max; i++) {
67 fPortArray[i].Release();
68 }
69
70 fPortMax = port_max;
71 }
72
73 JackPort* JackGraphManager::GetPort(jack_port_id_t port_index)
74 {
75 AssertPort(port_index);
76 return &fPortArray[port_index];
77 }
78
79 jack_default_audio_sample_t* JackGraphManager::GetBuffer(jack_port_id_t port_index)
80 {
81 return fPortArray[port_index].GetBuffer();
82 }
83
84 // Server
85 void JackGraphManager::InitRefNum(int refnum)
86 {
87 JackConnectionManager* manager = WriteNextStateStart();
88 manager->InitRefNum(refnum);
89 WriteNextStateStop();
90 }
91
92 // RT
93 void JackGraphManager::RunCurrentGraph()
94 {
95 JackConnectionManager* manager = ReadCurrentState();
96 manager->ResetGraph(fClientTiming);
97 }
98
99 // RT
100 bool JackGraphManager::RunNextGraph()
101 {
102 bool res;
103 JackConnectionManager* manager = TrySwitchState(&res);
104 manager->ResetGraph(fClientTiming);
105 return res;
106 }
107
108 // RT
109 bool JackGraphManager::IsFinishedGraph()
110 {
111 JackConnectionManager* manager = ReadCurrentState();
112 return (manager->GetActivation(FREEWHEEL_DRIVER_REFNUM) == 0);
113 }
114
115 // RT
116 int JackGraphManager::ResumeRefNum(JackClientControl* control, JackSynchro* table)
117 {
118 JackConnectionManager* manager = ReadCurrentState();
119 return manager->ResumeRefNum(control, table, fClientTiming);
120 }
121
122 // RT
123 int JackGraphManager::SuspendRefNum(JackClientControl* control, JackSynchro* table, long usec)
124 {
125 JackConnectionManager* manager = ReadCurrentState();
126 return manager->SuspendRefNum(control, table, fClientTiming, usec);
127 }
128
129 void JackGraphManager::TopologicalSort(std::vector<jack_int_t>& sorted)
130 {
131 UInt16 cur_index;
132 UInt16 next_index;
133
134 do {
135 cur_index = GetCurrentIndex();
136 sorted.clear();
137 ReadCurrentState()->TopologicalSort(sorted);
138 next_index = GetCurrentIndex();
139 } while (cur_index != next_index); // Until a coherent state has been read
140 }
141
142 // Server
143 void JackGraphManager::DirectConnect(int ref1, int ref2)
144 {
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();
149 }
150
151 // Server
152 void JackGraphManager::DirectDisconnect(int ref1, int ref2)
153 {
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();
158 }
159
160 // Server
161 bool JackGraphManager::IsDirectConnection(int ref1, int ref2)
162 {
163 JackConnectionManager* manager = ReadCurrentState();
164 return manager->IsDirectConnection(ref1, ref2);
165 }
166
167 // RT
168 void* JackGraphManager::GetBuffer(jack_port_id_t port_index, jack_nframes_t buffer_size)
169 {
170 AssertPort(port_index);
171 AssertBufferSize(buffer_size);
172
173 JackConnectionManager* manager = ReadCurrentState();
174 JackPort* port = GetPort(port_index);
175
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
180 }
181
182 jack_int_t len = manager->Connections(port_index);
183
184 // Output port
185 if (port->fFlags & JackPortIsOutput) {
186 return (port->fTied != NO_PORT) ? GetBuffer(port->fTied, buffer_size) : GetBuffer(port_index);
187 }
188
189 // No connections : return a zero-filled buffer
190 if (len == 0) {
191 port->ClearBuffer(buffer_size);
192 return port->GetBuffer();
193
194 // One connection
195 } else if (len == 1) {
196 jack_port_id_t src_index = manager->GetPort(port_index, 0);
197
198 // Ports in same client : copy the buffer
199 if (GetPort(src_index)->GetRefNum() == port->GetRefNum()) {
200 void* buffers[1];
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.
205 } else {
206 return GetBuffer(src_index, buffer_size);
207 }
208
209 // Multiple connections : mix all buffers
210 } else {
211
212 const jack_int_t* connections = manager->GetConnections(port_index);
213 void* buffers[CONNECTION_NUM_FOR_PORT];
214 jack_port_id_t src_index;
215 int i;
216
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);
220 }
221
222 port->MixBuffers(buffers, i, buffer_size);
223 return port->GetBuffer();
224 }
225 }
226
227 // Server
228 int JackGraphManager::RequestMonitor(jack_port_id_t port_index, bool onoff) // Client
229 {
230 AssertPort(port_index);
231 JackPort* port = GetPort(port_index);
232
242 port->RequestMonitor(onoff);
243
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);
250 }
251 }
252
253 return 0;
254 }
255
256 // Client
257 jack_nframes_t JackGraphManager::ComputeTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count)
258 {
259 const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index);
260 jack_nframes_t max_latency = 0;
261 jack_port_id_t dst_index;
262
263 if (hop_count > 8)
264 return GetPort(port_index)->GetLatency();
265
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);
274 }
275 }
276
277 return max_latency + GetPort(port_index)->GetLatency();
278 }
279
280 // Client
281 int JackGraphManager::ComputeTotalLatency(jack_port_id_t port_index)
282 {
283 UInt16 cur_index;
284 UInt16 next_index;
285 JackPort* port = GetPort(port_index);
286 AssertPort(port_index);
287
288 do {
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
293
294 jack_log("JackGraphManager::GetTotalLatency port_index = %ld total latency = %ld", port_index, port->fTotalLatency);
295 return 0;
296 }
297
298 // Client
299 int JackGraphManager::ComputeTotalLatencies()
300 {
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);
306 }
307 }
308 return 0;
309 }
310
311 void JackGraphManager::RecalculateLatencyAux(jack_port_id_t port_index, jack_latency_callback_mode_t mode)
312 {
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;
317
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;
322
323 dst_port->GetLatencyRange(mode, &other_latency);
324
325 if (other_latency.max > latency.max) {
326 latency.max = other_latency.max;
327 }
328 if (other_latency.min < latency.min) {
329 latency.min = other_latency.min;
330 }
331 }
332
333 if (latency.min == UINT32_MAX) {
334 latency.min = 0;
335 }
336
337 port->SetLatencyRange(mode, &latency);
338 }
339
340 void JackGraphManager::RecalculateLatency(jack_port_id_t port_index, jack_latency_callback_mode_t mode)
341 {
342 UInt16 cur_index;
343 UInt16 next_index;
344
345 do {
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
350
351 //jack_log("JackGraphManager::RecalculateLatency port_index = %ld", port_index);
352 }
353
354 // Server
355 void JackGraphManager::SetBufferSize(jack_nframes_t buffer_size)
356 {
357 jack_log("JackGraphManager::SetBufferSize size = %ld", buffer_size);
358
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);
364 }
365 }
366 }
367
368 // Server
369 jack_port_id_t JackGraphManager::AllocatePortAux(int refnum, const char* port_name, const char* port_type, JackPortFlags flags)
370 {
371 jack_port_id_t port_index;
372
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)) {
379 return NO_PORT;
380 }
381 break;
382 }
383 }
384
385 return (port_index < fPortMax) ? port_index : NO_PORT;
386 }
387
388 // Server
389 jack_port_id_t JackGraphManager::AllocatePort(int refnum, const char* port_name, const char* port_type, JackPortFlags flags, jack_nframes_t buffer_size)
390 {
391 JackConnectionManager* manager = WriteNextStateStart();
392 jack_port_id_t port_index = AllocatePortAux(refnum, port_name, port_type, flags);
393
394 if (port_index != NO_PORT) {
395 JackPort* port = GetPort(port_index);
396 assert(port);
397 port->ClearBuffer(buffer_size);
398
399 int res;
400 if (flags & JackPortIsOutput) {
401 res = manager->AddOutputPort(refnum, port_index);
402 } else {
403 res = manager->AddInputPort(refnum, port_index);
404 }
405 // Insertion failure
406 if (res < 0) {
407 port->Release();
408 port_index = NO_PORT;
409 }
410 }
411
412 WriteNextStateStop();
413 return port_index;
414 }
415
416 // Server
417 int JackGraphManager::ReleasePort(int refnum, jack_port_id_t port_index)
418 {
419 JackConnectionManager* manager = WriteNextStateStart();
420 JackPort* port = GetPort(port_index);
421 int res;
422
423 if (port->fFlags & JackPortIsOutput) {
424 DisconnectAllOutput(port_index);
425 res = manager->RemoveOutputPort(refnum, port_index);
426 } else {
427 DisconnectAllInput(port_index);
428 res = manager->RemoveInputPort(refnum, port_index);
429 }
430
431 port->Release();
432 WriteNextStateStop();
433 return res;
434 }
435
436 void JackGraphManager::GetInputPorts(int refnum, jack_int_t* res)
437 {
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();
442 }
443
444 void JackGraphManager::GetOutputPorts(int refnum, jack_int_t* res)
445 {
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();
450 }
451
452 // Server
453 void JackGraphManager::RemoveAllPorts(int refnum)
454 {
455 jack_log("JackGraphManager::RemoveAllPorts ref = %ld", refnum);
456 JackConnectionManager* manager = WriteNextStateStart();
457 jack_port_id_t port_index;
458
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);
463 if (res < 0) {
464 jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum, port_index);
465 assert(true);
466 break;
467 }
468 }
469
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);
474 if (res < 0) {
475 jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum, port_index);
476 assert(true);
477 break;
478 }
479 }
480
481 WriteNextStateStop();
482 }
483
484 // Server
485 void JackGraphManager::DisconnectAllPorts(int refnum)
486 {
487 int i;
488 jack_log("JackGraphManager::DisconnectAllPorts ref = %ld", refnum);
489 JackConnectionManager* manager = WriteNextStateStart();
490
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]);
494 }
495
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]);
499 }
500
501 WriteNextStateStop();
502 }
503
504 // Server
505 void JackGraphManager::DisconnectAllInput(jack_port_id_t port_index)
506 {
507 jack_log("JackGraphManager::DisconnectAllInput port_index = %ld", port_index);
508 JackConnectionManager* manager = WriteNextStateStart();
509
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);
514 }
515 }
516 WriteNextStateStop();
517 }
518
519 // Server
520 void JackGraphManager::DisconnectAllOutput(jack_port_id_t port_index)
521 {
522 jack_log("JackGraphManager::DisconnectAllOutput port_index = %ld ", port_index);
523 JackConnectionManager* manager = WriteNextStateStart();
524
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
528 }
529 WriteNextStateStop();
530 }
531
532 // Server
533 int JackGraphManager::DisconnectAll(jack_port_id_t port_index)
534 {
535 AssertPort(port_index);
536
537 JackPort* port = GetPort(port_index);
538 if (port->fFlags & JackPortIsOutput) {
539 DisconnectAllOutput(port_index);
540 } else {
541 DisconnectAllInput(port_index);
542 }
543 return 0;
544 }
545
546 // Server
547 void JackGraphManager::GetConnections(jack_port_id_t port_index, jack_int_t* res)
548 {
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();
553 }
554
555 // Server
556 void JackGraphManager::Activate(int refnum)
557 {
558 DirectConnect(FREEWHEEL_DRIVER_REFNUM, refnum);
559 DirectConnect(refnum, FREEWHEEL_DRIVER_REFNUM);
560 }
561
562 /*
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.
565 */
566
567 // Server
568 void JackGraphManager::Deactivate(int refnum)
569 {
570 // Disconnect only when needed
571 if (IsDirectConnection(refnum, FREEWHEEL_DRIVER_REFNUM)) {
572 DirectDisconnect(refnum, FREEWHEEL_DRIVER_REFNUM);
573 } else {
574 jack_log("JackServer::Deactivate client = %ld was not activated", refnum);
575 }
576
577 // Disconnect only when needed
578 if (IsDirectConnection(FREEWHEEL_DRIVER_REFNUM, refnum)) {
579 DirectDisconnect(FREEWHEEL_DRIVER_REFNUM, refnum);
580 } else {
581 jack_log("JackServer::Deactivate client = %ld was not activated", refnum);
582 }
583 }
584
585 // Server
586 int JackGraphManager::GetInputRefNum(jack_port_id_t port_index)
587 {
588 AssertPort(port_index);
589 JackConnectionManager* manager = WriteNextStateStart();
590 int res = manager->GetInputRefNum(port_index);
591 WriteNextStateStop();
592 return res;
593 }
594
595 // Server
596 int JackGraphManager::GetOutputRefNum(jack_port_id_t port_index)
597 {
598 AssertPort(port_index);
599 JackConnectionManager* manager = WriteNextStateStart();
600 int res = manager->GetOutputRefNum(port_index);
601 WriteNextStateStop();
602 return res;
603 }
604
605 int JackGraphManager::Connect(jack_port_id_t port_src, jack_port_id_t port_dst)
606 {
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);
611 int res = 0;
612
613 if (!src->fInUse || !dst->fInUse) {
614 if (!src->fInUse)
615 jack_error("JackGraphManager::Connect port_src = %ld not used name = %s", port_src, GetPort(port_src)->fName);
616 if (!dst->fInUse)
617 jack_error("JackGraphManager::Connect port_dst = %ld not used name = %s", port_dst, GetPort(port_dst)->fName);
618 res = -1;
619 goto end;
620 }
621 if (src->fTypeId != dst->fTypeId) {
622 jack_error("JackGraphManager::Connect different port types port_src = %ld port_dst = %ld", port_src, port_dst);
623 res = -1;
624 goto end;
625 }
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);
628 res = EEXIST;
629 goto end;
630 }
631
632 res = manager->Connect(port_src, port_dst);
633 if (res < 0) {
634 jack_error("JackGraphManager::Connect failed port_src = %ld port_dst = %ld", port_src, port_dst);
635 goto end;
636 }
637 res = manager->Connect(port_dst, port_src);
638 if (res < 0) {
639 jack_error("JackGraphManager::Connect failed port_dst = %ld port_src = %ld", port_dst, port_src);
640 goto end;
641 }
642
643 if (manager->IsLoopPath(port_src, port_dst)) {
644 jack_log("JackGraphManager::Connect: LOOP detected");
645 manager->IncFeedbackConnection(port_src, port_dst);
646 } else {
647 manager->IncDirectConnection(port_src, port_dst);
648 }
649
650 end:
651 WriteNextStateStop();
652 return res;
653 }
654
655 // Server
656 int JackGraphManager::Disconnect(jack_port_id_t port_src, jack_port_id_t port_dst)
657 {
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;
662 int res = 0;
663
664 if (!in_use_src || !in_use_dst) {
665 if (!in_use_src)
666 jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_src, GetPort(port_src)->fName);
667 if (!in_use_dst)
668 jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_dst, GetPort(port_dst)->fName);
669 res = -1;
670 goto end;
671 }
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);
674 res = -1;
675 goto end;
676 }
677
678 res = manager->Disconnect(port_src, port_dst);
679 if (res < 0) {
680 jack_error("JackGraphManager::Disconnect failed port_src = %ld port_dst = %ld", port_src, port_dst);
681 goto end;
682 }
683 res = manager->Disconnect(port_dst, port_src);
684 if (res < 0) {
685 jack_error("JackGraphManager::Disconnect failed port_dst = %ld port_src = %ld", port_dst, port_src);
686 goto end;
687 }
688
689 if (manager->IsFeedbackConnection(port_src, port_dst)) {
690 jack_log("JackGraphManager::Disconnect: FEEDBACK removed");
691 manager->DecFeedbackConnection(port_src, port_dst);
692 } else {
693 manager->DecDirectConnection(port_src, port_dst);
694 }
695
696 end:
697 WriteNextStateStop();
698 return res;
699 }
700
701 // Client
702 int JackGraphManager::IsConnected(jack_port_id_t port_src, jack_port_id_t port_dst)
703 {
704 JackConnectionManager* manager = ReadCurrentState();
705 return manager->IsConnected(port_src, port_dst);
706 }
707
708 // Server
709 int JackGraphManager::CheckPorts(jack_port_id_t port_src, jack_port_id_t port_dst)
710 {
711 JackPort* src = GetPort(port_src);
712 JackPort* dst = GetPort(port_dst);
713
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);
716 return -1;
717 }
718
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);
721 return -1;
722 }
723
724 return 0;
725 }
726
727 int JackGraphManager::GetTwoPorts(const char* src_name, const char* dst_name, jack_port_id_t* port_src, jack_port_id_t* port_dst)
728 {
729 jack_log("JackGraphManager::CheckConnect src_name = %s dst_name = %s", src_name, dst_name);
730
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);
733 return -1;
734 }
735
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);
738 return -1;
739 }
740
741 return 0;
742 }
743
744 // Client : port array
745 jack_port_id_t JackGraphManager::GetPort(const char* name)
746 {
747 for (unsigned int i = 0; i < fPortMax; i++) {
748 JackPort* port = GetPort(i);
749 if (port->IsUsed() && port->NameEquals(name)) {
750 return i;
751 }
752 }
753 return NO_PORT;
754 }
755
760 // Client
761 void JackGraphManager::GetConnectionsAux(JackConnectionManager* manager, const char** res, jack_port_id_t port_index)
762 {
763 const jack_int_t* connections = manager->GetConnections(port_index);
764 jack_int_t index;
765 int i;
766
767 // Cleanup connection array
768 memset(res, 0, sizeof(char*) * CONNECTION_NUM_FOR_PORT);
769
770 for (i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((index = connections[i]) != EMPTY); i++) {
771 JackPort* port = GetPort(index);
772 res[i] = port->fName;
773 }
774
775 res[i] = NULL;
776 }
777
778 /*
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.
782 */
783
784 // Client
785 const char** JackGraphManager::GetConnections(jack_port_id_t port_index)
786 {
787 const char** res = (const char**)malloc(sizeof(char*) * CONNECTION_NUM_FOR_PORT);
788 UInt16 cur_index, next_index;
789
790 if (!res)
791 return NULL;
792
793 do {
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
798
799 if (res[0]) { // At least one connection
800 return res;
801 } else { // Empty array, should return NULL
802 free(res);
803 return NULL;
804 }
805 }
806
807 // Client
808 void JackGraphManager::GetPortsAux(const char** matching_ports, const char* port_name_pattern, const char* type_name_pattern, unsigned long flags)
809 {
810 int match_cnt = 0;
811 regex_t port_regex, type_regex;
812
813 if (port_name_pattern && port_name_pattern[0]) {
814 regcomp(&port_regex, port_name_pattern, REG_EXTENDED | REG_NOSUB);
815 }
816 if (type_name_pattern && type_name_pattern[0]) {
817 regcomp(&type_regex, type_name_pattern, REG_EXTENDED | REG_NOSUB);
818 }
819
820 // Cleanup port array
821 memset(matching_ports, 0, sizeof(char*) * fPortMax);
822
823 for (unsigned int i = 0; i < fPortMax; i++) {
824 bool matching = true;
825 JackPort* port = GetPort(i);
826
827 if (port->IsUsed()) {
828
829 if (flags) {
830 if ((port->fFlags & flags) != flags) {
831 matching = false;
832 }
833 }
834
835 if (matching && port_name_pattern && port_name_pattern[0]) {
836 if (regexec(&port_regex, port->GetName(), 0, NULL, 0)) {
837 matching = false;
838 }
839 }
840 if (matching && type_name_pattern && type_name_pattern[0]) {
841 if (regexec(&type_regex, port->GetType(), 0, NULL, 0)) {
842 matching = false;
843 }
844 }
845
846 if (matching) {
847 matching_ports[match_cnt++] = port->fName;
848 }
849 }
850 }
851
852 matching_ports[match_cnt] = 0;
853
854 if (port_name_pattern && port_name_pattern[0]) {
855 regfree(&port_regex);
856 }
857 if (type_name_pattern && type_name_pattern[0]) {
858 regfree(&type_regex);
859 }
860 }
861
862 // Client
863 /*
864 Check that the state was not changed during the read operation.
865 The operation is lock-free since there is no intermediate state in the write operation that could cause the
866 read to loop forever.
867 */
868 const char** JackGraphManager::GetPorts(const char* port_name_pattern, const char* type_name_pattern, unsigned long flags)
869 {
870 const char** res = (const char**)malloc(sizeof(char*) * fPortMax);
871 UInt16 cur_index, next_index;
872
873 if (!res)
874 return NULL;
875
876 do {
877 cur_index = GetCurrentIndex();
878 GetPortsAux(res, port_name_pattern, type_name_pattern, flags);
879 next_index = GetCurrentIndex();
880 } while (cur_index != next_index); // Until a coherent state has been read
881
882 if (res[0]) { // At least one port
883 return res;
884 } else {
885 free(res); // Empty array, should return NULL
886 return NULL;
887 }
888 }
889
890 // Server
891 void JackGraphManager::Save(JackConnectionManager* dst)
892 {
893 JackConnectionManager* manager = WriteNextStateStart();
894 memcpy(dst, manager, sizeof(JackConnectionManager));
895 WriteNextStateStop();
896 }
897
898 // Server
899 void JackGraphManager::Restore(JackConnectionManager* src)
900 {
901 JackConnectionManager* manager = WriteNextStateStart();
902 memcpy(manager, src, sizeof(JackConnectionManager));
903 WriteNextStateStop();
904 }
905
906 } // end of namespace
907
908
Jack::JackAtomicState< JackConnectionManager >::ReadCurrentState
JackConnectionManager * ReadCurrentState()
Returns the current state : only valid in the RT reader thread.
Definition: JackAtomicState.h:144
Jack::JackConnectionManager
Connection manager.
Definition: JackConnectionManager.h:411
Jack::JackPort
Base class for port.
Definition: JackPort.h:39
Jack::JackAtomicState< JackConnectionManager >::WriteNextStateStop
void WriteNextStateStop()
Stop write operation : make the next state ready to be used by the RT thread.
Definition: JackAtomicState.h:202
jack_error
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
_jack_latency_range::min
jack_nframes_t min
Definition: types.h:270
Jack::JackAtomicState< JackConnectionManager >::WriteNextStateStart
JackConnectionManager * WriteNextStateStart()
Start write operation : setup and returns the next state to update, check for recursive write calls.
Definition: JackAtomicState.h:191
_jack_latency_range
Definition: types.h:265
_jack_latency_range::max
jack_nframes_t max
Definition: types.h:274
Jack::JackAtomicState< JackConnectionManager >::GetCurrentIndex
UInt16 GetCurrentIndex()
Returns the current state index.
Definition: JackAtomicState.h:152
Jack::JackAtomicState< JackConnectionManager >::TrySwitchState
JackConnectionManager * TrySwitchState()
Tries to switch to the next state and returns the new current state (either the same as before if cas...
Definition: JackAtomicState.h:160
Jack::JackPort::RequestMonitor
int RequestMonitor(bool onoff)
Definition: JackPort.cpp:156
Jack::JackGraphManager::RequestMonitor
int RequestMonitor(jack_port_id_t port_index, bool onoff)
Definition: JackGraphManager.cpp:228
Jack::JackConnectionManager::GetConnections
const jack_int_t * GetConnections(jack_port_id_t port_index) const
Get the connection port array.
Definition: JackConnectionManager.cpp:126
jack_log
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108