Jack2 1.9.8

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