JackServer.cpp

00001 /*
00002 Copyright (C) 2001 Paul Davis 
00003 Copyright (C) 2004-2008 Grame
00004 
00005 This program is free software; you can redistribute it and/or modify
00006 it under the terms of the GNU General Public License as published by
00007 the Free Software Foundation; either version 2 of the License, or
00008 (at your option) any later version.
00009 
00010 This program is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 GNU General Public License for more details.
00014 
00015 You should have received a copy of the GNU General Public License
00016 along with this program; if not, write to the Free Software
00017 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 
00019 */
00020 
00021 #ifdef WIN32 
00022 #pragma warning (disable : 4786)
00023 #endif
00024 
00025 #include "JackServer.h"
00026 #include "JackTime.h"
00027 #include "JackFreewheelDriver.h"
00028 #include "JackLoopbackDriver.h"
00029 #include "JackThreadedDriver.h"
00030 #include "JackGlobals.h"
00031 #include "JackEngine.h"
00032 #include "JackAudioDriver.h"
00033 #include "JackChannel.h"
00034 #include "JackClientControl.h"
00035 #include "JackEngineControl.h"
00036 #include "JackSyncInterface.h"
00037 #include "JackGraphManager.h"
00038 #include "JackInternalClient.h"
00039 
00040 namespace Jack
00041 {
00042 
00043 JackServer* JackServer::fInstance = NULL;
00044 
00045 JackServer::JackServer(bool sync,  bool temporary, long timeout, bool rt, long priority, long loopback, bool verbose, const char* server_name)
00046 {
00047     JackGlobals::InitServer();
00048     for (int i = 0; i < CLIENT_NUM; i++)
00049         fSynchroTable[i] = JackGlobals::MakeSynchro();
00050     fGraphManager = new JackGraphManager();
00051     fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, server_name);
00052     fEngine = new JackEngine(fGraphManager, fSynchroTable, fEngineControl);
00053     fFreewheelDriver = new JackThreadedDriver(new JackFreewheelDriver("freewheel", fEngine, fSynchroTable));
00054     fLoopbackDriver = new JackLoopbackDriver("loopback", fEngine, fSynchroTable);
00055     fChannel = JackGlobals::MakeServerChannel();
00056         fFreewheel = false;
00057     fLoopback = loopback;
00058     fDriverInfo = NULL;
00059     fAudioDriver = NULL;
00060     fInstance = this; // Unique instance
00061         jack_verbose = verbose;
00062 }
00063 
00064 JackServer::~JackServer()
00065 {
00066     for (int i = 0; i < CLIENT_NUM; i++)
00067         delete fSynchroTable[i];
00068     delete fGraphManager;
00069     delete fAudioDriver;
00070     delete fFreewheelDriver;
00071     delete fLoopbackDriver;
00072     delete fEngine;
00073     delete fChannel;
00074     delete fEngineControl;
00075     if (fDriverInfo) {
00076         UnloadDriverModule(fDriverInfo->handle);
00077         free(fDriverInfo);
00078     }
00079     JackGlobals::Destroy();
00080 }
00081 
00082 // TODO : better handling of intermediate failing cases...
00083 
00084 int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params)
00085 {
00086     if (fChannel->Open(fEngineControl->fServerName, this) < 0) {
00087         jack_error("Server channel open error");
00088         return -1;
00089     }
00090 
00091     if (fEngine->Open() != 0) {
00092         jack_error("Cannot open engine");
00093         return -1;
00094     }
00095 
00096     if ((fDriverInfo = jack_load_driver(driver_desc)) == NULL) {
00097         return -1;
00098     }
00099 
00100     if ((fAudioDriver = fDriverInfo->initialize(fEngine, fSynchroTable, driver_params)) == NULL) {
00101         jack_error("Cannot initialize driver");
00102         return -1;
00103     }
00104 
00105     if (fFreewheelDriver->Open() != 0) { // before engine open
00106         jack_error("Cannot open driver");
00107         return -1;
00108     }
00109 
00110     // Before engine open
00111     if (fLoopbackDriver->Open(fEngineControl->fBufferSize, fEngineControl->fSampleRate, 1, 1, fLoopback, fLoopback, false, "loopback", "loopback", 0, 0) != 0) {
00112         jack_error("Cannot open driver");
00113         return -1;
00114     }
00115 
00116     if (fAudioDriver->Attach() != 0) {
00117         jack_error("Cannot attach audio driver");
00118         return -1;
00119     }
00120         
00121     if (fLoopback > 0 && fLoopbackDriver->Attach() != 0) {
00122         jack_error("Cannot attach loopback driver");
00123         return -1;
00124     }
00125 
00126     fFreewheelDriver->SetMaster(false);
00127     fAudioDriver->SetMaster(true);
00128     if (fLoopback > 0)
00129         fAudioDriver->AddSlave(fLoopbackDriver);
00130     fAudioDriver->AddSlave(fFreewheelDriver); // After ???
00131     InitTime();
00132     return 0;
00133 }
00134 
00135 int JackServer::Close()
00136 {
00137     JackLog("JackServer::Close\n");
00138     fChannel->Close();
00139     fAudioDriver->Detach();
00140     if (fLoopback > 0)
00141         fLoopbackDriver->Detach();
00142     fAudioDriver->Close();
00143     fFreewheelDriver->Close();
00144     fLoopbackDriver->Close();
00145     fEngine->Close();
00146     return 0;
00147 }
00148 
00149 int JackServer::InternalClientLoad(const char* client_name, const char* so_name, const char* objet_data, int options, int* int_ref, int* status)
00150 {
00151         try {
00152                 // Clear status
00153                 *status = 0;
00154                 JackLoadableInternalClient* client = new JackLoadableInternalClient(fInstance, GetSynchroTable(), so_name, objet_data); 
00155                 assert(client);
00156                 int res = client->Open("unused", client_name, (jack_options_t)options, (jack_status_t*)status);
00157                 if (res < 0) {
00158                         delete client;
00159                         *int_ref = 0;
00160                 } else {
00161                         *int_ref = client->GetClientControl()->fRefNum;
00162                 }
00163         } catch (...) {
00164                 int my_status1 = *status | JackFailure;
00165                 *status = (jack_status_t)my_status1;
00166                 *int_ref = 0;
00167         }
00168         
00169         return 0;
00170 }
00171 
00172 int JackServer::Start()
00173 {
00174     JackLog("JackServer::Start\n");
00175     fEngineControl->InitFrameTime();
00176     return fAudioDriver->Start();
00177 }
00178 
00179 int JackServer::Stop()
00180 {
00181     JackLog("JackServer::Stop\n");
00182     return fAudioDriver->Stop();
00183 }
00184 
00185 int JackServer::SetBufferSize(jack_nframes_t buffer_size)
00186 {
00187     JackLog("JackServer::SetBufferSize nframes = %ld\n", buffer_size);
00188         jack_nframes_t current_buffer_size = fEngineControl->fBufferSize;
00189 
00190     if (fAudioDriver->Stop() != 0) {
00191         jack_error("Cannot stop audio driver");
00192         return -1;
00193     }
00194 
00195     if (fAudioDriver->SetBufferSize(buffer_size) == 0) {
00196                 fFreewheelDriver->SetBufferSize(buffer_size);
00197                 fEngine->NotifyBufferSize(buffer_size);
00198                 fEngineControl->InitFrameTime();
00199                 return fAudioDriver->Start();
00200         } else { // Failure: try to restore current value
00201                 jack_error("Cannot SetBufferSize for audio driver, restore current value %ld", current_buffer_size);
00202                 fFreewheelDriver->SetBufferSize(current_buffer_size);
00203                 fEngineControl->InitFrameTime();
00204                 return fAudioDriver->Start();
00205         }
00206 }
00207 
00208 /*
00209 Freewheel mode is implemented by switching from the (audio + freewheel) driver to the freewheel driver only:
00210  
00211     - "global" connection state is saved
00212     - all audio driver ports are deconnected, thus there is no more dependancies with the audio driver
00213     - the freewheel driver will be synchronized with the end of graph execution : all clients are connected to the freewheel driver
00214     - the freewheel driver becomes the "master"
00215     
00216 Normal mode is restored with the connections state valid before freewheel mode was done. Thus one consider that 
00217 no graph state change can be done during freewheel mode.
00218 */
00219 
00220 int JackServer::SetFreewheel(bool onoff)
00221 {
00222     JackLog("JackServer::SetFreewheel state = %ld\n", onoff);
00223 
00224     if (fFreewheel) {
00225         if (onoff) {
00226             return -1;
00227         } else {
00228             fFreewheel = false;
00229             fFreewheelDriver->Stop();
00230             fGraphManager->Restore(&fConnectionState);   // Restore previous connection state
00231             fEngine->NotifyFreewheel(onoff);
00232             fFreewheelDriver->SetMaster(false);
00233             fEngineControl->InitFrameTime();
00234                         return fAudioDriver->Start();
00235         }
00236     } else {
00237         if (onoff) {
00238             fFreewheel = true;
00239             fAudioDriver->Stop();
00240             fGraphManager->Save(&fConnectionState);     // Save connection state
00241             fGraphManager->DisconnectAllPorts(fAudioDriver->GetClientControl()->fRefNum);
00242             fEngine->NotifyFreewheel(onoff);
00243             fFreewheelDriver->SetMaster(true);
00244                         return fFreewheelDriver->Start();
00245         } else {
00246             return -1;
00247         }
00248     }
00249 }
00250 
00251 // Coming from the RT thread or server channel
00252 void JackServer::Notify(int refnum, int notify, int value)
00253 {
00254     switch (notify) {
00255 
00256         case kGraphOrderCallback:
00257             fEngine->NotifyGraphReorder();
00258             break;
00259 
00260         case kXRunCallback:
00261             fEngine->NotifyXRun(refnum);
00262             break;
00263 
00264         case kDeadClient:
00265             JackLog("JackServer: kDeadClient ref = %ld\n", refnum);
00266                         if (fEngine->ClientDeactivate(refnum) < 0)
00267                                 jack_error("JackServer: DeadClient ref = %ld cannot be removed from the graph !!", refnum);
00268                         fEngine->ClientExternalClose(refnum);
00269                         break;
00270     }
00271 }
00272 
00273 //----------------------
00274 // Transport management
00275 //----------------------
00276 
00277 int JackServer::ReleaseTimebase(int refnum)
00278 {
00279     return fEngineControl->fTransport.ResetTimebase(refnum);
00280 }
00281 
00282 int JackServer::SetTimebaseCallback(int refnum, int conditional)
00283 {
00284     return fEngineControl->fTransport.SetTimebase(refnum, conditional);
00285 }
00286 
00287 JackEngine* JackServer::GetEngine()
00288 {
00289     return fEngine;
00290 }
00291 
00292 JackSynchro** JackServer::GetSynchroTable()
00293 {
00294     return fSynchroTable;
00295 }
00296 
00297 JackEngineControl* JackServer::GetEngineControl()
00298 {
00299     return fEngineControl;
00300 }
00301 
00302 JackGraphManager* JackServer::GetGraphManager()
00303 {
00304     return fGraphManager;
00305 }
00306 
00307 } // end of namespace
00308 

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