Jack2 1.9.12

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
212 void JackConnectionManager::InitRefNum(int refnum)
213 {
214 fInputPort[refnum].Init();
215 fOutputPort[refnum].Init();
216 fConnectionRef.Init(refnum);
217 fInputCounter[refnum].SetValue(0);
218 }
219
223 void JackConnectionManager::ResetGraph(JackClientTiming* timing)
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
248 int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing)
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 = new JackFixedMatrix<CLIENT_NUM>;
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 delete tmp;
316 }
317
321 void JackConnectionManager::IncDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
322 {
323 int ref1 = GetOutputRefNum(port_src);
324 int ref2 = GetInputRefNum(port_dst);
325
326 assert(ref1 >= 0 && ref2 >= 0);
327
328 DirectConnect(ref1, ref2);
329 jack_log("JackConnectionManager::IncConnectionRef: ref1 = %ld ref2 = %ld", ref1, ref2);
330 }
331
335 void JackConnectionManager::DecDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
336 {
337 int ref1 = GetOutputRefNum(port_src);
338 int ref2 = GetInputRefNum(port_dst);
339
340 assert(ref1 >= 0 && ref2 >= 0);
341
342 DirectDisconnect(ref1, ref2);
343 jack_log("JackConnectionManager::DecConnectionRef: ref1 = %ld ref2 = %ld", ref1, ref2);
344 }
345
349 void JackConnectionManager::DirectConnect(int ref1, int ref2)
350 {
351 assert(ref1 >= 0 && ref2 >= 0);
352
353 if (fConnectionRef.IncItem(ref1, ref2) == 1) { // First connection between client ref1 and client ref2
354 jack_log("JackConnectionManager::DirectConnect first: ref1 = %ld ref2 = %ld", ref1, ref2);
355 fInputCounter[ref2].IncValue();
356 }
357 }
358
362 void JackConnectionManager::DirectDisconnect(int ref1, int ref2)
363 {
364 assert(ref1 >= 0 && ref2 >= 0);
365
366 if (fConnectionRef.DecItem(ref1, ref2) == 0) { // Last connection between client ref1 and client ref2
367 jack_log("JackConnectionManager::DirectDisconnect last: ref1 = %ld ref2 = %ld", ref1, ref2);
368 fInputCounter[ref2].DecValue();
369 }
370 }
371
375 bool JackConnectionManager::IsDirectConnection(int ref1, int ref2) const
376 {
377 assert(ref1 >= 0 && ref2 >= 0);
378 return (fConnectionRef.GetItemCount(ref1, ref2) > 0);
379 }
380
384 int JackConnectionManager::GetInputRefNum(jack_port_id_t port_index) const
385 {
386 for (int i = 0; i < CLIENT_NUM; i++) {
387 if (fInputPort[i].CheckItem(port_index)) {
388 return i;
389 }
390 }
391
392 return -1;
393 }
394
398 int JackConnectionManager::GetOutputRefNum(jack_port_id_t port_index) const
399 {
400 for (int i = 0; i < CLIENT_NUM; i++) {
401 if (fOutputPort[i].CheckItem(port_index)) {
402 return i;
403 }
404 }
405
406 return -1;
407 }
408
412 bool JackConnectionManager::IsLoopPath(jack_port_id_t port_src, jack_port_id_t port_dst) const
413 {
414 return IsLoopPathAux(GetInputRefNum(port_dst), GetOutputRefNum(port_src));
415 }
416
417 bool JackConnectionManager::IsFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst) const
418 {
419 return (fLoopFeedback.GetConnectionIndex(GetOutputRefNum(port_src), GetInputRefNum(port_dst)) >= 0);
420 }
421
422 bool JackConnectionManager::IncFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
423 {
424 int ref1 = GetOutputRefNum(port_src);
425 int ref2 = GetInputRefNum(port_dst);
426
427 // Add an activation connection in the other direction
428 jack_log("JackConnectionManager::IncFeedbackConnection ref1 = %ld ref2 = %ld", ref1, ref2);
429 assert(ref1 >= 0 && ref2 >= 0);
430
431 if (ref1 != ref2) {
432 DirectConnect(ref2, ref1);
433 }
434
435 return fLoopFeedback.IncConnection(ref1, ref2); // Add the feedback connection
436 }
437
438 bool JackConnectionManager::DecFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
439 {
440 int ref1 = GetOutputRefNum(port_src);
441 int ref2 = GetInputRefNum(port_dst);
442
443 // Remove an activation connection in the other direction
444 jack_log("JackConnectionManager::DecFeedbackConnection ref1 = %ld ref2 = %ld", ref1, ref2);
445 assert(ref1 >= 0 && ref2 >= 0);
446
447 if (ref1 != ref2) {
448 DirectDisconnect(ref2, ref1);
449 }
450
451 return fLoopFeedback.DecConnection(ref1, ref2); // Remove the feedback connection
452 }
453
454 } // end of namespace
455
456
Jack::JackConnectionManager::DirectDisconnect
void DirectDisconnect(int ref1, int ref2)
Directly disconnect 2 reference numbers.
Definition: JackConnectionManager.cpp:362
Jack::JackConnectionManager::GetOutputRefNum
int GetOutputRefNum(jack_port_id_t port_index) const
Get the client refnum of a given ouput port.
Definition: JackConnectionManager.cpp:398
Jack::JackConnectionManager::Disconnect
int Disconnect(jack_port_id_t port_src, jack_port_id_t port_dst)
Disconnect port_src from port_dst.
Definition: JackConnectionManager.cpp:103
Jack::JackConnectionManager::IsDirectConnection
bool IsDirectConnection(int ref1, int ref2) const
Returns the connections state between 2 refnum.
Definition: JackConnectionManager.cpp:375
Jack::JackConnectionManager::IncDirectConnection
void IncDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
Increment the number of ports between 2 clients, if the 2 clients become connected,...
Definition: JackConnectionManager.cpp:321
Jack::JackLoopFeedback::GetConnectionIndex
int GetConnectionIndex(int ref1, int ref2) const
Test if a connection between 2 refnum is a feedback connection.
Definition: JackConnectionManager.h:358
Jack::JackConnectionManager::SuspendRefNum
int SuspendRefNum(JackClientControl *control, JackSynchro *table, JackClientTiming *timing, long time_out_usec)
Wait on the input synchro.
Definition: JackConnectionManager.cpp:235
Jack::JackPosixSemaphore
Inter process synchronization using POSIX semaphore.
Definition: JackPosixSemaphore.h:36
Jack::JackConnectionManager::ResetGraph
void ResetGraph(JackClientTiming *timing)
Reset all clients activation.
Definition: JackConnectionManager.cpp:223
jack_error
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
Jack::JackConnectionManager::RemoveInputPort
int RemoveInputPort(int refnum, jack_port_id_t port_index)
Remove an input port from a client.
Definition: JackConnectionManager.cpp:166
Jack::JackConnectionManager::AddOutputPort
int AddOutputPort(int refnum, jack_port_id_t port_index)
Add an output port to a client.
Definition: JackConnectionManager.cpp:152
Jack::JackFixedMatrix::GetOutputTable
void GetOutputTable(jack_int_t index, jack_int_t *output) const
Get the output indexes of a given index.
Definition: JackConnectionManager.h:214
Jack::JackConnectionManager::GetInputRefNum
int GetInputRefNum(jack_port_id_t port_index) const
Get the client refnum of a given input port.
Definition: JackConnectionManager.cpp:384
Jack::JackConnectionManager::DecDirectConnection
void DecDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
Decrement the number of ports between 2 clients, if the 2 clients become disconnected,...
Definition: JackConnectionManager.cpp:335
Jack::JackConnectionManager::Connect
int Connect(jack_port_id_t port_src, jack_port_id_t port_dst)
Connect port_src to port_dst.
Definition: JackConnectionManager.cpp:88
Jack::JackConnectionManager::GetOutputPorts
const jack_int_t * GetOutputPorts(int refnum)
Get the output port array of a given refnum.
Definition: JackConnectionManager.cpp:204
Jack::JackConnectionManager::IsLoopPath
bool IsLoopPath(jack_port_id_t port_src, jack_port_id_t port_dst) const
Test is a connection path exists between port_src and port_dst.
Definition: JackConnectionManager.cpp:412
Jack::JackConnectionManager::DirectConnect
void DirectConnect(int ref1, int ref2)
Directly connect 2 reference numbers.
Definition: JackConnectionManager.cpp:349
Jack::JackConnectionManager::RemoveOutputPort
int RemoveOutputPort(int refnum, jack_port_id_t port_index)
Remove an output port from a client.
Definition: JackConnectionManager.cpp:181
Jack::JackClientTiming
For client timing measurements.
Definition: JackConnectionManager.h:374
Jack::JackConnectionManager::InitRefNum
void InitRefNum(int refnum)
Init the refnum.
Definition: JackConnectionManager.cpp:212
Jack::JackConnectionManager::AddInputPort
int AddInputPort(int refnum, jack_port_id_t port_index)
Add an input port to a client.
Definition: JackConnectionManager.cpp:138
Jack::JackConnectionManager::ResumeRefNum
int ResumeRefNum(JackClientControl *control, JackSynchro *table, JackClientTiming *timing)
Signal clients connected to the given client.
Definition: JackConnectionManager.cpp:248
Jack::JackConnectionManager::IsConnected
bool IsConnected(jack_port_id_t port_src, jack_port_id_t port_dst) const
Check if port_src and port_dst are connected.
Definition: JackConnectionManager.cpp:118
Jack::JackConnectionManager::GetConnections
const jack_int_t * GetConnections(jack_port_id_t port_index) const
Get the connection port array.
Definition: JackConnectionManager.cpp:126
jack_log
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108
Jack::JackConnectionManager::GetInputPorts
const jack_int_t * GetInputPorts(int refnum)
Get the input port array of a given refnum.
Definition: JackConnectionManager.cpp:196
Jack::JackClientControl
Client control possibly in shared memory.
Definition: JackClientControl.h:38