Jack2 1.9.6

JackConnectionManager.cpp

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