JackEngine.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 <fstream>
00022 #include <assert.h>
00023 
00024 #ifndef WIN32
00025 #include <sys/types.h>
00026 #include <signal.h>
00027 #endif
00028 
00029 #include "JackEngine.h"
00030 #include "JackExternalClient.h"
00031 #include "JackInternalClient.h"
00032 #include "JackEngineControl.h"
00033 #include "JackClientControl.h"
00034 #include "JackGlobals.h"
00035 #include "JackChannel.h"
00036 #include "JackSyncInterface.h"
00037 
00038 namespace Jack
00039 {
00040 
00041 JackEngine::JackEngine(JackGraphManager* manager, 
00042                                                 JackSynchro** table, 
00043                                                 JackEngineControl* control)
00044 {
00045     fGraphManager = manager;
00046     fSynchroTable = table;
00047     fEngineControl = control;
00048         fChannel = JackGlobals::MakeServerNotifyChannel();
00049         fSignal = JackGlobals::MakeInterProcessSync();
00050     for (int i = 0; i < CLIENT_NUM; i++)
00051         fClientTable[i] = NULL;
00052 }
00053 
00054 JackEngine::~JackEngine()
00055 {
00056     delete fChannel;
00057         delete fSignal;
00058 }
00059 
00060 int JackEngine::Open()
00061 {
00062     JackLog("JackEngine::Open\n");
00063 
00064     // Open audio thread => request thread communication channel
00065     if (fChannel->Open(fEngineControl->fServerName) < 0) {
00066         jack_error("Cannot connect to server");
00067         return -1;
00068     } else {
00069         return 0;
00070     }
00071 }
00072 
00073 int JackEngine::Close()
00074 {
00075     JackLog("JackEngine::Close\n");
00076     fChannel->Close();
00077 
00078     // Close (possibly) remaining clients (RT is stopped)
00079     for (int i = 0; i < CLIENT_NUM; i++) {
00080         JackClientInterface* client = fClientTable[i];
00081         if (client) {
00082                 JackLog("JackEngine::Close remaining client %ld\n", i);
00083                         fClientTable[i] = NULL;
00084             client->Close();
00085             delete client;
00086         }
00087     }
00088         
00089         fSignal->Destroy();
00090     return 0;
00091 }
00092 
00093 //-----------------------------
00094 // Client ressource management
00095 //-----------------------------
00096 
00097 int JackEngine::AllocateRefnum()
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     return -1;
00106 }
00107 
00108 void JackEngine::ReleaseRefnum(int ref)
00109 {
00110         fClientTable[ref] = NULL;
00111         
00112         if (fEngineControl->fTemporary) {
00113                 int i;
00114                 for (i = REAL_REFNUM; i < CLIENT_NUM; i++) {
00115                         if (fClientTable[i]) 
00116                                 break;
00117                 }
00118                 if (i == CLIENT_NUM) {
00119                         // last client and temporay case: quit the server
00120                         JackLog("JackEngine::ReleaseRefnum server quit\n");
00121                         fEngineControl->fTemporary = false;
00122                 #ifndef WIN32
00123                         kill(getpid(), SIGINT);
00124                 #endif
00125                 }
00126         }
00127 }
00128 
00129 //------------------
00130 // Graph management
00131 //------------------
00132 
00133 void JackEngine::ProcessNext(jack_time_t callback_usecs)
00134 {
00135         fLastSwitchUsecs = callback_usecs;
00136         if (fGraphManager->RunNextGraph())      // True if the graph actually switched to a new state
00137                 fChannel->ClientNotify(ALL_CLIENTS, kGraphOrderCallback, 0, 0);
00138         fSignal->SignalAll();                           // Signal for threads waiting for next cycle
00139 }
00140 
00141 void JackEngine::ProcessCurrent(jack_time_t callback_usecs)
00142 {
00143         if (callback_usecs < fLastSwitchUsecs + 2 * fEngineControl->fPeriodUsecs) // Signal XRun only for the first failing cycle
00144                 CheckXRun(callback_usecs);
00145         fGraphManager->RunCurrentGraph();
00146 }
00147 
00148 bool JackEngine::Process(jack_time_t callback_usecs)
00149 {
00150         bool res = true;
00151         
00152     // Cycle  begin
00153         fEngineControl->CycleBegin(fClientTable, fGraphManager, callback_usecs);
00154 
00155         // Graph
00156     if (fGraphManager->IsFinishedGraph()) {
00157         ProcessNext(callback_usecs);
00158                 res = true;
00159     } else {
00160         JackLog("Process: graph not finished!\n");
00161                 if (callback_usecs > fLastSwitchUsecs + fEngineControl->fTimeOutUsecs) {
00162             JackLog("Process: switch to next state delta = %ld\n", long(callback_usecs - fLastSwitchUsecs));
00163                         ProcessNext(callback_usecs);
00164                         res = true;
00165         } else {
00166             JackLog("Process: waiting to switch delta = %ld\n", long(callback_usecs - fLastSwitchUsecs));
00167             ProcessCurrent(callback_usecs);
00168                         res = false;
00169                 }
00170     }
00171 
00172     // Cycle end
00173         fEngineControl->CycleEnd(fClientTable);
00174         return res;
00175 }
00176 
00177 
00178 /*
00179 Client that finish *after* the callback date are considered late even if their output buffers may have been
00180 correctly mixed in the time window: callbackUsecs <==> Read <==> Write.
00181 */
00182 
00183 void JackEngine::CheckXRun(jack_time_t callback_usecs)  // REVOIR les conditions de fin
00184 {
00185     for (int i = REAL_REFNUM; i < CLIENT_NUM; i++) {
00186         JackClientInterface* client = fClientTable[i];
00187         if (client && client->GetClientControl()->fActive) {
00188                         JackClientTiming* timing = fGraphManager->GetClientTiming(i);
00189                 jack_client_state_t status = timing->fStatus;
00190             jack_time_t finished_date = timing->fFinishedAt;
00191            
00192             if (status != NotTriggered && status != Finished) {
00193                 jack_error("JackEngine::XRun: client = %s was not run: state = %ld", client->GetClientControl()->fName, status);
00194                 fChannel->ClientNotify(ALL_CLIENTS, kXRunCallback, 0, 0);  // Notify all clients
00195             }
00196                         
00197             if (status == Finished && (long)(finished_date - callback_usecs) > 0) {
00198                 jack_error("JackEngine::XRun: client %s finished after current callback", client->GetClientControl()->fName);
00199                 fChannel->ClientNotify(ALL_CLIENTS, kXRunCallback, 0, 0);  // Notify all clients
00200             }
00201         }
00202     }
00203 }
00204 
00205 //---------------
00206 // Notifications
00207 //---------------
00208 
00209 void JackEngine::NotifyClient(int refnum, int event, int sync, int value1, int value2)
00210 {
00211     JackClientInterface* client = fClientTable[refnum];
00212         
00213     // The client may be notified by the RT thread while closing
00214     if (!client) {
00215                 JackLog("JackEngine::NotifyClient: client not available anymore\n");
00216         } else if (client->GetClientControl()->fCallback[event]) {
00217                 if (client->ClientNotify(refnum, client->GetClientControl()->fName, event, sync, value1, value2) < 0)
00218                         jack_error("NotifyClient fails name = %s event = %ld = val1 = %ld val2 = %ld", client->GetClientControl()->fName, event, value1, value2);
00219     } else {
00220         JackLog("JackEngine::NotifyClient: no callback for event = %ld\n", event);
00221     }
00222 }
00223 
00224 void JackEngine::NotifyClients(int event, int sync, int value1, int value2)
00225 {
00226     for (int i = 0; i < CLIENT_NUM; i++) {
00227         JackClientInterface* client = fClientTable[i];
00228                 if (client) {
00229                         if (client->GetClientControl()->fCallback[event]) {
00230                                 if (client->ClientNotify(i, client->GetClientControl()->fName, event, sync, value1, value2) < 0) 
00231                                         jack_error("NotifyClient fails name = %s event = %ld = val1 = %ld val2 = %ld", client->GetClientControl()->fName, event, value1, value2);
00232                         } else {
00233                                 JackLog("JackEngine::NotifyClients: no callback for event = %ld\n", event);
00234                         }
00235                 }
00236     }
00237 }
00238 
00239 int JackEngine::NotifyAddClient(JackClientInterface* new_client, const char* name, int refnum)
00240 {
00241     // Notify existing clients of the new client and new client of existing clients.
00242     for (int i = 0; i < CLIENT_NUM; i++) {
00243         JackClientInterface* old_client = fClientTable[i];
00244         if (old_client) {
00245             if (old_client->ClientNotify(refnum, name, kAddClient, true, 0, 0) < 0) {
00246                 jack_error("NotifyAddClient old_client fails name = %s", old_client->GetClientControl()->fName);
00247                                 return -1;
00248                         }
00249                         if (new_client->ClientNotify(i, old_client->GetClientControl()->fName, kAddClient, true, 0, 0) < 0) {
00250                 jack_error("NotifyAddClient new_client fails name = %s", name);
00251                                 return -1;
00252                         }
00253         }
00254     }
00255 
00256     return 0;
00257 }
00258 
00259 void JackEngine::NotifyRemoveClient(const char* name, int refnum)
00260 {
00261     // Notify existing clients (including the one beeing suppressed) of the removed client
00262     for (int i = 0; i < CLIENT_NUM; i++) {
00263         JackClientInterface* client = fClientTable[i];
00264         if (client) {
00265             client->ClientNotify(refnum, name, kRemoveClient, true, 0, 0);
00266         }
00267     }
00268 }
00269 
00270 // Coming from the driver
00271 void JackEngine::NotifyXRun(jack_time_t callback_usecs)
00272 {
00273     // Use the audio thread => request thread communication channel
00274         fEngineControl->ResetFrameTime(callback_usecs);
00275     fChannel->ClientNotify(ALL_CLIENTS, kXRunCallback, 0, 0);
00276 }
00277 
00278 void JackEngine::NotifyXRun(int refnum)
00279 {
00280     if (refnum == ALL_CLIENTS) {
00281         NotifyClients(kXRunCallback, false, 0, 0);
00282     } else {
00283         NotifyClient(refnum, kXRunCallback, false, 0, 0);
00284     }
00285 }
00286 
00287 void JackEngine::NotifyGraphReorder()
00288 {
00289     NotifyClients(kGraphOrderCallback, false, 0, 0);
00290 }
00291 
00292 void JackEngine::NotifyBufferSize(jack_nframes_t nframes)
00293 {
00294     NotifyClients(kBufferSizeCallback, true, nframes, 0);
00295 }
00296 
00297 void JackEngine::NotifyFreewheel(bool onoff)
00298 {
00299     fEngineControl->fRealTime = !onoff;
00300     NotifyClients((onoff ? kStartFreewheelCallback : kStopFreewheelCallback), true, 0, 0);
00301 }
00302 
00303 void JackEngine::NotifyPortRegistation(jack_port_id_t port_index, bool onoff)
00304 {
00305     NotifyClients((onoff ? kPortRegistrationOnCallback : kPortRegistrationOffCallback), false, port_index, 0);
00306 }
00307 
00308 void JackEngine::NotifyPortConnect(jack_port_id_t src, jack_port_id_t dst, bool onoff)
00309 {
00310     NotifyClients((onoff ? kPortConnectCallback : kPortDisconnectCallback), false, src, dst);
00311 }
00312 
00313 void JackEngine::NotifyActivate(int refnum)
00314 {
00315         NotifyClient(refnum, kActivateClient, true, 0, 0);
00316 }
00317 
00318 //----------------------------
00319 // Loadable client management
00320 //----------------------------
00321 
00322 int JackEngine::GetInternalClientName(int refnum, char* name_res)
00323 {
00324         assert(refnum >= 0 && refnum < CLIENT_NUM);
00325         JackClientInterface* client = fClientTable[refnum];
00326         if (client) {
00327                 strncpy(name_res, client->GetClientControl()->fName, JACK_CLIENT_NAME_SIZE);
00328                 return 0;
00329         } else {
00330                 return -1;
00331         }
00332 }
00333 
00334 int JackEngine::InternalClientHandle(const char* client_name, int* status, int* int_ref)
00335 {
00336         // Clear status
00337         *status = 0;
00338         
00339         for (int i = 0; i < CLIENT_NUM; i++) {
00340         JackClientInterface* client = fClientTable[i];
00341         if (client && dynamic_cast<JackLoadableInternalClient*>(client) && (strcmp(client->GetClientControl()->fName, client_name) == 0)) {
00342                         JackLog("InternalClientHandle found client name = %s ref = %ld\n",  client_name, i);
00343                         *int_ref = i;
00344                         return 0;
00345                 }
00346     }
00347         
00348         *status |= (JackNoSuchClient | JackFailure);
00349         return -1;
00350 }
00351 
00352 int JackEngine::InternalClientUnload(int refnum, int* status)
00353 {
00354         assert(refnum >= 0 && refnum < CLIENT_NUM);
00355         JackClientInterface* client = fClientTable[refnum];
00356         if (client) {
00357                 int res = client->Close();
00358                 delete client;
00359                 *status = 0;
00360                 return res;
00361         } else {
00362                 *status = (JackNoSuchClient | JackFailure);
00363         return -1;
00364     }
00365 }
00366 
00367 //-------------------
00368 // Client management
00369 //-------------------
00370 
00371 int JackEngine::ClientCheck(const char* name, char* name_res, int protocol, int options, int* status)
00372 {
00373         // Clear status
00374         *status = 0;
00375         strcpy(name_res, name);
00376         
00377         JackLog("Check protocol client  %ld server = %ld\n", protocol, JACK_PROTOCOL_VERSION);
00378         
00379         if (protocol != JACK_PROTOCOL_VERSION) {
00380                 *status |= (JackFailure | JackVersionError);
00381                 jack_error("JACK protocol mismatch (%d vs %d)", protocol, JACK_PROTOCOL_VERSION);
00382                 return -1;
00383         }
00384         
00385         if (ClientCheckName(name)) {
00386 
00387                 *status |= JackNameNotUnique;
00388 
00389                 if (options & JackUseExactName) {
00390                         jack_error("cannot create new client; %s already exists", name);
00391                         *status |= JackFailure;
00392                         return -1;
00393                 }
00394                 
00395                 if (GenerateUniqueName(name_res)) {
00396                         *status |= JackFailure;
00397                         return -1;
00398                 }
00399         }
00400 
00401         return 0;
00402 }
00403 
00404 bool JackEngine::GenerateUniqueName(char* name)
00405 {
00406         int tens, ones;
00407         int length = strlen(name);
00408 
00409         if (length > JACK_CLIENT_NAME_SIZE - 4) {
00410                 jack_error("%s exists and is too long to make unique", name);
00411                 return true;            /* failure */
00412         }
00413 
00414         /*  generate a unique name by appending "-01".."-99" */
00415         name[length++] = '-';
00416         tens = length++;
00417         ones = length++;
00418         name[tens] = '0';
00419         name[ones] = '1';
00420         name[length] = '\0';
00421         
00422         while (ClientCheckName(name)) {
00423                 if (name[ones] == '9') {
00424                         if (name[tens] == '9') {
00425                                 jack_error("client %s has 99 extra instances already", name);
00426                                 return true; /* give up */
00427                         }
00428                         name[tens]++;
00429                         name[ones] = '0';
00430                 } else {
00431                         name[ones]++;
00432                 }
00433         }
00434         return false;
00435 }
00436 
00437 bool JackEngine::ClientCheckName(const char* name)
00438 {
00439     for (int i = 0; i < CLIENT_NUM; i++) {
00440         JackClientInterface* client = fClientTable[i];
00441         if (client && (strcmp(client->GetClientControl()->fName, name) == 0))
00442             return true;
00443     }
00444 
00445     return false;
00446 }
00447 
00448 // Used for external clients
00449 int JackEngine::ClientExternalOpen(const char* name, int* ref, int* shared_engine, int* shared_client, int* shared_graph_manager)
00450 {
00451     JackLog("JackEngine::ClientOpen: name = %s \n", name);
00452         
00453         int refnum = AllocateRefnum();
00454     if (refnum < 0) {
00455         jack_error("No more refnum available");
00456         return -1;
00457     }
00458         
00459         JackExternalClient* client = new JackExternalClient();
00460 
00461     if (!fSynchroTable[refnum]->Allocate(name, fEngineControl->fServerName, 0)) {
00462         jack_error("Cannot allocate synchro");
00463                 goto error;
00464     }
00465 
00466     if (client->Open(name, refnum, shared_client) < 0) {
00467         jack_error("Cannot open client");
00468         goto error;
00469     }
00470 
00471     if (!fSignal->TimedWait(DRIVER_OPEN_TIMEOUT * 1000000)) {
00472         // Failure if RT thread is not running (problem with the driver...)
00473         jack_error("Driver is not running");
00474         goto error;
00475     }
00476 
00477     if (NotifyAddClient(client, name, refnum) < 0) {
00478         jack_error("Cannot notify add client");
00479         goto error;
00480     }
00481 
00482     fClientTable[refnum] = client;
00483         fGraphManager->InitRefNum(refnum);
00484         fEngineControl->ResetRollingUsecs();
00485     *shared_engine = fEngineControl->GetShmIndex();
00486     *shared_graph_manager = fGraphManager->GetShmIndex();
00487     *ref = refnum;
00488     return 0;
00489 
00490 error:
00491     ClientCloseAux(refnum, client, false);
00492     client->Close();
00493         delete client;
00494     return -1;
00495 }
00496 
00497 // Used for server driver clients
00498 int JackEngine::ClientInternalOpen(const char* name, int* ref, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client, bool wait)
00499 {
00500     JackLog("JackEngine::ClientInternalNew: name = %s\n", name);
00501         
00502         int refnum = AllocateRefnum();
00503         if (refnum < 0) {
00504         jack_error("No more refnum available");
00505         return -1;
00506     }
00507 
00508     if (!fSynchroTable[refnum]->Allocate(name, fEngineControl->fServerName, 0)) {
00509         jack_error("Cannot allocate synchro");
00510                 return -1;
00511     }
00512         
00513         if (wait && !fSignal->TimedWait(DRIVER_OPEN_TIMEOUT * 1000000)) {
00514         // Failure if RT thread is not running (problem with the driver...)
00515         jack_error("Driver is not running");
00516                 return -1;
00517     }
00518 
00519     if (NotifyAddClient(client, name, refnum) < 0) {
00520         jack_error("Cannot notify add client");
00521                 return -1;
00522     }
00523 
00524     fClientTable[refnum] = client;
00525         fGraphManager->InitRefNum(refnum);
00526         fEngineControl->ResetRollingUsecs();
00527     *shared_engine = fEngineControl;
00528     *shared_manager = fGraphManager;
00529     *ref = refnum;
00530     return 0;
00531 }
00532 
00533 // Used for external clients
00534 int JackEngine::ClientExternalClose(int refnum)
00535 {
00536     JackClientInterface* client = fClientTable[refnum];
00537     if (client) {
00538         fEngineControl->fTransport.ResetTimebase(refnum);
00539         int res = ClientCloseAux(refnum, client, true);
00540         client->Close();
00541         delete client;
00542         return res;
00543     } else {
00544         return -1;
00545     }
00546 }
00547 
00548 // Used for server internal clients or drivers when the RT thread is stopped
00549 int JackEngine::ClientInternalClose(int refnum, bool wait)
00550 {
00551     JackClientInterface* client = fClientTable[refnum];
00552     return (client)     ? ClientCloseAux(refnum, client, wait) : -1;
00553 }
00554 
00555 int JackEngine::ClientCloseAux(int refnum, JackClientInterface* client, bool wait)
00556 {
00557     JackLog("JackEngine::ClientCloseAux ref = %ld name = %s\n", 
00558                         refnum, 
00559                         (client->GetClientControl()) ? client->GetClientControl()->fName : "No name");
00560 
00561     // Remove the client from the table
00562         ReleaseRefnum(refnum);
00563 
00564     // Notiy unregister 
00565         jack_int_t ports[PORT_NUM_FOR_CLIENT];
00566         int i;
00567         
00568         fGraphManager->GetInputPorts(refnum, ports);
00569         for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY) ; i++) {
00570                 NotifyPortRegistation(ports[i], false);
00571         }       
00572         
00573         fGraphManager->GetOutputPorts(refnum, ports);
00574         for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY) ; i++) {
00575                 NotifyPortRegistation(ports[i], false);
00576         }
00577 
00578         // Remove all ports
00579     fGraphManager->RemoveAllPorts(refnum);
00580 
00581     // Wait until next cycle to be sure client is not used anymore
00582     if (wait) {
00583         if (!fSignal->TimedWait(fEngineControl->fTimeOutUsecs * 2)) { // Must wait at least until a switch occurs in Process, even in case of graph end failure
00584             jack_error("JackEngine::ClientCloseAux wait error ref = %ld", refnum);
00585         }
00586     }
00587 
00588     // Notify running clients
00589         if (client->GetClientControl())  // When called in error cases, client may not be completely allocated
00590                 NotifyRemoveClient(client->GetClientControl()->fName, client->GetClientControl()->fRefNum);
00591 
00592     // Cleanup...
00593     fSynchroTable[refnum]->Destroy();
00594         fEngineControl->ResetRollingUsecs();
00595     return 0;
00596 }
00597 
00598 int JackEngine::ClientActivate(int refnum)
00599 {
00600     JackClientInterface* client = fClientTable[refnum];
00601         assert(fClientTable[refnum]);
00602         
00603         JackLog("JackEngine::ClientActivate ref = %ld name = %s\n", refnum, client->GetClientControl()->fName);
00604         fGraphManager->Activate(refnum);
00605         
00606         // Wait for graph state change to be effective
00607         if (!fSignal->TimedWait(fEngineControl->fTimeOutUsecs * 10)) {
00608                 jack_error("JackEngine::ClientActivate wait error ref = %ld name = %s", refnum, client->GetClientControl()->fName);
00609                 return -1;
00610         } else {
00611                 NotifyActivate(refnum);
00612                 return 0;
00613         }
00614 }
00615 
00616 // May be called without client
00617 int JackEngine::ClientDeactivate(int refnum)
00618 {
00619     JackClientInterface* client = fClientTable[refnum];
00620         if (client == NULL) 
00621             return -1;
00622 
00623         JackLog("JackEngine::ClientDeactivate ref = %ld name = %s\n", refnum, client->GetClientControl()->fName);       
00624         fGraphManager->Deactivate(refnum);
00625         fLastSwitchUsecs = 0; // Force switch to occur next cycle, even when called with "dead" clients
00626                 
00627         // Wait for graph state change to be effective
00628         if (!fSignal->TimedWait(fEngineControl->fTimeOutUsecs * 10)) {
00629                 jack_error("JackEngine::ClientDeactivate wait error ref = %ld name = %s", refnum, client->GetClientControl()->fName);
00630                 return -1;
00631         } else {
00632                 return 0;
00633         }
00634 }
00635 
00636 //-----------------
00637 // Port management
00638 //-----------------
00639 
00640 int JackEngine::PortRegister(int refnum, const char* name, const char *type, unsigned int flags, unsigned int buffer_size, unsigned int* port_index)
00641 {
00642     JackLog("JackEngine::PortRegister ref = %ld name = %s type = %s flags = %d buffer_size = %d\n", refnum, name, type, flags, buffer_size);
00643     assert(fClientTable[refnum]);
00644 
00645     *port_index = fGraphManager->AllocatePort(refnum, name, type, (JackPortFlags)flags, fEngineControl->fBufferSize);
00646     if (*port_index != NO_PORT) {
00647         NotifyPortRegistation(*port_index, true);
00648         return 0;
00649     } else {
00650         return -1;
00651     }
00652 }
00653 
00654 int JackEngine::PortUnRegister(int refnum, jack_port_id_t port_index)
00655 {
00656     JackLog("JackEngine::PortUnRegister ref = %ld port_index = %ld\n", refnum, port_index);
00657     assert(fClientTable[refnum]);
00658 
00659     if (fGraphManager->ReleasePort(refnum, port_index) == 0) {
00660         NotifyPortRegistation(port_index, false);
00661         return 0;
00662     } else {
00663         return -1;
00664     }
00665 }
00666 
00667 int JackEngine::PortConnect(int refnum, const char* src, const char* dst)
00668 {
00669     JackLog("JackEngine::PortConnect src = %s dst = %s\n", src, dst);
00670     jack_port_id_t port_src, port_dst;
00671 
00672     return (fGraphManager->CheckPorts(src, dst, &port_src, &port_dst) < 0)
00673            ? -1
00674            : PortConnect(refnum, port_src, port_dst);
00675 }
00676 
00677 int JackEngine::PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
00678 {
00679     JackLog("JackEngine::PortConnect src = %d dst = %d\n", src, dst);
00680     JackClientInterface* client;
00681     int ref;
00682 
00683     if (fGraphManager->CheckPorts(src, dst) < 0)
00684         return -1;
00685 
00686     ref = fGraphManager->GetOutputRefNum(src);
00687     assert(ref >= 0);
00688     client = fClientTable[ref];
00689     assert(client);
00690     if (!client->GetClientControl()->fActive) {
00691         jack_error("Cannot connect ports owned by inactive clients:"
00692                    " \"%s\" is not active", client->GetClientControl()->fName);
00693         return -1;
00694     }
00695 
00696     ref = fGraphManager->GetInputRefNum(dst);
00697     assert(ref >= 0);
00698     client = fClientTable[ref];
00699     assert(client);
00700     if (!client->GetClientControl()->fActive) {
00701         jack_error("Cannot connect ports owned by inactive clients:"
00702                    " \"%s\" is not active", client->GetClientControl()->fName);
00703         return -1;
00704     }
00705         
00706         int res = fGraphManager->Connect(src, dst);
00707         if (res == 0) 
00708                 NotifyPortConnect(src, dst, true);
00709         return res;
00710 }
00711 
00712 int JackEngine::PortDisconnect(int refnum, const char* src, const char* dst)
00713 {
00714     JackLog("JackEngine::PortDisconnect src = %s dst = %s\n", src, dst);
00715     jack_port_id_t port_src, port_dst;
00716         
00717         if (fGraphManager->CheckPorts(src, dst, &port_src, &port_dst) < 0) {
00718                 return -1;
00719         } else if (fGraphManager->Disconnect(port_src, port_dst) == 0){
00720                 NotifyPortConnect(port_src, port_dst, false);
00721                 return 0;
00722         } else {
00723                 return -1;
00724         }
00725 }
00726 
00727 int JackEngine::PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
00728 {
00729     JackLog("JackEngine::PortDisconnect src = %d dst = %d\n", src, dst);
00730         
00731     if (dst == ALL_PORTS) {
00732                 
00733                 jack_int_t connections[CONNECTION_NUM];
00734                 fGraphManager->GetConnections(src, connections);
00735                 
00736                 // Notifications
00737                 JackPort* port = fGraphManager->GetPort(src);
00738                 if (port->GetFlags() & JackPortIsOutput) {
00739                         for (int i = 0; (i < CONNECTION_NUM) && (connections[i] != EMPTY); i++) {
00740                                 JackLog("NotifyPortConnect src = %ld dst = %ld false\n", src, connections[i]);
00741                                 NotifyPortConnect(src, connections[i], false);
00742                         }
00743                 } else {
00744                         for (int i = 0; (i < CONNECTION_NUM) && (connections[i] != EMPTY); i++) {
00745                                 JackLog("NotifyPortConnect src = %ld dst = %ld false\n", connections[i], src);
00746                                 NotifyPortConnect(connections[i], src, false);
00747                         }
00748                 }
00749                 
00750                 return fGraphManager->DisconnectAll(src);
00751         } else if (fGraphManager->CheckPorts(src, dst) < 0) {
00752                 return -1;
00753         } else if (fGraphManager->Disconnect(src, dst) == 0) {
00754                 // Notifications
00755                 NotifyPortConnect(src, dst, false);
00756                 return 0;
00757     } else {
00758                 return -1;
00759         }
00760 }
00761 
00762 
00763 } // end of namespace
00764 

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