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 General Public License as published by
00006 the Free Software Foundation; either version 2 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 General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017 
00018 */
00019 
00020 #include <iostream>
00021 #include <assert.h>
00022 #include "JackConnectionManager.h"
00023 #include "JackClientControl.h"
00024 #include "JackError.h"
00025 
00026 namespace Jack
00027 {
00028 
00029 JackConnectionManager::JackConnectionManager()
00030 {
00031     int i;
00032     JackLog("JackConnectionManager::InitConnections size = %ld \n", sizeof(JackConnectionManager));
00033 
00034     for (i = 0; i < PORT_NUM; i++) {
00035         fConnection[i].Init();
00036     }
00037 
00038     fLoopFeedback.Init();
00039 
00040     JackLog("JackConnectionManager::InitClients\n");
00041     for (i = 0; i < CLIENT_NUM; i++) {
00042         InitRefNum(i);
00043     }
00044 }
00045 
00046 JackConnectionManager::~JackConnectionManager()
00047 {}
00048 
00049 //--------------
00050 // Internal API
00051 //--------------
00052 
00053 bool JackConnectionManager::IsLoopPathAux(int ref1, int ref2) const
00054 {
00055     JackLog("JackConnectionManager::IsLoopPathAux ref1 = %ld ref2 = %ld\n", ref1, ref2);
00056 
00057     if (ref1 == AUDIO_DRIVER_REFNUM // Driver is reached
00058             || ref2 == AUDIO_DRIVER_REFNUM
00059             || ref1 == FREEWHEEL_DRIVER_REFNUM
00060             || ref2 == FREEWHEEL_DRIVER_REFNUM
00061             || ref1 == LOOPBACK_DRIVER_REFNUM
00062             || ref2 == LOOPBACK_DRIVER_REFNUM) {
00063         return false;
00064     } else if (ref1 == ref2) {  // Same refnum
00065         return true;
00066     } else {
00067         jack_int_t output[CLIENT_NUM];
00068         fConnectionRef.GetOutputTable(ref1, output);
00069 
00070         if (fConnectionRef.IsInsideTable(ref2, output)) { // If ref2 is contained in the outputs of ref1
00071             return true;
00072         } else {
00073             for (int i = 0; i < CLIENT_NUM && output[i] != EMPTY; i++) { // Otherwise recurse for all ref1 outputs
00074                 if (IsLoopPathAux(output[i], ref2))
00075                     return true; // Stop when a path is found
00076             }
00077             return false;
00078         }
00079     }
00080 }
00081 
00082 //--------------
00083 // External API
00084 //--------------
00085 
00086 int JackConnectionManager::GetActivation(int refnum) const
00087 {
00088     return fInputCounter[refnum].GetValue();
00089 }
00090 
00094 int JackConnectionManager::Connect(jack_port_id_t port_src, jack_port_id_t port_dst)
00095 {
00096     JackLog("JackConnectionManager::Connect port_src = %ld port_dst = %ld\n", port_src, port_dst);
00097 
00098     if (fConnection[port_src].AddItem(port_dst)) {
00099         return 0;
00100     } else {
00101         jack_error("Connection table is full !!");
00102         return -1;
00103     }
00104 }
00105 
00109 int JackConnectionManager::Disconnect(jack_port_id_t port_src, jack_port_id_t port_dst)
00110 {
00111     JackLog("JackConnectionManager::Disconnect port_src = %ld port_dst = %ld\n", port_src, port_dst);
00112 
00113     if (fConnection[port_src].RemoveItem(port_dst)) {
00114         return 0;
00115     } else {
00116         jack_error("Connection not found !!");
00117         return -1;
00118     }
00119 }
00120 
00124 bool JackConnectionManager::IsConnected(jack_port_id_t port_src, jack_port_id_t port_dst) const
00125 {
00126     return fConnection[port_src].CheckItem(port_dst);
00127 }
00128 
00132 jack_int_t JackConnectionManager::Connections(jack_port_id_t port_index) const
00133 {
00134     return fConnection[port_index].GetItemCount();
00135 }
00136 
00137 jack_port_id_t JackConnectionManager::GetPort(jack_port_id_t port_index, int connection) const
00138 {
00139     assert(connection < CONNECTION_NUM);
00140     return (jack_port_id_t)fConnection[port_index].GetItem(connection);
00141 }
00142 
00146 const jack_int_t* JackConnectionManager::GetConnections(jack_port_id_t port_index) const
00147 {
00148     return fConnection[port_index].GetItems();
00149 }
00150 
00151 //------------------------
00152 // Client port management
00153 //------------------------
00154 
00158 int JackConnectionManager::AddInputPort(int refnum, jack_port_id_t port_index)
00159 {
00160     if (fInputPort[refnum].AddItem(port_index)) {
00161         JackLog("JackConnectionManager::AddInputPort ref = %ld port = %ld\n", refnum, port_index);
00162         return 0;
00163     } else {
00164         jack_error("Maximum number of input ports is reached for application ref = %ld", refnum);
00165         return -1;
00166     }
00167 }
00168 
00172 int JackConnectionManager::AddOutputPort(int refnum, jack_port_id_t port_index)
00173 {
00174     if (fOutputPort[refnum].AddItem(port_index)) {
00175         JackLog("JackConnectionManager::AddOutputPort ref = %ld port = %ld\n", refnum, port_index);
00176         return 0;
00177     } else {
00178         jack_error("Maximum number of output ports is reached for application ref = %ld", refnum);
00179         return -1;
00180     }
00181 }
00182 
00186 int JackConnectionManager::RemoveInputPort(int refnum, jack_port_id_t port_index)
00187 {
00188     JackLog("JackConnectionManager::RemoveInputPort ref = %ld port_index = %ld \n", refnum, port_index);
00189 
00190     if (fInputPort[refnum].RemoveItem(port_index)) {
00191         return 0;
00192     } else {
00193         jack_error("Input port index = %ld not found for application ref = %ld", port_index, refnum);
00194         return -1;
00195     }
00196 }
00197 
00201 int JackConnectionManager::RemoveOutputPort(int refnum, jack_port_id_t port_index)
00202 {
00203     JackLog("JackConnectionManager::RemoveOutputPort ref = %ld port_index = %ld \n", refnum, port_index);
00204 
00205     if (fOutputPort[refnum].RemoveItem(port_index)) {
00206         return 0;
00207     } else {
00208         jack_error("Output port index = %ld not found for application ref = %ld", port_index, refnum);
00209         return -1;
00210     }
00211 }
00212 
00216 const jack_int_t* JackConnectionManager::GetInputPorts(int refnum)
00217 {
00218     return fInputPort[refnum].GetItems();
00219 }
00220 
00224 const jack_int_t* JackConnectionManager::GetOutputPorts(int refnum)
00225 {
00226     return fOutputPort[refnum].GetItems();
00227 }
00228 
00232 void JackConnectionManager::InitRefNum(int refnum)
00233 {
00234     fInputPort[refnum].Init();
00235     fOutputPort[refnum].Init();
00236     fConnectionRef.Init(refnum);
00237     fInputCounter[refnum].SetValue(0);
00238 }
00239 
00243 void JackConnectionManager::ResetGraph(JackClientTiming* timing)
00244 {
00245     // Reset activation counter : must be done *before* starting to resume clients
00246     for (int i = 0; i < CLIENT_NUM; i++) {
00247         fInputCounter[i].Reset();
00248                 timing[i].fStatus = NotTriggered;
00249     }
00250 }
00251 
00255 int JackConnectionManager::SuspendRefNum(JackClientControl* control, JackSynchro** table, JackClientTiming* timing, long time_out_usec)
00256 {
00257     bool res;
00258     if ((res = table[control->fRefNum]->TimedWait(time_out_usec))) {
00259                 timing[control->fRefNum].fStatus = Running;
00260                 timing[control->fRefNum].fAwakeAt = GetMicroSeconds();
00261     }
00262     return (res) ? 0 : -1;
00263 }
00264 
00268 int JackConnectionManager::ResumeRefNum(JackClientControl* control, JackSynchro** table, JackClientTiming* timing)
00269 {
00270         jack_time_t current_date = GetMicroSeconds(); 
00271     const jack_int_t* outputRef = fConnectionRef.GetItems(control->fRefNum);
00272         int res = 0;
00273 
00274     // Update state and timestamp of current client
00275         timing[control->fRefNum].fStatus = Finished;
00276         timing[control->fRefNum].fFinishedAt = current_date;
00277 
00278     for (int i = 0; i < CLIENT_NUM; i++) {
00279         
00280         // Signal connected clients or drivers
00281         if (outputRef[i] > 0) {
00282                 
00283                         // Update state and timestamp of destination clients
00284                         timing[i].fStatus = Triggered;
00285                         timing[i].fSignaledAt = current_date;
00286 
00287             if (!fInputCounter[i].Signal(table[i], control)) {
00288                 JackLog("JackConnectionManager::ResumeRefNum error: ref = %ld output = %ld \n", control->fRefNum, i);
00289                 res = -1;
00290             }
00291         }
00292     }
00293 
00294     return res;
00295 }
00296 
00300 void JackConnectionManager::IncDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
00301 {
00302     int ref1 = GetOutputRefNum(port_src);
00303     int ref2 = GetInputRefNum(port_dst);
00304 
00305     assert(ref1 >= 0 && ref2 >= 0);
00306 
00307     DirectConnect(ref1, ref2);
00308     JackLog("JackConnectionManager::IncConnectionRef: ref1 = %ld ref2 = %ld\n", ref1, ref2);
00309 }
00310 
00314 void JackConnectionManager::DecDirectConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
00315 {
00316     int ref1 = GetOutputRefNum(port_src);
00317     int ref2 = GetInputRefNum(port_dst);
00318 
00319     assert(ref1 >= 0 && ref2 >= 0);
00320 
00321     DirectDisconnect(ref1, ref2);
00322     JackLog("JackConnectionManager::DecConnectionRef: ref1 = %ld ref2 = %ld\n", ref1, ref2);
00323 }
00324 
00328 void JackConnectionManager::DirectConnect(int ref1, int ref2)
00329 {
00330     assert(ref1 >= 0 && ref2 >= 0);
00331 
00332     if (fConnectionRef.IncItem(ref1, ref2) == 1) { // First connection between client ref1 and client ref2
00333         JackLog("JackConnectionManager::DirectConnect first: ref1 = %ld ref2 = %ld\n", ref1, ref2);
00334         fInputCounter[ref2].IncValue();
00335     }
00336 }
00337 
00341 void JackConnectionManager::DirectDisconnect(int ref1, int ref2)
00342 {
00343     assert(ref1 >= 0 && ref2 >= 0);
00344 
00345     if (fConnectionRef.DecItem(ref1, ref2) == 0) { // Last connection between client ref1 and client ref2
00346         JackLog("JackConnectionManager::DirectDisconnect last: ref1 = %ld ref2 = %ld\n", ref1, ref2);
00347         fInputCounter[ref2].DecValue();
00348     }
00349 }
00350 
00354 bool JackConnectionManager::IsDirectConnection(int ref1, int ref2) const
00355 {
00356     assert(ref1 >= 0 && ref2 >= 0);
00357     return fConnectionRef.GetItemCount(ref1, ref2);
00358 }
00359 
00363 int JackConnectionManager::GetInputRefNum(jack_port_id_t port_index) const
00364 {
00365     for (int i = 0; i < CLIENT_NUM; i++) {
00366         if (fInputPort[i].CheckItem(port_index))
00367             return i;
00368     }
00369 
00370     return -1;
00371 }
00372 
00376 int JackConnectionManager::GetOutputRefNum(jack_port_id_t port_index) const
00377 {
00378     for (int i = 0; i < CLIENT_NUM; i++) {
00379         if (fOutputPort[i].CheckItem(port_index))
00380             return i;
00381     }
00382 
00383     return -1;
00384 }
00385 
00389 bool JackConnectionManager::IsLoopPath(jack_port_id_t port_src, jack_port_id_t port_dst) const
00390 {
00391     return IsLoopPathAux(GetInputRefNum(port_dst), GetOutputRefNum(port_src));
00392 }
00393 
00394 bool JackConnectionManager::IsFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst) const
00395 {
00396     return (fLoopFeedback.GetConnectionIndex(GetOutputRefNum(port_src), GetInputRefNum(port_dst)) >= 0);
00397 }
00398 
00399 bool JackConnectionManager::IncFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
00400 {
00401     int ref1 = GetOutputRefNum(port_src);
00402     int ref2 = GetInputRefNum(port_dst);
00403 
00404     // Add an activation connection in the other direction
00405     JackLog("JackConnectionManager::IncFeedbackConnection ref1 = %ld ref2 = %ld\n", ref1, ref2);
00406     assert(ref1 >= 0 && ref2 >= 0);
00407 
00408     if (ref1 != ref2)
00409         DirectConnect(ref2, ref1);
00410 
00411     return fLoopFeedback.IncConnection(ref1, ref2); // Add the feedback connection
00412 }
00413 
00414 bool JackConnectionManager::DecFeedbackConnection(jack_port_id_t port_src, jack_port_id_t port_dst)
00415 {
00416     int ref1 = GetOutputRefNum(port_src);
00417     int ref2 = GetInputRefNum(port_dst);
00418 
00419     // Remove an activation connection in the other direction
00420     JackLog("JackConnectionManager::DecFeedbackConnection ref1 = %ld ref2 = %ld\n", ref1, ref2);
00421     assert(ref1 >= 0 && ref2 >= 0);
00422 
00423     if (ref1 != ref2)
00424         DirectDisconnect(ref2, ref1);
00425 
00426     return fLoopFeedback.DecConnection(ref1, ref2); // Remove the feedback connection
00427 }
00428 
00429 } // end of namespace
00430 
00431 

Generated on Thu Feb 14 11:16:01 2008 for Jackdmp by  doxygen 1.5.1