Jack2 1.9.6

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 #include "JackSystemDeps.h"
00025 #include "JackLockedEngine.h"
00026 #include "JackExternalClient.h"
00027 #include "JackInternalClient.h"
00028 #include "JackEngineControl.h"
00029 #include "JackClientControl.h"
00030 #include "JackServerGlobals.h"
00031 #include "JackGlobals.h"
00032 #include "JackChannel.h"
00033 #include "JackError.h"
00034 
00035 namespace Jack
00036 {
00037 
00038 JackEngine::JackEngine(JackGraphManager* manager,
00039                        JackSynchro* table,
00040                        JackEngineControl* control)
00041 {
00042     fGraphManager = manager;
00043     fSynchroTable = table;
00044     fEngineControl = control;
00045     for (int i = 0; i < CLIENT_NUM; i++)
00046         fClientTable[i] = NULL;
00047 }
00048 
00049 JackEngine::~JackEngine()
00050 {
00051     jack_log("JackEngine::~JackEngine");
00052 }
00053 
00054 int JackEngine::Open()
00055 {
00056     jack_log("JackEngine::Open");
00057 
00058     // Open audio thread => request thread communication channel
00059     if (fChannel.Open(fEngineControl->fServerName) < 0) {
00060         jack_error("Cannot connect to server");
00061         return -1;
00062     } else {
00063         return 0;
00064     }
00065 }
00066 
00067 int JackEngine::Close()
00068 {
00069     jack_log("JackEngine::Close");
00070     fChannel.Close();
00071 
00072     // Close remaining clients (RT is stopped)
00073     for (int i = fEngineControl->fDriverNum; i < CLIENT_NUM; i++) {
00074         if (JackLoadableInternalClient* loadable_client = dynamic_cast<JackLoadableInternalClient*>(fClientTable[i])) {
00075             jack_log("JackEngine::Close loadable client = %s", loadable_client->GetClientControl()->fName);
00076             loadable_client->Close();
00077             // Close does not delete the pointer for internal clients
00078             fClientTable[i] = NULL;
00079             delete loadable_client;
00080         } else if (JackExternalClient* external_client = dynamic_cast<JackExternalClient*>(fClientTable[i])) {
00081             jack_log("JackEngine::Close external client = %s", external_client->GetClientControl()->fName);
00082             external_client->Close();
00083             // Close deletes the pointer for external clients
00084             fClientTable[i] = NULL;
00085         }
00086     }
00087 
00088     return 0;
00089 }
00090     
00091 void JackEngine::NotifyQuit()
00092 {
00093     fChannel.NotifyQuit();
00094 }
00095 
00096 //-----------------------------
00097 // Client ressource management
00098 //-----------------------------
00099 
00100 int JackEngine::AllocateRefnum()
00101 {
00102     for (int i = 0; i < CLIENT_NUM; i++) {
00103         if (!fClientTable[i]) {
00104             jack_log("JackEngine::AllocateRefNum ref = %ld", i);
00105             return i;
00106         }
00107     }
00108     return -1;
00109 }
00110 
00111 void JackEngine::ReleaseRefnum(int ref)
00112 {
00113     fClientTable[ref] = NULL;
00114 
00115     if (fEngineControl->fTemporary) {
00116         int i;
00117         for (i = fEngineControl->fDriverNum; i < CLIENT_NUM; i++) {
00118             if (fClientTable[i])
00119                 break;
00120         }
00121         if (i == CLIENT_NUM) {
00122             // last client and temporay case: quit the server
00123             jack_log("JackEngine::ReleaseRefnum server quit");
00124             fEngineControl->fTemporary = false;
00125             throw JackTemporaryException();
00126         }
00127     }
00128 }
00129 
00130 //------------------
00131 // Graph management
00132 //------------------
00133 
00134 void JackEngine::ProcessNext(jack_time_t cur_cycle_begin)
00135 {
00136     fLastSwitchUsecs = cur_cycle_begin;
00137     if (fGraphManager->RunNextGraph())  // True if the graph actually switched to a new state
00138         fChannel.Notify(ALL_CLIENTS, kGraphOrderCallback, 0);
00139     fSignal.Signal();                   // Signal for threads waiting for next cycle
00140 }
00141 
00142 void JackEngine::ProcessCurrent(jack_time_t cur_cycle_begin)
00143 {
00144     if (cur_cycle_begin < fLastSwitchUsecs + 2 * fEngineControl->fPeriodUsecs) // Signal XRun only for the first failing cycle
00145         CheckXRun(cur_cycle_begin);
00146     fGraphManager->RunCurrentGraph();
00147 }
00148 
00149 bool JackEngine::Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end)
00150 {
00151     bool res = true;
00152 
00153     // Cycle  begin
00154     fEngineControl->CycleBegin(fClientTable, fGraphManager, cur_cycle_begin, prev_cycle_end);
00155 
00156     // Graph
00157     if (fGraphManager->IsFinishedGraph()) {
00158         ProcessNext(cur_cycle_begin);
00159         res = true;
00160     } else {
00161         jack_log("Process: graph not finished!");
00162         if (cur_cycle_begin > fLastSwitchUsecs + fEngineControl->fTimeOutUsecs) {
00163             jack_log("Process: switch to next state delta = %ld", long(cur_cycle_begin - fLastSwitchUsecs));
00164             ProcessNext(cur_cycle_begin);
00165             res = true;
00166         } else {
00167             jack_log("Process: waiting to switch delta = %ld", long(cur_cycle_begin - fLastSwitchUsecs));
00168             ProcessCurrent(cur_cycle_begin);
00169             res = false;
00170         }
00171     }
00172 
00173     // Cycle end
00174     fEngineControl->CycleEnd(fClientTable);
00175     return res;
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 = fEngineControl->fDriverNum; 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.Notify(ALL_CLIENTS, kXRunCallback, 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.Notify(ALL_CLIENTS, kXRunCallback, 0);  // Notify all clients
00200             }
00201         }
00202     }
00203 }
00204 
00205 //---------------
00206 // Notifications
00207 //---------------
00208 
00209 void JackEngine::NotifyClient(int refnum, int event, int sync, const char* message, 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     
00216         if (client && client->GetClientControl()->fCallback[event]) {
00217             /*
00218                 Important for internal clients : unlock before calling the notification callbacks.
00219             */
00220             bool res = fMutex.Unlock();
00221             if (client->ClientNotify(refnum, client->GetClientControl()->fName, event, sync, message, value1, value2) < 0)
00222                 jack_error("NotifyClient fails name = %s event = %ld val1 = %ld val2 = %ld", client->GetClientControl()->fName, event, value1, value2);
00223             if (res)
00224                 fMutex.Lock();
00225        
00226         } else {
00227             jack_log("JackEngine::NotifyClient: no callback for event = %ld", event);
00228         }
00229     }
00230 }
00231 
00232 void JackEngine::NotifyClients(int event, int sync, const char* message, int value1, int value2)
00233 {
00234     for (int i = 0; i < CLIENT_NUM; i++) {
00235         NotifyClient(i, event, sync, message, value1, value2);
00236     }
00237 }
00238 
00239 int JackEngine::NotifyAddClient(JackClientInterface* new_client, const char* name, int refnum)
00240 {
00241     jack_log("JackEngine::NotifyAddClient: name = %s", name);
00242     // Notify existing clients of the new client and new client of existing clients.
00243     for (int i = 0; i < CLIENT_NUM; i++) {
00244         JackClientInterface* old_client = fClientTable[i];
00245         if (old_client) {
00246             if (old_client->ClientNotify(refnum, name, kAddClient, true, "", 0, 0) < 0) {
00247                 jack_error("NotifyAddClient old_client fails name = %s", old_client->GetClientControl()->fName);
00248                 return -1;
00249             }
00250             if (new_client->ClientNotify(i, old_client->GetClientControl()->fName, kAddClient, true, "", 0, 0) < 0) {
00251                 jack_error("NotifyAddClient new_client fails name = %s", name);
00252                 return -1;
00253             }
00254         }
00255     }
00256 
00257     return 0;
00258 }
00259 
00260 void JackEngine::NotifyRemoveClient(const char* name, int refnum)
00261 {
00262     // Notify existing clients (including the one beeing suppressed) of the removed client
00263     for (int i = 0; i < CLIENT_NUM; i++) {
00264         JackClientInterface* client = fClientTable[i];
00265         if (client) {
00266             client->ClientNotify(refnum, name, kRemoveClient, true, "",0, 0);
00267         }
00268     }
00269 }
00270 
00271 // Coming from the driver
00272 void JackEngine::NotifyXRun(jack_time_t callback_usecs, float delayed_usecs)
00273 {
00274     // Use the audio thread => request thread communication channel
00275     fEngineControl->NotifyXRun(callback_usecs, delayed_usecs);
00276     fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0);
00277 }
00278 
00279 void JackEngine::NotifyXRun(int refnum)
00280 {
00281     if (refnum == ALL_CLIENTS) {
00282         NotifyClients(kXRunCallback, false, "", 0, 0);
00283     } else {
00284         NotifyClient(refnum, kXRunCallback, false, "", 0, 0);
00285     }
00286 }
00287 
00288 void JackEngine::NotifyGraphReorder()
00289 {
00290     NotifyClients(kGraphOrderCallback, false, "", 0, 0);
00291 }
00292 
00293 void JackEngine::NotifyBufferSize(jack_nframes_t buffer_size)
00294 {
00295     NotifyClients(kBufferSizeCallback, true, "", buffer_size, 0);
00296 }
00297 
00298 void JackEngine::NotifySampleRate(jack_nframes_t sample_rate)
00299 {
00300     NotifyClients(kSampleRateCallback, true, "", sample_rate, 0);
00301 }
00302 
00303 void JackEngine::NotifyFailure(int code, const char* reason)
00304 {
00305     NotifyClients(kShutDownCallback, false, reason, code, 0);
00306 }
00307     
00308 void JackEngine::NotifyFreewheel(bool onoff)
00309 {
00310     if (onoff) {
00311         // Save RT state
00312         fEngineControl->fSavedRealTime = fEngineControl->fRealTime;
00313         fEngineControl->fRealTime = false;
00314     } else {
00315         // Restore RT state
00316         fEngineControl->fRealTime = fEngineControl->fSavedRealTime;
00317         fEngineControl->fSavedRealTime = false;
00318     }
00319     NotifyClients((onoff ? kStartFreewheelCallback : kStopFreewheelCallback), true, "", 0, 0);
00320 }
00321 
00322 void JackEngine::NotifyPortRegistation(jack_port_id_t port_index, bool onoff)
00323 {
00324     NotifyClients((onoff ? kPortRegistrationOnCallback : kPortRegistrationOffCallback), false, "", port_index, 0);
00325 }
00326 
00327 void JackEngine::NotifyPortRename(jack_port_id_t port, const char* old_name)
00328 {
00329     NotifyClients(kPortRenameCallback, false, old_name, port, 0);
00330 }
00331 
00332 void JackEngine::NotifyPortConnect(jack_port_id_t src, jack_port_id_t dst, bool onoff)
00333 {
00334     NotifyClients((onoff ? kPortConnectCallback : kPortDisconnectCallback), false, "", src, dst);
00335 }
00336 
00337 void JackEngine::NotifyActivate(int refnum)
00338 {
00339     NotifyClient(refnum, kActivateClient, true, "", 0, 0);
00340 }
00341 
00342 //----------------------------
00343 // Loadable client management
00344 //----------------------------
00345 
00346 int JackEngine::GetInternalClientName(int refnum, char* name_res)
00347 {
00348     JackClientInterface* client = fClientTable[refnum];
00349     strncpy(name_res, client->GetClientControl()->fName, JACK_CLIENT_NAME_SIZE);
00350     return 0;
00351 }
00352 
00353 int JackEngine::InternalClientHandle(const char* client_name, int* status, int* int_ref)
00354 {
00355     // Clear status
00356     *status = 0;
00357 
00358     for (int i = 0; i < CLIENT_NUM; i++) {
00359         JackClientInterface* client = fClientTable[i];
00360         if (client && dynamic_cast<JackLoadableInternalClient*>(client) && (strcmp(client->GetClientControl()->fName, client_name) == 0)) {
00361             jack_log("InternalClientHandle found client name = %s ref = %ld",  client_name, i);
00362             *int_ref = i;
00363             return 0;
00364         }
00365     }
00366 
00367     *status |= (JackNoSuchClient | JackFailure);
00368     return -1;
00369 }
00370 
00371 int JackEngine::InternalClientUnload(int refnum, int* status)
00372 {
00373     JackClientInterface* client = fClientTable[refnum];
00374     if (client) {
00375         int res = client->Close();
00376         delete client;
00377         *status = 0;
00378         return res;
00379     } else {
00380         *status = (JackNoSuchClient | JackFailure);
00381         return -1;
00382     }
00383 }
00384 
00385 //-------------------
00386 // Client management
00387 //-------------------
00388 
00389 int JackEngine::ClientCheck(const char* name, char* name_res, int protocol, int options, int* status)
00390 {
00391     // Clear status
00392     *status = 0;
00393     strcpy(name_res, name);
00394 
00395     jack_log("Check protocol client %ld server = %ld", protocol, JACK_PROTOCOL_VERSION);
00396 
00397     if (protocol != JACK_PROTOCOL_VERSION) {
00398         *status |= (JackFailure | JackVersionError);
00399         jack_error("JACK protocol mismatch (%d vs %d)", protocol, JACK_PROTOCOL_VERSION);
00400         return -1;
00401     }
00402 
00403     if (ClientCheckName(name)) {
00404 
00405         *status |= JackNameNotUnique;
00406 
00407         if (options & JackUseExactName) {
00408             jack_error("cannot create new client; %s already exists", name);
00409             *status |= JackFailure;
00410             return -1;
00411         }
00412 
00413         if (GenerateUniqueName(name_res)) {
00414             *status |= JackFailure;
00415             return -1;
00416         }
00417     }
00418 
00419     return 0;
00420 }
00421 
00422 bool JackEngine::GenerateUniqueName(char* name)
00423 {
00424     int tens, ones;
00425     int length = strlen(name);
00426 
00427     if (length > JACK_CLIENT_NAME_SIZE - 4) {
00428         jack_error("%s exists and is too long to make unique", name);
00429         return true;            /* failure */
00430     }
00431 
00432     /*  generate a unique name by appending "-01".."-99" */
00433     name[length++] = '-';
00434     tens = length++;
00435     ones = length++;
00436     name[tens] = '0';
00437     name[ones] = '1';
00438     name[length] = '\0';
00439 
00440     while (ClientCheckName(name)) {
00441         if (name[ones] == '9') {
00442             if (name[tens] == '9') {
00443                 jack_error("client %s has 99 extra instances already", name);
00444                 return true; /* give up */
00445             }
00446             name[tens]++;
00447             name[ones] = '0';
00448         } else {
00449             name[ones]++;
00450         }
00451     }
00452     return false;
00453 }
00454 
00455 bool JackEngine::ClientCheckName(const char* name)
00456 {
00457     for (int i = 0; i < CLIENT_NUM; i++) {
00458         JackClientInterface* client = fClientTable[i];
00459         if (client && (strcmp(client->GetClientControl()->fName, name) == 0))
00460             return true;
00461     }
00462 
00463     return false;
00464 }
00465 
00466 int JackEngine::GetClientPID(const char* name)
00467 {
00468     for (int i = 0; i < CLIENT_NUM; i++) {
00469         JackClientInterface* client = fClientTable[i];
00470         if (client && (strcmp(client->GetClientControl()->fName, name) == 0))
00471             return client->GetClientControl()->fPID;
00472     }
00473 
00474     return 0;
00475 }
00476 
00477 int JackEngine::GetClientRefNum(const char* name)
00478 {
00479     for (int i = 0; i < CLIENT_NUM; i++) {
00480         JackClientInterface* client = fClientTable[i];
00481         if (client && (strcmp(client->GetClientControl()->fName, name) == 0))
00482             return client->GetClientControl()->fRefNum;
00483     }
00484 
00485     return -1;
00486 }
00487 
00488 // Used for external clients
00489 int JackEngine::ClientExternalOpen(const char* name, int pid, int* ref, int* shared_engine, int* shared_client, int* shared_graph_manager)
00490 {
00491     jack_log("JackEngine::ClientExternalOpen: name = %s ", name);
00492 
00493     int refnum = AllocateRefnum();
00494     if (refnum < 0) {
00495         jack_error("No more refnum available");
00496         return -1;
00497     }
00498 
00499     JackExternalClient* client = new JackExternalClient();
00500 
00501     if (!fSynchroTable[refnum].Allocate(name, fEngineControl->fServerName, 0)) {
00502         jack_error("Cannot allocate synchro");
00503         goto error;
00504     }
00505 
00506     if (client->Open(name, pid, refnum, shared_client) < 0) {
00507         jack_error("Cannot open client");
00508         goto error;
00509     }
00510 
00511     if (!fSignal.LockedTimedWait(DRIVER_OPEN_TIMEOUT * 1000000)) {
00512         // Failure if RT thread is not running (problem with the driver...)
00513         jack_error("Driver is not running");
00514         goto error;
00515     }
00516 
00517     fClientTable[refnum] = client;
00518 
00519     if (NotifyAddClient(client, name, refnum) < 0) {
00520         jack_error("Cannot notify add client");
00521         goto error;
00522     }
00523 
00524     fGraphManager->InitRefNum(refnum);
00525     fEngineControl->ResetRollingUsecs();
00526     *shared_engine = fEngineControl->GetShmIndex();
00527     *shared_graph_manager = fGraphManager->GetShmIndex();
00528     *ref = refnum;
00529     return 0;
00530 
00531 error:
00532     // Cleanup...
00533     fSynchroTable[refnum].Destroy();
00534     fClientTable[refnum] = 0;
00535     client->Close();
00536     delete client;
00537     return -1;
00538 }
00539 
00540 // Used for server driver clients
00541 int JackEngine::ClientInternalOpen(const char* name, int* ref, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client, bool wait)
00542 {
00543     jack_log("JackEngine::ClientInternalOpen: name = %s", name);
00544 
00545     int refnum = AllocateRefnum();
00546     if (refnum < 0) {
00547         jack_error("No more refnum available");
00548         goto error;
00549     }
00550 
00551     if (!fSynchroTable[refnum].Allocate(name, fEngineControl->fServerName, 0)) {
00552         jack_error("Cannot allocate synchro");
00553         goto error;
00554     }
00555 
00556     if (wait && !fSignal.LockedTimedWait(DRIVER_OPEN_TIMEOUT * 1000000)) {
00557         // Failure if RT thread is not running (problem with the driver...)
00558         jack_error("Driver is not running");
00559         goto error;
00560     }
00561 
00562     fClientTable[refnum] = client;
00563 
00564     if (NotifyAddClient(client, name, refnum) < 0) {
00565         jack_error("Cannot notify add client");
00566         goto error;
00567     }
00568 
00569     fGraphManager->InitRefNum(refnum);
00570     fEngineControl->ResetRollingUsecs();
00571     *shared_engine = fEngineControl;
00572     *shared_manager = fGraphManager;
00573     *ref = refnum;
00574     return 0;
00575 
00576 error:
00577     // Cleanup...
00578     fSynchroTable[refnum].Destroy();
00579     fClientTable[refnum] = 0;
00580     return -1;
00581 }
00582 
00583 // Used for external clients
00584 int JackEngine::ClientExternalClose(int refnum)
00585 {
00586     JackClientInterface* client = fClientTable[refnum];
00587     fEngineControl->fTransport.ResetTimebase(refnum);
00588     int res = ClientCloseAux(refnum, client, true);
00589     client->Close();
00590     delete client;
00591     return res;
00592 }
00593 
00594 // Used for server internal clients or drivers when the RT thread is stopped
00595 int JackEngine::ClientInternalClose(int refnum, bool wait)
00596 {
00597     JackClientInterface* client = fClientTable[refnum];
00598     return ClientCloseAux(refnum, client, wait);
00599 }
00600 
00601 int JackEngine::ClientCloseAux(int refnum, JackClientInterface* client, bool wait)
00602 {
00603     jack_log("JackEngine::ClientCloseAux ref = %ld", refnum);
00604 
00605     // Unregister all ports ==> notifications are sent
00606     jack_int_t ports[PORT_NUM_FOR_CLIENT];
00607     int i;
00608 
00609     fGraphManager->GetInputPorts(refnum, ports);
00610     for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY) ; i++) {
00611         PortUnRegister(refnum, ports[i]);
00612     }
00613 
00614     fGraphManager->GetOutputPorts(refnum, ports);
00615     for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY) ; i++) {
00616         PortUnRegister(refnum, ports[i]);
00617     }
00618 
00619     // Remove the client from the table
00620     ReleaseRefnum(refnum);
00621 
00622     // Remove all ports
00623     fGraphManager->RemoveAllPorts(refnum);
00624 
00625     // Wait until next cycle to be sure client is not used anymore
00626     if (wait) {
00627         if (!fSignal.LockedTimedWait(fEngineControl->fTimeOutUsecs * 2)) { // Must wait at least until a switch occurs in Process, even in case of graph end failure
00628             jack_error("JackEngine::ClientCloseAux wait error ref = %ld", refnum);
00629         }
00630     }
00631 
00632     // Notify running clients
00633     NotifyRemoveClient(client->GetClientControl()->fName, client->GetClientControl()->fRefNum);
00634 
00635     // Cleanup...
00636     fSynchroTable[refnum].Destroy();
00637     fEngineControl->ResetRollingUsecs();
00638     return 0;
00639 }
00640 
00641 int JackEngine::ClientActivate(int refnum, bool is_real_time)
00642 {
00643     JackClientInterface* client = fClientTable[refnum];
00644     jack_log("JackEngine::ClientActivate ref = %ld name = %s", refnum, client->GetClientControl()->fName);
00645     
00646     if (is_real_time)
00647         fGraphManager->Activate(refnum);
00648 
00649     // Wait for graph state change to be effective
00650     if (!fSignal.LockedTimedWait(fEngineControl->fTimeOutUsecs * 10)) {
00651         jack_error("JackEngine::ClientActivate wait error ref = %ld name = %s", refnum, client->GetClientControl()->fName);
00652         return -1;
00653     } else {
00654         jack_int_t input_ports[PORT_NUM_FOR_CLIENT];
00655         jack_int_t output_ports[PORT_NUM_FOR_CLIENT];
00656         fGraphManager->GetInputPorts(refnum, input_ports);
00657         fGraphManager->GetOutputPorts(refnum, output_ports);
00658         
00659         // First add port state to JackPortIsActive
00660         for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) {
00661             fGraphManager->ActivatePort(input_ports[i]);
00662         }
00663         for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) {
00664             fGraphManager->ActivatePort(output_ports[i]);
00665         }
00666         
00667         // Notify client
00668         NotifyActivate(refnum);
00669         
00670         // Then issue port registration notification
00671         for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) {
00672             NotifyPortRegistation(input_ports[i], true);
00673         }
00674         for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) {
00675             NotifyPortRegistation(output_ports[i], true);
00676         }
00677 
00678         return 0;
00679     }
00680 }
00681 
00682 // May be called without client
00683 int JackEngine::ClientDeactivate(int refnum)
00684 {
00685     JackClientInterface* client = fClientTable[refnum];
00686     jack_log("JackEngine::ClientDeactivate ref = %ld name = %s", refnum, client->GetClientControl()->fName);
00687 
00688     jack_int_t input_ports[PORT_NUM_FOR_CLIENT];
00689     jack_int_t output_ports[PORT_NUM_FOR_CLIENT];
00690     fGraphManager->GetInputPorts(refnum, input_ports);
00691     fGraphManager->GetOutputPorts(refnum, output_ports);
00692 
00693     // First disconnect all ports and remove their JackPortIsActive state
00694     for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) {
00695         PortDisconnect(refnum, input_ports[i], ALL_PORTS);
00696         fGraphManager->DeactivatePort(input_ports[i]);
00697     }
00698     for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) {
00699         PortDisconnect(refnum, output_ports[i], ALL_PORTS);
00700         fGraphManager->DeactivatePort(output_ports[i]);
00701     }
00702     
00703     // Then issue port registration notification
00704     for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) {
00705         NotifyPortRegistation(input_ports[i], false);
00706     }
00707     for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) {
00708         NotifyPortRegistation(output_ports[i], false);
00709     }
00710 
00711     fGraphManager->Deactivate(refnum);
00712     fLastSwitchUsecs = 0; // Force switch to occur next cycle, even when called with "dead" clients
00713 
00714     // Wait for graph state change to be effective
00715     if (!fSignal.LockedTimedWait(fEngineControl->fTimeOutUsecs * 10)) {
00716         jack_error("JackEngine::ClientDeactivate wait error ref = %ld name = %s", refnum, client->GetClientControl()->fName);
00717         return -1;
00718     } else {
00719         return 0;
00720     }
00721 }
00722 
00723 //-----------------
00724 // Port management
00725 //-----------------
00726 
00727 int JackEngine::PortRegister(int refnum, const char* name, const char *type, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index)
00728 {
00729     jack_log("JackEngine::PortRegister ref = %ld name = %s type = %s flags = %d buffer_size = %d", refnum, name, type, flags, buffer_size);
00730     JackClientInterface* client = fClientTable[refnum];
00731 
00732     // Check if port name already exists
00733     if (fGraphManager->GetPort(name) != NO_PORT) {
00734         jack_error("port_name \"%s\" already exists", name);
00735         return -1;
00736     }
00737 
00738     *port_index = fGraphManager->AllocatePort(refnum, name, type, (JackPortFlags)flags, fEngineControl->fBufferSize);
00739     if (*port_index != NO_PORT) {
00740         if (client->GetClientControl()->fActive)
00741             NotifyPortRegistation(*port_index, true);
00742         return 0;
00743     } else {
00744         return -1;
00745     }
00746 }
00747 
00748 int JackEngine::PortUnRegister(int refnum, jack_port_id_t port_index)
00749 {
00750     jack_log("JackEngine::PortUnRegister ref = %ld port_index = %ld", refnum, port_index);
00751     JackClientInterface* client = fClientTable[refnum];
00752 
00753     // Disconnect port ==> notification is sent
00754     PortDisconnect(refnum, port_index, ALL_PORTS);
00755 
00756     if (fGraphManager->ReleasePort(refnum, port_index) == 0) {
00757         if (client->GetClientControl()->fActive)
00758             NotifyPortRegistation(port_index, false);
00759         return 0;
00760     } else {
00761         return -1;
00762     }
00763 }
00764 
00765 int JackEngine::PortConnect(int refnum, const char* src, const char* dst)
00766 {
00767     jack_log("JackEngine::PortConnect src = %s dst = %s", src, dst);
00768     jack_port_id_t port_src, port_dst;
00769 
00770     return (fGraphManager->GetTwoPorts(src, dst, &port_src, &port_dst) < 0)
00771            ? -1
00772            : PortConnect(refnum, port_src, port_dst);
00773 }
00774 
00775 int JackEngine::PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
00776 {
00777     jack_log("JackEngine::PortConnect src = %d dst = %d", src, dst);
00778     JackClientInterface* client;
00779     int ref;
00780 
00781     if (fGraphManager->CheckPorts(src, dst) < 0)
00782         return -1;
00783 
00784     ref = fGraphManager->GetOutputRefNum(src);
00785     assert(ref >= 0);
00786     client = fClientTable[ref];
00787     assert(client);
00788     if (!client->GetClientControl()->fActive) {
00789         jack_error("Cannot connect ports owned by inactive clients:"
00790                    " \"%s\" is not active", client->GetClientControl()->fName);
00791         return -1;
00792     }
00793 
00794     ref = fGraphManager->GetInputRefNum(dst);
00795     assert(ref >= 0);
00796     client = fClientTable[ref];
00797     assert(client);
00798     if (!client->GetClientControl()->fActive) {
00799         jack_error("Cannot connect ports owned by inactive clients:"
00800                    " \"%s\" is not active", client->GetClientControl()->fName);
00801         return -1;
00802     }
00803 
00804     int res = fGraphManager->Connect(src, dst);
00805     if (res == 0)
00806         NotifyPortConnect(src, dst, true);
00807     return res;
00808 }
00809 
00810 int JackEngine::PortDisconnect(int refnum, const char* src, const char* dst)
00811 {
00812     jack_log("JackEngine::PortDisconnect src = %s dst = %s", src, dst);
00813     jack_port_id_t port_src, port_dst;
00814 
00815     return (fGraphManager->GetTwoPorts(src, dst, &port_src, &port_dst) < 0)
00816            ? -1
00817            : PortDisconnect(refnum, port_src, port_dst);
00818 }
00819 
00820 int JackEngine::PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
00821 {
00822     jack_log("JackEngine::PortDisconnect src = %d dst = %d", src, dst);
00823  
00824     if (dst == ALL_PORTS) {
00825 
00826         jack_int_t connections[CONNECTION_NUM_FOR_PORT];
00827         fGraphManager->GetConnections(src, connections);
00828 
00829         JackPort* port = fGraphManager->GetPort(src);
00830         int ret = 0;
00831         if (port->GetFlags() & JackPortIsOutput) {
00832             for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && (connections[i] != EMPTY); i++) {
00833                 if (PortDisconnect(refnum, src, connections[i]) != 0) {
00834                     ret = -1;
00835                 }
00836             }
00837         } else {
00838             for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && (connections[i] != EMPTY); i++) {
00839                 if (PortDisconnect(refnum, connections[i], src) != 0) {
00840                     ret = -1;
00841                 }
00842             }
00843         }
00844 
00845         return ret;
00846     } else if (fGraphManager->CheckPorts(src, dst) < 0) {
00847         return -1;
00848     } else if (fGraphManager->Disconnect(src, dst) == 0) {
00849         // Notifications
00850         NotifyPortConnect(src, dst, false);
00851         return 0;
00852     } else {
00853         return -1;
00854     }
00855 }
00856 
00857 int JackEngine::PortRename(int refnum, jack_port_id_t port, const char* name)
00858 {
00859     char old_name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE];
00860     strcpy(old_name, fGraphManager->GetPort(port)->GetName());
00861     fGraphManager->GetPort(port)->SetName(name);
00862     NotifyPortRename(port, old_name);
00863     return 0;
00864 }
00865 
00866 } // end of namespace
00867