Jack2  1.9.10
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 <set>
00023 #include <assert.h>
00024 #include <ctype.h>
00025 
00026 #include "JackSystemDeps.h"
00027 #include "JackLockedEngine.h"
00028 #include "JackExternalClient.h"
00029 #include "JackInternalClient.h"
00030 #include "JackEngineControl.h"
00031 #include "JackClientControl.h"
00032 #include "JackServerGlobals.h"
00033 #include "JackGlobals.h"
00034 #include "JackChannel.h"
00035 #include "JackError.h"
00036 
00037 namespace Jack
00038 {
00039 
00040 JackEngine::JackEngine(JackGraphManager* manager,
00041                        JackSynchro* table,
00042                        JackEngineControl* control,
00043                        char self_connect_mode)
00044                     : JackLockAble(control->fServerName), 
00045                     fSignal(control->fServerName)
00046 {
00047     fGraphManager = manager;
00048     fSynchroTable = table;
00049     fEngineControl = control;
00050     fSelfConnectMode = self_connect_mode;
00051     for (int i = 0; i < CLIENT_NUM; i++) {
00052         fClientTable[i] = NULL;
00053     }
00054     fLastSwitchUsecs = 0;
00055     fMaxUUID = 0;
00056     fSessionPendingReplies = 0;
00057     fSessionTransaction = NULL;
00058     fSessionResult = NULL;
00059 }
00060 
00061 JackEngine::~JackEngine()
00062 {}
00063 
00064 int JackEngine::Open()
00065 {
00066     jack_log("JackEngine::Open");
00067 
00068     // Open audio thread => request thread communication channel
00069     if (fChannel.Open(fEngineControl->fServerName) < 0) {
00070         jack_error("Cannot connect to server");
00071         return -1;
00072     } else {
00073         return 0;
00074     }
00075 }
00076 
00077 int JackEngine::Close()
00078 {
00079     jack_log("JackEngine::Close");
00080     fChannel.Close();
00081 
00082     // Close remaining clients (RT is stopped)
00083     for (int i = fEngineControl->fDriverNum; i < CLIENT_NUM; i++) {
00084         if (JackLoadableInternalClient* loadable_client = dynamic_cast<JackLoadableInternalClient*>(fClientTable[i])) {
00085             jack_log("JackEngine::Close loadable client = %s", loadable_client->GetClientControl()->fName);
00086             loadable_client->Close();
00087             fClientTable[i] = NULL;
00088             delete loadable_client;
00089         } else if (JackExternalClient* external_client = dynamic_cast<JackExternalClient*>(fClientTable[i])) {
00090             jack_log("JackEngine::Close external client = %s", external_client->GetClientControl()->fName);
00091             external_client->Close();
00092             fClientTable[i] = NULL;
00093             delete external_client;
00094         }
00095     }
00096 
00097     return 0;
00098 }
00099 
00100 void JackEngine::NotifyQuit()
00101 {
00102     fChannel.NotifyQuit();
00103 }
00104 
00105 //-----------------------------
00106 // Client ressource management
00107 //-----------------------------
00108 
00109 int JackEngine::AllocateRefnum()
00110 {
00111     for (int i = 0; i < CLIENT_NUM; i++) {
00112         if (!fClientTable[i]) {
00113             jack_log("JackEngine::AllocateRefNum ref = %ld", i);
00114             return i;
00115         }
00116     }
00117     return -1;
00118 }
00119 
00120 void JackEngine::ReleaseRefnum(int refnum)
00121 {
00122     fClientTable[refnum] = NULL;
00123 
00124     if (fEngineControl->fTemporary) {
00125         int i;
00126         for (i = fEngineControl->fDriverNum; i < CLIENT_NUM; i++) {
00127             if (fClientTable[i]) {
00128                 break;
00129             }
00130         }
00131         if (i == CLIENT_NUM) {
00132             // Last client and temporay case: quit the server
00133             jack_log("JackEngine::ReleaseRefnum server quit");
00134             fEngineControl->fTemporary = false;
00135             throw JackTemporaryException();
00136         }
00137     }
00138 }
00139 
00140 //------------------
00141 // Graph management
00142 //------------------
00143 
00144 void JackEngine::ProcessNext(jack_time_t cur_cycle_begin)
00145 {
00146     fLastSwitchUsecs = cur_cycle_begin;
00147     if (fGraphManager->RunNextGraph())  {   // True if the graph actually switched to a new state
00148         fChannel.Notify(ALL_CLIENTS, kGraphOrderCallback, 0);
00149     }
00150     fSignal.Signal();                       // Signal for threads waiting for next cycle
00151 }
00152 
00153 void JackEngine::ProcessCurrent(jack_time_t cur_cycle_begin)
00154 {
00155     if (cur_cycle_begin < fLastSwitchUsecs + 2 * fEngineControl->fPeriodUsecs) { // Signal XRun only for the first failing cycle
00156         CheckXRun(cur_cycle_begin);
00157     }
00158     fGraphManager->RunCurrentGraph();
00159 }
00160 
00161 bool JackEngine::Process(jack_time_t cur_cycle_begin, jack_time_t prev_cycle_end)
00162 {
00163     bool res = true;
00164 
00165     // Cycle  begin
00166     fEngineControl->CycleBegin(fClientTable, fGraphManager, cur_cycle_begin, prev_cycle_end);
00167   
00168     // Graph
00169     if (fGraphManager->IsFinishedGraph()) {
00170         ProcessNext(cur_cycle_begin);
00171         res = true;
00172     } else {
00173         jack_log("Process: graph not finished!");
00174         if (cur_cycle_begin > fLastSwitchUsecs + fEngineControl->fTimeOutUsecs) {
00175             jack_log("Process: switch to next state delta = %ld", long(cur_cycle_begin - fLastSwitchUsecs));
00176             ProcessNext(cur_cycle_begin);
00177             res = true;
00178         } else {
00179             jack_log("Process: waiting to switch delta = %ld", long(cur_cycle_begin - fLastSwitchUsecs));
00180             ProcessCurrent(cur_cycle_begin);
00181             res = false;
00182         }
00183     }
00184 
00185     // Cycle end
00186     fEngineControl->CycleEnd(fClientTable);
00187     return res;
00188 }
00189 
00190 /*
00191 Client that finish *after* the callback date are considered late even if their output buffers may have been
00192 correctly mixed in the time window: callbackUsecs <==> Read <==> Write.
00193 */
00194 
00195 static const char* State2String(jack_client_state_t state)
00196 {
00197     switch (state) {
00198         case NotTriggered:
00199             return "NotTriggered";
00200         case Triggered:
00201             return "Triggered";
00202         case Running:
00203             return "Running";
00204         case Finished:
00205             return "Finished";
00206         default:
00207             return "";
00208     }
00209 }
00210 
00211 void JackEngine::CheckXRun(jack_time_t callback_usecs)  // REVOIR les conditions de fin
00212 {
00213     for (int i = fEngineControl->fDriverNum; i < CLIENT_NUM; i++) {
00214         JackClientInterface* client = fClientTable[i];
00215         if (client && client->GetClientControl()->fActive) {
00216             JackClientTiming* timing = fGraphManager->GetClientTiming(i);
00217             jack_client_state_t status = timing->fStatus;
00218             jack_time_t finished_date = timing->fFinishedAt;
00219 
00220             if (status != NotTriggered && status != Finished) {
00221                 jack_error("JackEngine::XRun: client = %s was not finished, state = %s", client->GetClientControl()->fName, State2String(status));
00222                 fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0);  // Notify all clients
00223             }
00224 
00225             if (status == Finished && (long)(finished_date - callback_usecs) > 0) {
00226                 jack_error("JackEngine::XRun: client %s finished after current callback", client->GetClientControl()->fName);
00227                 fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0);  // Notify all clients
00228             }
00229         }
00230     }
00231 }
00232 
00233 int JackEngine::ComputeTotalLatencies()
00234 {
00235     std::vector<jack_int_t> sorted;
00236     std::vector<jack_int_t>::iterator it;
00237     std::vector<jack_int_t>::reverse_iterator rit;
00238 
00239     fGraphManager->TopologicalSort(sorted);
00240 
00241     /* iterate over all clients in graph order, and emit
00242          * capture latency callback.
00243          */
00244 
00245     for (it = sorted.begin(); it != sorted.end(); it++) {
00246         NotifyClient(*it, kLatencyCallback, true, "", 0, 0);
00247     }
00248 
00249     /* now issue playback latency callbacks in reverse graph order.
00250          */
00251     for (rit = sorted.rbegin(); rit != sorted.rend(); rit++) {
00252         NotifyClient(*rit, kLatencyCallback, true, "", 1, 0);
00253     }
00254 
00255     return 0;
00256 }
00257 
00258 //---------------
00259 // Notifications
00260 //---------------
00261 
00262 int JackEngine::ClientNotify(JackClientInterface* client, int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2)
00263 {   
00264     // Check if notification is needed
00265     if (!client->GetClientControl()->fCallback[notify]) {
00266         jack_log("JackEngine::ClientNotify: no callback for notification = %ld", notify);
00267         return 0;
00268     }
00269     
00270     int res1;
00271    
00272     // External client
00273     if (dynamic_cast<JackExternalClient*>(client)) {
00274        res1 = client->ClientNotify(refnum, name, notify, sync, message, value1, value2);
00275     // Important for internal client : unlock before calling the notification callbacks
00276     } else {
00277         bool res2 = Unlock();
00278         res1 = client->ClientNotify(refnum, name, notify, sync, message, value1, value2);
00279         if (res2) {
00280             Lock();
00281         }
00282     }
00283     
00284     if (res1 < 0) {
00285         jack_error("ClientNotify fails name = %s notification = %ld val1 = %ld val2 = %ld", name, notify, value1, value2);
00286     }
00287     return res1;
00288 }
00289 
00290 void JackEngine::NotifyClient(int refnum, int event, int sync, const char* message, int value1, int value2)
00291 {
00292     JackClientInterface* client = fClientTable[refnum];
00293     if (client) {
00294         ClientNotify(client, refnum, client->GetClientControl()->fName, event, sync, message, value1, value2);
00295     }
00296 }
00297 
00298 void JackEngine::NotifyClients(int event, int sync, const char* message, int value1, int value2)
00299 {
00300     for (int i = 0; i < CLIENT_NUM; i++) {
00301         NotifyClient(i, event, sync, message, value1, value2);
00302     }
00303 }
00304 
00305 int JackEngine::NotifyAddClient(JackClientInterface* new_client, const char* new_name, int refnum)
00306 {
00307     jack_log("JackEngine::NotifyAddClient: name = %s", new_name);
00308     
00309     // Notify existing clients of the new client and new client of existing clients.
00310     for (int i = 0; i < CLIENT_NUM; i++) {
00311         JackClientInterface* old_client = fClientTable[i];
00312         if (old_client && old_client != new_client) {
00313             char* old_name = old_client->GetClientControl()->fName;
00314             if (ClientNotify(old_client, refnum, new_name, kAddClient, false, "", 0, 0) < 0) {
00315                 jack_error("NotifyAddClient old_client fails name = %s", old_name);
00316                 // Not considered as a failure...
00317             }
00318             if (ClientNotify(new_client, i, old_name, kAddClient, true, "", 0, 0) < 0) {
00319                 jack_error("NotifyAddClient new_client fails name = %s", new_name);
00320                 return -1;
00321             }
00322         }
00323     }
00324 
00325     return 0;
00326 }
00327 
00328 void JackEngine::NotifyRemoveClient(const char* name, int refnum)
00329 {
00330     // Notify existing clients (including the one beeing suppressed) of the removed client
00331     for (int i = 0; i < CLIENT_NUM; i++) {
00332         JackClientInterface* client = fClientTable[i];
00333         if (client) {
00334             ClientNotify(client, refnum, name, kRemoveClient, false, "", 0, 0);
00335         }
00336     }
00337 }
00338 
00339 // Coming from the driver
00340 void JackEngine::NotifyDriverXRun()
00341 {
00342     // Use the audio thread => request thread communication channel
00343     fChannel.Notify(ALL_CLIENTS, kXRunCallback, 0);
00344 }
00345 
00346 void JackEngine::NotifyClientXRun(int refnum)
00347 {
00348     if (refnum == ALL_CLIENTS) {
00349         NotifyClients(kXRunCallback, false, "", 0, 0);
00350     } else {
00351         NotifyClient(refnum, kXRunCallback, false, "", 0, 0);
00352     }
00353 }
00354 
00355 void JackEngine::NotifyGraphReorder()
00356 {
00357     ComputeTotalLatencies();
00358     NotifyClients(kGraphOrderCallback, false, "", 0, 0);
00359 }
00360 
00361 void JackEngine::NotifyBufferSize(jack_nframes_t buffer_size)
00362 {
00363     NotifyClients(kBufferSizeCallback, true, "", buffer_size, 0);
00364 }
00365 
00366 void JackEngine::NotifySampleRate(jack_nframes_t sample_rate)
00367 {
00368     NotifyClients(kSampleRateCallback, true, "", sample_rate, 0);
00369 }
00370 
00371 void JackEngine::NotifyFailure(int code, const char* reason)
00372 {
00373     NotifyClients(kShutDownCallback, false, reason, code, 0);
00374 }
00375 
00376 void JackEngine::NotifyFreewheel(bool onoff)
00377 {
00378     if (onoff) {
00379         // Save RT state
00380         fEngineControl->fSavedRealTime = fEngineControl->fRealTime;
00381         fEngineControl->fRealTime = false;
00382     } else {
00383         // Restore RT state
00384         fEngineControl->fRealTime = fEngineControl->fSavedRealTime;
00385         fEngineControl->fSavedRealTime = false;
00386     }
00387     NotifyClients((onoff ? kStartFreewheelCallback : kStopFreewheelCallback), true, "", 0, 0);
00388 }
00389 
00390 void JackEngine::NotifyPortRegistation(jack_port_id_t port_index, bool onoff)
00391 {
00392     NotifyClients((onoff ? kPortRegistrationOnCallback : kPortRegistrationOffCallback), false, "", port_index, 0);
00393 }
00394 
00395 void JackEngine::NotifyPortRename(jack_port_id_t port, const char* old_name)
00396 {
00397     NotifyClients(kPortRenameCallback, false, old_name, port, 0);
00398 }
00399 
00400 void JackEngine::NotifyPortConnect(jack_port_id_t src, jack_port_id_t dst, bool onoff)
00401 {
00402     NotifyClients((onoff ? kPortConnectCallback : kPortDisconnectCallback), false, "", src, dst);
00403 }
00404 
00405 void JackEngine::NotifyActivate(int refnum)
00406 {
00407     NotifyClient(refnum, kActivateClient, true, "", 0, 0);
00408 }
00409 
00410 //----------------------------
00411 // Loadable client management
00412 //----------------------------
00413 
00414 int JackEngine::GetInternalClientName(int refnum, char* name_res)
00415 {
00416     JackClientInterface* client = fClientTable[refnum];
00417     assert(client);
00418     strncpy(name_res, client->GetClientControl()->fName, JACK_CLIENT_NAME_SIZE);
00419     return 0;
00420 }
00421 
00422 int JackEngine::InternalClientHandle(const char* client_name, int* status, int* int_ref)
00423 {
00424     // Clear status
00425     *status = 0;
00426 
00427     for (int i = 0; i < CLIENT_NUM; i++) {
00428         JackClientInterface* client = fClientTable[i];
00429         if (client && dynamic_cast<JackLoadableInternalClient*>(client) && (strcmp(client->GetClientControl()->fName, client_name) == 0)) {
00430             jack_log("InternalClientHandle found client name = %s ref = %ld",  client_name, i);
00431             *int_ref = i;
00432             return 0;
00433         }
00434     }
00435 
00436     *status |= (JackNoSuchClient | JackFailure);
00437     return -1;
00438 }
00439 
00440 int JackEngine::InternalClientUnload(int refnum, int* status)
00441 {
00442     JackClientInterface* client = fClientTable[refnum];
00443     if (client) {
00444         int res = client->Close();
00445         delete client;
00446         *status = 0;
00447         return res;
00448     } else {
00449         *status = (JackNoSuchClient | JackFailure);
00450         return -1;
00451     }
00452 }
00453 
00454 //-------------------
00455 // Client management
00456 //-------------------
00457 
00458 int JackEngine::ClientCheck(const char* name, int uuid, char* name_res, int protocol, int options, int* status)
00459 {
00460     // Clear status
00461     *status = 0;
00462     strcpy(name_res, name);
00463 
00464     jack_log("Check protocol client = %ld server = %ld", protocol, JACK_PROTOCOL_VERSION);
00465 
00466     if (protocol != JACK_PROTOCOL_VERSION) {
00467         *status |= (JackFailure | JackVersionError);
00468         jack_error("JACK protocol mismatch (%d vs %d)", protocol, JACK_PROTOCOL_VERSION);
00469         return -1;
00470     }
00471 
00472     std::map<int,std::string>::iterator res = fReservationMap.find(uuid);
00473 
00474     if (res != fReservationMap.end()) {
00475         strncpy(name_res, res->second.c_str(), JACK_CLIENT_NAME_SIZE);
00476     } else if (ClientCheckName(name)) {
00477 
00478         *status |= JackNameNotUnique;
00479 
00480         if (options & JackUseExactName) {
00481             jack_error("cannot create new client; %s already exists", name);
00482             *status |= JackFailure;
00483             return -1;
00484         }
00485 
00486         if (GenerateUniqueName(name_res)) {
00487             *status |= JackFailure;
00488             return -1;
00489         }
00490     }
00491 
00492     return 0;
00493 }
00494 
00495 bool JackEngine::GenerateUniqueName(char* name)
00496 {
00497     int tens, ones;
00498     int length = strlen(name);
00499 
00500     if (length > JACK_CLIENT_NAME_SIZE - 4) {
00501         jack_error("%s exists and is too long to make unique", name);
00502         return true;            /* failure */
00503     }
00504 
00505     /*  generate a unique name by appending "-01".."-99" */
00506     name[length++] = '-';
00507     tens = length++;
00508     ones = length++;
00509     name[tens] = '0';
00510     name[ones] = '1';
00511     name[length] = '\0';
00512 
00513     while (ClientCheckName(name)) {
00514         if (name[ones] == '9') {
00515             if (name[tens] == '9') {
00516                 jack_error("client %s has 99 extra instances already", name);
00517                 return true; /* give up */
00518             }
00519             name[tens]++;
00520             name[ones] = '0';
00521         } else {
00522             name[ones]++;
00523         }
00524     }
00525     return false;
00526 }
00527 
00528 bool JackEngine::ClientCheckName(const char* name)
00529 {
00530     for (int i = 0; i < CLIENT_NUM; i++) {
00531         JackClientInterface* client = fClientTable[i];
00532         if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) {
00533             return true;
00534         }
00535     }
00536 
00537     for (std::map<int,std::string>::iterator i = fReservationMap.begin(); i != fReservationMap.end(); i++) {
00538         if (i->second == name) {
00539             return true;
00540         }
00541     }
00542 
00543     return false;
00544 }
00545 
00546 int JackEngine::GetNewUUID()
00547 {
00548     return fMaxUUID++;
00549 }
00550 
00551 void JackEngine::EnsureUUID(int uuid)
00552 {
00553     if (uuid > fMaxUUID) {
00554         fMaxUUID = uuid + 1;
00555     }
00556 
00557     for (int i = 0; i < CLIENT_NUM; i++) {
00558         JackClientInterface* client = fClientTable[i];
00559         if (client && (client->GetClientControl()->fSessionID == uuid)) {
00560             client->GetClientControl()->fSessionID = GetNewUUID();
00561         }
00562     }
00563 }
00564 
00565 int JackEngine::GetClientPID(const char* name)
00566 {
00567     for (int i = 0; i < CLIENT_NUM; i++) {
00568         JackClientInterface* client = fClientTable[i];
00569         if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) {
00570             return client->GetClientControl()->fPID;
00571         }
00572     }
00573 
00574     return 0;
00575 }
00576 
00577 int JackEngine::GetClientRefNum(const char* name)
00578 {
00579     for (int i = 0; i < CLIENT_NUM; i++) {
00580         JackClientInterface* client = fClientTable[i];
00581         if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) {
00582             return client->GetClientControl()->fRefNum;
00583         }
00584     }
00585 
00586     return -1;
00587 }
00588 
00589 // Used for external clients
00590 int JackEngine::ClientExternalOpen(const char* name, int pid, int uuid, int* ref, int* shared_engine, int* shared_client, int* shared_graph_manager)
00591 {
00592     char real_name[JACK_CLIENT_NAME_SIZE + 1];
00593 
00594     if (uuid < 0) {
00595         uuid = GetNewUUID();
00596         strncpy(real_name, name, JACK_CLIENT_NAME_SIZE);
00597     } else {
00598         std::map<int, std::string>::iterator res = fReservationMap.find(uuid);
00599         if (res != fReservationMap.end()) {
00600             strncpy(real_name, res->second.c_str(), JACK_CLIENT_NAME_SIZE);
00601             fReservationMap.erase(uuid);
00602         } else {
00603             strncpy(real_name, name, JACK_CLIENT_NAME_SIZE);
00604         }
00605         EnsureUUID(uuid);
00606     }
00607 
00608     jack_log("JackEngine::ClientExternalOpen: uuid = %d, name = %s", uuid, real_name);
00609 
00610     int refnum = AllocateRefnum();
00611     if (refnum < 0) {
00612         jack_error("No more refnum available");
00613         return -1;
00614     }
00615 
00616     JackExternalClient* client = new JackExternalClient();
00617 
00618     if (!fSynchroTable[refnum].Allocate(real_name, fEngineControl->fServerName, 0)) {
00619         jack_error("Cannot allocate synchro");
00620         goto error;
00621     }
00622 
00623     if (client->Open(real_name, pid, refnum, uuid, shared_client) < 0) {
00624         jack_error("Cannot open client");
00625         goto error;
00626     }
00627 
00628     if (!fSignal.LockedTimedWait(DRIVER_OPEN_TIMEOUT * 1000000)) {
00629         // Failure if RT thread is not running (problem with the driver...)
00630         jack_error("Driver is not running");
00631         goto error;
00632     }
00633 
00634     fClientTable[refnum] = client;
00635 
00636     if (NotifyAddClient(client, real_name, refnum) < 0) {
00637         jack_error("Cannot notify add client");
00638         goto error;
00639     }
00640 
00641     fGraphManager->InitRefNum(refnum);
00642     fEngineControl->ResetRollingUsecs();
00643     *shared_engine = fEngineControl->GetShmIndex();
00644     *shared_graph_manager = fGraphManager->GetShmIndex();
00645     *ref = refnum;
00646     return 0;
00647 
00648 error:
00649     // Cleanup...
00650     fSynchroTable[refnum].Destroy();
00651     fClientTable[refnum] = 0;
00652     client->Close();
00653     delete client;
00654     return -1;
00655 }
00656 
00657 // Used for server driver clients
00658 int JackEngine::ClientInternalOpen(const char* name, int* ref, JackEngineControl** shared_engine, JackGraphManager** shared_manager, JackClientInterface* client, bool wait)
00659 {
00660     jack_log("JackEngine::ClientInternalOpen: name = %s", name);
00661 
00662     int refnum = AllocateRefnum();
00663     if (refnum < 0) {
00664         jack_error("No more refnum available");
00665         goto error;
00666     }
00667 
00668     if (!fSynchroTable[refnum].Allocate(name, fEngineControl->fServerName, 0)) {
00669         jack_error("Cannot allocate synchro");
00670         goto error;
00671     }
00672 
00673     if (wait && !fSignal.LockedTimedWait(DRIVER_OPEN_TIMEOUT * 1000000)) {
00674         // Failure if RT thread is not running (problem with the driver...)
00675         jack_error("Driver is not running");
00676         goto error;
00677     }
00678 
00679     fClientTable[refnum] = client;
00680 
00681     if (NotifyAddClient(client, name, refnum) < 0) {
00682         jack_error("Cannot notify add client");
00683         goto error;
00684     }
00685 
00686     fGraphManager->InitRefNum(refnum);
00687     fEngineControl->ResetRollingUsecs();
00688     *shared_engine = fEngineControl;
00689     *shared_manager = fGraphManager;
00690     *ref = refnum;
00691     return 0;
00692 
00693 error:
00694     // Cleanup...
00695     fSynchroTable[refnum].Destroy();
00696     fClientTable[refnum] = 0;
00697     return -1;
00698 }
00699 
00700 // Used for external clients
00701 int JackEngine::ClientExternalClose(int refnum)
00702 {
00703     jack_log("JackEngine::ClientExternalClose ref = %ld", refnum);
00704     JackClientInterface* client = fClientTable[refnum];
00705     assert(client);
00706     int res = ClientCloseAux(refnum, true);
00707     client->Close();
00708     delete client;
00709     return res;
00710 }
00711 
00712 // Used for server internal clients or drivers when the RT thread is stopped
00713 int JackEngine::ClientInternalClose(int refnum, bool wait)
00714 {
00715     jack_log("JackEngine::ClientInternalClose ref = %ld", refnum);
00716     return ClientCloseAux(refnum, wait);
00717 }
00718 
00719 int JackEngine::ClientCloseAux(int refnum, bool wait)
00720 {
00721     jack_log("JackEngine::ClientCloseAux ref = %ld", refnum);
00722     
00723     JackClientInterface* client = fClientTable[refnum];
00724     fEngineControl->fTransport.ResetTimebase(refnum);
00725 
00726     // Unregister all ports ==> notifications are sent
00727     jack_int_t ports[PORT_NUM_FOR_CLIENT];
00728     int i;
00729 
00730     fGraphManager->GetInputPorts(refnum, ports);
00731     for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY); i++) {
00732         PortUnRegister(refnum, ports[i]);
00733     }
00734 
00735     fGraphManager->GetOutputPorts(refnum, ports);
00736     for (i = 0; (i < PORT_NUM_FOR_CLIENT) && (ports[i] != EMPTY); i++) {
00737         PortUnRegister(refnum, ports[i]);
00738     }
00739 
00740     // Remove the client from the table
00741     ReleaseRefnum(refnum);
00742 
00743     // Remove all ports
00744     fGraphManager->RemoveAllPorts(refnum);
00745 
00746     // Wait until next cycle to be sure client is not used anymore
00747     if (wait) {
00748         if (!fSignal.LockedTimedWait(fEngineControl->fTimeOutUsecs * 2)) { // Must wait at least until a switch occurs in Process, even in case of graph end failure
00749             jack_error("JackEngine::ClientCloseAux wait error ref = %ld", refnum);
00750         }
00751     }
00752 
00753     // Notify running clients
00754     NotifyRemoveClient(client->GetClientControl()->fName, refnum);
00755 
00756     // Cleanup...
00757     fSynchroTable[refnum].Destroy();
00758     fEngineControl->ResetRollingUsecs();
00759     return 0;
00760 }
00761 
00762 int JackEngine::ClientActivate(int refnum, bool is_real_time)
00763 {
00764     JackClientInterface* client = fClientTable[refnum];
00765     jack_log("JackEngine::ClientActivate ref = %ld name = %s", refnum, client->GetClientControl()->fName);
00766 
00767     if (is_real_time) {
00768         fGraphManager->Activate(refnum);
00769     }
00770 
00771     // Wait for graph state change to be effective
00772     if (!fSignal.LockedTimedWait(fEngineControl->fTimeOutUsecs * 10)) {
00773         jack_error("JackEngine::ClientActivate wait error ref = %ld name = %s", refnum, client->GetClientControl()->fName);
00774         return -1;
00775     } else {
00776         jack_int_t input_ports[PORT_NUM_FOR_CLIENT];
00777         jack_int_t output_ports[PORT_NUM_FOR_CLIENT];
00778         fGraphManager->GetInputPorts(refnum, input_ports);
00779         fGraphManager->GetOutputPorts(refnum, output_ports);
00780 
00781         // Notify client
00782         NotifyActivate(refnum);
00783 
00784         // Then issue port registration notification
00785         for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) {
00786             NotifyPortRegistation(input_ports[i], true);
00787         }
00788         for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) {
00789             NotifyPortRegistation(output_ports[i], true);
00790         }
00791 
00792         return 0;
00793     }
00794 }
00795 
00796 // May be called without client
00797 int JackEngine::ClientDeactivate(int refnum)
00798 {
00799     JackClientInterface* client = fClientTable[refnum];
00800     jack_log("JackEngine::ClientDeactivate ref = %ld name = %s", refnum, client->GetClientControl()->fName);
00801 
00802     jack_int_t input_ports[PORT_NUM_FOR_CLIENT];
00803     jack_int_t output_ports[PORT_NUM_FOR_CLIENT];
00804     fGraphManager->GetInputPorts(refnum, input_ports);
00805     fGraphManager->GetOutputPorts(refnum, output_ports);
00806 
00807     // First disconnect all ports
00808     for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) {
00809         PortDisconnect(-1, input_ports[i], ALL_PORTS);
00810     }
00811     for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) {
00812         PortDisconnect(-1, output_ports[i], ALL_PORTS);
00813     }
00814 
00815     // Then issue port registration notification
00816     for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (input_ports[i] != EMPTY); i++) {
00817         NotifyPortRegistation(input_ports[i], false);
00818     }
00819     for (int i = 0; (i < PORT_NUM_FOR_CLIENT) && (output_ports[i] != EMPTY); i++) {
00820         NotifyPortRegistation(output_ports[i], false);
00821     }
00822 
00823     fGraphManager->Deactivate(refnum);
00824     fLastSwitchUsecs = 0; // Force switch to occur next cycle, even when called with "dead" clients
00825 
00826     // Wait for graph state change to be effective
00827     if (!fSignal.LockedTimedWait(fEngineControl->fTimeOutUsecs * 10)) {
00828         jack_error("JackEngine::ClientDeactivate wait error ref = %ld name = %s", refnum, client->GetClientControl()->fName);
00829         return -1;
00830     } else {
00831         return 0;
00832     }
00833 }
00834 
00835 void JackEngine::ClientKill(int refnum)
00836 {
00837     jack_log("JackEngine::ClientKill ref = %ld", refnum);
00838     if (ClientDeactivate(refnum) < 0) {
00839         jack_error("JackEngine::ClientKill ref = %ld cannot be removed from the graph !!", refnum);
00840     }
00841     if (ClientExternalClose(refnum) < 0) {
00842         jack_error("JackEngine::ClientKill ref = %ld cannot be closed", refnum);
00843     }
00844 }
00845 
00846 //-----------------
00847 // Port management
00848 //-----------------
00849 
00850 int JackEngine::PortRegister(int refnum, const char* name, const char *type, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index)
00851 {
00852     jack_log("JackEngine::PortRegister ref = %ld name = %s type = %s flags = %d buffer_size = %d", refnum, name, type, flags, buffer_size);
00853     JackClientInterface* client = fClientTable[refnum];
00854 
00855     // Check if port name already exists
00856     if (fGraphManager->GetPort(name) != NO_PORT) {
00857         jack_error("port_name \"%s\" already exists", name);
00858         return -1;
00859     }
00860 
00861     // buffer_size is actually ignored...
00862     *port_index = fGraphManager->AllocatePort(refnum, name, type, (JackPortFlags)flags, fEngineControl->fBufferSize);
00863     if (*port_index != NO_PORT) {
00864         if (client->GetClientControl()->fActive) {
00865             NotifyPortRegistation(*port_index, true);
00866         }
00867         return 0;
00868     } else {
00869         return -1;
00870     }
00871 }
00872 
00873 int JackEngine::PortUnRegister(int refnum, jack_port_id_t port_index)
00874 {
00875     jack_log("JackEngine::PortUnRegister ref = %ld port_index = %ld", refnum, port_index);
00876     JackClientInterface* client = fClientTable[refnum];
00877     assert(client);
00878 
00879     // Disconnect port ==> notification is sent
00880     PortDisconnect(-1, port_index, ALL_PORTS);
00881 
00882     if (fGraphManager->ReleasePort(refnum, port_index) == 0) {
00883         if (client->GetClientControl()->fActive) {
00884             NotifyPortRegistation(port_index, false);
00885         }
00886         return 0;
00887     } else {
00888         return -1;
00889     }
00890 }
00891 
00892 // this check is to prevent apps to self connect to other apps
00893 // TODO: make this work with multiple clients per app
00894 int JackEngine::CheckPortsConnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
00895 {
00896     if (fSelfConnectMode == ' ') return 1;
00897 
00898     JackPort* src_port = fGraphManager->GetPort(src);
00899     JackPort* dst_port = fGraphManager->GetPort(dst);
00900 
00901     jack_log("JackEngine::CheckPortsConnect(ref = %d, src = %d, dst = %d)", refnum, src_port->GetRefNum(), dst_port->GetRefNum());
00902 
00903     //jack_log("%s -> %s", src_port->GetName(), dst_port->GetName());
00904     //jack_log("mode = '%c'", fSelfConnectMode);
00905 
00906     int src_self = src_port->GetRefNum() == refnum ? 1 : 0;
00907     int dst_self = dst_port->GetRefNum() == refnum ? 1 : 0;
00908 
00909     //jack_log("src_self is %s", src_self ? "true" : "false");
00910     //jack_log("dst_self is %s", dst_self ? "true" : "false");
00911 
00912     // 0 means client is connecting other client ports (control app patchbay functionality)
00913     // 1 means client is connecting its own port to port of other client (e.g. self connecting into "system" client)
00914     // 2 means client is connecting its own ports (for app internal functionality)
00915     int sum = src_self + dst_self;
00916     //jack_log("sum = %d", sum);
00917     if (sum == 0) return 1;
00918     char lmode = tolower(fSelfConnectMode);
00919     //jack_log("lmode = '%c'", lmode);
00920     if (sum == 2 && lmode == 'e') return 1;
00921     bool fail = lmode != fSelfConnectMode; // fail modes are upper case
00922     //jack_log("fail = %d", (int)fail);
00923 
00924     jack_info(
00925         "%s port self connect request%s (%s -> %s)",
00926         fail ? "rejecting" : "ignoring",
00927         sum == 1 ? " to external port" : "",
00928         src_port->GetName(),
00929         dst_port->GetName());
00930 
00931     return fail ? -1 : 0;
00932 }
00933 
00934 int JackEngine::PortConnect(int refnum, const char* src, const char* dst)
00935 {
00936     jack_log("JackEngine::PortConnect ref = %d src = %s dst = %s", refnum, src, dst);
00937     jack_port_id_t port_src, port_dst;
00938 
00939     return (fGraphManager->GetTwoPorts(src, dst, &port_src, &port_dst) < 0)
00940            ? -1
00941            : PortConnect(refnum, port_src, port_dst);
00942 }
00943 
00944 int JackEngine::PortConnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
00945 {
00946     jack_log("JackEngine::PortConnect ref = %d src = %d dst = %d", refnum, src, dst);
00947     JackClientInterface* client;
00948     int ref;
00949 
00950     if (fGraphManager->CheckPorts(src, dst) < 0) {
00951         return -1;
00952     }
00953 
00954     ref = fGraphManager->GetOutputRefNum(src);
00955     assert(ref >= 0);
00956     client = fClientTable[ref];
00957     assert(client);
00958     if (!client->GetClientControl()->fActive) {
00959         jack_error("Cannot connect ports owned by inactive clients:"
00960                    " \"%s\" is not active", client->GetClientControl()->fName);
00961         return -1;
00962     }
00963 
00964     ref = fGraphManager->GetInputRefNum(dst);
00965     assert(ref >= 0);
00966     client = fClientTable[ref];
00967     assert(client);
00968     if (!client->GetClientControl()->fActive) {
00969         jack_error("Cannot connect ports owned by inactive clients:"
00970                    " \"%s\" is not active", client->GetClientControl()->fName);
00971         return -1;
00972     }
00973 
00974     int res = CheckPortsConnect(refnum, src, dst);
00975     if (res != 1) {
00976         return res;
00977     }
00978 
00979     res = fGraphManager->Connect(src, dst);
00980     if (res == 0) {
00981         NotifyPortConnect(src, dst, true);
00982     }
00983     return res;
00984 }
00985 
00986 int JackEngine::PortDisconnect(int refnum, const char* src, const char* dst)
00987 {
00988     jack_log("JackEngine::PortDisconnect ref = %d src = %s dst = %s", refnum, src, dst);
00989     jack_port_id_t port_src, port_dst;
00990 
00991     return (fGraphManager->GetTwoPorts(src, dst, &port_src, &port_dst) < 0)
00992            ? -1
00993            : PortDisconnect(refnum, port_src, port_dst);
00994 }
00995 
00996 int JackEngine::PortDisconnect(int refnum, jack_port_id_t src, jack_port_id_t dst)
00997 {
00998     jack_log("JackEngine::PortDisconnect ref = %d src = %d dst = %d", refnum, src, dst);
00999 
01000     if (dst == ALL_PORTS) {
01001 
01002         jack_int_t connections[CONNECTION_NUM_FOR_PORT];
01003         fGraphManager->GetConnections(src, connections);
01004 
01005         JackPort* port = fGraphManager->GetPort(src);
01006         int res = 0;
01007         if (port->GetFlags() & JackPortIsOutput) {
01008             for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && (connections[i] != EMPTY); i++) {
01009                 if (PortDisconnect(refnum, src, connections[i]) != 0) {
01010                     res = -1;
01011                 }
01012             }
01013         } else {
01014             for (int i = 0; (i < CONNECTION_NUM_FOR_PORT) && (connections[i] != EMPTY); i++) {
01015                 if (PortDisconnect(refnum, connections[i], src) != 0) {
01016                     res = -1;
01017                 }
01018             }
01019         }
01020 
01021         return res;
01022     }
01023 
01024     if (fGraphManager->CheckPorts(src, dst) < 0) {
01025         return -1;
01026     }
01027 
01028     int res = CheckPortsConnect(refnum, src, dst);
01029     if (res != 1) {
01030         return res;
01031     }
01032 
01033     res = fGraphManager->Disconnect(src, dst);
01034     if (res == 0)
01035         NotifyPortConnect(src, dst, false);
01036     return res;
01037 }
01038 
01039 int JackEngine::PortRename(int refnum, jack_port_id_t port, const char* name)
01040 {
01041     char old_name[REAL_JACK_PORT_NAME_SIZE];
01042     strcpy(old_name, fGraphManager->GetPort(port)->GetName());
01043     fGraphManager->GetPort(port)->SetName(name);
01044     NotifyPortRename(port, old_name);
01045     return 0;
01046 }
01047 
01048 //--------------------
01049 // Session management
01050 //--------------------
01051 
01052 void JackEngine::SessionNotify(int refnum, const char *target, jack_session_event_type_t type, const char *path, detail::JackChannelTransactionInterface *socket, JackSessionNotifyResult** result)
01053 {
01054     if (fSessionPendingReplies != 0) {
01055         JackSessionNotifyResult res(-1);
01056         res.Write(socket);
01057         jack_log("JackEngine::SessionNotify ... busy");
01058         if (result != NULL) *result = NULL;
01059         return;
01060     }
01061 
01062     for (int i = 0; i < CLIENT_NUM; i++) {
01063         JackClientInterface* client = fClientTable[i];
01064         if (client && (client->GetClientControl()->fSessionID < 0)) {
01065             client->GetClientControl()->fSessionID = GetNewUUID();
01066         }
01067     }
01068     fSessionResult = new JackSessionNotifyResult();
01069 
01070     for (int i = 0; i < CLIENT_NUM; i++) {
01071         JackClientInterface* client = fClientTable[i];
01072         if (client && client->GetClientControl()->fCallback[kSessionCallback]) {
01073 
01074             // check if this is a notification to a specific client.
01075             if (target != NULL && strlen(target) != 0) {
01076                 if (strcmp(target, client->GetClientControl()->fName)) {
01077                     continue;
01078                 }
01079             }
01080 
01081             char path_buf[JACK_PORT_NAME_SIZE];
01082             if (path[strlen(path) - 1] == DIR_SEPARATOR) {
01083                snprintf(path_buf, sizeof path_buf, "%s%s%c", path, client->GetClientControl()->fName, DIR_SEPARATOR);
01084             } else {
01085                snprintf(path_buf, sizeof path_buf, "%s%c%s%c", path, DIR_SEPARATOR, client->GetClientControl()->fName, DIR_SEPARATOR);
01086             }
01087 
01088             int res = JackTools::MkDir(path_buf);
01089             if (res) jack_error("JackEngine::SessionNotify: can not create session directory '%s'", path_buf);
01090 
01091             int result = client->ClientNotify(i, client->GetClientControl()->fName, kSessionCallback, true, path_buf, (int)type, 0);
01092 
01093             if (result == kPendingSessionReply) {
01094                 fSessionPendingReplies += 1;
01095             } else if (result == kImmediateSessionReply) {
01096                 char uuid_buf[JACK_UUID_SIZE];
01097                 snprintf(uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID);
01098                 fSessionResult->fCommandList.push_back(JackSessionCommand(uuid_buf,
01099                                                                         client->GetClientControl()->fName,
01100                                                                         client->GetClientControl()->fSessionCommand,
01101                                                                         client->GetClientControl()->fSessionFlags));
01102             }
01103         }
01104     }
01105 
01106     if (result != NULL) *result = fSessionResult;
01107 
01108     if (fSessionPendingReplies == 0) {
01109         fSessionResult->Write(socket);
01110         if (result == NULL) delete fSessionResult;
01111         fSessionResult = NULL;
01112     } else {
01113         fSessionTransaction = socket;
01114     }
01115 }
01116 
01117 int JackEngine::SessionReply(int refnum)
01118 {
01119     JackClientInterface* client = fClientTable[refnum];
01120     assert(client);
01121     char uuid_buf[JACK_UUID_SIZE];
01122     snprintf(uuid_buf, sizeof(uuid_buf), "%d", client->GetClientControl()->fSessionID);
01123     fSessionResult->fCommandList.push_back(JackSessionCommand(uuid_buf,
01124                                                             client->GetClientControl()->fName,
01125                                                             client->GetClientControl()->fSessionCommand,
01126                                                             client->GetClientControl()->fSessionFlags));
01127     fSessionPendingReplies -= 1;
01128 
01129     if (fSessionPendingReplies == 0) {
01130         fSessionResult->Write(fSessionTransaction);
01131         if (fSessionTransaction != NULL) {
01132             delete fSessionResult;
01133         }
01134         fSessionResult = NULL;
01135     }
01136     
01137     return 0;
01138 }
01139 
01140 int JackEngine::GetUUIDForClientName(const char *client_name, char *uuid_res)
01141 {
01142     for (int i = 0; i < CLIENT_NUM; i++) {
01143         JackClientInterface* client = fClientTable[i];
01144 
01145         if (client && (strcmp(client_name, client->GetClientControl()->fName) == 0)) {
01146             snprintf(uuid_res, JACK_UUID_SIZE, "%d", client->GetClientControl()->fSessionID);
01147             return 0;
01148         }
01149     }
01150     // Did not find name.
01151     return -1;
01152 }
01153 
01154 int JackEngine::GetClientNameForUUID(const char *uuid, char *name_res)
01155 {
01156     for (int i = 0; i < CLIENT_NUM; i++) {
01157         JackClientInterface* client = fClientTable[i];
01158 
01159         if (!client) {
01160             continue;
01161         }
01162 
01163         char uuid_buf[JACK_UUID_SIZE];
01164         snprintf(uuid_buf, JACK_UUID_SIZE, "%d", client->GetClientControl()->fSessionID);
01165 
01166         if (strcmp(uuid,uuid_buf) == 0) {
01167             strncpy(name_res, client->GetClientControl()->fName, JACK_CLIENT_NAME_SIZE);
01168             return 0;
01169         }
01170     }
01171     // Did not find uuid.
01172     return -1;
01173 }
01174 
01175 int JackEngine::ReserveClientName(const char *name, const char *uuid)
01176 {
01177     jack_log("JackEngine::ReserveClientName ( name = %s, uuid = %s )", name, uuid);
01178 
01179     if (ClientCheckName(name)) {
01180         jack_log("name already taken");
01181         return -1;
01182     }
01183 
01184     EnsureUUID(atoi(uuid));
01185     fReservationMap[atoi(uuid)] = name;
01186     return 0;
01187 }
01188 
01189 int JackEngine::ClientHasSessionCallback(const char *name)
01190 {
01191     JackClientInterface* client = NULL;
01192     for (int i = 0; i < CLIENT_NUM; i++) {
01193         client = fClientTable[i];
01194         if (client && (strcmp(client->GetClientControl()->fName, name) == 0)) {
01195             break;
01196         }
01197     }
01198 
01199     if (client) {
01200         return client->GetClientControl()->fCallback[kSessionCallback];
01201      } else {
01202         return -1;
01203     }
01204 }
01205 
01206 } // end of namespace
01207