2 Copyright (C) 2004-2008 Grame
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.
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.
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.
20 #include "JackConnectionManager.h"
21 #include "JackClientControl.h"
22 #include "JackEngineControl.h"
23 #include "JackGlobals.h"
24 #include "JackError.h"
31 JackConnectionManager::JackConnectionManager()
34 jack_log("JackConnectionManager::InitConnections size = %ld ", sizeof(JackConnectionManager
));
36 for (i
= 0; i
< PORT_NUM
; i
++) {
37 fConnection
[i
].Init();
42 jack_log("JackConnectionManager::InitClients");
43 for (i
= 0; i
< CLIENT_NUM
; i
++) {
48 JackConnectionManager::~JackConnectionManager()
55 bool JackConnectionManager::IsLoopPathAux(int ref1
, int ref2
) const
57 jack_log("JackConnectionManager::IsLoopPathAux ref1 = %ld ref2 = %ld", ref1
, ref2
);
59 if (ref1
< GetEngineControl()->fDriverNum
|| ref2
< GetEngineControl()->fDriverNum
) {
61 } else if (ref1
== ref2
) { // Same refnum
64 jack_int_t output
[CLIENT_NUM
];
65 fConnectionRef
.GetOutputTable(ref1
, output
);
67 if (fConnectionRef
.IsInsideTable(ref2
, output
)) { // If ref2 is contained in the outputs of ref1
70 for (int i
= 0; i
< CLIENT_NUM
&& output
[i
] != EMPTY
; i
++) { // Otherwise recurse for all ref1 outputs
71 if (IsLoopPathAux(output
[i
], ref2
))
72 return true; // Stop when a path is found
84 \brief Connect port_src to port_dst.
86 int JackConnectionManager::Connect(jack_port_id_t port_src
, jack_port_id_t port_dst
)
88 jack_log("JackConnectionManager::Connect port_src = %ld port_dst = %ld", port_src
, port_dst
);
90 if (fConnection
[port_src
].AddItem(port_dst
)) {
93 jack_error("Connection table is full !!");
99 \brief Disconnect port_src from port_dst.
101 int JackConnectionManager::Disconnect(jack_port_id_t port_src
, jack_port_id_t port_dst
)
103 jack_log("JackConnectionManager::Disconnect port_src = %ld port_dst = %ld", port_src
, port_dst
);
105 if (fConnection
[port_src
].RemoveItem(port_dst
)) {
108 jack_error("Connection not found !!");
114 \brief Check if port_src and port_dst are connected.
116 bool JackConnectionManager::IsConnected(jack_port_id_t port_src
, jack_port_id_t port_dst
) const
118 return fConnection
[port_src
].CheckItem(port_dst
);
122 \brief Get the connection port array.
124 const jack_int_t
* JackConnectionManager::GetConnections(jack_port_id_t port_index
) const
126 return fConnection
[port_index
].GetItems();
129 //------------------------
130 // Client port management
131 //------------------------
134 \brief Add an input port to a client.
136 int JackConnectionManager::AddInputPort(int refnum
, jack_port_id_t port_index
)
138 if (fInputPort
[refnum
].AddItem(port_index
)) {
139 jack_log("JackConnectionManager::AddInputPort ref = %ld port = %ld", refnum
, port_index
);
142 jack_error("Maximum number of input ports is reached for application ref = %ld", refnum
);
148 \brief Add an output port to a client.
150 int JackConnectionManager::AddOutputPort(int refnum
, jack_port_id_t port_index
)
152 if (fOutputPort
[refnum
].AddItem(port_index
)) {
153 jack_log("JackConnectionManager::AddOutputPort ref = %ld port = %ld", refnum
, port_index
);
156 jack_error("Maximum number of output ports is reached for application ref = %ld", refnum
);
162 \brief Remove an input port from a client.
164 int JackConnectionManager::RemoveInputPort(int refnum
, jack_port_id_t port_index
)
166 jack_log("JackConnectionManager::RemoveInputPort ref = %ld port_index = %ld ", refnum
, port_index
);
168 if (fInputPort
[refnum
].RemoveItem(port_index
)) {
171 jack_error("Input port index = %ld not found for application ref = %ld", port_index
, refnum
);
177 \brief Remove an output port from a client.
179 int JackConnectionManager::RemoveOutputPort(int refnum
, jack_port_id_t port_index
)
181 jack_log("JackConnectionManager::RemoveOutputPort ref = %ld port_index = %ld ", refnum
, port_index
);
183 if (fOutputPort
[refnum
].RemoveItem(port_index
)) {
186 jack_error("Output port index = %ld not found for application ref = %ld", port_index
, refnum
);
192 \brief Get the input port array of a given refnum.
194 const jack_int_t
* JackConnectionManager::GetInputPorts(int refnum
)
196 return fInputPort
[refnum
].GetItems();
200 \brief Get the output port array of a given refnum.
202 const jack_int_t
* JackConnectionManager::GetOutputPorts(int refnum
)
204 return fOutputPort
[refnum
].GetItems();
208 \brief Init the refnum.
210 void JackConnectionManager::InitRefNum(int refnum
)
212 fInputPort
[refnum
].Init();
213 fOutputPort
[refnum
].Init();
214 fConnectionRef
.Init(refnum
);
215 fInputCounter
[refnum
].SetValue(0);
219 \brief Reset all clients activation.
221 void JackConnectionManager::ResetGraph(JackClientTiming
* timing
)
223 // Reset activation counter : must be done *before* starting to resume clients
224 for (int i
= 0; i
< CLIENT_NUM
; i
++) {
225 fInputCounter
[i
].Reset();
226 timing
[i
].fStatus
= NotTriggered
;
231 \brief Wait on the input synchro.
233 int JackConnectionManager::SuspendRefNum(JackClientControl
* control
, JackSynchro
* table
, JackClientTiming
* timing
, long time_out_usec
)
236 if ((res
= table
[control
->fRefNum
].TimedWait(time_out_usec
))) {
237 timing
[control
->fRefNum
].fStatus
= Running
;
238 timing
[control
->fRefNum
].fAwakeAt
= GetMicroSeconds();
240 return (res
) ? 0 : -1;
244 \brief Signal clients connected to the given client.
246 int JackConnectionManager::ResumeRefNum(JackClientControl
* control
, JackSynchro
* table
, JackClientTiming
* timing
)
248 jack_time_t current_date
= GetMicroSeconds();
249 const jack_int_t
* outputRef
= fConnectionRef
.GetItems(control
->fRefNum
);
252 // Update state and timestamp of current client
253 timing
[control
->fRefNum
].fStatus
= Finished
;
254 timing
[control
->fRefNum
].fFinishedAt
= current_date
;
256 for (int i
= 0; i
< CLIENT_NUM
; i
++) {
258 // Signal connected clients or drivers
259 if (outputRef
[i
] > 0) {
261 // Update state and timestamp of destination clients
262 timing
[i
].fStatus
= Triggered
;
263 timing
[i
].fSignaledAt
= current_date
;
265 if (!fInputCounter
[i
].Signal(table
+ i
, control
)) {
266 jack_log("JackConnectionManager::ResumeRefNum error: ref = %ld output = %ld ", control
->fRefNum
, i
);
276 \brief Increment the number of ports between 2 clients, if the 2 clients become connected, then the Activation counter is updated.
278 void JackConnectionManager::IncDirectConnection(jack_port_id_t port_src
, jack_port_id_t port_dst
)
280 int ref1
= GetOutputRefNum(port_src
);
281 int ref2
= GetInputRefNum(port_dst
);
283 assert(ref1
>= 0 && ref2
>= 0);
285 DirectConnect(ref1
, ref2
);
286 jack_log("JackConnectionManager::IncConnectionRef: ref1 = %ld ref2 = %ld", ref1
, ref2
);
290 \brief Decrement the number of ports between 2 clients, if the 2 clients become disconnected, then the Activation counter is updated.
292 void JackConnectionManager::DecDirectConnection(jack_port_id_t port_src
, jack_port_id_t port_dst
)
294 int ref1
= GetOutputRefNum(port_src
);
295 int ref2
= GetInputRefNum(port_dst
);
297 assert(ref1
>= 0 && ref2
>= 0);
299 DirectDisconnect(ref1
, ref2
);
300 jack_log("JackConnectionManager::DecConnectionRef: ref1 = %ld ref2 = %ld", ref1
, ref2
);
304 \brief Directly connect 2 reference numbers.
306 void JackConnectionManager::DirectConnect(int ref1
, int ref2
)
308 assert(ref1
>= 0 && ref2
>= 0);
310 if (fConnectionRef
.IncItem(ref1
, ref2
) == 1) { // First connection between client ref1 and client ref2
311 jack_log("JackConnectionManager::DirectConnect first: ref1 = %ld ref2 = %ld", ref1
, ref2
);
312 fInputCounter
[ref2
].IncValue();
317 \brief Directly disconnect 2 reference numbers.
319 void JackConnectionManager::DirectDisconnect(int ref1
, int ref2
)
321 assert(ref1
>= 0 && ref2
>= 0);
323 if (fConnectionRef
.DecItem(ref1
, ref2
) == 0) { // Last connection between client ref1 and client ref2
324 jack_log("JackConnectionManager::DirectDisconnect last: ref1 = %ld ref2 = %ld", ref1
, ref2
);
325 fInputCounter
[ref2
].DecValue();
330 \brief Returns the connections state between 2 refnum.
332 bool JackConnectionManager::IsDirectConnection(int ref1
, int ref2
) const
334 assert(ref1
>= 0 && ref2
>= 0);
335 return (fConnectionRef
.GetItemCount(ref1
, ref2
) > 0);
339 \brief Get the client refnum of a given input port.
341 int JackConnectionManager::GetInputRefNum(jack_port_id_t port_index
) const
343 for (int i
= 0; i
< CLIENT_NUM
; i
++) {
344 if (fInputPort
[i
].CheckItem(port_index
))
352 \brief Get the client refnum of a given ouput port.
354 int JackConnectionManager::GetOutputRefNum(jack_port_id_t port_index
) const
356 for (int i
= 0; i
< CLIENT_NUM
; i
++) {
357 if (fOutputPort
[i
].CheckItem(port_index
))
365 \brief Test is a connection path exists between port_src and port_dst.
367 bool JackConnectionManager::IsLoopPath(jack_port_id_t port_src
, jack_port_id_t port_dst
) const
369 return IsLoopPathAux(GetInputRefNum(port_dst
), GetOutputRefNum(port_src
));
372 bool JackConnectionManager::IsFeedbackConnection(jack_port_id_t port_src
, jack_port_id_t port_dst
) const
374 return (fLoopFeedback
.GetConnectionIndex(GetOutputRefNum(port_src
), GetInputRefNum(port_dst
)) >= 0);
377 bool JackConnectionManager::IncFeedbackConnection(jack_port_id_t port_src
, jack_port_id_t port_dst
)
379 int ref1
= GetOutputRefNum(port_src
);
380 int ref2
= GetInputRefNum(port_dst
);
382 // Add an activation connection in the other direction
383 jack_log("JackConnectionManager::IncFeedbackConnection ref1 = %ld ref2 = %ld", ref1
, ref2
);
384 assert(ref1
>= 0 && ref2
>= 0);
387 DirectConnect(ref2
, ref1
);
389 return fLoopFeedback
.IncConnection(ref1
, ref2
); // Add the feedback connection
392 bool JackConnectionManager::DecFeedbackConnection(jack_port_id_t port_src
, jack_port_id_t port_dst
)
394 int ref1
= GetOutputRefNum(port_src
);
395 int ref2
= GetInputRefNum(port_dst
);
397 // Remove an activation connection in the other direction
398 jack_log("JackConnectionManager::DecFeedbackConnection ref1 = %ld ref2 = %ld", ref1
, ref2
);
399 assert(ref1
>= 0 && ref2
>= 0);
402 DirectDisconnect(ref2
, ref1
);
404 return fLoopFeedback
.DecConnection(ref1
, ref2
); // Remove the feedback connection
407 } // end of namespace