Jack2  1.9.9
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);
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);
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);
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  return 0;
308 }
309 
310 void JackGraphManager::RecalculateLatencyAux(jack_port_id_t port_index, jack_latency_callback_mode_t mode)
311 {
312  const jack_int_t* connections = ReadCurrentState()->GetConnections(port_index);
313  JackPort* port = GetPort(port_index);
314  jack_latency_range_t latency = { UINT32_MAX, 0 };
315  jack_port_id_t dst_index;
316 
317  for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((dst_index = connections[i]) != EMPTY); i++) {
318  AssertPort(dst_index);
319  JackPort* dst_port = GetPort(dst_index);
320  jack_latency_range_t other_latency;
321 
322  dst_port->GetLatencyRange(mode, &other_latency);
323 
324  if (other_latency.max > latency.max)
325  latency.max = other_latency.max;
326  if (other_latency.min < latency.min)
327  latency.min = other_latency.min;
328  }
329 
330  if (latency.min == UINT32_MAX)
331  latency.min = 0;
332 
333  port->SetLatencyRange(mode, &latency);
334 }
335 
336 void JackGraphManager::RecalculateLatency(jack_port_id_t port_index, jack_latency_callback_mode_t mode)
337 {
338  UInt16 cur_index;
339  UInt16 next_index;
340 
341  do {
342  cur_index = GetCurrentIndex();
343  RecalculateLatencyAux(port_index, mode);
344  next_index = GetCurrentIndex();
345  } while (cur_index != next_index); // Until a coherent state has been read
346 
347  //jack_log("JackGraphManager::RecalculateLatency port_index = %ld", port_index);
348 }
349 
350 // Server
351 void JackGraphManager::SetBufferSize(jack_nframes_t buffer_size)
352 {
353  jack_log("JackGraphManager::SetBufferSize size = %ld", buffer_size);
354 
355  jack_port_id_t port_index;
356  for (port_index = FIRST_AVAILABLE_PORT; port_index < fPortMax; port_index++) {
357  JackPort* port = GetPort(port_index);
358  if (port->IsUsed())
359  port->ClearBuffer(buffer_size);
360  }
361 }
362 
363 // Server
364 jack_port_id_t JackGraphManager::AllocatePortAux(int refnum, const char* port_name, const char* port_type, JackPortFlags flags)
365 {
366  jack_port_id_t port_index;
367 
368  // Available ports start at FIRST_AVAILABLE_PORT (= 1), otherwise a port_index of 0 is "seen" as a NULL port by the external API...
369  for (port_index = FIRST_AVAILABLE_PORT; port_index < fPortMax; port_index++) {
370  JackPort* port = GetPort(port_index);
371  if (!port->IsUsed()) {
372  jack_log("JackGraphManager::AllocatePortAux port_index = %ld name = %s type = %s", port_index, port_name, port_type);
373  if (!port->Allocate(refnum, port_name, port_type, flags))
374  return NO_PORT;
375  break;
376  }
377  }
378 
379  return (port_index < fPortMax) ? port_index : NO_PORT;
380 }
381 
382 // Server
383 jack_port_id_t JackGraphManager::AllocatePort(int refnum, const char* port_name, const char* port_type, JackPortFlags flags, jack_nframes_t buffer_size)
384 {
385  JackConnectionManager* manager = WriteNextStateStart();
386  jack_port_id_t port_index = AllocatePortAux(refnum, port_name, port_type, flags);
387 
388  if (port_index != NO_PORT) {
389  JackPort* port = GetPort(port_index);
390  assert(port);
391  port->ClearBuffer(buffer_size);
392 
393  int res;
394  if (flags & JackPortIsOutput) {
395  res = manager->AddOutputPort(refnum, port_index);
396  } else {
397  res = manager->AddInputPort(refnum, port_index);
398  }
399  // Insertion failure
400  if (res < 0) {
401  port->Release();
402  port_index = NO_PORT;
403  }
404  }
405 
407  return port_index;
408 }
409 
410 // Server
411 int JackGraphManager::ReleasePort(int refnum, jack_port_id_t port_index)
412 {
413  JackConnectionManager* manager = WriteNextStateStart();
414  JackPort* port = GetPort(port_index);
415  int res;
416 
417  if (port->fFlags & JackPortIsOutput) {
418  DisconnectAllOutput(port_index);
419  res = manager->RemoveOutputPort(refnum, port_index);
420  } else {
421  DisconnectAllInput(port_index);
422  res = manager->RemoveInputPort(refnum, port_index);
423  }
424 
425  port->Release();
427  return res;
428 }
429 
430 void JackGraphManager::GetInputPorts(int refnum, jack_int_t* res)
431 {
432  JackConnectionManager* manager = WriteNextStateStart();
433  const jack_int_t* input = manager->GetInputPorts(refnum);
434  memcpy(res, input, sizeof(jack_int_t) * PORT_NUM_FOR_CLIENT);
436 }
437 
438 void JackGraphManager::GetOutputPorts(int refnum, jack_int_t* res)
439 {
440  JackConnectionManager* manager = WriteNextStateStart();
441  const jack_int_t* output = manager->GetOutputPorts(refnum);
442  memcpy(res, output, sizeof(jack_int_t) * PORT_NUM_FOR_CLIENT);
444 }
445 
446 // Server
447 void JackGraphManager::RemoveAllPorts(int refnum)
448 {
449  jack_log("JackGraphManager::RemoveAllPorts ref = %ld", refnum);
450  JackConnectionManager* manager = WriteNextStateStart();
451  jack_port_id_t port_index;
452 
453  // Warning : ReleasePort shift port to left, thus we always remove the first port until the "input" table is empty
454  const jack_int_t* input = manager->GetInputPorts(refnum);
455  while ((port_index = input[0]) != EMPTY) {
456  int res = ReleasePort(refnum, port_index);
457  if (res < 0) {
458  jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum, port_index);
459  assert(true);
460  break;
461  }
462  }
463 
464  // Warning : ReleasePort shift port to left, thus we always remove the first port until the "output" table is empty
465  const jack_int_t* output = manager->GetOutputPorts(refnum);
466  while ((port_index = output[0]) != EMPTY) {
467  int res = ReleasePort(refnum, port_index);
468  if (res < 0) {
469  jack_error("JackGraphManager::RemoveAllPorts failure ref = %ld port_index = %ld", refnum, port_index);
470  assert(true);
471  break;
472  }
473  }
474 
476 }
477 
478 // Server
479 void JackGraphManager::DisconnectAllPorts(int refnum)
480 {
481  int i;
482  jack_log("JackGraphManager::DisconnectAllPorts ref = %ld", refnum);
483  JackConnectionManager* manager = WriteNextStateStart();
484 
485  const jack_int_t* input = manager->GetInputPorts(refnum);
486  for (i = 0; i < PORT_NUM_FOR_CLIENT && input[i] != EMPTY ; i++) {
487  DisconnectAllInput(input[i]);
488  }
489 
490  const jack_int_t* output = manager->GetOutputPorts(refnum);
491  for (i = 0; i < PORT_NUM_FOR_CLIENT && output[i] != EMPTY; i++) {
492  DisconnectAllOutput(output[i]);
493  }
494 
496 }
497 
498 // Server
499 void JackGraphManager::DisconnectAllInput(jack_port_id_t port_index)
500 {
501  jack_log("JackGraphManager::DisconnectAllInput port_index = %ld", port_index);
502  JackConnectionManager* manager = WriteNextStateStart();
503 
504  for (unsigned int i = 0; i < fPortMax; i++) {
505  if (manager->IsConnected(i, port_index)) {
506  jack_log("JackGraphManager::Disconnect i = %ld port_index = %ld", i, port_index);
507  Disconnect(i, port_index);
508  }
509  }
511 }
512 
513 // Server
514 void JackGraphManager::DisconnectAllOutput(jack_port_id_t port_index)
515 {
516  jack_log("JackGraphManager::DisconnectAllOutput port_index = %ld ", port_index);
517  JackConnectionManager* manager = WriteNextStateStart();
518 
519  const jack_int_t* connections = manager->GetConnections(port_index);
520  while (connections[0] != EMPTY) {
521  Disconnect(port_index, connections[0]); // Warning : Disconnect shift port to left
522  }
524 }
525 
526 // Server
527 int JackGraphManager::DisconnectAll(jack_port_id_t port_index)
528 {
529  AssertPort(port_index);
530 
531  JackPort* port = GetPort(port_index);
532  if (port->fFlags & JackPortIsOutput) {
533  DisconnectAllOutput(port_index);
534  } else {
535  DisconnectAllInput(port_index);
536  }
537  return 0;
538 }
539 
540 // Server
541 void JackGraphManager::GetConnections(jack_port_id_t port_index, jack_int_t* res)
542 {
543  JackConnectionManager* manager = WriteNextStateStart();
544  const jack_int_t* connections = manager->GetConnections(port_index);
545  memcpy(res, connections, sizeof(jack_int_t) * CONNECTION_NUM_FOR_PORT);
547 }
548 
549 // Server
550 void JackGraphManager::Activate(int refnum)
551 {
552  DirectConnect(FREEWHEEL_DRIVER_REFNUM, refnum);
553  DirectConnect(refnum, FREEWHEEL_DRIVER_REFNUM);
554 }
555 
556 /*
557  Disconnection from the FW must be done in last otherwise an intermediate "unconnected"
558  (thus unactivated) state may happen where the client is still checked for its end.
559 */
560 
561 // Server
562 void JackGraphManager::Deactivate(int refnum)
563 {
564  // Disconnect only when needed
565  if (IsDirectConnection(refnum, FREEWHEEL_DRIVER_REFNUM)) {
566  DirectDisconnect(refnum, FREEWHEEL_DRIVER_REFNUM);
567  } else {
568  jack_log("JackServer::Deactivate client = %ld was not activated", refnum);
569  }
570 
571  // Disconnect only when needed
572  if (IsDirectConnection(FREEWHEEL_DRIVER_REFNUM, refnum)) {
573  DirectDisconnect(FREEWHEEL_DRIVER_REFNUM, refnum);
574  } else {
575  jack_log("JackServer::Deactivate client = %ld was not activated", refnum);
576  }
577 }
578 
579 // Server
580 int JackGraphManager::GetInputRefNum(jack_port_id_t port_index)
581 {
582  AssertPort(port_index);
583  JackConnectionManager* manager = WriteNextStateStart();
584  int res = manager->GetInputRefNum(port_index);
586  return res;
587 }
588 
589 // Server
590 int JackGraphManager::GetOutputRefNum(jack_port_id_t port_index)
591 {
592  AssertPort(port_index);
593  JackConnectionManager* manager = WriteNextStateStart();
594  int res = manager->GetOutputRefNum(port_index);
596  return res;
597 }
598 
599 int JackGraphManager::Connect(jack_port_id_t port_src, jack_port_id_t port_dst)
600 {
601  JackConnectionManager* manager = WriteNextStateStart();
602  jack_log("JackGraphManager::Connect port_src = %ld port_dst = %ld", port_src, port_dst);
603  JackPort* src = GetPort(port_src);
604  JackPort* dst = GetPort(port_dst);
605  int res = 0;
606 
607  if (!src->fInUse || !dst->fInUse) {
608  if (!src->fInUse)
609  jack_error("JackGraphManager::Connect port_src = %ld not used name = %s", port_src, GetPort(port_src)->fName);
610  if (!dst->fInUse)
611  jack_error("JackGraphManager::Connect port_dst = %ld not used name = %s", port_dst, GetPort(port_dst)->fName);
612  res = -1;
613  goto end;
614  }
615  if (src->fTypeId != dst->fTypeId) {
616  jack_error("JackGraphManager::Connect different port types port_src = %ld port_dst = %ld", port_src, port_dst);
617  res = -1;
618  goto end;
619  }
620  if (manager->IsConnected(port_src, port_dst)) {
621  jack_error("JackGraphManager::Connect already connected port_src = %ld port_dst = %ld", port_src, port_dst);
622  res = EEXIST;
623  goto end;
624  }
625 
626  res = manager->Connect(port_src, port_dst);
627  if (res < 0) {
628  jack_error("JackGraphManager::Connect failed port_src = %ld port_dst = %ld", port_src, port_dst);
629  goto end;
630  }
631  res = manager->Connect(port_dst, port_src);
632  if (res < 0) {
633  jack_error("JackGraphManager::Connect failed port_dst = %ld port_src = %ld", port_dst, port_src);
634  goto end;
635  }
636 
637  if (manager->IsLoopPath(port_src, port_dst)) {
638  jack_log("JackGraphManager::Connect: LOOP detected");
639  manager->IncFeedbackConnection(port_src, port_dst);
640  } else {
641  manager->IncDirectConnection(port_src, port_dst);
642  }
643 
644 end:
646  return res;
647 }
648 
649 // Server
650 int JackGraphManager::Disconnect(jack_port_id_t port_src, jack_port_id_t port_dst)
651 {
652  JackConnectionManager* manager = WriteNextStateStart();
653  jack_log("JackGraphManager::Disconnect port_src = %ld port_dst = %ld", port_src, port_dst);
654  bool in_use_src = GetPort(port_src)->fInUse;
655  bool in_use_dst = GetPort(port_dst)->fInUse;
656  int res = 0;
657 
658  if (!in_use_src || !in_use_dst) {
659  if (!in_use_src)
660  jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_src, GetPort(port_src)->fName);
661  if (!in_use_dst)
662  jack_error("JackGraphManager::Disconnect: port_src = %ld not used name = %s", port_dst, GetPort(port_dst)->fName);
663  res = -1;
664  goto end;
665  }
666  if (!manager->IsConnected(port_src, port_dst)) {
667  jack_error("JackGraphManager::Disconnect not connected port_src = %ld port_dst = %ld", port_src, port_dst);
668  res = -1;
669  goto end;
670  }
671 
672  res = manager->Disconnect(port_src, port_dst);
673  if (res < 0) {
674  jack_error("JackGraphManager::Disconnect failed port_src = %ld port_dst = %ld", port_src, port_dst);
675  goto end;
676  }
677  res = manager->Disconnect(port_dst, port_src);
678  if (res < 0) {
679  jack_error("JackGraphManager::Disconnect failed port_dst = %ld port_src = %ld", port_dst, port_src);
680  goto end;
681  }
682 
683  if (manager->IsFeedbackConnection(port_src, port_dst)) {
684  jack_log("JackGraphManager::Disconnect: FEEDBACK removed");
685  manager->DecFeedbackConnection(port_src, port_dst);
686  } else {
687  manager->DecDirectConnection(port_src, port_dst);
688  }
689 
690 end:
692  return res;
693 }
694 
695 // Client
696 int JackGraphManager::IsConnected(jack_port_id_t port_src, jack_port_id_t port_dst)
697 {
698  JackConnectionManager* manager = ReadCurrentState();
699  return manager->IsConnected(port_src, port_dst);
700 }
701 
702 // Server
703 int JackGraphManager::CheckPorts(jack_port_id_t port_src, jack_port_id_t port_dst)
704 {
705  JackPort* src = GetPort(port_src);
706  JackPort* dst = GetPort(port_dst);
707 
708  if ((dst->fFlags & JackPortIsInput) == 0) {
709  jack_error("Destination port in attempted (dis)connection of %s and %s is not an input port", src->fName, dst->fName);
710  return -1;
711  }
712 
713  if ((src->fFlags & JackPortIsOutput) == 0) {
714  jack_error("Source port in attempted (dis)connection of %s and %s is not an output port", src->fName, dst->fName);
715  return -1;
716  }
717 
718  return 0;
719 }
720 
721 int JackGraphManager::GetTwoPorts(const char* src_name, const char* dst_name, jack_port_id_t* port_src, jack_port_id_t* port_dst)
722 {
723  jack_log("JackGraphManager::CheckConnect src_name = %s dst_name = %s", src_name, dst_name);
724 
725  if ((*port_src = GetPort(src_name)) == NO_PORT) {
726  jack_error("Unknown source port in attempted (dis)connection src_name [%s] dst_name [%s]", src_name, dst_name);
727  return -1;
728  }
729 
730  if ((*port_dst = GetPort(dst_name)) == NO_PORT) {
731  jack_error("Unknown destination port in attempted (dis)connection src_name [%s] dst_name [%s]", src_name, dst_name);
732  return -1;
733  }
734 
735  return 0;
736 }
737 
738 // Client : port array
739 jack_port_id_t JackGraphManager::GetPort(const char* name)
740 {
741  for (unsigned int i = 0; i < fPortMax; i++) {
742  JackPort* port = GetPort(i);
743  if (port->IsUsed() && port->NameEquals(name)) {
744  return i;
745  }
746  }
747  return NO_PORT;
748 }
749 
754 // Client
755 void JackGraphManager::GetConnectionsAux(JackConnectionManager* manager, const char** res, jack_port_id_t port_index)
756 {
757  const jack_int_t* connections = manager->GetConnections(port_index);
758  jack_int_t index;
759  int i;
760 
761  // Cleanup connection array
762  memset(res, 0, sizeof(char*) * CONNECTION_NUM_FOR_PORT);
763 
764  for (i = 0; (i < CONNECTION_NUM_FOR_PORT) && ((index = connections[i]) != EMPTY); i++) {
765  JackPort* port = GetPort(index);
766  res[i] = port->fName;
767  }
768 
769  res[i] = NULL;
770 }
771 
772 /*
773  Use the state returned by ReadCurrentState and check that the state was not changed during the read operation.
774  The operation is lock-free since there is no intermediate state in the write operation that could cause the
775  read to loop forever.
776 */
777 
778 // Client
779 const char** JackGraphManager::GetConnections(jack_port_id_t port_index)
780 {
781  const char** res = (const char**)malloc(sizeof(char*) * CONNECTION_NUM_FOR_PORT);
782  UInt16 cur_index, next_index;
783 
784  if (!res)
785  return NULL;
786 
787  do {
788  cur_index = GetCurrentIndex();
789  GetConnectionsAux(ReadCurrentState(), res, port_index);
790  next_index = GetCurrentIndex();
791  } while (cur_index != next_index); // Until a coherent state has been read
792 
793  if (res[0]) { // At least one connection
794  return res;
795  } else { // Empty array, should return NULL
796  free(res);
797  return NULL;
798  }
799 }
800 
801 // Client
802 void JackGraphManager::GetPortsAux(const char** matching_ports, const char* port_name_pattern, const char* type_name_pattern, unsigned long flags)
803 {
804  int match_cnt = 0;
805  regex_t port_regex, type_regex;
806 
807  if (port_name_pattern && port_name_pattern[0]) {
808  regcomp(&port_regex, port_name_pattern, REG_EXTENDED | REG_NOSUB);
809  }
810  if (type_name_pattern && type_name_pattern[0]) {
811  regcomp(&type_regex, type_name_pattern, REG_EXTENDED | REG_NOSUB);
812  }
813 
814  // Cleanup port array
815  memset(matching_ports, 0, sizeof(char*) * fPortMax);
816 
817  for (unsigned int i = 0; i < fPortMax; i++) {
818  bool matching = true;
819  JackPort* port = GetPort(i);
820 
821  if (port->IsUsed()) {
822 
823  if (flags) {
824  if ((port->fFlags & flags) != flags) {
825  matching = false;
826  }
827  }
828 
829  if (matching && port_name_pattern && port_name_pattern[0]) {
830  if (regexec(&port_regex, port->GetName(), 0, NULL, 0)) {
831  matching = false;
832  }
833  }
834  if (matching && type_name_pattern && type_name_pattern[0]) {
835  if (regexec(&type_regex, port->GetType(), 0, NULL, 0)) {
836  matching = false;
837  }
838  }
839 
840  if (matching) {
841  matching_ports[match_cnt++] = port->fName;
842  }
843  }
844  }
845 
846  matching_ports[match_cnt] = 0;
847 
848  if (port_name_pattern && port_name_pattern[0]) {
849  regfree(&port_regex);
850  }
851  if (type_name_pattern && type_name_pattern[0]) {
852  regfree(&type_regex);
853  }
854 }
855 
856 // Client
857 /*
858  Check that the state was not changed during the read operation.
859  The operation is lock-free since there is no intermediate state in the write operation that could cause the
860  read to loop forever.
861 */
862 const char** JackGraphManager::GetPorts(const char* port_name_pattern, const char* type_name_pattern, unsigned long flags)
863 {
864  const char** res = (const char**)malloc(sizeof(char*) * fPortMax);
865  UInt16 cur_index, next_index;
866 
867  if (!res)
868  return NULL;
869 
870  do {
871  cur_index = GetCurrentIndex();
872  GetPortsAux(res, port_name_pattern, type_name_pattern, flags);
873  next_index = GetCurrentIndex();
874  } while (cur_index != next_index); // Until a coherent state has been read
875 
876  if (res[0]) { // At least one port
877  return res;
878  } else {
879  free(res); // Empty array, should return NULL
880  return NULL;
881  }
882 }
883 
884 // Server
885 void JackGraphManager::Save(JackConnectionManager* dst)
886 {
887  JackConnectionManager* manager = WriteNextStateStart();
888  memcpy(dst, manager, sizeof(JackConnectionManager));
890 }
891 
892 // Server
893 void JackGraphManager::Restore(JackConnectionManager* src)
894 {
895  JackConnectionManager* manager = WriteNextStateStart();
896  memcpy(manager, src, sizeof(JackConnectionManager));
898 }
899 
900 } // end of namespace
901 
902 
JackConnectionManager * ReadCurrentState()
Returns the current state : only valid in the RT reader thread.
Base class for port.
Definition: JackPort.h:39
void WriteNextStateStop()
Stop write operation : make the next state ready to be used by the RT thread.
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:91
jack_nframes_t min
Definition: types.h:268
JackConnectionManager * WriteNextStateStart()
Start write operation : setup and returns the next state to update, check for recursive write calls...
jack_nframes_t max
Definition: types.h:272
UInt16 GetCurrentIndex()
Returns the current state index.
JackConnectionManager * TrySwitchState()
Tries to switch to the next state and returns the new current state (either the same as before if cas...
int RequestMonitor(bool onoff)
Definition: JackPort.cpp:153
const jack_int_t * GetConnections(jack_port_id_t port_index) const
Get the connection port array.
int RequestMonitor(jack_port_id_t port_index, bool onoff)
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:107