Remove non-jackdbus man pages
[jackdbus.git] / common / JackConnectionManager.cpp
blobdb240d2202846012e9cdfbdfeb1466f1bfe36145
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 <set>
26 #include <iostream>
27 #include <assert.h>
29 namespace Jack
32 JackConnectionManager::JackConnectionManager()
34 int i;
35 static_assert(offsetof(JackConnectionManager, fInputCounter) % sizeof(UInt32) == 0,
36 "fInputCounter must be aligned within JackConnectionManager");
38 jack_log("JackConnectionManager::InitConnections size = %ld ", sizeof(JackConnectionManager));
40 for (i = 0; i < PORT_NUM_MAX; i++) {
41 fConnection[i].Init();
44 fLoopFeedback.Init();
46 jack_log("JackConnectionManager::InitClients");
47 for (i = 0; i < CLIENT_NUM; i++) {
48 InitRefNum(i);
52 JackConnectionManager::~JackConnectionManager()
55 //--------------
56 // Internal API
57 //--------------
59 bool JackConnectionManager::IsLoopPathAux(int ref1, int ref2) const
61 jack_log("JackConnectionManager::IsLoopPathAux ref1 = %ld ref2 = %ld", ref1, ref2);
63 if (ref1 < GetEngineControl()->fDriverNum || ref2 < GetEngineControl()->fDriverNum) {
64 return false;
65 } else if (ref1 == ref2) { // Same refnum
66 return true;
67 } else {
68 jack_int_t output[CLIENT_NUM];
69 fConnectionRef.GetOutputTable(ref1, output);
71 if (fConnectionRef.IsInsideTable(ref2, output)) { // If ref2 is contained in the outputs of ref1
72 return true;
73 } else {
74 for (int i = 0; i < CLIENT_NUM && output[i] != EMPTY; i++) { // Otherwise recurse for all ref1 outputs
75 if (IsLoopPathAux(output[i], ref2)) {
76 return true; // Stop when a path is found
79 return false;
84 //--------------
85 // External API
86 //--------------
88 /*!
89 \brief Connect port_src to port_dst.
91 int JackConnectionManager::Connect(jack_port_id_t port_src, jack_port_id_t port_dst)
93 jack_log("JackConnectionManager::Connect port_src = %ld port_dst = %ld", port_src, port_dst);
95 if (fConnection[port_src].AddItem(port_dst)) {
96 return 0;
97 } else {
98 jack_error("Connection table is full !!");
99 return -1;
104 \brief Disconnect port_src from port_dst.
106 int JackConnectionManager::Disconnect(jack_port_id_t port_src, jack_port_id_t port_dst)
108 jack_log("JackConnectionManager::Disconnect port_src = %ld port_dst = %ld", port_src, port_dst);
110 if (fConnection[port_src].RemoveItem(port_dst)) {
111 return 0;
112 } else {
113 jack_error("Connection not found !!");
114 return -1;
119 \brief Check if port_src and port_dst are connected.
121 bool JackConnectionManager::IsConnected(jack_port_id_t port_src, jack_port_id_t port_dst) const
123 return fConnection[port_src].CheckItem(port_dst);
127 \brief Get the connection port array.
129 const jack_int_t* JackConnectionManager::GetConnections(jack_port_id_t port_index) const
131 return fConnection[port_index].GetItems();
134 //------------------------
135 // Client port management
136 //------------------------
139 \brief Add an input port to a client.
141 int JackConnectionManager::AddInputPort(int refnum, jack_port_id_t port_index)
143 if (fInputPort[refnum].AddItem(port_index)) {
144 jack_log("JackConnectionManager::AddInputPort ref = %ld port = %ld", refnum, port_index);
145 return 0;
146 } else {
147 jack_error("Maximum number of input ports is reached for application ref = %ld", refnum);
148 return -1;
153 \brief Add an output port to a client.
155 int JackConnectionManager::AddOutputPort(int refnum, jack_port_id_t port_index)
157 if (fOutputPort[refnum].AddItem(port_index)) {
158 jack_log("JackConnectionManager::AddOutputPort ref = %ld port = %ld", refnum, port_index);
159 return 0;
160 } else {
161 jack_error("Maximum number of output ports is reached for application ref = %ld", refnum);
162 return -1;
167 \brief Remove an input port from a client.
169 int JackConnectionManager::RemoveInputPort(int refnum, jack_port_id_t port_index)
171 jack_log("JackConnectionManager::RemoveInputPort ref = %ld port_index = %ld ", refnum, port_index);
173 if (fInputPort[refnum].RemoveItem(port_index)) {
174 return 0;
175 } else {
176 jack_error("Input port index = %ld not found for application ref = %ld", port_index, refnum);
177 return -1;
182 \brief Remove an output port from a client.
184 int JackConnectionManager::RemoveOutputPort(int refnum, jack_port_id_t port_index)
186 jack_log("JackConnectionManager::RemoveOutputPort ref = %ld port_index = %ld ", refnum, port_index);
188 if (fOutputPort[refnum].RemoveItem(port_index)) {
189 return 0;
190 } else {
191 jack_error("Output port index = %ld not found for application ref = %ld", port_index, refnum);
192 return -1;
197 \brief Get the input port array of a given refnum.
199 const jack_int_t* JackConnectionManager::GetInputPorts(int refnum)
201 return fInputPort[refnum].GetItems();
205 \brief Get the output port array of a given refnum.
207 const jack_int_t* JackConnectionManager::GetOutputPorts(int refnum)
209 return fOutputPort[refnum].GetItems();
213 \brief Init the refnum.
215 void JackConnectionManager::InitRefNum(int refnum)
217 fInputPort[refnum].Init();
218 fOutputPort[refnum].Init();
219 fConnectionRef.Init(refnum);
220 fInputCounter[refnum].SetValue(0);
224 \brief Reset all clients activation.
226 void JackConnectionManager::ResetGraph(JackClientTiming* timing)
228 // Reset activation counter : must be done *before* starting to resume clients
229 for (int i = 0; i < CLIENT_NUM; i++) {
230 fInputCounter[i].Reset();
231 timing[i].fStatus = NotTriggered;
236 \brief Wait on the input synchro.
238 int JackConnectionManager::SuspendRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing, long time_out_usec)
240 bool res;
241 if ((res = table[control->fRefNum].TimedWait(time_out_usec))) {
242 timing[control->fRefNum].fStatus = Running;
243 timing[control->fRefNum].fAwakeAt = GetMicroSeconds();
245 return (res) ? 0 : -1;
249 \brief Signal clients connected to the given client.
251 int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing)
253 jack_time_t current_date = GetMicroSeconds();
254 const jack_int_t* output_ref = fConnectionRef.GetItems(control->fRefNum);
255 int res = 0;
257 // Update state and timestamp of current client
258 timing[control->fRefNum].fStatus = Finished;
259 timing[control->fRefNum].fFinishedAt = current_date;
261 for (int i = 0; i < CLIENT_NUM; i++) {
263 // Signal connected clients or drivers
264 if (output_ref[i] > 0) {
266 // Update state and timestamp of destination clients
267 timing[i].fStatus = Triggered;
268 timing[i].fSignaledAt = current_date;
270 if (!fInputCounter[i].Signal(table + i, control)) {
271 jack_log("JackConnectionManager::ResumeRefNum error: ref = %ld output = %ld ", control->fRefNum, i);
272 res = -1;
277 return res;
280 static bool HasNoConnection(jack_int_t* table)
282 for (int ref = 0; ref < CLIENT_NUM; ref++) {
283 if (table[ref] > 0) return false;
285 return true;
288 // Using http://en.wikipedia.org/wiki/Topological_sorting
290 void JackConnectionManager::TopologicalSort(std::vector<jack_int_t>& sorted)
292 JackFixedMatrix<CLIENT_NUM>* tmp = new JackFixedMatrix<CLIENT_NUM>;
293 std::set<jack_int_t> level;
295 fConnectionRef.Copy(*tmp);
297 // Inputs of the graph
298 level.insert(AUDIO_DRIVER_REFNUM);
299 level.insert(FREEWHEEL_DRIVER_REFNUM);
301 while (level.size() > 0) {
302 jack_int_t refnum = *level.begin();
303 sorted.push_back(refnum);
304 level.erase(level.begin());
305 const jack_int_t* output_ref1 = tmp->GetItems(refnum);
306 for (int dst = 0; dst < CLIENT_NUM; dst++) {
307 if (output_ref1[dst] > 0) {
308 tmp->ClearItem(refnum, dst);
309 jack_int_t output_ref2[CLIENT_NUM];
310 tmp->GetOutputTable1(dst, output_ref2);
311 if (HasNoConnection(output_ref2)) {
312 level.insert(dst);
318 delete tmp;
322 \brief Increment the number of ports between 2 clients, if the 2 clients become connected, then the Activation counter is updated.
324 void JackConnectionManager::IncDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
326 int ref1 = GetOutputRefNum(port_src);
327 int ref2 = GetInputRefNum(port_dst);
329 assert(ref1 >= 0 && ref2 >= 0);
331 DirectConnect(ref1, ref2);
332 jack_log("JackConnectionManager::IncConnectionRef: ref1 = %ld ref2 = %ld", ref1, ref2);
336 \brief Decrement the number of ports between 2 clients, if the 2 clients become disconnected, then the Activation counter is updated.
338 void JackConnectionManager::DecDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
340 int ref1 = GetOutputRefNum(port_src);
341 int ref2 = GetInputRefNum(port_dst);
343 assert(ref1 >= 0 && ref2 >= 0);
345 DirectDisconnect(ref1, ref2);
346 jack_log("JackConnectionManager::DecConnectionRef: ref1 = %ld ref2 = %ld", ref1, ref2);
350 \brief Directly connect 2 reference numbers.
352 void JackConnectionManager::DirectConnect(int ref1, int ref2)
354 assert(ref1 >= 0 && ref2 >= 0);
356 if (fConnectionRef.IncItem(ref1, ref2) == 1) { // First connection between client ref1 and client ref2
357 jack_log("JackConnectionManager::DirectConnect first: ref1 = %ld ref2 = %ld", ref1, ref2);
358 fInputCounter[ref2].IncValue();
363 \brief Directly disconnect 2 reference numbers.
365 void JackConnectionManager::DirectDisconnect(int ref1, int ref2)
367 assert(ref1 >= 0 && ref2 >= 0);
369 if (fConnectionRef.DecItem(ref1, ref2) == 0) { // Last connection between client ref1 and client ref2
370 jack_log("JackConnectionManager::DirectDisconnect last: ref1 = %ld ref2 = %ld", ref1, ref2);
371 fInputCounter[ref2].DecValue();
376 \brief Returns the connections state between 2 refnum.
378 bool JackConnectionManager::IsDirectConnection(int ref1, int ref2) const
380 assert(ref1 >= 0 && ref2 >= 0);
381 return (fConnectionRef.GetItemCount(ref1, ref2) > 0);
385 \brief Get the client refnum of a given input port.
387 int JackConnectionManager::GetInputRefNum(jack_port_id_t port_index) const
389 for (int i = 0; i < CLIENT_NUM; i++) {
390 if (fInputPort[i].CheckItem(port_index)) {
391 return i;
395 return -1;
399 \brief Get the client refnum of a given output port.
401 int JackConnectionManager::GetOutputRefNum(jack_port_id_t port_index) const
403 for (int i = 0; i < CLIENT_NUM; i++) {
404 if (fOutputPort[i].CheckItem(port_index)) {
405 return i;
409 return -1;
413 \brief Test is a connection path exists between port_src and port_dst.
415 bool JackConnectionManager::IsLoopPath(jack_port_id_t port_src, jack_port_id_t port_dst) const
417 return IsLoopPathAux(GetInputRefNum(port_dst), GetOutputRefNum(port_src));
420 bool JackConnectionManager::IsFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst) const
422 return (fLoopFeedback.GetConnectionIndex(GetOutputRefNum(port_src), GetInputRefNum(port_dst)) >= 0);
425 bool JackConnectionManager::IncFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
427 int ref1 = GetOutputRefNum(port_src);
428 int ref2 = GetInputRefNum(port_dst);
430 // Add an activation connection in the other direction
431 jack_log("JackConnectionManager::IncFeedbackConnection ref1 = %ld ref2 = %ld", ref1, ref2);
432 assert(ref1 >= 0 && ref2 >= 0);
434 if (ref1 != ref2) {
435 DirectConnect(ref2, ref1);
438 return fLoopFeedback.IncConnection(ref1, ref2); // Add the feedback connection
441 bool JackConnectionManager::DecFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
443 int ref1 = GetOutputRefNum(port_src);
444 int ref2 = GetInputRefNum(port_dst);
446 // Remove an activation connection in the other direction
447 jack_log("JackConnectionManager::DecFeedbackConnection ref1 = %ld ref2 = %ld", ref1, ref2);
448 assert(ref1 >= 0 && ref2 >= 0);
450 if (ref1 != ref2) {
451 DirectDisconnect(ref2, ref1);
454 return fLoopFeedback.DecConnection(ref1, ref2); // Remove the feedback connection
457 } // end of namespace