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 #ifdef HAVE_TRE_REGEX_H
28 #include <tre/regex.h>
29 #else
30 #include <regex.h>
31 #endif
32
33 namespace Jack
34 {
35
AssertBufferSize(jack_nframes_t buffer_size)36 static void AssertBufferSize(jack_nframes_t buffer_size)
37 {
38 if (buffer_size > BUFFER_SIZE_MAX) {
39 jack_log("JackGraphManager::AssertBufferSize frames = %ld", buffer_size);
40 assert(buffer_size <= BUFFER_SIZE_MAX);
41 }
42 }
43
AssertPort(jack_port_id_t port_index)44 void JackGraphManager::AssertPort(jack_port_id_t port_index)
45 {
46 if (port_index >= fPortMax) {
47 jack_log("JackGraphManager::AssertPort port_index = %ld", port_index);
48 assert(port_index < fPortMax);
49 }
50 }
51
Allocate(int port_max)52 JackGraphManager* JackGraphManager::Allocate(int port_max)
53 {
54 // Using "Placement" new
55 void* shared_ptr = JackShmMem::operator new(sizeof(JackGraphManager) + port_max * sizeof(JackPort));
56 return new(shared_ptr) JackGraphManager(port_max);
57 }
58
Destroy(JackGraphManager * manager)59 void JackGraphManager::Destroy(JackGraphManager* manager)
60 {
61 // "Placement" new was used
62 manager->~JackGraphManager();
63 JackShmMem::operator delete(manager);
64 }
65
JackGraphManager(int port_max)66 JackGraphManager::JackGraphManager(int port_max)
67 {
68 assert(port_max <= PORT_NUM_MAX);
69
70 for (int i = 0; i < port_max; i++) {
71 fPortArray[i].Release();
72 }
73
74 fPortMax = port_max;
75 }
76
GetPort(jack_port_id_t port_index)77 JackPort* JackGraphManager::GetPort(jack_port_id_t port_index)
78 {
79 AssertPort(port_index);
80 return &fPortArray[port_index];
81 }
82
GetBuffer(jack_port_id_t port_index)83 jack_default_audio_sample_t* JackGraphManager::GetBuffer(jack_port_id_t port_index)
84 {
85 return fPortArray[port_index].GetBuffer();
86 }
87
88 // Server
InitRefNum(int refnum)89 void JackGraphManager::InitRefNum(int refnum)
90 {
91 JackConnectionManager* manager = WriteNextStateStart();
92 manager->InitRefNum(refnum);
93 WriteNextStateStop();
94 }
95
96 // RT
RunCurrentGraph()97 void JackGraphManager::RunCurrentGraph()
98 {
99 JackConnectionManager* manager = ReadCurrentState();
100 manager->ResetGraph(fClientTiming);
101 }
102
103 // RT
RunNextGraph()104 bool JackGraphManager::RunNextGraph()
105 {
106 bool res;
107 JackConnectionManager* manager = TrySwitchState(&res);
108 manager->ResetGraph(fClientTiming);
109 return res;
110 }
111
112 // RT
IsFinishedGraph()113 bool JackGraphManager::IsFinishedGraph()
114 {
115 JackConnectionManager* manager = ReadCurrentState();
116 return (manager->GetActivation(FREEWHEEL_DRIVER_REFNUM) == 0);
117 }
118
119 // RT
ResumeRefNum(JackClientControl * control,JackSynchro * table)120 int JackGraphManager::ResumeRefNum(JackClientControl* control, JackSynchro* table)
121 {
122 JackConnectionManager* manager = ReadCurrentState();
123 return manager->ResumeRefNum(control, table, fClientTiming);
124 }
125
126 // RT
SuspendRefNum(JackClientControl * control,JackSynchro * table,long usec)127 int JackGraphManager::SuspendRefNum(JackClientControl* control, JackSynchro* table, long usec)
128 {
129 JackConnectionManager* manager = ReadCurrentState();
130 return manager->SuspendRefNum(control, table, fClientTiming, usec);
131 }
132
TopologicalSort(std::vector<jack_int_t> & sorted)133 void JackGraphManager::TopologicalSort(std::vector<jack_int_t>& sorted)
134 {
135 UInt16 cur_index;
136 UInt16 next_index;
137
138 do {
139 cur_index = GetCurrentIndex();
140 sorted.clear();
141 ReadCurrentState()->TopologicalSort(sorted);
142 next_index = GetCurrentIndex();
143 } while (cur_index != next_index); // Until a coherent state has been read
144 }
145
146 // Server
DirectConnect(int ref1,int ref2)147 void JackGraphManager::DirectConnect(int ref1, int ref2)
148 {
149 JackConnectionManager* manager = WriteNextStateStart();
150 manager->DirectConnect(ref1, ref2);
151 jack_log("JackGraphManager::ConnectRefNum cur_index = %ld ref1 = %ld ref2 = %ld", CurIndex(fCounter), ref1, ref2);
152 WriteNextStateStop();
153 }
154
155 // Server
DirectDisconnect(int ref1,int ref2)156 void JackGraphManager::DirectDisconnect(int ref1, int ref2)
157 {
158 JackConnectionManager* manager = WriteNextStateStart();
159 manager->DirectDisconnect(ref1, ref2);
160 jack_log("JackGraphManager::DisconnectRefNum cur_index = %ld ref1 = %ld ref2 = %ld", CurIndex(fCounter), ref1, ref2);
161 WriteNextStateStop();
162 }
163
164 // Server
IsDirectConnection(int ref1,int ref2)165 bool JackGraphManager::IsDirectConnection(int ref1, int ref2)
166 {
167 JackConnectionManager* manager = ReadCurrentState();
168 return manager->IsDirectConnection(ref1, ref2);
169 }
170
171 // RT
GetBuffer(jack_port_id_t port_index,jack_nframes_t buffer_size)172 void* JackGraphManager::GetBuffer(jack_port_id_t port_index, jack_nframes_t buffer_size)
173 {
174 AssertPort(port_index);
175 AssertBufferSize(buffer_size);
176
177 JackConnectionManager* manager = ReadCurrentState();
178 JackPort* port = GetPort(port_index);
179
180 // This happens when a port has just been unregistered and is still used by the RT code
181 if (!port->IsUsed()) {
182 jack_log("JackGraphManager::GetBuffer : port = %ld is released state", port_index);
183 return GetBuffer(0); // port_index 0 is not used
184 }
185
186 jack_int_t len = manager->Connections(port_index);
187
188 // Output port
189 if (port->fFlags & JackPortIsOutput) {
190 return (port->fTied != NO_PORT) ? GetBuffer(port->fTied, buffer_size) : GetBuffer(port_index);
191 }
192
193 // No connections : return a zero-filled buffer
194 if (len == 0) {
195 port->ClearBuffer(buffer_size);
196 return port->GetBuffer();
197
198 // One connection
199 } else if (len == 1) {
200 jack_port_id_t src_index = manager->GetPort(port_index, 0);
201
202 // Ports in same client : copy the buffer
203 if (GetPort(src_index)->GetRefNum() == port->GetRefNum()) {
204 void* buffers[1];
205 buffers[0] = GetBuffer(src_index, buffer_size);
206 port->MixBuffers(buffers, 1, buffer_size);
207 return port->GetBuffer();
208 // Otherwise, use zero-copy mode, just pass the buffer of the connected (output) port.
209 } else {
210 return GetBuffer(src_index, buffer_size);
211 }
212
213 // Multiple connections : mix all buffers
214 } else {
215
216 const jack_int_t* connections = manager->GetConnections(port_index);
217 void* buffers[CONNECTION_NUM_FOR_PORT];
218 jack_port_id_t src_index;
219 int i;
220
221 for (i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((src_index = connections[i]) != EMPTY); i++) {
222 AssertPort(src_index);
223 buffers[i] = GetBuffer(src_index, buffer_size);
224 }
225
226 port->MixBuffers(buffers, i, buffer_size);
227 return port->GetBuffer();
228 }
229 }
230
231 // Server
RequestMonitor(jack_port_id_t port_index,bool onoff)232 int JackGraphManager::RequestMonitor(jack_port_id_t port_index, bool onoff) // Client
233 {
234 AssertPort(port_index);
235 JackPort* port = GetPort(port_index);
236
237 /**
238 jackd.h
239 * If @ref JackPortCanMonitor is set for this @a port, turn input
240 * monitoring on or off. Otherwise, do nothing.
241
242 if (!(fFlags & JackPortCanMonitor))
243 return -1;
244 */
245
246 port->RequestMonitor(onoff);
247
248 const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index);
249 if ((port->fFlags & JackPortIsOutput) == 0) { // ?? Taken from jack, why not (port->fFlags & JackPortIsInput) ?
250 jack_port_id_t src_index;
251 for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((src_index = connections[i]) != EMPTY); i++) {
252 // XXX much worse things will happen if there is a feedback loop !!!
253 RequestMonitor(src_index, onoff);
254 }
255 }
256
257 return 0;
258 }
259
260 // Client
ComputeTotalLatencyAux(jack_port_id_t port_index,jack_port_id_t src_port_index,JackConnectionManager * manager,int hop_count)261 jack_nframes_t JackGraphManager::ComputeTotalLatencyAux(jack_port_id_t port_index, jack_port_id_t src_port_index, JackConnectionManager* manager, int hop_count)
262 {
263 const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index);
264 jack_nframes_t max_latency = 0;
265 jack_port_id_t dst_index;
266
267 if (hop_count > 8)
268 return GetPort(port_index)->GetLatency();
269
270 for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((dst_index = connections[i]) != EMPTY); i++) {
271 if (src_port_index != dst_index) {
272 AssertPort(dst_index);
273 JackPort* dst_port = GetPort(dst_index);
274 jack_nframes_t this_latency = (dst_port->fFlags & JackPortIsTerminal)
275 ? dst_port->GetLatency()
276 : ComputeTotalLatencyAux(dst_index, port_index, manager, hop_count + 1);
277 max_latency = ((max_latency > this_latency) ? max_latency : this_latency);
278 }
279 }
280
281 return max_latency + GetPort(port_index)->GetLatency();
282 }
283
284 // Client
ComputeTotalLatency(jack_port_id_t port_index)285 int JackGraphManager::ComputeTotalLatency(jack_port_id_t port_index)
286 {
287 UInt16 cur_index;
288 UInt16 next_index;
289 JackPort* port = GetPort(port_index);
290 AssertPort(port_index);
291
292 do {
293 cur_index = GetCurrentIndex();
294 port->fTotalLatency = ComputeTotalLatencyAux(port_index, port_index, ReadCurrentState(), 0);
295 next_index = GetCurrentIndex();
296 } while (cur_index != next_index); // Until a coherent state has been read
297
298 jack_log("JackGraphManager::GetTotalLatency port_index = %ld total latency = %ld", port_index, port->fTotalLatency);
299 return 0;
300 }
301
302 // Client
ComputeTotalLatencies()303 int JackGraphManager::ComputeTotalLatencies()
304 {
305 jack_port_id_t port_index;
306 for (port_index = FIRST_AVAILABLE_PORT; port_index < fPortMax; port_index++) {
307 JackPort* port = GetPort(port_index);
308 if (port->IsUsed()) {
309 ComputeTotalLatency(port_index);
310 }
311 }
312 return 0;
313 }
314
RecalculateLatencyAux(jack_port_id_t port_index,jack_latency_callback_mode_t mode)315 void JackGraphManager::RecalculateLatencyAux(jack_port_id_t port_index, jack_latency_callback_mode_t mode)
316 {
317 const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index);
318 JackPort* port = GetPort(port_index);
319 jack_latency_range_t latency = { UINT32_MAX, 0 };
320 jack_port_id_t dst_index;
321
322 for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((dst_index = connections[i]) != EMPTY); i++) {
323 AssertPort(dst_index);
324 JackPort* dst_port = GetPort(dst_index);
325 jack_latency_range_t other_latency;
326
327 dst_port->GetLatencyRange(mode, &other_latency);
328
329 if (other_latency.max > latency.max) {
330 latency.max = other_latency.max;
331 }
332 if (other_latency.min < latency.min) {
333 latency.min = other_latency.min;
334 }
335 }
336
337 if (latency.min == UINT32_MAX) {
338 latency.min = 0;
339 }
340
341 port->SetLatencyRange(mode, &latency);
342 }
343
RecalculateLatency(jack_port_id_t port_index,jack_latency_callback_mode_t mode)344 void JackGraphManager::RecalculateLatency(jack_port_id_t port_index, jack_latency_callback_mode_t mode)
345 {
346 UInt16 cur_index;
347 UInt16 next_index;
348
349 do {
350 cur_index = GetCurrentIndex();
351 RecalculateLatencyAux(port_index, mode);
352 next_index = GetCurrentIndex();
353 } while (cur_index != next_index); // Until a coherent state has been read
354
355 //jack_log("JackGraphManager::RecalculateLatency port_index = %ld", port_index);
356 }
357
358 // Server
SetBufferSize(jack_nframes_t buffer_size)359 void JackGraphManager::SetBufferSize(jack_nframes_t buffer_size)
360 {
361 jack_log("JackGraphManager::SetBufferSize size = %ld", buffer_size);
362
363 jack_port_id_t port_index;
364 for (port_index = FIRST_AVAILABLE_PORT; port_index < fPortMax; port_index++) {
365 JackPort* port = GetPort(port_index);
366 if (port->IsUsed()) {
367 port->ClearBuffer(buffer_size);
368 }
369 }
370 }
371
372 // Server
AllocatePortAux(int refnum,const char * port_name,const char * port_type,JackPortFlags flags)373 jack_port_id_t JackGraphManager::AllocatePortAux(int refnum, const char* port_name, const char* port_type, JackPortFlags flags)
374 {
375 jack_port_id_t port_index;
376
377 // Available ports start at FIRST_AVAILABLE_PORT (= 1), otherwise a port_index of 0 is "seen" as a NULL port by the external API...
378 for (port_index = FIRST_AVAILABLE_PORT; port_index < fPortMax; port_index++) {
379 JackPort* port = GetPort(port_index);
380 if (!port->IsUsed()) {
381 jack_log("JackGraphManager::AllocatePortAux port_index = %ld name = %s type = %s", port_index, port_name, port_type);
382 if (!port->Allocate(refnum, port_name, port_type, flags)) {
383 return NO_PORT;
384 }
385 break;
386 }
387 }
388
389 return (port_index < fPortMax) ? port_index : NO_PORT;
390 }
391
392 // Server
AllocatePort(int refnum,const char * port_name,const char * port_type,JackPortFlags flags,jack_nframes_t buffer_size)393 jack_port_id_t JackGraphManager::AllocatePort(int refnum, const char* port_name, const char* port_type, JackPortFlags flags, jack_nframes_t buffer_size)
394 {
395 JackConnectionManager* manager = WriteNextStateStart();
396 jack_port_id_t port_index = AllocatePortAux(refnum, port_name, port_type, flags);
397
398 if (port_index != NO_PORT) {
399 JackPort* port = GetPort(port_index);
400 assert(port);
401 port->ClearBuffer(buffer_size);
402
403 int res;
404 if (flags & JackPortIsOutput) {
405 res = manager->AddOutputPort(refnum, port_index);
406 } else {
407 res = manager->AddInputPort(refnum, port_index);
408 }
409 // Insertion failure
410 if (res < 0) {
411 port->Release();
412 port_index = NO_PORT;
413 }
414 }
415
416 WriteNextStateStop();
417 return port_index;
418 }
419
420 // Server
ReleasePort(int refnum,jack_port_id_t port_index)421 int JackGraphManager::ReleasePort(int refnum, jack_port_id_t port_index)
422 {
423 JackConnectionManager* manager = WriteNextStateStart();
424 JackPort* port = GetPort(port_index);
425 int res;
426
427 if (port->fFlags & JackPortIsOutput) {
428 DisconnectAllOutput(port_index);
429 res = manager->RemoveOutputPort(refnum, port_index);
430 } else {
431 DisconnectAllInput(port_index);
432 res = manager->RemoveInputPort(refnum, port_index);
433 }
434
435 port->Release();
436 WriteNextStateStop();
437 return res;
438 }
439
GetInputPorts(int refnum,jack_int_t * res)440 void JackGraphManager::GetInputPorts(int refnum, jack_int_t* res)
441 {
442 JackConnectionManager* manager = WriteNextStateStart();
443 const jack_int_t* input = manager->GetInputPorts(refnum);
444 memcpy(res, input, sizeof(jack_int_t) * PORT_NUM_FOR_CLIENT);
445 WriteNextStateStop();
446 }
447
GetOutputPorts(int refnum,jack_int_t * res)448 void JackGraphManager::GetOutputPorts(int refnum, jack_int_t* res)
449 {
450 JackConnectionManager* manager = WriteNextStateStart();
451 const jack_int_t* output = manager->GetOutputPorts(refnum);
452 memcpy(res, output, sizeof(jack_int_t) * PORT_NUM_FOR_CLIENT);
453 WriteNextStateStop();
454 }
455
456 // Server
RemoveAllPorts(int refnum)457 void JackGraphManager::RemoveAllPorts(int refnum)
458 {
459 jack_log("JackGraphManager::RemoveAllPorts ref = %ld", refnum);
460 JackConnectionManager* manager = WriteNextStateStart();
461 jack_port_id_t port_index;
462
463 // Warning : ReleasePort shift port to left, thus we always remove the first port until the "input" table is empty
464 const jack_int_t* input = manager->GetInputPorts(refnum);
465 while ((port_index = input[0]) != EMPTY) {
466 int res = ReleasePort(refnum, port_index);
467 if (res < 0) {
468 jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum, port_index);
469 assert(true);
470 break;
471 }
472 }
473
474 // Warning : ReleasePort shift port to left, thus we always remove the first port until the "output" table is empty
475 const jack_int_t* output = manager->GetOutputPorts(refnum);
476 while ((port_index = output[0]) != EMPTY) {
477 int res = ReleasePort(refnum, port_index);
478 if (res < 0) {
479 jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum, port_index);
480 assert(true);
481 break;
482 }
483 }
484
485 WriteNextStateStop();
486 }
487
488 // Server
DisconnectAllPorts(int refnum)489 void JackGraphManager::DisconnectAllPorts(int refnum)
490 {
491 int i;
492 jack_log("JackGraphManager::DisconnectAllPorts ref = %ld", refnum);
493 JackConnectionManager* manager = WriteNextStateStart();
494
495 const jack_int_t* input = manager->GetInputPorts(refnum);
496 for (i = 0; i < PORT_NUM_FOR_CLIENT && input[i] != EMPTY ; i++) {
497 DisconnectAllInput(input[i]);
498 }
499
500 const jack_int_t* output = manager->GetOutputPorts(refnum);
501 for (i = 0; i < PORT_NUM_FOR_CLIENT && output[i] != EMPTY; i++) {
502 DisconnectAllOutput(output[i]);
503 }
504
505 WriteNextStateStop();
506 }
507
508 // Server
DisconnectAllInput(jack_port_id_t port_index)509 void JackGraphManager::DisconnectAllInput(jack_port_id_t port_index)
510 {
511 jack_log("JackGraphManager::DisconnectAllInput port_index = %ld", port_index);
512 JackConnectionManager* manager = WriteNextStateStart();
513
514 for (unsigned int i = 0; i < fPortMax; i++) {
515 if (manager->IsConnected(i, port_index)) {
516 jack_log("JackGraphManager::Disconnect i = %ld port_index = %ld", i, port_index);
517 Disconnect(i, port_index);
518 }
519 }
520 WriteNextStateStop();
521 }
522
523 // Server
DisconnectAllOutput(jack_port_id_t port_index)524 void JackGraphManager::DisconnectAllOutput(jack_port_id_t port_index)
525 {
526 jack_log("JackGraphManager::DisconnectAllOutput port_index = %ld ", port_index);
527 JackConnectionManager* manager = WriteNextStateStart();
528
529 const jack_int_t* connections = manager->GetConnections(port_index);
530 while (connections[0] != EMPTY) {
531 Disconnect(port_index, connections[0]); // Warning : Disconnect shift port to left
532 }
533 WriteNextStateStop();
534 }
535
536 // Server
DisconnectAll(jack_port_id_t port_index)537 int JackGraphManager::DisconnectAll(jack_port_id_t port_index)
538 {
539 AssertPort(port_index);
540
541 JackPort* port = GetPort(port_index);
542 if (port->fFlags & JackPortIsOutput) {
543 DisconnectAllOutput(port_index);
544 } else {
545 DisconnectAllInput(port_index);
546 }
547 return 0;
548 }
549
550 // Server
GetConnections(jack_port_id_t port_index,jack_int_t * res)551 void JackGraphManager::GetConnections(jack_port_id_t port_index, jack_int_t* res)
552 {
553 JackConnectionManager* manager = WriteNextStateStart();
554 const jack_int_t* connections = manager->GetConnections(port_index);
555 memcpy(res, connections, sizeof(jack_int_t) * CONNECTION_NUM_FOR_PORT);
556 WriteNextStateStop();
557 }
558
559 // Server
Activate(int refnum)560 void JackGraphManager::Activate(int refnum)
561 {
562 DirectConnect(FREEWHEEL_DRIVER_REFNUM, refnum);
563 DirectConnect(refnum, FREEWHEEL_DRIVER_REFNUM);
564 }
565
566 /*
567 Disconnection from the FW must be done in last otherwise an intermediate "unconnected"
568 (thus unactivated) state may happen where the client is still checked for its end.
569 */
570
571 // Server
Deactivate(int refnum)572 void JackGraphManager::Deactivate(int refnum)
573 {
574 // Disconnect only when needed
575 if (IsDirectConnection(refnum, FREEWHEEL_DRIVER_REFNUM)) {
576 DirectDisconnect(refnum, FREEWHEEL_DRIVER_REFNUM);
577 } else {
578 jack_log("JackServer::Deactivate client = %ld was not activated", refnum);
579 }
580
581 // Disconnect only when needed
582 if (IsDirectConnection(FREEWHEEL_DRIVER_REFNUM, refnum)) {
583 DirectDisconnect(FREEWHEEL_DRIVER_REFNUM, refnum);
584 } else {
585 jack_log("JackServer::Deactivate client = %ld was not activated", refnum);
586 }
587 }
588
589 // Server
GetInputRefNum(jack_port_id_t port_index)590 int JackGraphManager::GetInputRefNum(jack_port_id_t port_index)
591 {
592 AssertPort(port_index);
593 JackConnectionManager* manager = WriteNextStateStart();
594 int res = manager->GetInputRefNum(port_index);
595 WriteNextStateStop();
596 return res;
597 }
598
599 // Server
GetOutputRefNum(jack_port_id_t port_index)600 int JackGraphManager::GetOutputRefNum(jack_port_id_t port_index)
601 {
602 AssertPort(port_index);
603 JackConnectionManager* manager = WriteNextStateStart();
604 int res = manager->GetOutputRefNum(port_index);
605 WriteNextStateStop();
606 return res;
607 }
608
Connect(jack_port_id_t port_src,jack_port_id_t port_dst)609 int JackGraphManager::Connect(jack_port_id_t port_src, jack_port_id_t port_dst)
610 {
611 JackConnectionManager* manager = WriteNextStateStart();
612 jack_log("JackGraphManager::Connect port_src = %ld port_dst = %ld", port_src, port_dst);
613 JackPort* src = GetPort(port_src);
614 JackPort* dst = GetPort(port_dst);
615 int res = 0;
616
617 if (!src->fInUse || !dst->fInUse) {
618 if (!src->fInUse)
619 jack_error("JackGraphManager::Connect port_src = %ld not used name = %s", port_src, GetPort(port_src)->fName);
620 if (!dst->fInUse)
621 jack_error("JackGraphManager::Connect port_dst = %ld not used name = %s", port_dst, GetPort(port_dst)->fName);
622 res = -1;
623 goto end;
624 }
625 if (src->fTypeId != dst->fTypeId) {
626 jack_error("JackGraphManager::Connect different port types port_src = %ld port_dst = %ld", port_src, port_dst);
627 res = -1;
628 goto end;
629 }
630 if (manager->IsConnected(port_src, port_dst)) {
631 jack_error("JackGraphManager::Connect already connected port_src = %ld port_dst = %ld", port_src, port_dst);
632 res = EEXIST;
633 goto end;
634 }
635
636 res = manager->Connect(port_src, port_dst);
637 if (res < 0) {
638 jack_error("JackGraphManager::Connect failed port_src = %ld port_dst = %ld", port_src, port_dst);
639 goto end;
640 }
641 res = manager->Connect(port_dst, port_src);
642 if (res < 0) {
643 jack_error("JackGraphManager::Connect failed port_dst = %ld port_src = %ld", port_dst, port_src);
644 goto end;
645 }
646
647 if (manager->IsLoopPath(port_src, port_dst)) {
648 jack_log("JackGraphManager::Connect: LOOP detected");
649 manager->IncFeedbackConnection(port_src, port_dst);
650 } else {
651 manager->IncDirectConnection(port_src, port_dst);
652 }
653
654 end:
655 WriteNextStateStop();
656 return res;
657 }
658
659 // Server
Disconnect(jack_port_id_t port_src,jack_port_id_t port_dst)660 int JackGraphManager::Disconnect(jack_port_id_t port_src, jack_port_id_t port_dst)
661 {
662 JackConnectionManager* manager = WriteNextStateStart();
663 jack_log("JackGraphManager::Disconnect port_src = %ld port_dst = %ld", port_src, port_dst);
664 bool in_use_src = GetPort(port_src)->fInUse;
665 bool in_use_dst = GetPort(port_dst)->fInUse;
666 int res = 0;
667
668 if (!in_use_src || !in_use_dst) {
669 if (!in_use_src)
670 jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_src, GetPort(port_src)->fName);
671 if (!in_use_dst)
672 jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_dst, GetPort(port_dst)->fName);
673 res = -1;
674 goto end;
675 }
676 if (!manager->IsConnected(port_src, port_dst)) {
677 jack_error("JackGraphManager::Disconnect not connected port_src = %ld port_dst = %ld", port_src, port_dst);
678 res = -1;
679 goto end;
680 }
681
682 res = manager->Disconnect(port_src, port_dst);
683 if (res < 0) {
684 jack_error("JackGraphManager::Disconnect failed port_src = %ld port_dst = %ld", port_src, port_dst);
685 goto end;
686 }
687 res = manager->Disconnect(port_dst, port_src);
688 if (res < 0) {
689 jack_error("JackGraphManager::Disconnect failed port_dst = %ld port_src = %ld", port_dst, port_src);
690 goto end;
691 }
692
693 if (manager->IsFeedbackConnection(port_src, port_dst)) {
694 jack_log("JackGraphManager::Disconnect: FEEDBACK removed");
695 manager->DecFeedbackConnection(port_src, port_dst);
696 } else {
697 manager->DecDirectConnection(port_src, port_dst);
698 }
699
700 end:
701 WriteNextStateStop();
702 return res;
703 }
704
705 // Client
IsConnected(jack_port_id_t port_src,jack_port_id_t port_dst)706 int JackGraphManager::IsConnected(jack_port_id_t port_src, jack_port_id_t port_dst)
707 {
708 JackConnectionManager* manager = ReadCurrentState();
709 return manager->IsConnected(port_src, port_dst);
710 }
711
712 // Server
CheckPorts(jack_port_id_t port_src,jack_port_id_t port_dst)713 int JackGraphManager::CheckPorts(jack_port_id_t port_src, jack_port_id_t port_dst)
714 {
715 JackPort* src = GetPort(port_src);
716 JackPort* dst = GetPort(port_dst);
717
718 if ((dst->fFlags & JackPortIsInput) == 0) {
719 jack_error("Destination port in attempted (dis)connection of %s and %s is not an input port", src->fName, dst->fName);
720 return -1;
721 }
722
723 if ((src->fFlags & JackPortIsOutput) == 0) {
724 jack_error("Source port in attempted (dis)connection of %s and %s is not an output port", src->fName, dst->fName);
725 return -1;
726 }
727
728 return 0;
729 }
730
GetTwoPorts(const char * src_name,const char * dst_name,jack_port_id_t * port_src,jack_port_id_t * port_dst)731 int JackGraphManager::GetTwoPorts(const char* src_name, const char* dst_name, jack_port_id_t* port_src, jack_port_id_t* port_dst)
732 {
733 jack_log("JackGraphManager::CheckConnect src_name = %s dst_name = %s", src_name, dst_name);
734
735 if ((*port_src = GetPort(src_name)) == NO_PORT) {
736 jack_error("Unknown source port in attempted (dis)connection src_name [%s] dst_name [%s]", src_name, dst_name);
737 return -1;
738 }
739
740 if ((*port_dst = GetPort(dst_name)) == NO_PORT) {
741 jack_error("Unknown destination port in attempted (dis)connection src_name [%s] dst_name [%s]", src_name, dst_name);
742 return -1;
743 }
744
745 return 0;
746 }
747
748 // Client : port array
GetPort(const char * name)749 jack_port_id_t JackGraphManager::GetPort(const char* name)
750 {
751 for (unsigned int i = 0; i < fPortMax; i++) {
752 JackPort* port = GetPort(i);
753 if (port->IsUsed() && port->NameEquals(name)) {
754 return i;
755 }
756 }
757 return NO_PORT;
758 }
759
760 /*!
761 \brief Get the connection port name array.
762 */
763
764 // Client
GetConnectionsAux(JackConnectionManager * manager,const char ** res,jack_port_id_t port_index)765 void JackGraphManager::GetConnectionsAux(JackConnectionManager* manager, const char** res, jack_port_id_t port_index)
766 {
767 const jack_int_t* connections = manager->GetConnections(port_index);
768 jack_int_t index;
769 int i;
770
771 // Cleanup connection array
772 memset(res, 0, sizeof(char*) * CONNECTION_NUM_FOR_PORT);
773
774 for (i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((index = connections[i]) != EMPTY); i++) {
775 JackPort* port = GetPort(index);
776 res[i] = port->fName;
777 }
778
779 res[i] = NULL;
780 }
781
782 /*
783 Use the state returned by ReadCurrentState and check that the state was not changed during the read operation.
784 The operation is lock-free since there is no intermediate state in the write operation that could cause the
785 read to loop forever.
786 */
787
788 // Client
GetConnections(jack_port_id_t port_index)789 const char** JackGraphManager::GetConnections(jack_port_id_t port_index)
790 {
791 const char** res = (const char**)malloc(sizeof(char*) * CONNECTION_NUM_FOR_PORT);
792 UInt16 cur_index, next_index;
793
794 if (!res)
795 return NULL;
796
797 do {
798 cur_index = GetCurrentIndex();
799 GetConnectionsAux(ReadCurrentState(), res, port_index);
800 next_index = GetCurrentIndex();
801 } while (cur_index != next_index); // Until a coherent state has been read
802
803 if (res[0]) { // At least one connection
804 return res;
805 } else { // Empty array, should return NULL
806 free(res);
807 return NULL;
808 }
809 }
810
811 // Client
GetPortsAux(const char ** matching_ports,const char * port_name_pattern,const char * type_name_pattern,unsigned long flags)812 void JackGraphManager::GetPortsAux(const char** matching_ports, const char* port_name_pattern, const char* type_name_pattern, unsigned long flags)
813 {
814 // Cleanup port array
815 memset(matching_ports, 0, sizeof(char*) * fPortMax);
816
817 int match_cnt = 0;
818 regex_t port_regex, type_regex;
819
820 if (port_name_pattern && port_name_pattern[0]) {
821 if (regcomp(&port_regex, port_name_pattern, REG_EXTENDED | REG_NOSUB)!=0) {
822 jack_log("JackGraphManager::GetPortsAux could not compile regex for port_name_pattern '%s'", port_name_pattern);
823 return;
824 }
825 }
826 if (type_name_pattern && type_name_pattern[0]) {
827 if (regcomp(&type_regex, type_name_pattern, REG_EXTENDED | REG_NOSUB)!=0) {
828 jack_log("JackGraphManager::GetPortsAux could not compile regex for type_name_pattern '%s'", type_name_pattern);
829 return;
830 }
831 }
832
833 for (unsigned int i = 0; i < fPortMax; i++) {
834 bool matching = true;
835 JackPort* port = GetPort(i);
836
837 if (port->IsUsed()) {
838
839 if (flags) {
840 if ((port->fFlags & flags) != flags) {
841 matching = false;
842 }
843 }
844
845 if (matching && port_name_pattern && port_name_pattern[0]) {
846 if (regexec(&port_regex, port->GetName(), 0, NULL, 0)) {
847 matching = false;
848 }
849 }
850 if (matching && type_name_pattern && type_name_pattern[0]) {
851 if (regexec(&type_regex, port->GetType(), 0, NULL, 0)) {
852 matching = false;
853 }
854 }
855
856 if (matching) {
857 matching_ports[match_cnt++] = port->fName;
858 }
859 }
860 }
861
862 matching_ports[match_cnt] = 0;
863
864 if (port_name_pattern && port_name_pattern[0]) {
865 regfree(&port_regex);
866 }
867 if (type_name_pattern && type_name_pattern[0]) {
868 regfree(&type_regex);
869 }
870 }
871
872 // Client
873 /*
874 Check that the state was not changed during the read operation.
875 The operation is lock-free since there is no intermediate state in the write operation that could cause the
876 read to loop forever.
877 */
GetPorts(const char * port_name_pattern,const char * type_name_pattern,unsigned long flags)878 const char** JackGraphManager::GetPorts(const char* port_name_pattern, const char* type_name_pattern, unsigned long flags)
879 {
880 const char** res = (const char**)malloc(sizeof(char*) * fPortMax);
881 UInt16 cur_index, next_index;
882
883 if (!res)
884 return NULL;
885
886 do {
887 cur_index = GetCurrentIndex();
888 GetPortsAux(res, port_name_pattern, type_name_pattern, flags);
889 next_index = GetCurrentIndex();
890 } while (cur_index != next_index); // Until a coherent state has been read
891
892 if (res[0]) { // At least one port
893 return res;
894 } else {
895 free(res); // Empty array, should return NULL
896 return NULL;
897 }
898 }
899
900 // Server
Save(JackConnectionManager * dst)901 void JackGraphManager::Save(JackConnectionManager* dst)
902 {
903 JackConnectionManager* manager = WriteNextStateStart();
904 memcpy(dst, manager, sizeof(JackConnectionManager));
905 WriteNextStateStop();
906 }
907
908 // Server
Restore(JackConnectionManager * src)909 void JackGraphManager::Restore(JackConnectionManager* src)
910 {
911 JackConnectionManager* manager = WriteNextStateStart();
912 memcpy(manager, src, sizeof(JackConnectionManager));
913 WriteNextStateStop();
914 }
915
916 } // end of namespace
917
918
919