JackEngine.cpp

00001 /*
00002 Copyright (C) 2004-2006 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 <fstream>
00022 #include <assert.h>
00023 
00024 #include "JackEngine.h"
00025 #include "JackExternalClient.h"
00026 #include "JackEngineControl.h"
00027 #include "JackClientControl.h"
00028 #include "JackEngineTiming.h"
00029 #include "JackGlobals.h"
00030 #include "JackChannel.h"
00031 #include "JackSyncInterface.h"
00032 
00033 namespace Jack
00034 {
00035 
00036 JackEngine::JackEngine(JackGraphManager* manager, JackSynchro** table, JackEngineControl* control, JackSyncInterface* signal, bool sync, long time_out_ms, bool rt, long priority, bool ve)
00037 {
00038     fGraphManager = manager;
00039     fSynchroTable = table;
00040     fEngineControl = control;
00041     fEngineControl->fSyncMode = sync;
00042     fEngineControl->fTimeOutUsecs = time_out_ms * 1000;
00043     fEngineControl->fRealTime = rt;
00044     fEngineControl->fPriority = priority;
00045     fEngineControl->fVerbose = ve;
00046     fChannel = JackGlobals::MakeServerNotifyChannel();
00047     fEngineTiming = new JackEngineTiming(fClientTable, fGraphManager, fEngineControl);
00048     fSignal = signal;
00049     for (int i = 0; i < CLIENT_NUM; i++)
00050         fClientTable[i] = NULL;
00051     fEngineTiming->ClearTimeMeasures();
00052     fEngineTiming->ResetRollingUsecs();
00053 }
00054 
00055 JackEngine::~JackEngine()
00056 {
00057     delete fChannel;
00058     delete fEngineTiming;
00059 }
00060 
00061 //-------------------
00062 // Client management
00063 //-------------------
00064 
00065 int JackEngine::Open()
00066 {
00067     JackLog("JackEngine::Open\n");
00068 
00069     // Open audio thread => request thread communication channel
00070     if (fChannel->Open() < 0) {
00071         jack_error("Cannot connect to server");
00072         return -1;
00073     } else {
00074         return 0;
00075     }
00076 }
00077 
00078 int JackEngine::Close()
00079 {
00080     JackLog("JackEngine::Close\n");
00081     fChannel->Close();
00082 
00083     // Close (possibly) remaining clients (RT is stopped)
00084     for (int i = 0; i < CLIENT_NUM; i++) {
00085         JackClientInterface* client = fClientTable[i];
00086         if (client) {
00087             JackLog("JackEngine::Close remaining client %ld\n", i);
00088             ClientCloseAux(i, client, false);
00089             client->Close();
00090             delete client;
00091         }
00092     }
00093 
00094     return 0;
00095 }
00096 
00097 int JackEngine::Allocate()
00098 {
00099     for (int i = 0; i < CLIENT_NUM; i++) {
00100         if (!fClientTable[i]) {
00101             JackLog("JackEngine::AllocateRefNum ref = %ld\n", i);
00102             return i;
00103         }
00104     }
00105 
00106     return -1;
00107 }
00108 
00109 //------------------
00110 // Graph management
00111 //------------------
00112 
00113 bool JackEngine::Process(jack_time_t callback_usecs)
00114 {
00115         bool res = true;
00116         
00117     // Transport
00118         fEngineControl->CycleBegin(callback_usecs);
00119 
00120     // Timing
00121         fEngineControl->IncFrameTime(callback_usecs);
00122     fEngineTiming->UpdateTiming(callback_usecs);
00123 
00124     // Graph
00125     if (fGraphManager->IsFinishedGraph()) {
00126         fLastSwitchUsecs = callback_usecs;
00127         if (fGraphManager->RunNextGraph())      // True if the graph actually switched to a new state
00128             fChannel->ClientNotify(ALL_CLIENTS, JackNotifyChannelInterface::kGraphOrderCallback, 0);
00129         fSignal->SignalAll();                           // Signal for threads waiting for next cycle
00130                 res = true;
00131     } else {
00132         JackLog("Process: graph not finished!\n");
00133                 if (callback_usecs > fLastSwitchUsecs + fEngineControl->fTimeOutUsecs) {
00134             JackLog("Process: switch to next state %ld\n", long(callback_usecs - fLastSwitchUsecs));
00135             //RemoveZombifiedClients(callback_usecs); TODO
00136             fLastSwitchUsecs = callback_usecs;
00137             if (fGraphManager->RunNextGraph())
00138                 fChannel->ClientNotify(ALL_CLIENTS, JackNotifyChannelInterface::kGraphOrderCallback, 0);
00139             fSignal->SignalAll();                       // Signal for threads waiting for next cycle
00140                         res = true;
00141         } else {
00142             JackLog("Process: waiting to switch %ld\n", long(callback_usecs - fLastSwitchUsecs));
00143             if (callback_usecs < fLastSwitchUsecs + 2 * fEngineControl->fPeriodUsecs) // Signal XRun only for the first failling cycle
00144                 CheckXRun(callback_usecs);
00145             fGraphManager->RunCurrentGraph();
00146                         res = false;
00147         }
00148     }
00149 
00150     // Transport
00151         fEngineControl->CycleEnd(fClientTable);
00152         return res;
00153 }
00154 
00155 /*
00156 Client that finish *after* the callback date are considered late even if their output buffers may have been
00157 correctly mixed in the time window: callbackUsecs <==> Read <==> Write.
00158 */
00159 
00160 void JackEngine::CheckXRun(jack_time_t callback_usecs)  // REVOIR les conditions de fin
00161 {
00162     for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
00163         JackClientInterface* client = fClientTable[i];
00164         if (client && client->GetClientControl()->fActive) {
00165                         JackClientTiming* timing = fGraphManager->GetClientTiming(i);
00166                 jack_client_state_t status = timing->fStatus;
00167             jack_time_t finished_date = timing->fFinishedAt;
00168            
00169             if (status != NotTriggered && status != Finished) {
00170                 jack_error("JackEngine::XRun: client = %s was not runned: state = %ld", client->GetClientControl()->fName, status);
00171                 //fChannel->ClientNotify(i, kXRunCallback, 0); // Notify the failing client
00172                 fChannel->ClientNotify(ALL_CLIENTS, JackNotifyChannelInterface::kXRunCallback, 0);  // Notify all clients
00173             }
00174             if (status == Finished && (long)(finished_date - callback_usecs) > 0) {
00175                 jack_error("JackEngine::XRun: client %s finished after current callback", client->GetClientControl()->fName);
00176                 //fChannel->ClientNotify(i, kXRunCallback, 0); // Notify the failing client
00177                 fChannel->ClientNotify(ALL_CLIENTS, JackNotifyChannelInterface::kXRunCallback, 0);  // Notify all clients
00178             }
00179         }
00180     }
00181 }
00182 
00183 //---------------
00184 // Zombification
00185 //---------------
00186 
00187 bool JackEngine::IsZombie(JackClientInterface* client, jack_time_t current_time)
00188 {
00189         return ((current_time - fGraphManager->GetClientTiming(client->GetClientControl()->fRefNum)->fFinishedAt) > 2 * fEngineControl->fTimeOutUsecs);  // A VERIFIER
00190 }
00191 
00192 // TODO : check what happens with looped sub-graph....
00193 void JackEngine::GetZombifiedClients(bool zombi_clients[CLIENT_NUM], jack_time_t current_time)
00194 {
00195     for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
00196         JackClientInterface* client1 = fClientTable[i];
00197         if (client1 && IsZombie(client1, current_time)) {
00198             JackLog("JackEngine::GetZombifiedClients: %s\n", client1->GetClientControl()->fName);
00199             zombi_clients[i] = true; // Assume client is dead
00200             // If another dead client is connected to the scanned one, then the scanned one is not the first of the dead subgraph
00201             for (int j = REAL_REFNUM; j < CLIENT_NUM; j++) {
00202                 JackClientInterface* client2 = fClientTable[j];
00203                 if (client2 && IsZombie(client2, current_time) && fGraphManager->IsDirectConnection(j, i)) {
00204                     zombi_clients[i] = false;
00205                     break;
00206                 }
00207             }
00208         } else {
00209             zombi_clients[i] = false;
00210         }
00211     }
00212 }
00213 
00214 void JackEngine::RemoveZombifiedClients(jack_time_t current_time)
00215 {
00216     bool zombi_clients[CLIENT_NUM];
00217     GetZombifiedClients(zombi_clients, current_time);
00218 
00219     for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
00220         if (zombi_clients[i] && !fClientTable[i]->GetClientControl()->fZombie) {
00221             fClientTable[i]->GetClientControl()->fZombie = true;
00222             JackLog("RemoveZombifiedCients: name = %s\n", fClientTable[i]->GetClientControl()->fName);
00223             fGraphManager->DirectDisconnect(FREEWHEEL_DRIVER_REFNUM, i);
00224             fGraphManager->DirectDisconnect(i, FREEWHEEL_DRIVER_REFNUM);
00225             fGraphManager->DisconnectAllPorts(i);
00226             fChannel->ClientNotify(i, JackNotifyChannelInterface::kZombifyClient, 0); // Signal engine
00227         }
00228     }
00229 }
00230 
00231 void JackEngine::ZombifyClient(int refnum)
00232 {
00233     NotifyClient(refnum, JackNotifyChannelInterface::kZombifyClient, false, 0);
00234 }
00235 
00236 //---------------
00237 // Notifications
00238 //---------------
00239 
00240 void JackEngine::NotifyClient(int refnum, int event, int sync, int value)
00241 {
00242     JackClientInterface* client = fClientTable[refnum];
00243     // The client may be notified by the RT thread while closing
00244     if (client && (client->ClientNotify(refnum, client->GetClientControl()->fName, event, sync, value) < 0)) {
00245         jack_error("NotifyClient fails name = %s event = %ld = val = %ld", client->GetClientControl()->fName, event, value);
00246     } else {
00247         JackLog("JackEngine::NotifyClient: client not available anymore\n");
00248     }
00249 }
00250 
00251 void JackEngine::NotifyClients(int event, int sync, int value)
00252 {
00253     for (int i = 0; i < CLIENT_NUM; i++) {
00254         JackClientInterface* client = fClientTable[i];
00255         if (client && (client->ClientNotify(i, client->GetClientControl()->fName, event, sync, value) < 0)) {
00256             jack_error("NotifyClient fails name = %s event = %ld = val = %ld", client->GetClientControl()->fName, event, value);
00257         }
00258     }
00259 }
00260 
00261 int JackEngine::NotifyAddClient(JackClientInterface* new_client, const char* name, int refnum)
00262 {
00263     // Notify existing clients of the new client and new client of existing clients.
00264     for (int i = 0; i < CLIENT_NUM; i++) {
00265         JackClientInterface* old_client = fClientTable[i];
00266         if (old_client) {
00267             if (old_client->ClientNotify(refnum, name, JackNotifyChannelInterface::kAddClient, true, 0) < 0)
00268                 return -1;
00269             if (new_client->ClientNotify(i, old_client->GetClientControl()->fName, JackNotifyChannelInterface::kAddClient, true, 0) < 0)
00270                 return -1;
00271         }
00272     }
00273 
00274     return 0;
00275 }
00276 
00277 void JackEngine::NotifyRemoveClient(const char* name, int refnum)
00278 {
00279     // Notify existing clients (including the one beeing suppressed) of the removed client
00280     for (int i = 0; i < CLIENT_NUM; i++) {
00281         JackClientInterface* client = fClientTable[i];
00282         if (client) {
00283             client->ClientNotify(refnum, name, JackNotifyChannelInterface::kRemoveClient, true, 0);
00284         }
00285     }
00286 }
00287 
00288 // Coming from the driver
00289 void JackEngine::NotifyXRun(jack_time_t callback_usecs)
00290 {
00291     // Use the audio thread => request thread communication channel
00292         fEngineControl->ResetFrameTime(callback_usecs);
00293     fChannel->ClientNotify(ALL_CLIENTS, JackNotifyChannelInterface::kXRunCallback, 0);
00294 }
00295 
00296 void JackEngine::NotifyXRun(int refnum)
00297 {
00298     if (refnum == ALL_CLIENTS) {
00299         NotifyClients(JackNotifyChannelInterface::kXRunCallback, false, 0);
00300     } else {
00301         NotifyClient(refnum, JackNotifyChannelInterface::kXRunCallback, false, 0);
00302     }
00303 }
00304 
00305 void JackEngine::NotifyGraphReorder()
00306 {
00307     NotifyClients(JackNotifyChannelInterface::kGraphOrderCallback, false, 0);
00308 }
00309 
00310 void JackEngine::NotifyBufferSize(jack_nframes_t nframes)
00311 {
00312     NotifyClients(JackNotifyChannelInterface::kBufferSizeCallback, true, nframes);
00313 }
00314 
00315 void JackEngine::NotifyFreewheel(bool onoff)
00316 {
00317     fEngineControl->fRealTime = !onoff;
00318     NotifyClients((onoff ? JackNotifyChannelInterface::kStartFreewheel : JackNotifyChannelInterface::kStopFreewheel), true, 0);
00319 }
00320 
00321 void JackEngine::NotifyPortRegistation(jack_port_id_t port_index, bool onoff)
00322 {
00323     NotifyClients((onoff ? JackNotifyChannelInterface::kPortRegistrationOn : JackNotifyChannelInterface::kPortRegistrationOff), false, port_index);
00324 }
00325 
00326 void JackEngine::NotifyActivate(int refnum)
00327 {
00328     NotifyClient(refnum, JackNotifyChannelInterface::kActivateClient, false, 0);
00329 }
00330 
00331 //-------------------
00332 // Client management
00333 //-------------------
00334 
00335 bool JackEngine::ClientCheckName(const char* name)
00336 {
00337     for (int i = 0; i < CLIENT_NUM; i++) {
00338         JackClientInterface* client = fClientTable[i];
00339         if (client && (strcmp(client->GetClientControl()->fName, name) == 0))
00340             return true;
00341     }
00342 
00343     return false;
00344 }
00345 
00346 // Used for external clients
00347 int JackEngine::ClientNew(const char* name, int* ref, int* shared_engine, int* shared_client, int* shared_graph_manager)
00348 {
00349     if (ClientCheckName(name)) {
00350         jack_error("client %s already registered", name);
00351         return -1;
00352     }
00353 
00354     JackExternalClient* client = new JackExternalClient();
00355     if (ClientExternalNew(name, ref, shared_engine, shared_client, shared_graph_manager, client) < 0) {
00356         delete client;
00357         return -1;
00358     }
00359 
00360     return 0;
00361 }
00362 
00363 // Used for external clients
00364 int JackEngine::ClientExternalNew(const char* name, int* ref, int* shared_engine, int* shared_client, int* shared_graph_manager, JackExternalClient* client)
00365 {
00366     JackLog("JackEngine::ClientNew: name = %s \n", name);
00367         int refnum = Allocate();
00368 
00369     if (refnum < 0) {
00370         jack_error("No more refnum available");
00371         return -1;
00372     }
00373 
00374     if (!fSynchroTable[refnum]->Allocate(name, 0)) {
00375         jack_error("Cannot allocate synchro");
00376                 goto error;
00377     }
00378 
00379     if (client->Open(name, refnum, shared_client) < 0) {
00380         jack_error("Cannot open client");
00381         goto error;
00382     }
00383 
00384     if (!fSignal->TimedWait(5 * 1000000)) {
00385         // Failure if RT thread is not running (problem with the driver...)
00386         jack_error("Driver is not running");
00387         goto error;
00388     }
00389 
00390     if (NotifyAddClient(client, name, refnum) < 0) {
00391         jack_error("Cannot notify add client");
00392         goto error;
00393     }
00394 
00395     fClientTable[refnum] = client;
00396         fGraphManager->InitRefNum(refnum);
00397     fEngineTiming->ResetRollingUsecs();
00398     *shared_engine = fEngineControl->GetShmIndex();
00399     *shared_graph_manager = fGraphManager->GetShmIndex();
00400     *ref = refnum;
00401     return 0;
00402 
00403 error:
00404     ClientCloseAux(refnum, client, false);
00405     client->Close();
00406     return -1;
00407 }
00408 
00409 // Used for server driver clients
00410 int JackEngine::ClientInternalNew(const char* name, int* ref, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client)
00411 {
00412     JackLog("JackEngine::ClientInternalNew: name = %s\n", name);
00413         int refnum = Allocate();
00414 
00415     if (refnum < 0) {
00416         jack_error("No more refnum available");
00417         return -1;
00418     }
00419 
00420     if (!fSynchroTable[refnum]->Allocate(name, 0)) {
00421         jack_error("Cannot allocate synchro");
00422                 return -1;
00423     }
00424 
00425     if (NotifyAddClient(client, name, refnum) < 0) {
00426         jack_error("Cannot notify add client");
00427                 return -1;
00428     }
00429 
00430     fClientTable[refnum] = client;
00431         fGraphManager->InitRefNum(refnum);
00432     fEngineTiming->ResetRollingUsecs();
00433     *shared_engine = fEngineControl;
00434     *shared_manager = fGraphManager;
00435     *ref = refnum;
00436     return 0;
00437 }
00438 
00439 // Used for externall clients
00440 int JackEngine::ClientClose(int refnum)
00441 {
00442     JackClientInterface* client = fClientTable[refnum];
00443     if (client) {
00444         fEngineControl->fTransport.ResetTimebase(refnum);
00445         int res = ClientCloseAux(refnum, client, true);
00446         client->Close();
00447         delete client;
00448         return res;
00449     } else {
00450         return -1;
00451     }
00452 }
00453 
00454 // Used for server internal clients
00455 int JackEngine::ClientInternalClose(int refnum)
00456 {
00457     JackClientInterface* client = fClientTable[refnum];
00458     return (client)     ? ClientCloseAux(refnum, client, true) : -1;
00459 }
00460 
00461 // Used for drivers that close when the RT thread is stopped
00462 int JackEngine::ClientInternalCloseIm(int refnum)
00463 {
00464     JackClientInterface* client = fClientTable[refnum];
00465     return (client)     ? ClientCloseAux(refnum, client, false) : -1;
00466 }
00467 
00468 int JackEngine::ClientCloseAux(int refnum, JackClientInterface* client, bool wait)
00469 {
00470     JackLog("JackEngine::ClientCloseAux ref = %ld name = %s\n", refnum, client->GetClientControl()->fName);
00471 
00472     // Remove the client from the table
00473     fClientTable[refnum] = NULL;
00474 
00475     // Remove ports
00476     fGraphManager->RemoveAllPorts(refnum);
00477 
00478     // Wait until next cycle to be sure client is not used anymore
00479     if (wait) {
00480         if (!fSignal->TimedWait(fEngineControl->fTimeOutUsecs * 2)) { // Must wait at least until a switch occurs in Process, even in case of graph end failure
00481             JackLog("JackEngine::ClientCloseAux wait error ref = %ld \n", refnum);
00482         }
00483     }
00484 
00485     // Notify running clients
00486     NotifyRemoveClient(client->GetClientControl()->fName, client->GetClientControl()->fRefNum);
00487 
00488     // Cleanup...
00489     fSynchroTable[refnum]->Destroy();
00490     fEngineTiming->ResetRollingUsecs();
00491     return 0;
00492 }
00493 
00494 int JackEngine::ClientActivate(int refnum)
00495 {
00496     JackClientInterface* client = fClientTable[refnum];
00497         assert(fClientTable[refnum]);
00498         
00499         JackLog("JackEngine::ClientActivate ref = %ld name = %s\n", refnum, client->GetClientControl()->fName);
00500         // Wait for graph state change to be effective
00501         if (!fSignal->TimedWait(fEngineControl->fPeriodUsecs * 10)) {
00502                 JackLog("JackEngine::ClientActivate wait error ref = %ld name = %s\n", refnum, client->GetClientControl()->fName);
00503                 return -1;
00504         } else {
00505                 NotifyActivate(refnum);
00506                 return 0;
00507         }
00508 }
00509 
00510 // May be called without client
00511 int JackEngine::ClientDeactivate(int refnum)
00512 {
00513     JackClientInterface* client = fClientTable[refnum];
00514         if (client == NULL) 
00515             return -1;
00516 
00517         JackLog("JackEngine::ClientDeactivate ref = %ld name = %s\n", refnum, client->GetClientControl()->fName);
00518         fGraphManager->DisconnectAllPorts(refnum);
00519         // Wait for graph state change to be effective
00520         if (!fSignal->TimedWait(fEngineControl->fPeriodUsecs * 10)) {
00521                 JackLog("JackEngine::ClientDeactivate wait error ref = %ld name = %s\n", refnum, client->GetClientControl()->fName);
00522                 return -1;
00523         } else {
00524                 return 0;
00525         }
00526 }
00527 
00528 //-----------------
00529 // Port management
00530 //-----------------
00531 
00532 int JackEngine::PortRegister(int refnum, const char* name, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index)
00533 {
00534     JackLog("JackEngine::PortRegister ref = %ld name = %s flags = %d buffer_size = %d\n", refnum, name, flags, buffer_size);
00535     assert(fClientTable[refnum]);
00536 
00537     *port_index = fGraphManager->AllocatePort(refnum, name, (JackPortFlags)flags);
00538     if (*port_index != NO_PORT) {
00539         NotifyPortRegistation(*port_index, true);
00540         return 0;
00541     } else {
00542         return -1;
00543     }
00544 }
00545 
00546 int JackEngine::PortUnRegister(int refnum, jack_port_id_t port_index)
00547 {
00548     JackLog("JackEngine::PortUnRegister ref = %ld port_index = %ld\n", refnum, port_index);
00549     assert(fClientTable[refnum]);
00550 
00551     if (fGraphManager->RemovePort(refnum, port_index) == 0) {
00552         fGraphManager->ReleasePort(port_index);
00553         NotifyPortRegistation(port_index, false);
00554         return 0;
00555     } else {
00556         return -1;
00557     }
00558 }
00559 
00560 int JackEngine::PortConnect(int refnum, const char* src, const char* dst)
00561 {
00562     JackLog("JackEngine::PortConnect src = %s dst = %s\n", src, dst);
00563     jack_port_id_t port_src, port_dst;
00564 
00565     return (fGraphManager->CheckPorts(src, dst, &port_src, &port_dst) < 0)
00566            ? -1
00567            : PortConnect(refnum, port_src, port_dst);
00568 }
00569 
00570 int JackEngine::PortDisconnect(int refnum, const char* src, const char* dst)
00571 {
00572     JackLog("JackEngine::PortDisconnect src = %s dst = %s\n", src, dst);
00573     jack_port_id_t port_src, port_dst;
00574 
00575     return (fGraphManager->CheckPorts(src, dst, &port_src, &port_dst) < 0)
00576            ? -1
00577            : fGraphManager->Disconnect(port_src, port_dst);
00578 }
00579 
00580 int JackEngine::PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
00581 {
00582     JackLog("JackEngine::PortConnect src = %d dst = %d\n", src, dst);
00583     JackClientInterface* client;
00584     int ref;
00585 
00586     if (fGraphManager->CheckPorts(src, dst) < 0)
00587         return -1;
00588 
00589     ref = fGraphManager->GetOutputRefNum(src);
00590     assert(ref >= 0);
00591     client = fClientTable[ref];
00592     assert(client);
00593     if (!client->GetClientControl()->fActive) {
00594         jack_error("Cannot connect ports owned by inactive clients:"
00595                    " \"%s\" is not active", client->GetClientControl()->fName);
00596         return -1;
00597     }
00598 
00599     ref = fGraphManager->GetInputRefNum(dst);
00600     assert(ref >= 0);
00601     client = fClientTable[ref];
00602     assert(client);
00603     if (!client->GetClientControl()->fActive) {
00604         jack_error("Cannot connect ports owned by inactive clients:"
00605                    " \"%s\" is not active", client->GetClientControl()->fName);
00606         return -1;
00607     }
00608 
00609     return fGraphManager->Connect(src, dst);
00610 }
00611 
00612 int JackEngine::PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
00613 {
00614     JackLog("JackEngine::PortDisconnect src = %d dst = %d\n", src, dst);
00615 
00616     if (dst == ALL_PORTS) {
00617         return (fGraphManager->CheckPort(src) < 0)
00618                ? -1
00619                : fGraphManager->DisconnectAll(src);
00620     } else {
00621         return (fGraphManager->CheckPorts(src, dst) < 0)
00622                ? -1
00623                : fGraphManager->Disconnect(src, dst);
00624     }
00625 }
00626 
00627 //----------------------
00628 // Transport management
00629 //----------------------
00630 
00631 int JackEngine::ReleaseTimebase(int refnum)
00632 {
00633     return fEngineControl->fTransport.ResetTimebase(refnum);
00634 }
00635 
00636 int JackEngine::SetTimebaseCallback(int refnum, int conditional)
00637 {
00638     return fEngineControl->fTransport.SetTimebase(refnum, conditional);
00639 }
00640 
00641 //-----------
00642 // Debugging
00643 //-----------
00644 
00645 void JackEngine::PrintState()
00646 {
00647     std::cout << "Engine State" << std::endl;
00648 
00649     for (int i = 0; i < CLIENT_NUM; i++) {
00650         JackClientInterface* client = fClientTable[i];
00651         if (client)
00652             std::cout << "Client : " << client->GetClientControl()->fName << " : " << i << std::endl;
00653     }
00654 
00655     //fGraphManager->PrintState();
00656     fEngineTiming->PrintState();
00657 }
00658 
00659 } // end of namespace
00660 

Generated on Wed Jan 10 11:42:45 2007 for Jackdmp by  doxygen 1.4.5