Jack2 1.9.10

JackLibClient.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 Lesser General Public License as published by
00006 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
00013 
00014 You should have received a copy of the GNU Lesser General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 
00018 */
00019 
00020 #include "JackLibClient.h"
00021 #include "JackTime.h"
00022 #include "JackLibGlobals.h"
00023 #include "JackGlobals.h"
00024 #include "JackPlatformPlug.h"
00025 #include "JackTools.h"
00026 
00027 namespace Jack
00028 {
00029 
00030 // Used for external C API (JackAPI.cpp)
00031 JackGraphManager* GetGraphManager()
00032 {
00033     if (JackLibGlobals::fGlobals) {
00034         return JackLibGlobals::fGlobals->fGraphManager;
00035     } else {
00036         return NULL;
00037     }
00038 }
00039 
00040 JackEngineControl* GetEngineControl()
00041 {
00042     if (JackLibGlobals::fGlobals) {
00043         return JackLibGlobals::fGlobals->fEngineControl;
00044     } else {
00045         return NULL;
00046     }
00047 }
00048 
00049 JackSynchro* GetSynchroTable()
00050 {
00051     return (JackLibGlobals::fGlobals ? JackLibGlobals::fGlobals->fSynchroTable : 0);
00052 }
00053 
00054 //-------------------
00055 // Client management
00056 //-------------------
00057 
00058 /*
00059 ShutDown is called:
00060 - from the RT thread when Execute method fails
00061 - possibly from a "closed" notification channel
00062 (Not needed since the synch object used (Sema of Fifo will fails when server quits... see ShutDown))
00063 */
00064 
00065 void JackLibClient::ShutDown(jack_status_t code, const char* message)
00066 {
00067     jack_log("JackLibClient::ShutDown");
00068     JackGlobals::fServerRunning = false;
00069     JackClient::ShutDown(code, message);
00070 }
00071 
00072 JackLibClient::JackLibClient(JackSynchro* table): JackClient(table)
00073 {
00074     jack_log("JackLibClient::JackLibClient table = %x", table);
00075     fChannel = new JackClientChannel();
00076 }
00077 
00078 JackLibClient::~JackLibClient()
00079 {
00080     jack_log("JackLibClient::~JackLibClient");
00081     delete fChannel;
00082 }
00083 
00084 int JackLibClient::Open(const char* server_name, const char* name, int uuid, jack_options_t options, jack_status_t* status)
00085 {
00086     int shared_engine, shared_client, shared_graph, result;
00087     bool res;
00088     jack_log("JackLibClient::Open name = %s", name);
00089     
00090     if (strlen(name) >= JACK_CLIENT_NAME_SIZE) {
00091         jack_error("\"%s\" is too long to be used as a JACK client name.\n"
00092                    "Please use %lu characters or less",
00093                    name,
00094                    JACK_CLIENT_NAME_SIZE - 1);
00095         return -1; 
00096     }
00097     
00098     strncpy(fServerName, server_name, sizeof(fServerName));
00099 
00100     // Open server/client channel
00101     char name_res[JACK_CLIENT_NAME_SIZE + 1];
00102     if (fChannel->Open(server_name, name, uuid, name_res, this, options, status) < 0) {
00103         jack_error("Cannot connect to the server");
00104         goto error;
00105     }
00106 
00107     // Start receiving notifications
00108     if (fChannel->Start() < 0) {
00109         jack_error("Cannot start channel");
00110         goto error;
00111     }
00112 
00113     // Require new client
00114     fChannel->ClientOpen(name_res, JackTools::GetPID(), uuid, &shared_engine, &shared_client, &shared_graph, &result);
00115     if (result < 0) {
00116         jack_error("Cannot open %s client", name_res);
00117         goto error;
00118     }
00119 
00120     try {
00121         // Map shared memory segments
00122         JackLibGlobals::fGlobals->fEngineControl.SetShmIndex(shared_engine, fServerName);
00123         JackLibGlobals::fGlobals->fGraphManager.SetShmIndex(shared_graph, fServerName);
00124         fClientControl.SetShmIndex(shared_client, fServerName);
00125         JackGlobals::fVerbose = GetEngineControl()->fVerbose;
00126     } catch (...) {
00127         jack_error("Map shared memory segments exception");
00128         goto error;
00129     }
00130 
00131     SetupDriverSync(false);
00132 
00133     // Connect shared synchro : the synchro must be usable in I/O mode when several clients live in the same process
00134     assert(JackGlobals::fSynchroMutex);
00135     JackGlobals::fSynchroMutex->Lock();
00136     res = fSynchroTable[GetClientControl()->fRefNum].Connect(name_res, fServerName);
00137     JackGlobals::fSynchroMutex->Unlock();
00138     if (!res) {
00139         jack_error("Cannot ConnectSemaphore %s client", name_res);
00140         goto error;
00141     }
00142 
00143     JackGlobals::fClientTable[GetClientControl()->fRefNum] = this;
00144     SetClockSource(GetEngineControl()->fClockSource);
00145     jack_log("JackLibClient::Open name = %s refnum = %ld", name_res, GetClientControl()->fRefNum);
00146     return 0;
00147 
00148 error:
00149     fChannel->Stop();
00150     fChannel->Close();
00151     return -1;
00152 }
00153 
00154 // Notifications received from the server
00155 // TODO this should be done once for all clients in the process, when a shared notification channel
00156 // will be shared by all clients...
00157 int JackLibClient::ClientNotifyImp(int refnum, const char* name, int notify, int sync, const char* message, int value1, int value2)
00158 {
00159     int res = 0;
00160     assert(JackGlobals::fSynchroMutex);
00161     JackGlobals::fSynchroMutex->Lock();
00162 
00163     // Done all time
00164     switch (notify) {
00165 
00166         case kAddClient:
00167             jack_log("JackClient::AddClient name = %s, ref = %ld ", name, refnum);
00168             // the synchro must be usable in I/O mode when several clients live in the same process
00169             res = fSynchroTable[refnum].Connect(name, fServerName) ? 0 : -1;
00170             break;
00171 
00172         case kRemoveClient:
00173             jack_log("JackClient::RemoveClient name = %s, ref = %ld ", name, refnum);
00174             if (GetClientControl() && strcmp(GetClientControl()->fName, name) != 0) {
00175                 res = fSynchroTable[refnum].Disconnect() ? 0 : -1;
00176             }
00177             break;
00178     }
00179 
00180     JackGlobals::fSynchroMutex->Unlock();
00181     return res;
00182 }
00183 
00184 JackGraphManager* JackLibClient::GetGraphManager() const
00185 {
00186     assert(JackLibGlobals::fGlobals->fGraphManager);
00187     return JackLibGlobals::fGlobals->fGraphManager;
00188 }
00189 
00190 JackEngineControl* JackLibClient::GetEngineControl() const
00191 {
00192     assert(JackLibGlobals::fGlobals->fEngineControl);
00193     return JackLibGlobals::fGlobals->fEngineControl;
00194 }
00195 
00196 JackClientControl* JackLibClient::GetClientControl() const
00197 {
00198     return fClientControl;
00199 }
00200 
00201 } // end of namespace
00202 
00203 
00204