Jack2 1.9.10

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