Jack2  1.9.10
JackConnectionManager.cpp
1 /*
2 Copyright (C) 2004-2008 Grame
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13 
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 
18 */
19 
20 #include "JackConnectionManager.h"
21 #include "JackClientControl.h"
22 #include "JackEngineControl.h"
23 #include "JackGlobals.h"
24 #include "JackError.h"
25 #include <set>
26 #include <iostream>
27 #include <assert.h>
28 
29 namespace Jack
30 {
31 
32 JackConnectionManager::JackConnectionManager()
33 {
34  int i;
35  jack_log("JackConnectionManager::InitConnections size = %ld ", sizeof(JackConnectionManager));
36 
37  for (i = 0; i < PORT_NUM_MAX; i++) {
38  fConnection[i].Init();
39  }
40 
41  fLoopFeedback.Init();
42 
43  jack_log("JackConnectionManager::InitClients");
44  for (i = 0; i < CLIENT_NUM; i++) {
45  InitRefNum(i);
46  }
47 }
48 
49 JackConnectionManager::~JackConnectionManager()
50 {}
51 
52 //--------------
53 // Internal API
54 //--------------
55 
56 bool JackConnectionManager::IsLoopPathAux(int ref1, int ref2) const
57 {
58  jack_log("JackConnectionManager::IsLoopPathAux ref1 = %ld ref2 = %ld", ref1, ref2);
59 
60  if (ref1 < GetEngineControl()->fDriverNum || ref2 < GetEngineControl()->fDriverNum) {
61  return false;
62  } else if (ref1 == ref2) { // Same refnum
63  return true;
64  } else {
65  jack_int_t output[CLIENT_NUM];
66  fConnectionRef.GetOutputTable(ref1, output);
67 
68  if (fConnectionRef.IsInsideTable(ref2, output)) { // If ref2 is contained in the outputs of ref1
69  return true;
70  } else {
71  for (int i = 0; i < CLIENT_NUM && output[i] != EMPTY; i++) { // Otherwise recurse for all ref1 outputs
72  if (IsLoopPathAux(output[i], ref2)) {
73  return true; // Stop when a path is found
74  }
75  }
76  return false;
77  }
78  }
79 }
80 
81 //--------------
82 // External API
83 //--------------
84 
88 int JackConnectionManager::Connect(jack_port_id_t port_src, jack_port_id_t port_dst)
89 {
90  jack_log("JackConnectionManager::Connect port_src = %ld port_dst = %ld", port_src, port_dst);
91 
92  if (fConnection[port_src].AddItem(port_dst)) {
93  return 0;
94  } else {
95  jack_error("Connection table is full !!");
96  return -1;
97  }
98 }
99 
103 int JackConnectionManager::Disconnect(jack_port_id_t port_src, jack_port_id_t port_dst)
104 {
105  jack_log("JackConnectionManager::Disconnect port_src = %ld port_dst = %ld", port_src, port_dst);
106 
107  if (fConnection[port_src].RemoveItem(port_dst)) {
108  return 0;
109  } else {
110  jack_error("Connection not found !!");
111  return -1;
112  }
113 }
114 
118 bool JackConnectionManager::IsConnected(jack_port_id_t port_src, jack_port_id_t port_dst) const
119 {
120  return fConnection[port_src].CheckItem(port_dst);
121 }
122 
126 const jack_int_t* JackConnectionManager::GetConnections(jack_port_id_t port_index) const
127 {
128  return fConnection[port_index].GetItems();
129 }
130 
131 //------------------------
132 // Client port management
133 //------------------------
134 
138 int JackConnectionManager::AddInputPort(int refnum, jack_port_id_t port_index)
139 {
140  if (fInputPort[refnum].AddItem(port_index)) {
141  jack_log("JackConnectionManager::AddInputPort ref = %ld port = %ld", refnum, port_index);
142  return 0;
143  } else {
144  jack_error("Maximum number of input ports is reached for application ref = %ld", refnum);
145  return -1;
146  }
147 }
148 
152 int JackConnectionManager::AddOutputPort(int refnum, jack_port_id_t port_index)
153 {
154  if (fOutputPort[refnum].AddItem(port_index)) {
155  jack_log("JackConnectionManager::AddOutputPort ref = %ld port = %ld", refnum, port_index);
156  return 0;
157  } else {
158  jack_error("Maximum number of output ports is reached for application ref = %ld", refnum);
159  return -1;
160  }
161 }
162 
166 int JackConnectionManager::RemoveInputPort(int refnum, jack_port_id_t port_index)
167 {
168  jack_log("JackConnectionManager::RemoveInputPort ref = %ld port_index = %ld ", refnum, port_index);
169 
170  if (fInputPort[refnum].RemoveItem(port_index)) {
171  return 0;
172  } else {
173  jack_error("Input port index = %ld not found for application ref = %ld", port_index, refnum);
174  return -1;
175  }
176 }
177 
181 int JackConnectionManager::RemoveOutputPort(int refnum, jack_port_id_t port_index)
182 {
183  jack_log("JackConnectionManager::RemoveOutputPort ref = %ld port_index = %ld ", refnum, port_index);
184 
185  if (fOutputPort[refnum].RemoveItem(port_index)) {
186  return 0;
187  } else {
188  jack_error("Output port index = %ld not found for application ref = %ld", port_index, refnum);
189  return -1;
190  }
191 }
192 
196 const jack_int_t* JackConnectionManager::GetInputPorts(int refnum)
197 {
198  return fInputPort[refnum].GetItems();
199 }
200 
204 const jack_int_t* JackConnectionManager::GetOutputPorts(int refnum)
205 {
206  return fOutputPort[refnum].GetItems();
207 }
208 
213 {
214  fInputPort[refnum].Init();
215  fOutputPort[refnum].Init();
216  fConnectionRef.Init(refnum);
217  fInputCounter[refnum].SetValue(0);
218 }
219 
224 {
225  // Reset activation counter : must be done *before* starting to resume clients
226  for (int i = 0; i < CLIENT_NUM; i++) {
227  fInputCounter[i].Reset();
228  timing[i].fStatus = NotTriggered;
229  }
230 }
231 
235 int JackConnectionManager::SuspendRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing, long time_out_usec)
236 {
237  bool res;
238  if ((res = table[control->fRefNum].TimedWait(time_out_usec))) {
239  timing[control->fRefNum].fStatus = Running;
240  timing[control->fRefNum].fAwakeAt = GetMicroSeconds();
241  }
242  return (res) ? 0 : -1;
243 }
244 
249 {
250  jack_time_t current_date = GetMicroSeconds();
251  const jack_int_t* output_ref = fConnectionRef.GetItems(control->fRefNum);
252  int res = 0;
253 
254  // Update state and timestamp of current client
255  timing[control->fRefNum].fStatus = Finished;
256  timing[control->fRefNum].fFinishedAt = current_date;
257 
258  for (int i = 0; i < CLIENT_NUM; i++) {
259 
260  // Signal connected clients or drivers
261  if (output_ref[i] > 0) {
262 
263  // Update state and timestamp of destination clients
264  timing[i].fStatus = Triggered;
265  timing[i].fSignaledAt = current_date;
266 
267  if (!fInputCounter[i].Signal(table + i, control)) {
268  jack_log("JackConnectionManager::ResumeRefNum error: ref = %ld output = %ld ", control->fRefNum, i);
269  res = -1;
270  }
271  }
272  }
273 
274  return res;
275 }
276 
277 static bool HasNoConnection(jack_int_t* table)
278 {
279  for (int ref = 0; ref < CLIENT_NUM; ref++) {
280  if (table[ref] > 0) return false;
281  }
282  return true;
283 }
284 
285 // Using http://en.wikipedia.org/wiki/Topological_sorting
286 
287 void JackConnectionManager::TopologicalSort(std::vector<jack_int_t>& sorted)
288 {
289  JackFixedMatrix<CLIENT_NUM> tmp;
290  std::set<jack_int_t> level;
291 
292  fConnectionRef.Copy(tmp);
293 
294  // Inputs of the graph
295  level.insert(AUDIO_DRIVER_REFNUM);
296  level.insert(FREEWHEEL_DRIVER_REFNUM);
297 
298  while (level.size() > 0) {
299  jack_int_t refnum = *level.begin();
300  sorted.push_back(refnum);
301  level.erase(level.begin());
302  const jack_int_t* output_ref1 = tmp.GetItems(refnum);
303  for (int dst = 0; dst < CLIENT_NUM; dst++) {
304  if (output_ref1[dst] > 0) {
305  tmp.ClearItem(refnum, dst);
306  jack_int_t output_ref2[CLIENT_NUM];
307  tmp.GetOutputTable1(dst, output_ref2);
308  if (HasNoConnection(output_ref2)) {
309  level.insert(dst);
310  }
311  }
312  }
313  }
314 }
315 
319 void JackConnectionManager::IncDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
320 {
321  int ref1 = GetOutputRefNum(port_src);
322  int ref2 = GetInputRefNum(port_dst);
323 
324  assert(ref1 >= 0 && ref2 >= 0);
325 
326  DirectConnect(ref1, ref2);
327  jack_log("JackConnectionManager::IncConnectionRef: ref1 = %ld ref2 = %ld", ref1, ref2);
328 }
329 
333 void JackConnectionManager::DecDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
334 {
335  int ref1 = GetOutputRefNum(port_src);
336  int ref2 = GetInputRefNum(port_dst);
337 
338  assert(ref1 >= 0 && ref2 >= 0);
339 
340  DirectDisconnect(ref1, ref2);
341  jack_log("JackConnectionManager::DecConnectionRef: ref1 = %ld ref2 = %ld", ref1, ref2);
342 }
343 
347 void JackConnectionManager::DirectConnect(int ref1, int ref2)
348 {
349  assert(ref1 >= 0 && ref2 >= 0);
350 
351  if (fConnectionRef.IncItem(ref1, ref2) == 1) { // First connection between client ref1 and client ref2
352  jack_log("JackConnectionManager::DirectConnect first: ref1 = %ld ref2 = %ld", ref1, ref2);
353  fInputCounter[ref2].IncValue();
354  }
355 }
356 
361 {
362  assert(ref1 >= 0 && ref2 >= 0);
363 
364  if (fConnectionRef.DecItem(ref1, ref2) == 0) { // Last connection between client ref1 and client ref2
365  jack_log("JackConnectionManager::DirectDisconnect last: ref1 = %ld ref2 = %ld", ref1, ref2);
366  fInputCounter[ref2].DecValue();
367  }
368 }
369 
373 bool JackConnectionManager::IsDirectConnection(int ref1, int ref2) const
374 {
375  assert(ref1 >= 0 && ref2 >= 0);
376  return (fConnectionRef.GetItemCount(ref1, ref2) > 0);
377 }
378 
382 int JackConnectionManager::GetInputRefNum(jack_port_id_t port_index) const
383 {
384  for (int i = 0; i < CLIENT_NUM; i++) {
385  if (fInputPort[i].CheckItem(port_index)) {
386  return i;
387  }
388  }
389 
390  return -1;
391 }
392 
396 int JackConnectionManager::GetOutputRefNum(jack_port_id_t port_index) const
397 {
398  for (int i = 0; i < CLIENT_NUM; i++) {
399  if (fOutputPort[i].CheckItem(port_index)) {
400  return i;
401  }
402  }
403 
404  return -1;
405 }
406 
410 bool JackConnectionManager::IsLoopPath(jack_port_id_t port_src, jack_port_id_t port_dst) const
411 {
412  return IsLoopPathAux(GetInputRefNum(port_dst), GetOutputRefNum(port_src));
413 }
414 
415 bool JackConnectionManager::IsFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst) const
416 {
417  return (fLoopFeedback.GetConnectionIndex(GetOutputRefNum(port_src), GetInputRefNum(port_dst)) >= 0);
418 }
419 
420 bool JackConnectionManager::IncFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
421 {
422  int ref1 = GetOutputRefNum(port_src);
423  int ref2 = GetInputRefNum(port_dst);
424 
425  // Add an activation connection in the other direction
426  jack_log("JackConnectionManager::IncFeedbackConnection ref1 = %ld ref2 = %ld", ref1, ref2);
427  assert(ref1 >= 0 && ref2 >= 0);
428 
429  if (ref1 != ref2) {
430  DirectConnect(ref2, ref1);
431  }
432 
433  return fLoopFeedback.IncConnection(ref1, ref2); // Add the feedback connection
434 }
435 
436 bool JackConnectionManager::DecFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
437 {
438  int ref1 = GetOutputRefNum(port_src);
439  int ref2 = GetInputRefNum(port_dst);
440 
441  // Remove an activation connection in the other direction
442  jack_log("JackConnectionManager::DecFeedbackConnection ref1 = %ld ref2 = %ld", ref1, ref2);
443  assert(ref1 >= 0 && ref2 >= 0);
444 
445  if (ref1 != ref2) {
446  DirectDisconnect(ref2, ref1);
447  }
448 
449  return fLoopFeedback.DecConnection(ref1, ref2); // Remove the feedback connection
450 }
451 
452 } // end of namespace
453 
454