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);
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  }
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 
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();
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);
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);
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 
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 
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  }
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  }
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);
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);
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);
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:
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:
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));
896 }
897 
898 // Server
899 void JackGraphManager::Restore(JackConnectionManager* src)
900 {
901  JackConnectionManager* manager = WriteNextStateStart();
902  memcpy(manager, src, sizeof(JackConnectionManager));
904 }
905 
906 } // end of namespace
907 
908 
jack_log
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108
Jack::JackAtomicState< JackConnectionManager >::ReadCurrentState
JackConnectionManager * ReadCurrentState()
Returns the current state : only valid in the RT reader thread.
Definition: JackAtomicState.h:144
_jack_latency_range::min
jack_nframes_t min
Definition: types.h:270
_jack_latency_range
Definition: types.h:265
Jack::JackPort
Base class for port.
Definition: JackPort.h:39
jack_error
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
Jack::JackAtomicState< JackConnectionManager >::GetCurrentIndex
UInt16 GetCurrentIndex()
Returns the current state index.
Definition: JackAtomicState.h:152
Jack::JackPort::RequestMonitor
int RequestMonitor(bool onoff)
Definition: JackPort.cpp:156
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::max
jack_nframes_t max
Definition: types.h:274
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::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::JackConnectionManager
Connection manager.
Definition: JackConnectionManager.h:411
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