Jack2 1.9.6
|
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 <iostream> 00026 #include <assert.h> 00027 00028 namespace Jack 00029 { 00030 00031 JackConnectionManager::JackConnectionManager() 00032 { 00033 int i; 00034 jack_log("JackConnectionManager::InitConnections size = %ld ", sizeof(JackConnectionManager)); 00035 00036 for (i = 0; i < PORT_NUM_MAX; i++) { 00037 fConnection[i].Init(); 00038 } 00039 00040 fLoopFeedback.Init(); 00041 00042 jack_log("JackConnectionManager::InitClients"); 00043 for (i = 0; i < CLIENT_NUM; i++) { 00044 InitRefNum(i); 00045 } 00046 } 00047 00048 JackConnectionManager::~JackConnectionManager() 00049 {} 00050 00051 //-------------- 00052 // Internal API 00053 //-------------- 00054 00055 bool JackConnectionManager::IsLoopPathAux(int ref1, int ref2) const 00056 { 00057 jack_log("JackConnectionManager::IsLoopPathAux ref1 = %ld ref2 = %ld", ref1, ref2); 00058 00059 if (ref1 < GetEngineControl()->fDriverNum || ref2 < GetEngineControl()->fDriverNum) { 00060 return false; 00061 } else if (ref1 == ref2) { // Same refnum 00062 return true; 00063 } else { 00064 jack_int_t output[CLIENT_NUM]; 00065 fConnectionRef.GetOutputTable(ref1, output); 00066 00067 if (fConnectionRef.IsInsideTable(ref2, output)) { // If ref2 is contained in the outputs of ref1 00068 return true; 00069 } else { 00070 for (int i = 0; i < CLIENT_NUM && output[i] != EMPTY; i++) { // Otherwise recurse for all ref1 outputs 00071 if (IsLoopPathAux(output[i], ref2)) 00072 return true; // Stop when a path is found 00073 } 00074 return false; 00075 } 00076 } 00077 } 00078 00079 //-------------- 00080 // External API 00081 //-------------- 00082 00086 int JackConnectionManager::Connect(jack_port_id_t port_src, jack_port_id_t port_dst) 00087 { 00088 jack_log("JackConnectionManager::Connect port_src = %ld port_dst = %ld", port_src, port_dst); 00089 00090 if (fConnection[port_src].AddItem(port_dst)) { 00091 return 0; 00092 } else { 00093 jack_error("Connection table is full !!"); 00094 return -1; 00095 } 00096 } 00097 00101 int JackConnectionManager::Disconnect(jack_port_id_t port_src, jack_port_id_t port_dst) 00102 { 00103 jack_log("JackConnectionManager::Disconnect port_src = %ld port_dst = %ld", port_src, port_dst); 00104 00105 if (fConnection[port_src].RemoveItem(port_dst)) { 00106 return 0; 00107 } else { 00108 jack_error("Connection not found !!"); 00109 return -1; 00110 } 00111 } 00112 00116 bool JackConnectionManager::IsConnected(jack_port_id_t port_src, jack_port_id_t port_dst) const 00117 { 00118 return fConnection[port_src].CheckItem(port_dst); 00119 } 00120 00124 const jack_int_t* JackConnectionManager::GetConnections(jack_port_id_t port_index) const 00125 { 00126 return fConnection[port_index].GetItems(); 00127 } 00128 00129 //------------------------ 00130 // Client port management 00131 //------------------------ 00132 00136 int JackConnectionManager::AddInputPort(int refnum, jack_port_id_t port_index) 00137 { 00138 if (fInputPort[refnum].AddItem(port_index)) { 00139 jack_log("JackConnectionManager::AddInputPort ref = %ld port = %ld", refnum, port_index); 00140 return 0; 00141 } else { 00142 jack_error("Maximum number of input ports is reached for application ref = %ld", refnum); 00143 return -1; 00144 } 00145 } 00146 00150 int JackConnectionManager::AddOutputPort(int refnum, jack_port_id_t port_index) 00151 { 00152 if (fOutputPort[refnum].AddItem(port_index)) { 00153 jack_log("JackConnectionManager::AddOutputPort ref = %ld port = %ld", refnum, port_index); 00154 return 0; 00155 } else { 00156 jack_error("Maximum number of output ports is reached for application ref = %ld", refnum); 00157 return -1; 00158 } 00159 } 00160 00164 int JackConnectionManager::RemoveInputPort(int refnum, jack_port_id_t port_index) 00165 { 00166 jack_log("JackConnectionManager::RemoveInputPort ref = %ld port_index = %ld ", refnum, port_index); 00167 00168 if (fInputPort[refnum].RemoveItem(port_index)) { 00169 return 0; 00170 } else { 00171 jack_error("Input port index = %ld not found for application ref = %ld", port_index, refnum); 00172 return -1; 00173 } 00174 } 00175 00179 int JackConnectionManager::RemoveOutputPort(int refnum, jack_port_id_t port_index) 00180 { 00181 jack_log("JackConnectionManager::RemoveOutputPort ref = %ld port_index = %ld ", refnum, port_index); 00182 00183 if (fOutputPort[refnum].RemoveItem(port_index)) { 00184 return 0; 00185 } else { 00186 jack_error("Output port index = %ld not found for application ref = %ld", port_index, refnum); 00187 return -1; 00188 } 00189 } 00190 00194 const jack_int_t* JackConnectionManager::GetInputPorts(int refnum) 00195 { 00196 return fInputPort[refnum].GetItems(); 00197 } 00198 00202 const jack_int_t* JackConnectionManager::GetOutputPorts(int refnum) 00203 { 00204 return fOutputPort[refnum].GetItems(); 00205 } 00206 00210 void JackConnectionManager::InitRefNum(int refnum) 00211 { 00212 fInputPort[refnum].Init(); 00213 fOutputPort[refnum].Init(); 00214 fConnectionRef.Init(refnum); 00215 fInputCounter[refnum].SetValue(0); 00216 } 00217 00221 void JackConnectionManager::ResetGraph(JackClientTiming* timing) 00222 { 00223 // Reset activation counter : must be done *before* starting to resume clients 00224 for (int i = 0; i < CLIENT_NUM; i++) { 00225 fInputCounter[i].Reset(); 00226 timing[i].fStatus = NotTriggered; 00227 } 00228 } 00229 00233 int JackConnectionManager::SuspendRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing, long time_out_usec) 00234 { 00235 bool res; 00236 if ((res = table[control->fRefNum].TimedWait(time_out_usec))) { 00237 timing[control->fRefNum].fStatus = Running; 00238 timing[control->fRefNum].fAwakeAt = GetMicroSeconds(); 00239 } 00240 return (res) ? 0 : -1; 00241 } 00242 00246 int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro* table, JackClientTiming* timing) 00247 { 00248 jack_time_t current_date = GetMicroSeconds(); 00249 const jack_int_t* outputRef = fConnectionRef.GetItems(control->fRefNum); 00250 int res = 0; 00251 00252 // Update state and timestamp of current client 00253 timing[control->fRefNum].fStatus = Finished; 00254 timing[control->fRefNum].fFinishedAt = current_date; 00255 00256 for (int i = 0; i < CLIENT_NUM; i++) { 00257 00258 // Signal connected clients or drivers 00259 if (outputRef[i] > 0) { 00260 00261 // Update state and timestamp of destination clients 00262 timing[i].fStatus = Triggered; 00263 timing[i].fSignaledAt = current_date; 00264 00265 if (!fInputCounter[i].Signal(table + i, control)) { 00266 jack_log("JackConnectionManager::ResumeRefNum error: ref = %ld output = %ld ", control->fRefNum, i); 00267 res = -1; 00268 } 00269 } 00270 } 00271 00272 return res; 00273 } 00274 00278 void JackConnectionManager::IncDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst) 00279 { 00280 int ref1 = GetOutputRefNum(port_src); 00281 int ref2 = GetInputRefNum(port_dst); 00282 00283 assert(ref1 >= 0 && ref2 >= 0); 00284 00285 DirectConnect(ref1, ref2); 00286 jack_log("JackConnectionManager::IncConnectionRef: ref1 = %ld ref2 = %ld", ref1, ref2); 00287 } 00288 00292 void JackConnectionManager::DecDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst) 00293 { 00294 int ref1 = GetOutputRefNum(port_src); 00295 int ref2 = GetInputRefNum(port_dst); 00296 00297 assert(ref1 >= 0 && ref2 >= 0); 00298 00299 DirectDisconnect(ref1, ref2); 00300 jack_log("JackConnectionManager::DecConnectionRef: ref1 = %ld ref2 = %ld", ref1, ref2); 00301 } 00302 00306 void JackConnectionManager::DirectConnect(int ref1, int ref2) 00307 { 00308 assert(ref1 >= 0 && ref2 >= 0); 00309 00310 if (fConnectionRef.IncItem(ref1, ref2) == 1) { // First connection between client ref1 and client ref2 00311 jack_log("JackConnectionManager::DirectConnect first: ref1 = %ld ref2 = %ld", ref1, ref2); 00312 fInputCounter[ref2].IncValue(); 00313 } 00314 } 00315 00319 void JackConnectionManager::DirectDisconnect(int ref1, int ref2) 00320 { 00321 assert(ref1 >= 0 && ref2 >= 0); 00322 00323 if (fConnectionRef.DecItem(ref1, ref2) == 0) { // Last connection between client ref1 and client ref2 00324 jack_log("JackConnectionManager::DirectDisconnect last: ref1 = %ld ref2 = %ld", ref1, ref2); 00325 fInputCounter[ref2].DecValue(); 00326 } 00327 } 00328 00332 bool JackConnectionManager::IsDirectConnection(int ref1, int ref2) const 00333 { 00334 assert(ref1 >= 0 && ref2 >= 0); 00335 return (fConnectionRef.GetItemCount(ref1, ref2) > 0); 00336 } 00337 00341 int JackConnectionManager::GetInputRefNum(jack_port_id_t port_index) const 00342 { 00343 for (int i = 0; i < CLIENT_NUM; i++) { 00344 if (fInputPort[i].CheckItem(port_index)) 00345 return i; 00346 } 00347 00348 return -1; 00349 } 00350 00354 int JackConnectionManager::GetOutputRefNum(jack_port_id_t port_index) const 00355 { 00356 for (int i = 0; i < CLIENT_NUM; i++) { 00357 if (fOutputPort[i].CheckItem(port_index)) 00358 return i; 00359 } 00360 00361 return -1; 00362 } 00363 00367 bool JackConnectionManager::IsLoopPath(jack_port_id_t port_src, jack_port_id_t port_dst) const 00368 { 00369 return IsLoopPathAux(GetInputRefNum(port_dst), GetOutputRefNum(port_src)); 00370 } 00371 00372 bool JackConnectionManager::IsFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst) const 00373 { 00374 return (fLoopFeedback.GetConnectionIndex(GetOutputRefNum(port_src), GetInputRefNum(port_dst)) >= 0); 00375 } 00376 00377 bool JackConnectionManager::IncFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst) 00378 { 00379 int ref1 = GetOutputRefNum(port_src); 00380 int ref2 = GetInputRefNum(port_dst); 00381 00382 // Add an activation connection in the other direction 00383 jack_log("JackConnectionManager::IncFeedbackConnection ref1 = %ld ref2 = %ld", ref1, ref2); 00384 assert(ref1 >= 0 && ref2 >= 0); 00385 00386 if (ref1 != ref2) 00387 DirectConnect(ref2, ref1); 00388 00389 return fLoopFeedback.IncConnection(ref1, ref2); // Add the feedback connection 00390 } 00391 00392 bool JackConnectionManager::DecFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst) 00393 { 00394 int ref1 = GetOutputRefNum(port_src); 00395 int ref2 = GetInputRefNum(port_dst); 00396 00397 // Remove an activation connection in the other direction 00398 jack_log("JackConnectionManager::DecFeedbackConnection ref1 = %ld ref2 = %ld", ref1, ref2); 00399 assert(ref1 >= 0 && ref2 >= 0); 00400 00401 if (ref1 != ref2) 00402 DirectDisconnect(ref2, ref1); 00403 00404 return fLoopFeedback.DecConnection(ref1, ref2); // Remove the feedback connection 00405 } 00406 00407 } // end of namespace 00408 00409