2 Copyright (C) 2004-2006 Grame
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
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 General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "JackConnectionManager.h"
23 #include "JackClientControl.h"
24 #include "JackError.h"
29 JackConnectionManager::JackConnectionManager()
32 JackLog("JackConnectionManager::InitConnections size = %ld \n", sizeof(JackConnectionManager
));
34 for (i
= 0; i
< PORT_NUM
; i
++) {
35 fConnection
[i
].Init();
40 JackLog("JackConnectionManager::InitClients\n");
41 for (i
= 0; i
< CLIENT_NUM
; i
++) {
46 JackConnectionManager::~JackConnectionManager()
53 bool JackConnectionManager::IsLoopPathAux(int ref1
, int ref2
) const
55 JackLog("JackConnectionManager::IsLoopPathAux ref1 = %ld ref2 = %ld\n", ref1
, ref2
);
57 if (ref1
== AUDIO_DRIVER_REFNUM
// Driver is reached
58 || ref2
== AUDIO_DRIVER_REFNUM
59 || ref1
== FREEWHEEL_DRIVER_REFNUM
60 || ref2
== FREEWHEEL_DRIVER_REFNUM
61 || ref1
== LOOPBACK_DRIVER_REFNUM
62 || ref2
== LOOPBACK_DRIVER_REFNUM
) {
64 } else if (ref1
== ref2
) { // Same refnum
67 jack_int_t output
[CLIENT_NUM
];
68 fConnectionRef
.GetOutputTable(ref1
, output
);
70 if (fConnectionRef
.IsInsideTable(ref2
, output
)) { // If ref2 is contained in the outputs of ref1
73 for (int i
= 0; i
< CLIENT_NUM
&& output
[i
] != EMPTY
; i
++) { // Otherwise recurse for all ref1 outputs
74 if (IsLoopPathAux(output
[i
], ref2
))
75 return true; // Stop when a path is found
86 int JackConnectionManager::GetActivation(int refnum
) const
88 return fInputCounter
[refnum
].GetValue();
92 \brief Connect port_src to port_dst.
94 int JackConnectionManager::Connect(jack_port_id_t port_src
, jack_port_id_t port_dst
)
96 JackLog("JackConnectionManager::Connect port_src = %ld port_dst = %ld\n", port_src
, port_dst
);
98 if (fConnection
[port_src
].AddItem(port_dst
)) {
101 jack_error("Connection table is full !!");
107 \brief Disconnect port_src from port_dst.
109 int JackConnectionManager::Disconnect(jack_port_id_t port_src
, jack_port_id_t port_dst
)
111 JackLog("JackConnectionManager::Disconnect port_src = %ld port_dst = %ld\n", port_src
, port_dst
);
113 if (fConnection
[port_src
].RemoveItem(port_dst
)) {
116 jack_error("Connection not found !!");
122 \brief Check if port_src and port_dst are connected.
124 bool JackConnectionManager::IsConnected(jack_port_id_t port_src
, jack_port_id_t port_dst
) const
126 return fConnection
[port_src
].CheckItem(port_dst
);
130 \brief Get the connection number of a given port.
132 jack_int_t
JackConnectionManager::Connections(jack_port_id_t port_index
) const
134 return fConnection
[port_index
].GetItemCount();
137 jack_port_id_t
JackConnectionManager::GetPort(jack_port_id_t port_index
, int connection
) const
139 assert(connection
< CONNECTION_NUM
);
140 return (jack_port_id_t
)fConnection
[port_index
].GetItem(connection
);
144 \brief Get the connection port array.
146 const jack_int_t
* JackConnectionManager::GetConnections(jack_port_id_t port_index
) const
148 return fConnection
[port_index
].GetItems();
151 //------------------------
152 // Client port management
153 //------------------------
156 \brief Add an input port to a client.
158 int JackConnectionManager::AddInputPort(int refnum
, jack_port_id_t port_index
)
160 if (fInputPort
[refnum
].AddItem(port_index
)) {
161 JackLog("JackConnectionManager::AddInputPort ref = %ld port = %ld\n", refnum
, port_index
);
164 jack_error("Maximum number of input ports is reached for application ref = %ld", refnum
);
170 \brief Add an output port to a client.
172 int JackConnectionManager::AddOutputPort(int refnum
, jack_port_id_t port_index
)
174 if (fOutputPort
[refnum
].AddItem(port_index
)) {
175 JackLog("JackConnectionManager::AddOutputPort ref = %ld port = %ld\n", refnum
, port_index
);
178 jack_error("Maximum number of output ports is reached for application ref = %ld", refnum
);
184 \brief Remove an input port from a client.
186 int JackConnectionManager::RemoveInputPort(int refnum
, jack_port_id_t port_index
)
188 JackLog("JackConnectionManager::RemoveInputPort ref = %ld port_index = %ld \n", refnum
, port_index
);
190 if (fInputPort
[refnum
].RemoveItem(port_index
)) {
193 jack_error("Input port index = %ld not found for application ref = %ld", port_index
, refnum
);
199 \brief Remove an output port from a client.
201 int JackConnectionManager::RemoveOutputPort(int refnum
, jack_port_id_t port_index
)
203 JackLog("JackConnectionManager::RemoveOutputPort ref = %ld port_index = %ld \n", refnum
, port_index
);
205 if (fOutputPort
[refnum
].RemoveItem(port_index
)) {
208 jack_error("Output port index = %ld not found for application ref = %ld", port_index
, refnum
);
214 \brief Get the input port array of a given refnum.
216 const jack_int_t
* JackConnectionManager::GetInputPorts(int refnum
)
218 return fInputPort
[refnum
].GetItems();
222 \brief Get the output port array of a given refnum.
224 const jack_int_t
* JackConnectionManager::GetOutputPorts(int refnum
)
226 return fOutputPort
[refnum
].GetItems();
230 \brief Init the refnum.
232 void JackConnectionManager::InitRefNum(int refnum
)
234 fInputPort
[refnum
].Init();
235 fOutputPort
[refnum
].Init();
236 fConnectionRef
.Init(refnum
);
237 fInputCounter
[refnum
].SetValue(0);
241 \brief Reset all clients activation.
243 void JackConnectionManager::ResetGraph(JackClientTiming
* timing
)
245 // Reset activation counter : must be done *before* starting to resume clients
246 for (int i
= 0; i
< CLIENT_NUM
; i
++) {
247 fInputCounter
[i
].Reset();
248 timing
[i
].fStatus
= NotTriggered
;
253 \brief Wait on the input synchro.
255 int JackConnectionManager::SuspendRefNum(JackClientControl
* control
, JackSynchro
** table
, JackClientTiming
* timing
, long time_out_usec
)
258 if ((res
= table
[control
->fRefNum
]->TimedWait(time_out_usec
))) {
259 timing
[control
->fRefNum
].fStatus
= Running
;
260 timing
[control
->fRefNum
].fAwakeAt
= GetMicroSeconds();
262 return (res
) ? 0 : -1;
266 \brief Signal clients connected to the given client.
268 int JackConnectionManager::ResumeRefNum(JackClientControl
* control
, JackSynchro
** table
, JackClientTiming
* timing
)
270 jack_time_t current_date
= GetMicroSeconds();
271 const jack_int_t
* outputRef
= fConnectionRef
.GetItems(control
->fRefNum
);
274 // Update state and timestamp of current client
275 timing
[control
->fRefNum
].fStatus
= Finished
;
276 timing
[control
->fRefNum
].fFinishedAt
= current_date
;
278 for (int i
= 0; i
< CLIENT_NUM
; i
++) {
280 // Signal connected clients or drivers
281 if (outputRef
[i
] > 0) {
283 // Update state and timestamp of destination clients
284 timing
[i
].fStatus
= Triggered
;
285 timing
[i
].fSignaledAt
= current_date
;
287 if (!fInputCounter
[i
].Signal(table
[i
], control
)) {
288 JackLog("JackConnectionManager::ResumeRefNum error: ref = %ld output = %ld \n", control
->fRefNum
, i
);
298 \brief Increment the number of ports between 2 clients, if the 2 clients become connected, then the Activation counter is updated.
300 void JackConnectionManager::IncDirectConnection(jack_port_id_t port_src
, jack_port_id_t port_dst
)
302 int ref1
= GetOutputRefNum(port_src
);
303 int ref2
= GetInputRefNum(port_dst
);
305 assert(ref1
>= 0 && ref2
>= 0);
307 DirectConnect(ref1
, ref2
);
308 JackLog("JackConnectionManager::IncConnectionRef: ref1 = %ld ref2 = %ld\n", ref1
, ref2
);
312 \brief Decrement the number of ports between 2 clients, if the 2 clients become disconnected, then the Activation counter is updated.
314 void JackConnectionManager::DecDirectConnection(jack_port_id_t port_src
, jack_port_id_t port_dst
)
316 int ref1
= GetOutputRefNum(port_src
);
317 int ref2
= GetInputRefNum(port_dst
);
319 assert(ref1
>= 0 && ref2
>= 0);
321 DirectDisconnect(ref1
, ref2
);
322 JackLog("JackConnectionManager::DecConnectionRef: ref1 = %ld ref2 = %ld\n", ref1
, ref2
);
326 \brief Directly connect 2 reference numbers.
328 void JackConnectionManager::DirectConnect(int ref1
, int ref2
)
330 assert(ref1
>= 0 && ref2
>= 0);
332 if (fConnectionRef
.IncItem(ref1
, ref2
) == 1) { // First connection between client ref1 and client ref2
333 JackLog("JackConnectionManager::DirectConnect first: ref1 = %ld ref2 = %ld\n", ref1
, ref2
);
334 fInputCounter
[ref2
].IncValue();
339 \brief Directly disconnect 2 reference numbers.
341 void JackConnectionManager::DirectDisconnect(int ref1
, int ref2
)
343 assert(ref1
>= 0 && ref2
>= 0);
345 if (fConnectionRef
.DecItem(ref1
, ref2
) == 0) { // Last connection between client ref1 and client ref2
346 JackLog("JackConnectionManager::DirectDisconnect last: ref1 = %ld ref2 = %ld\n", ref1
, ref2
);
347 fInputCounter
[ref2
].DecValue();
352 \brief Returns the connections state between 2 refnum.
354 bool JackConnectionManager::IsDirectConnection(int ref1
, int ref2
) const
356 assert(ref1
>= 0 && ref2
>= 0);
357 return fConnectionRef
.GetItemCount(ref1
, ref2
);
361 \brief Get the client refnum of a given input port.
363 int JackConnectionManager::GetInputRefNum(jack_port_id_t port_index
) const
365 for (int i
= 0; i
< CLIENT_NUM
; i
++) {
366 if (fInputPort
[i
].CheckItem(port_index
))
374 \brief Get the client refnum of a given ouput port.
376 int JackConnectionManager::GetOutputRefNum(jack_port_id_t port_index
) const
378 for (int i
= 0; i
< CLIENT_NUM
; i
++) {
379 if (fOutputPort
[i
].CheckItem(port_index
))
387 \brief Test is a connection path exists between port_src and port_dst.
389 bool JackConnectionManager::IsLoopPath(jack_port_id_t port_src
, jack_port_id_t port_dst
) const
391 return IsLoopPathAux(GetInputRefNum(port_dst
), GetOutputRefNum(port_src
));
394 bool JackConnectionManager::IsFeedbackConnection(jack_port_id_t port_src
, jack_port_id_t port_dst
) const
396 return (fLoopFeedback
.GetConnectionIndex(GetOutputRefNum(port_src
), GetInputRefNum(port_dst
)) >= 0);
399 bool JackConnectionManager::IncFeedbackConnection(jack_port_id_t port_src
, jack_port_id_t port_dst
)
401 int ref1
= GetOutputRefNum(port_src
);
402 int ref2
= GetInputRefNum(port_dst
);
404 // Add an activation connection in the other direction
405 JackLog("JackConnectionManager::IncFeedbackConnection ref1 = %ld ref2 = %ld\n", ref1
, ref2
);
406 assert(ref1
>= 0 && ref2
>= 0);
409 DirectConnect(ref2
, ref1
);
411 return fLoopFeedback
.IncConnection(ref1
, ref2
); // Add the feedback connection
414 bool JackConnectionManager::DecFeedbackConnection(jack_port_id_t port_src
, jack_port_id_t port_dst
)
416 int ref1
= GetOutputRefNum(port_src
);
417 int ref2
= GetInputRefNum(port_dst
);
419 // Remove an activation connection in the other direction
420 JackLog("JackConnectionManager::DecFeedbackConnection ref1 = %ld ref2 = %ld\n", ref1
, ref2
);
421 assert(ref1
>= 0 && ref2
>= 0);
424 DirectDisconnect(ref2
, ref1
);
426 return fLoopFeedback
.DecConnection(ref1
, ref2
); // Remove the feedback connection
429 } // end of namespace