JackServer.cpp

00001 /*
00002 Copyright (C) 2001 Paul Davis 
00003 Copyright (C) 2004-2006 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 
00039 #ifdef __APPLE_
00040 #include <CoreFoundation/CFNotificationCenter.h>
00041 #endif
00042 
00043 namespace Jack
00044 {
00045 
00046 JackServer* JackServer::fInstance = NULL;
00047 
00048 JackServer::JackServer(bool sync, long timeout, bool rt, long priority, long loopback, bool verbose)
00049 {
00050     JackGlobals::InitServer();
00051     for (int i = 0; i < CLIENT_NUM; i++)
00052         fSynchroTable[i] = JackGlobals::MakeSynchro();
00053     fGraphManager = new JackGraphManager();
00054     fEngineControl = new JackEngineControl();
00055     fSignal = JackGlobals::MakeInterProcessSync();
00056     fEngine = new JackEngine(fGraphManager, fSynchroTable, fEngineControl, fSignal, sync, timeout, rt, priority, verbose);
00057     fFreewheelDriver = new JackThreadedDriver(new JackFreewheelDriver("freewheel", fEngine, fSynchroTable));
00058     fLoopbackDriver = new JackLoopbackDriver("loopback", fEngine, fSynchroTable);
00059     fChannel = JackGlobals::MakeServerChannel();
00060     fState = new JackConnectionManager();
00061     fFreewheel = false;
00062     fSyncMode = sync;
00063     fLoopback = loopback;
00064     fDriverInfo = NULL;
00065     fAudioDriver = NULL;
00066     fInstance = this; // Unique instance
00067         jack_verbose = verbose;
00068 }
00069 
00070 JackServer::~JackServer()
00071 {
00072     for (int i = 0; i < CLIENT_NUM; i++)
00073         delete fSynchroTable[i];
00074     delete fGraphManager;
00075     delete fAudioDriver;
00076     delete fFreewheelDriver;
00077     delete fLoopbackDriver;
00078     delete fEngine;
00079     delete fChannel;
00080     delete fEngineControl;
00081     delete fSignal;
00082     delete fState;
00083     if (fDriverInfo) {
00084         UnloadDriverModule(fDriverInfo->handle);
00085         free(fDriverInfo);
00086     }
00087     JackGlobals::Destroy();
00088 }
00089 
00090 // TODO : better handling of intermediate failing cases...
00091 
00092 int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params)
00093 {
00094     if (fChannel->Open(this) < 0) {
00095         jack_error("Server channel open error");
00096         return -1;
00097     }
00098 
00099     if (fEngine->Open() != 0) {
00100         jack_error("Cannot open engine");
00101         return -1;
00102     }
00103 
00104     if ((fDriverInfo = jack_load_driver(driver_desc)) == NULL) {
00105         return -1;
00106     }
00107 
00108     if ((fAudioDriver = fDriverInfo->initialize(fEngine, fSynchroTable, driver_params)) == NULL) {
00109         jack_error("Cannot initialize driver");
00110         return -1;
00111     }
00112 
00113     if (fFreewheelDriver->Open() != 0) { // before engine open
00114         jack_error("Cannot open driver");
00115         return -1;
00116     }
00117 
00118     // Before engine open
00119     if (fLoopbackDriver->Open(fEngineControl->fBufferSize, fEngineControl->fSampleRate, 1, 1, fLoopback, fLoopback, false, "loopback", "loopback", 0, 0) != 0) {
00120         jack_error("Cannot open driver");
00121         return -1;
00122     }
00123 
00124     if (fAudioDriver->Attach() != 0) {
00125         jack_error("Cannot attach audio driver");
00126         return -1;
00127     }
00128 
00129     if (fLoopback > 0 && fLoopbackDriver->Attach() != 0) {
00130         jack_error("Cannot attach loopback driver");
00131         return -1;
00132     }
00133 
00134     fFreewheelDriver->SetMaster(false);
00135     fAudioDriver->SetMaster(true);
00136     if (fLoopback > 0)
00137         fAudioDriver->AddSlave(fLoopbackDriver);
00138     fAudioDriver->AddSlave(fFreewheelDriver); // After ???
00139     InitTime();
00140 
00141 #ifdef __APPLE__
00142     // Send notification to be used in the Jack Router
00143     CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(),
00144                                          CFSTR("com.grame.jackserver.start"),
00145                                          CFSTR("com.grame.jackserver"),
00146                                          NULL,
00147                                          true);
00148 #endif
00149 
00150     return 0;
00151 }
00152 
00153 int JackServer::Close()
00154 {
00155     JackLog("JackServer::Close\n");
00156     fChannel->Close();
00157     fSignal->Destroy(); // A REVOIR
00158     fAudioDriver->Detach();
00159     if (fLoopback > 0)
00160         fLoopbackDriver->Detach();
00161     fAudioDriver->Close();
00162     fFreewheelDriver->Close();
00163     fLoopbackDriver->Close();
00164     fEngine->Close();
00165 
00166 #ifdef __APPLE__
00167     // Send notification to be used in the Jack Router
00168     CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(),
00169                                          CFSTR("com.grame.jackserver.stop"),
00170                                          CFSTR("com.grame.jackserver"),
00171                                          NULL,
00172                                          true);
00173 #endif
00174 
00175     return 0;
00176 }
00177 
00178 int JackServer::Start()
00179 {
00180     JackLog("JackServer::Start\n");
00181     fEngineControl->InitFrameTime();
00182     return fAudioDriver->Start();
00183 }
00184 
00185 int JackServer::Stop()
00186 {
00187     JackLog("JackServer::Stop\n");
00188     return fAudioDriver->Stop();
00189 }
00190 
00191 int JackServer::Activate(int refnum)
00192 {
00193         int fw_refnum = fFreewheelDriver->GetClientControl()->fRefNum;
00194     fGraphManager->DirectConnect(fw_refnum, refnum);
00195     fGraphManager->DirectConnect(refnum, fw_refnum);
00196     return fEngine->ClientActivate(refnum);
00197 }
00198 
00199 // Disconnection from the FW must be done in last otherwise an intermediate "unconnected"
00200 // (thus unactivated) state may happen where the client is still checked for its end.
00201 int JackServer::Deactivate(int refnum)
00202 {
00203     int res = fEngine->ClientDeactivate(refnum);
00204         int fw_refnum = fFreewheelDriver->GetClientControl()->fRefNum;
00205 
00206     // Disconnect only when needed
00207     if (fGraphManager->IsDirectConnection(refnum, fw_refnum)) {
00208         fGraphManager->DirectDisconnect(refnum, fw_refnum);
00209     } else {
00210         JackLog("JackServer::Deactivate: client = %ld was not activated \n", refnum);
00211     }
00212 
00213         // Disconnect only when needed
00214     if (fGraphManager->IsDirectConnection(fw_refnum, refnum)) {
00215         fGraphManager->DirectDisconnect(fw_refnum, refnum);
00216     } else {
00217         JackLog("JackServer::Deactivate: client = %ld was not activated \n", refnum);
00218     }
00219 
00220     return res;
00221 }
00222 
00223 int JackServer::SetBufferSize(jack_nframes_t buffer_size)
00224 {
00225     JackLog("JackServer::SetBufferSize nframes = %ld\n", buffer_size);
00226         jack_nframes_t current_buffer_size = fEngineControl->fBufferSize;
00227 
00228     if (fAudioDriver->Stop() != 0) {
00229         jack_error("Cannot stop audio driver");
00230         return -1;
00231     }
00232 
00233     if (fAudioDriver->SetBufferSize(buffer_size) == 0) {
00234                 fFreewheelDriver->SetBufferSize(buffer_size);
00235                 fEngine->NotifyBufferSize(buffer_size);
00236                 fEngineControl->InitFrameTime();
00237                 return fAudioDriver->Start();
00238         } else { // Failure: restore current value
00239                 jack_error("Cannot SetBufferSize for audio driver, restore current value %ld", current_buffer_size);
00240                 fFreewheelDriver->SetBufferSize(current_buffer_size);
00241                 fEngineControl->InitFrameTime();
00242                 return fAudioDriver->Start();
00243         }
00244 }
00245 
00246 /*
00247 Freewheel mode is implemented by switching from the (audio + freewheel) driver to the freewheel driver only:
00248  
00249     - "global" connection state is saved
00250     - all audio driver ports are deconnected, thus there is no more dependancies with the audio driver
00251     - the freewheel driver will be synchronized with the end of graph execution : all clients are connected to the freewheel driver
00252     - the freewheel driver becomes the "master"
00253     
00254 Normal mode is restored with the connections state valid before freewheel mode was done. Thus one consider that 
00255 no graph state change can be done during freewheel mode.
00256 */
00257 
00258 int JackServer::SetFreewheel(bool onoff)
00259 {
00260     JackLog("JackServer::SetFreewheel state = %ld\n", onoff);
00261 
00262     if (fFreewheel) {
00263         if (onoff) {
00264             return -1;
00265         } else {
00266             fFreewheel = false;
00267             fFreewheelDriver->Stop();
00268             fGraphManager->Restore(fState);   // Restore previous connection state
00269             fEngine->NotifyFreewheel(onoff);
00270             fFreewheelDriver->SetMaster(false);
00271             fEngineControl->InitFrameTime();
00272             return fAudioDriver->Start();
00273         }
00274     } else {
00275         if (onoff) {
00276             fFreewheel = true;
00277             fAudioDriver->Stop();
00278             fGraphManager->Save(fState);     // Save connection state
00279             fGraphManager->DisconnectAllPorts(fAudioDriver->GetClientControl()->fRefNum);
00280             fEngine->NotifyFreewheel(onoff);
00281             fFreewheelDriver->SetMaster(true);
00282             return fFreewheelDriver->Start();
00283         } else {
00284             return -1;
00285         }
00286     }
00287 }
00288 
00289 // Coming from the RT thread or server channel
00290 void JackServer::Notify(int refnum, int notify, int value)
00291 {
00292     switch (notify) {
00293 
00294         case JackNotifyChannelInterface::kGraphOrderCallback:
00295             fEngine->NotifyGraphReorder();
00296             break;
00297 
00298         case JackNotifyChannelInterface::kXRunCallback:
00299             fEngine->NotifyXRun(refnum);
00300             break;
00301 
00302         case JackNotifyChannelInterface::kZombifyClient:
00303             fEngine->ZombifyClient(refnum);
00304             break;
00305 
00306         case JackNotifyChannelInterface::kDeadClient:
00307             JackLog("JackServer: kDeadClient ref = %ld\n", refnum);
00308             Deactivate(refnum);
00309             fEngine->ClientClose(refnum);
00310             break;
00311     }
00312 }
00313 
00314 JackEngine* JackServer::GetEngine()
00315 {
00316     return fEngine;
00317 }
00318 
00319 JackSynchro** JackServer::GetSynchroTable()
00320 {
00321     return fSynchroTable;
00322 }
00323 
00324 JackEngineControl* JackServer::GetEngineControl()
00325 {
00326     return fEngineControl;
00327 }
00328 
00329 JackGraphManager* JackServer::GetGraphManager()
00330 {
00331     return fGraphManager;
00332 }
00333 
00334 void JackServer::PrintState()
00335 {
00336     fAudioDriver->PrintState();
00337     fEngine->PrintState();
00338 }
00339 
00340 } // end of namespace
00341 

Generated on Wed Jan 10 11:42:46 2007 for Jackdmp by  doxygen 1.4.5