Cleanup
[jack2.git] / common / JackConnectionManager.cpp
blob2898fd2b0e82cd6cf8a60410dc3cdff083d402b8
1 /*
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.
20 #include <iostream>
21 #include <assert.h>
22 #include "JackConnectionManager.h"
23 #include "JackClientControl.h"
24 #include "JackError.h"
26 namespace Jack
29 JackConnectionManager::JackConnectionManager()
31 int i;
32 JackLog("JackConnectionManager::InitConnections size = %ld \n", sizeof(JackConnectionManager));
34 for (i = 0; i < PORT_NUM; i++) {
35 fConnection[i].Init();
38 fLoopFeedback.Init();
40 JackLog("JackConnectionManager::InitClients\n");
41 for (i = 0; i < CLIENT_NUM; i++) {
42 InitRefNum(i);
46 JackConnectionManager::~JackConnectionManager()
49 //--------------
50 // Internal API
51 //--------------
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) {
63 return false;
64 } else if (ref1 == ref2) { // Same refnum
65 return true;
66 } else {
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
71 return true;
72 } else {
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
77 return false;
82 //--------------
83 // External API
84 //--------------
86 int JackConnectionManager::GetActivation(int refnum) const
88 return fInputCounter[refnum].GetValue();
91 /*!
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)) {
99 return 0;
100 } else {
101 jack_error("Connection table is full !!");
102 return -1;
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)) {
114 return 0;
115 } else {
116 jack_error("Connection not found !!");
117 return -1;
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);
162 return 0;
163 } else {
164 jack_error("Maximum number of input ports is reached for application ref = %ld", refnum);
165 return -1;
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);
176 return 0;
177 } else {
178 jack_error("Maximum number of output ports is reached for application ref = %ld", refnum);
179 return -1;
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)) {
191 return 0;
192 } else {
193 jack_error("Input port index = %ld not found for application ref = %ld", port_index, refnum);
194 return -1;
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)) {
206 return 0;
207 } else {
208 jack_error("Output port index = %ld not found for application ref = %ld", port_index, refnum);
209 return -1;
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)
257 bool res;
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);
272 int res = 0;
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);
289 res = -1;
294 return res;
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))
367 return i;
370 return -1;
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))
380 return i;
383 return -1;
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);
408 if (ref1 != ref2)
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);
423 if (ref1 != ref2)
424 DirectDisconnect(ref2, ref1);
426 return fLoopFeedback.DecConnection(ref1, ref2); // Remove the feedback connection
429 } // end of namespace