Jack2 1.9.8

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 <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