Use jack_client_open instead of old jack_client_new.
[jack2.git] / common / JackConnectionManager.cpp
blob043b0c81ac3fa63e7aaea4c46268192a4a772f30
1 /*
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"
25 #include <iostream>
26 #include <assert.h>
28 namespace Jack
31 JackConnectionManager::JackConnectionManager()
33 int i;
34 jack_log("JackConnectionManager::InitConnections size = %ld ", sizeof(JackConnectionManager));
36 for (i = 0; i < PORT_NUM; i++) {
37 fConnection[i].Init();
40 fLoopFeedback.Init();
42 jack_log("JackConnectionManager::InitClients");
43 for (i = 0; i < CLIENT_NUM; i++) {
44 InitRefNum(i);
48 JackConnectionManager::~JackConnectionManager()
51 //--------------
52 // Internal API
53 //--------------
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) {
60 return false;
61 } else if (ref1 == ref2) { // Same refnum
62 return true;
63 } else {
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
68 return true;
69 } else {
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
74 return false;
79 //--------------
80 // External API
81 //--------------
83 /*!
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)) {
91 return 0;
92 } else {
93 jack_error("Connection table is full !!");
94 return -1;
98 /*!
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)) {
106 return 0;
107 } else {
108 jack_error("Connection not found !!");
109 return -1;
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);
140 return 0;
141 } else {
142 jack_error("Maximum number of input ports is reached for application ref = %ld", refnum);
143 return -1;
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);
154 return 0;
155 } else {
156 jack_error("Maximum number of output ports is reached for application ref = %ld", refnum);
157 return -1;
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)) {
169 return 0;
170 } else {
171 jack_error("Input port index = %ld not found for application ref = %ld", port_index, refnum);
172 return -1;
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)) {
184 return 0;
185 } else {
186 jack_error("Output port index = %ld not found for application ref = %ld", port_index, refnum);
187 return -1;
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)
235 bool res;
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);
250 int res = 0;
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);
267 res = -1;
272 return res;
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))
345 return i;
348 return -1;
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))
358 return i;
361 return -1;
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);
386 if (ref1 != ref2)
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);
401 if (ref1 != ref2)
402 DirectDisconnect(ref2, ref1);
404 return fLoopFeedback.DecConnection(ref1, ref2); // Remove the feedback connection
407 } // end of namespace