Jack2 1.9.8
|
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 return false; 00076 } 00077 } 00078 } 00079 00080 //-------------- 00081 // External API 00082 //-------------- 00083 00087 int JackConnectionManager::Connect(jack_port_id_t port_src, jack_port_id_t port_dst) 00088 { 00089 jack_log("JackConnectionManager::Connect port_src = %ld port_dst = %ld", port_src, port_dst); 00090 00091 if (fConnection[port_src].AddItem(port_dst)) { 00092 return 0; 00093 } else { 00094 jack_error("Connection table is full !!"); 00095 return -1; 00096 } 00097 } 00098 00102 int JackConnectionManager::Disconnect(jack_port_id_t port_src, jack_port_id_t port_dst) 00103 { 00104 jack_log("JackConnectionManager::Disconnect port_src = %ld port_dst = %ld", port_src, port_dst); 00105 00106 if (fConnection[port_src].RemoveItem(port_dst)) { 00107 return 0; 00108 } else { 00109 jack_error("Connection not found !!"); 00110 return -1; 00111 } 00112 } 00113 00117 bool JackConnectionManager::IsConnected(jack_port_id_t port_src, jack_port_id_t port_dst) const 00118 { 00119 return fConnection[port_src].CheckItem(port_dst); 00120 } 00121 00125 const jack_int_t* JackConnectionManager::GetConnections(jack_port_id_t port_index) const 00126 { 00127 return fConnection[port_index].GetItems(); 00128 } 00129 00130 //------------------------ 00131 // Client port management 00132 //------------------------ 00133 00137 int JackConnectionManager::AddInputPort(int refnum, jack_port_id_t port_index) 00138 { 00139 if (fInputPort[refnum].AddItem(port_index)) { 00140 jack_log("JackConnectionManager::AddInputPort ref = %ld port = %ld", refnum, port_index); 00141 return 0; 00142 } else { 00143 jack_error("Maximum number of input ports is reached for application ref = %ld", refnum); 00144 return -1; 00145 } 00146 } 00147 00151 int JackConnectionManager::AddOutputPort(int refnum, jack_port_id_t port_index) 00152 { 00153 if (fOutputPort[refnum].AddItem(port_index)) { 00154 jack_log("JackConnectionManager::AddOutputPort ref = %ld port = %ld", refnum, port_index); 00155 return 0; 00156 } else { 00157 jack_error("Maximum number of output ports is reached for application ref = %ld", refnum); 00158 return -1; 00159 } 00160 } 00161 00165 int JackConnectionManager::RemoveInputPort(int refnum, jack_port_id_t port_index) 00166 { 00167 jack_log("JackConnectionManager::RemoveInputPort ref = %ld port_index = %ld ", refnum, port_index); 00168 00169 if (fInputPort[refnum].RemoveItem(port_index)) { 00170 return 0; 00171 } else { 00172 jack_error("Input port index = %ld not found for application ref = %ld", port_index, refnum); 00173 return -1; 00174 } 00175 } 00176 00180 int JackConnectionManager::RemoveOutputPort(int refnum, jack_port_id_t port_index) 00181 { 00182 jack_log("JackConnectionManager::RemoveOutputPort ref = %ld port_index = %ld ", refnum, port_index); 00183 00184 if (fOutputPort[refnum].RemoveItem(port_index)) { 00185 return 0; 00186 } else { 00187 jack_error("Output port index = %ld not found for application ref = %ld", port_index, refnum); 00188 return -1; 00189 } 00190 } 00191 00195 const jack_int_t* JackConnectionManager::GetInputPorts(int refnum) 00196 { 00197 return fInputPort[refnum].GetItems(); 00198 } 00199 00203 const jack_int_t* JackConnectionManager::GetOutputPorts(int refnum) 00204 { 00205 return fOutputPort[refnum].GetItems(); 00206 } 00207 00211 void JackConnectionManager::InitRefNum(int refnum) 00212 { 00213 fInputPort[refnum].Init(); 00214 fOutputPort[refnum].Init(); 00215 fConnectionRef.Init(refnum); 00216 fInputCounter[refnum].SetValue(0); 00217 } 00218 00222 void JackConnectionManager::ResetGraph(JackClientTiming* timing) 00223 { 00224 // Reset activation counter : must be done *before* starting to resume clients 00225 for (int i = 0; i < CLIENT_NUM; i++) { 00226 fInputCounter[i].Reset(); 00227 timing[i].fStatus = NotTriggered; 00228 } 00229 } 00230 00234 int JackConnectionManager::SuspendRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing, long time_out_usec) 00235 { 00236 bool res; 00237 if ((res = table[control->fRefNum].TimedWait(time_out_usec))) { 00238 timing[control->fRefNum].fStatus = Running; 00239 timing[control->fRefNum].fAwakeAt = GetMicroSeconds(); 00240 } 00241 return (res) ? 0 : -1; 00242 } 00243 00247 int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing) 00248 { 00249 jack_time_t current_date = GetMicroSeconds(); 00250 const jack_int_t* output_ref = fConnectionRef.GetItems(control->fRefNum); 00251 int res = 0; 00252 00253 // Update state and timestamp of current client 00254 timing[control->fRefNum].fStatus = Finished; 00255 timing[control->fRefNum].fFinishedAt = current_date; 00256 00257 for (int i = 0; i < CLIENT_NUM; i++) { 00258 00259 // Signal connected clients or drivers 00260 if (output_ref[i] > 0) { 00261 00262 // Update state and timestamp of destination clients 00263 timing[i].fStatus = Triggered; 00264 timing[i].fSignaledAt = current_date; 00265 00266 if (!fInputCounter[i].Signal(table + i, control)) { 00267 jack_log("JackConnectionManager::ResumeRefNum error: ref = %ld output = %ld ", control->fRefNum, i); 00268 res = -1; 00269 } 00270 } 00271 } 00272 00273 return res; 00274 } 00275 00276 static bool HasNoConnection(jack_int_t* table) 00277 { 00278 for (int ref = 0; ref < CLIENT_NUM; ref++) { 00279 if (table[ref] > 0) return false; 00280 } 00281 return true; 00282 } 00283 00284 // Using http://en.wikipedia.org/wiki/Topological_sorting 00285 00286 void JackConnectionManager::TopologicalSort(std::vector<jack_int_t>& sorted) 00287 { 00288 JackFixedMatrix<CLIENT_NUM> tmp; 00289 std::set<jack_int_t> level; 00290 00291 fConnectionRef.Copy(tmp); 00292 00293 // Inputs of the graph 00294 level.insert(AUDIO_DRIVER_REFNUM); 00295 level.insert(FREEWHEEL_DRIVER_REFNUM); 00296 00297 while (level.size() > 0) { 00298 jack_int_t refnum = *level.begin(); 00299 sorted.push_back(refnum); 00300 level.erase(level.begin()); 00301 const jack_int_t* output_ref1 = tmp.GetItems(refnum); 00302 for (int dst = 0; dst < CLIENT_NUM; dst++) { 00303 if (output_ref1[dst] > 0) { 00304 tmp.ClearItem(refnum, dst); 00305 jack_int_t output_ref2[CLIENT_NUM]; 00306 tmp.GetOutputTable1(dst, output_ref2); 00307 if (HasNoConnection(output_ref2)) 00308 level.insert(dst); 00309 } 00310 } 00311 } 00312 } 00313 00317 void JackConnectionManager::IncDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst) 00318 { 00319 int ref1 = GetOutputRefNum(port_src); 00320 int ref2 = GetInputRefNum(port_dst); 00321 00322 assert(ref1 >= 0 && ref2 >= 0); 00323 00324 DirectConnect(ref1, ref2); 00325 jack_log("JackConnectionManager::IncConnectionRef: ref1 = %ld ref2 = %ld", ref1, ref2); 00326 } 00327 00331 void JackConnectionManager::DecDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst) 00332 { 00333 int ref1 = GetOutputRefNum(port_src); 00334 int ref2 = GetInputRefNum(port_dst); 00335 00336 assert(ref1 >= 0 && ref2 >= 0); 00337 00338 DirectDisconnect(ref1, ref2); 00339 jack_log("JackConnectionManager::DecConnectionRef: ref1 = %ld ref2 = %ld", ref1, ref2); 00340 } 00341 00345 void JackConnectionManager::DirectConnect(int ref1, int ref2) 00346 { 00347 assert(ref1 >= 0 && ref2 >= 0); 00348 00349 if (fConnectionRef.IncItem(ref1, ref2) == 1) { // First connection between client ref1 and client ref2 00350 jack_log("JackConnectionManager::DirectConnect first: ref1 = %ld ref2 = %ld", ref1, ref2); 00351 fInputCounter[ref2].IncValue(); 00352 } 00353 } 00354 00358 void JackConnectionManager::DirectDisconnect(int ref1, int ref2) 00359 { 00360 assert(ref1 >= 0 && ref2 >= 0); 00361 00362 if (fConnectionRef.DecItem(ref1, ref2) == 0) { // Last connection between client ref1 and client ref2 00363 jack_log("JackConnectionManager::DirectDisconnect last: ref1 = %ld ref2 = %ld", ref1, ref2); 00364 fInputCounter[ref2].DecValue(); 00365 } 00366 } 00367 00371 bool JackConnectionManager::IsDirectConnection(int ref1, int ref2) const 00372 { 00373 assert(ref1 >= 0 && ref2 >= 0); 00374 return (fConnectionRef.GetItemCount(ref1, ref2) > 0); 00375 } 00376 00380 int JackConnectionManager::GetInputRefNum(jack_port_id_t port_index) const 00381 { 00382 for (int i = 0; i < CLIENT_NUM; i++) { 00383 if (fInputPort[i].CheckItem(port_index)) 00384 return i; 00385 } 00386 00387 return -1; 00388 } 00389 00393 int JackConnectionManager::GetOutputRefNum(jack_port_id_t port_index) const 00394 { 00395 for (int i = 0; i < CLIENT_NUM; i++) { 00396 if (fOutputPort[i].CheckItem(port_index)) 00397 return i; 00398 } 00399 00400 return -1; 00401 } 00402 00406 bool JackConnectionManager::IsLoopPath(jack_port_id_t port_src, jack_port_id_t port_dst) const 00407 { 00408 return IsLoopPathAux(GetInputRefNum(port_dst), GetOutputRefNum(port_src)); 00409 } 00410 00411 bool JackConnectionManager::IsFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst) const 00412 { 00413 return (fLoopFeedback.GetConnectionIndex(GetOutputRefNum(port_src), GetInputRefNum(port_dst)) >= 0); 00414 } 00415 00416 bool JackConnectionManager::IncFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst) 00417 { 00418 int ref1 = GetOutputRefNum(port_src); 00419 int ref2 = GetInputRefNum(port_dst); 00420 00421 // Add an activation connection in the other direction 00422 jack_log("JackConnectionManager::IncFeedbackConnection ref1 = %ld ref2 = %ld", ref1, ref2); 00423 assert(ref1 >= 0 && ref2 >= 0); 00424 00425 if (ref1 != ref2) 00426 DirectConnect(ref2, ref1); 00427 00428 return fLoopFeedback.IncConnection(ref1, ref2); // Add the feedback connection 00429 } 00430 00431 bool JackConnectionManager::DecFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst) 00432 { 00433 int ref1 = GetOutputRefNum(port_src); 00434 int ref2 = GetInputRefNum(port_dst); 00435 00436 // Remove an activation connection in the other direction 00437 jack_log("JackConnectionManager::DecFeedbackConnection ref1 = %ld ref2 = %ld", ref1, ref2); 00438 assert(ref1 >= 0 && ref2 >= 0); 00439 00440 if (ref1 != ref2) 00441 DirectDisconnect(ref2, ref1); 00442 00443 return fLoopFeedback.DecConnection(ref1, ref2); // Remove the feedback connection 00444 } 00445 00446 } // end of namespace 00447 00448