Jack2 1.9.10
|
00001 /* 00002 Copyright (C) 2004-2008 Grame 00003 00004 This program is free software; you can redistribute it and/or modify 00005 it under the terms of the GNU Lesser General Public License as published by 00006 the Free Software Foundation; either version 2.1 of the License, or 00007 (at your option) any later version. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU Lesser General Public License for more details. 00013 00014 You should have received a copy of the GNU Lesser General Public License 00015 along with this program; if not, write to the Free Software 00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 00018 */ 00019 00020 #include "JackConnectionManager.h" 00021 #include "JackClientControl.h" 00022 #include "JackEngineControl.h" 00023 #include "JackGlobals.h" 00024 #include "JackError.h" 00025 #include <set> 00026 #include <iostream> 00027 #include <assert.h> 00028 00029 namespace Jack 00030 { 00031 00032 JackConnectionManager::JackConnectionManager() 00033 { 00034 int i; 00035 jack_log("JackConnectionManager::InitConnections size = %ld ", sizeof(JackConnectionManager)); 00036 00037 for (i = 0; i < PORT_NUM_MAX; i++) { 00038 fConnection[i].Init(); 00039 } 00040 00041 fLoopFeedback.Init(); 00042 00043 jack_log("JackConnectionManager::InitClients"); 00044 for (i = 0; i < CLIENT_NUM; i++) { 00045 InitRefNum(i); 00046 } 00047 } 00048 00049 JackConnectionManager::~JackConnectionManager() 00050 {} 00051 00052 //-------------- 00053 // Internal API 00054 //-------------- 00055 00056 bool JackConnectionManager::IsLoopPathAux(int ref1, int ref2) const 00057 { 00058 jack_log("JackConnectionManager::IsLoopPathAux ref1 = %ld ref2 = %ld", ref1, ref2); 00059 00060 if (ref1 < GetEngineControl()->fDriverNum || ref2 < GetEngineControl()->fDriverNum) { 00061 return false; 00062 } else if (ref1 == ref2) { // Same refnum 00063 return true; 00064 } else { 00065 jack_int_t output[CLIENT_NUM]; 00066 fConnectionRef.GetOutputTable(ref1, output); 00067 00068 if (fConnectionRef.IsInsideTable(ref2, output)) { // If ref2 is contained in the outputs of ref1 00069 return true; 00070 } else { 00071 for (int i = 0; i < CLIENT_NUM && output[i] != EMPTY; i++) { // Otherwise recurse for all ref1 outputs 00072 if (IsLoopPathAux(output[i], ref2)) { 00073 return true; // Stop when a path is found 00074 } 00075 } 00076 return false; 00077 } 00078 } 00079 } 00080 00081 //-------------- 00082 // External API 00083 //-------------- 00084 00088 int JackConnectionManager::Connect(jack_port_id_t port_src, jack_port_id_t port_dst) 00089 { 00090 jack_log("JackConnectionManager::Connect port_src = %ld port_dst = %ld", port_src, port_dst); 00091 00092 if (fConnection[port_src].AddItem(port_dst)) { 00093 return 0; 00094 } else { 00095 jack_error("Connection table is full !!"); 00096 return -1; 00097 } 00098 } 00099 00103 int JackConnectionManager::Disconnect(jack_port_id_t port_src, jack_port_id_t port_dst) 00104 { 00105 jack_log("JackConnectionManager::Disconnect port_src = %ld port_dst = %ld", port_src, port_dst); 00106 00107 if (fConnection[port_src].RemoveItem(port_dst)) { 00108 return 0; 00109 } else { 00110 jack_error("Connection not found !!"); 00111 return -1; 00112 } 00113 } 00114 00118 bool JackConnectionManager::IsConnected(jack_port_id_t port_src, jack_port_id_t port_dst) const 00119 { 00120 return fConnection[port_src].CheckItem(port_dst); 00121 } 00122 00126 const jack_int_t* JackConnectionManager::GetConnections(jack_port_id_t port_index) const 00127 { 00128 return fConnection[port_index].GetItems(); 00129 } 00130 00131 //------------------------ 00132 // Client port management 00133 //------------------------ 00134 00138 int JackConnectionManager::AddInputPort(int refnum, jack_port_id_t port_index) 00139 { 00140 if (fInputPort[refnum].AddItem(port_index)) { 00141 jack_log("JackConnectionManager::AddInputPort ref = %ld port = %ld", refnum, port_index); 00142 return 0; 00143 } else { 00144 jack_error("Maximum number of input ports is reached for application ref = %ld", refnum); 00145 return -1; 00146 } 00147 } 00148 00152 int JackConnectionManager::AddOutputPort(int refnum, jack_port_id_t port_index) 00153 { 00154 if (fOutputPort[refnum].AddItem(port_index)) { 00155 jack_log("JackConnectionManager::AddOutputPort ref = %ld port = %ld", refnum, port_index); 00156 return 0; 00157 } else { 00158 jack_error("Maximum number of output ports is reached for application ref = %ld", refnum); 00159 return -1; 00160 } 00161 } 00162 00166 int JackConnectionManager::RemoveInputPort(int refnum, jack_port_id_t port_index) 00167 { 00168 jack_log("JackConnectionManager::RemoveInputPort ref = %ld port_index = %ld ", refnum, port_index); 00169 00170 if (fInputPort[refnum].RemoveItem(port_index)) { 00171 return 0; 00172 } else { 00173 jack_error("Input port index = %ld not found for application ref = %ld", port_index, refnum); 00174 return -1; 00175 } 00176 } 00177 00181 int JackConnectionManager::RemoveOutputPort(int refnum, jack_port_id_t port_index) 00182 { 00183 jack_log("JackConnectionManager::RemoveOutputPort ref = %ld port_index = %ld ", refnum, port_index); 00184 00185 if (fOutputPort[refnum].RemoveItem(port_index)) { 00186 return 0; 00187 } else { 00188 jack_error("Output port index = %ld not found for application ref = %ld", port_index, refnum); 00189 return -1; 00190 } 00191 } 00192 00196 const jack_int_t* JackConnectionManager::GetInputPorts(int refnum) 00197 { 00198 return fInputPort[refnum].GetItems(); 00199 } 00200 00204 const jack_int_t* JackConnectionManager::GetOutputPorts(int refnum) 00205 { 00206 return fOutputPort[refnum].GetItems(); 00207 } 00208 00212 void JackConnectionManager::InitRefNum(int refnum) 00213 { 00214 fInputPort[refnum].Init(); 00215 fOutputPort[refnum].Init(); 00216 fConnectionRef.Init(refnum); 00217 fInputCounter[refnum].SetValue(0); 00218 } 00219 00223 void JackConnectionManager::ResetGraph(JackClientTiming* timing) 00224 { 00225 // Reset activation counter : must be done *before* starting to resume clients 00226 for (int i = 0; i < CLIENT_NUM; i++) { 00227 fInputCounter[i].Reset(); 00228 timing[i].fStatus = NotTriggered; 00229 } 00230 } 00231 00235 int JackConnectionManager::SuspendRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing, long time_out_usec) 00236 { 00237 bool res; 00238 if ((res = table[control->fRefNum].TimedWait(time_out_usec))) { 00239 timing[control->fRefNum].fStatus = Running; 00240 timing[control->fRefNum].fAwakeAt = GetMicroSeconds(); 00241 } 00242 return (res) ? 0 : -1; 00243 } 00244 00248 int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing) 00249 { 00250 jack_time_t current_date = GetMicroSeconds(); 00251 const jack_int_t* output_ref = fConnectionRef.GetItems(control->fRefNum); 00252 int res = 0; 00253 00254 // Update state and timestamp of current client 00255 timing[control->fRefNum].fStatus = Finished; 00256 timing[control->fRefNum].fFinishedAt = current_date; 00257 00258 for (int i = 0; i < CLIENT_NUM; i++) { 00259 00260 // Signal connected clients or drivers 00261 if (output_ref[i] > 0) { 00262 00263 // Update state and timestamp of destination clients 00264 timing[i].fStatus = Triggered; 00265 timing[i].fSignaledAt = current_date; 00266 00267 if (!fInputCounter[i].Signal(table + i, control)) { 00268 jack_log("JackConnectionManager::ResumeRefNum error: ref = %ld output = %ld ", control->fRefNum, i); 00269 res = -1; 00270 } 00271 } 00272 } 00273 00274 return res; 00275 } 00276 00277 static bool HasNoConnection(jack_int_t* table) 00278 { 00279 for (int ref = 0; ref < CLIENT_NUM; ref++) { 00280 if (table[ref] > 0) return false; 00281 } 00282 return true; 00283 } 00284 00285 // Using http://en.wikipedia.org/wiki/Topological_sorting 00286 00287 void JackConnectionManager::TopologicalSort(std::vector<jack_int_t>& sorted) 00288 { 00289 JackFixedMatrix<CLIENT_NUM> tmp; 00290 std::set<jack_int_t> level; 00291 00292 fConnectionRef.Copy(tmp); 00293 00294 // Inputs of the graph 00295 level.insert(AUDIO_DRIVER_REFNUM); 00296 level.insert(FREEWHEEL_DRIVER_REFNUM); 00297 00298 while (level.size() > 0) { 00299 jack_int_t refnum = *level.begin(); 00300 sorted.push_back(refnum); 00301 level.erase(level.begin()); 00302 const jack_int_t* output_ref1 = tmp.GetItems(refnum); 00303 for (int dst = 0; dst < CLIENT_NUM; dst++) { 00304 if (output_ref1[dst] > 0) { 00305 tmp.ClearItem(refnum, dst); 00306 jack_int_t output_ref2[CLIENT_NUM]; 00307 tmp.GetOutputTable1(dst, output_ref2); 00308 if (HasNoConnection(output_ref2)) { 00309 level.insert(dst); 00310 } 00311 } 00312 } 00313 } 00314 } 00315 00319 void JackConnectionManager::IncDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst) 00320 { 00321 int ref1 = GetOutputRefNum(port_src); 00322 int ref2 = GetInputRefNum(port_dst); 00323 00324 assert(ref1 >= 0 && ref2 >= 0); 00325 00326 DirectConnect(ref1, ref2); 00327 jack_log("JackConnectionManager::IncConnectionRef: ref1 = %ld ref2 = %ld", ref1, ref2); 00328 } 00329 00333 void JackConnectionManager::DecDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst) 00334 { 00335 int ref1 = GetOutputRefNum(port_src); 00336 int ref2 = GetInputRefNum(port_dst); 00337 00338 assert(ref1 >= 0 && ref2 >= 0); 00339 00340 DirectDisconnect(ref1, ref2); 00341 jack_log("JackConnectionManager::DecConnectionRef: ref1 = %ld ref2 = %ld", ref1, ref2); 00342 } 00343 00347 void JackConnectionManager::DirectConnect(int ref1, int ref2) 00348 { 00349 assert(ref1 >= 0 && ref2 >= 0); 00350 00351 if (fConnectionRef.IncItem(ref1, ref2) == 1) { // First connection between client ref1 and client ref2 00352 jack_log("JackConnectionManager::DirectConnect first: ref1 = %ld ref2 = %ld", ref1, ref2); 00353 fInputCounter[ref2].IncValue(); 00354 } 00355 } 00356 00360 void JackConnectionManager::DirectDisconnect(int ref1, int ref2) 00361 { 00362 assert(ref1 >= 0 && ref2 >= 0); 00363 00364 if (fConnectionRef.DecItem(ref1, ref2) == 0) { // Last connection between client ref1 and client ref2 00365 jack_log("JackConnectionManager::DirectDisconnect last: ref1 = %ld ref2 = %ld", ref1, ref2); 00366 fInputCounter[ref2].DecValue(); 00367 } 00368 } 00369 00373 bool JackConnectionManager::IsDirectConnection(int ref1, int ref2) const 00374 { 00375 assert(ref1 >= 0 && ref2 >= 0); 00376 return (fConnectionRef.GetItemCount(ref1, ref2) > 0); 00377 } 00378 00382 int JackConnectionManager::GetInputRefNum(jack_port_id_t port_index) const 00383 { 00384 for (int i = 0; i < CLIENT_NUM; i++) { 00385 if (fInputPort[i].CheckItem(port_index)) { 00386 return i; 00387 } 00388 } 00389 00390 return -1; 00391 } 00392 00396 int JackConnectionManager::GetOutputRefNum(jack_port_id_t port_index) const 00397 { 00398 for (int i = 0; i < CLIENT_NUM; i++) { 00399 if (fOutputPort[i].CheckItem(port_index)) { 00400 return i; 00401 } 00402 } 00403 00404 return -1; 00405 } 00406 00410 bool JackConnectionManager::IsLoopPath(jack_port_id_t port_src, jack_port_id_t port_dst) const 00411 { 00412 return IsLoopPathAux(GetInputRefNum(port_dst), GetOutputRefNum(port_src)); 00413 } 00414 00415 bool JackConnectionManager::IsFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst) const 00416 { 00417 return (fLoopFeedback.GetConnectionIndex(GetOutputRefNum(port_src), GetInputRefNum(port_dst)) >= 0); 00418 } 00419 00420 bool JackConnectionManager::IncFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst) 00421 { 00422 int ref1 = GetOutputRefNum(port_src); 00423 int ref2 = GetInputRefNum(port_dst); 00424 00425 // Add an activation connection in the other direction 00426 jack_log("JackConnectionManager::IncFeedbackConnection ref1 = %ld ref2 = %ld", ref1, ref2); 00427 assert(ref1 >= 0 && ref2 >= 0); 00428 00429 if (ref1 != ref2) { 00430 DirectConnect(ref2, ref1); 00431 } 00432 00433 return fLoopFeedback.IncConnection(ref1, ref2); // Add the feedback connection 00434 } 00435 00436 bool JackConnectionManager::DecFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst) 00437 { 00438 int ref1 = GetOutputRefNum(port_src); 00439 int ref2 = GetInputRefNum(port_dst); 00440 00441 // Remove an activation connection in the other direction 00442 jack_log("JackConnectionManager::DecFeedbackConnection ref1 = %ld ref2 = %ld", ref1, ref2); 00443 assert(ref1 >= 0 && ref2 >= 0); 00444 00445 if (ref1 != ref2) { 00446 DirectDisconnect(ref2, ref1); 00447 } 00448 00449 return fLoopFeedback.DecConnection(ref1, ref2); // Remove the feedback connection 00450 } 00451 00452 } // end of namespace 00453 00454