Jack2  1.9.10
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 #include "JackSystemDeps.h"
00022 #include "JackServerGlobals.h"
00023 #include "JackTime.h"
00024 #include "JackFreewheelDriver.h"
00025 #include "JackThreadedDriver.h"
00026 #include "JackGlobals.h"
00027 #include "JackLockedEngine.h"
00028 #include "JackAudioDriver.h"
00029 #include "JackChannel.h"
00030 #include "JackClientControl.h"
00031 #include "JackEngineControl.h"
00032 #include "JackGraphManager.h"
00033 #include "JackInternalClient.h"
00034 #include "JackError.h"
00035 #include "JackMessageBuffer.h"
00036 
00037 const char * jack_get_self_connect_mode_description(char mode);
00038 
00039 namespace Jack
00040 {
00041 
00042 //----------------
00043 // Server control 
00044 //----------------
00045 JackServer::JackServer(bool sync, bool temporary, int timeout, bool rt, int priority, int port_max, bool verbose, jack_timer_type_t clock, char self_connect_mode, const char* server_name)
00046 {
00047     if (rt) {
00048         jack_info("JACK server starting in realtime mode with priority %ld", priority);
00049     } else {
00050         jack_info("JACK server starting in non-realtime mode");
00051     }
00052 
00053     jack_info("self-connect-mode is \"%s\"", jack_get_self_connect_mode_description(self_connect_mode));
00054 
00055     fGraphManager = JackGraphManager::Allocate(port_max);
00056     fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, clock, server_name);
00057     fEngine = new JackLockedEngine(fGraphManager, GetSynchroTable(), fEngineControl, self_connect_mode);
00058 
00059     // A distinction is made between the threaded freewheel driver and the
00060     // regular freewheel driver because the freewheel driver needs to run in
00061     // threaded mode when freewheel mode is active and needs to run as a slave
00062     // when freewheel mode isn't active.
00063     JackFreewheelDriver* freewheelDriver = new JackFreewheelDriver(fEngine, GetSynchroTable());
00064     fThreadedFreewheelDriver = new JackThreadedDriver(freewheelDriver);
00065 
00066     fFreewheelDriver = freewheelDriver;
00067     fDriverInfo = new JackDriverInfo();
00068     fAudioDriver = NULL;
00069     fFreewheel = false;
00070     JackServerGlobals::fInstance = this;   // Unique instance
00071     JackServerGlobals::fUserCount = 1;     // One user
00072     JackGlobals::fVerbose = verbose;
00073 }
00074 
00075 JackServer::~JackServer()
00076 {
00077     JackGraphManager::Destroy(fGraphManager);
00078     delete fDriverInfo;
00079     delete fThreadedFreewheelDriver;
00080     delete fEngine;
00081     delete fEngineControl;
00082 }
00083 
00084 int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params)
00085 {
00086     // TODO: move that in reworked JackServerGlobals::Init()
00087     if (!JackMessageBuffer::Create()) {
00088         jack_error("Cannot create message buffer");
00089     }
00090 
00091      if ((fAudioDriver = fDriverInfo->Open(driver_desc, fEngine, GetSynchroTable(), driver_params)) == NULL) {
00092         jack_error("Cannot initialize driver");
00093         goto fail_close1;
00094     }
00095 
00096     if (fRequestChannel.Open(fEngineControl->fServerName, this) < 0) {
00097         jack_error("Server channel open error");
00098         goto fail_close2;
00099     }
00100 
00101     if (fEngine->Open() < 0) {
00102         jack_error("Cannot open engine");
00103         goto fail_close3;
00104     }
00105 
00106     if (fFreewheelDriver->Open() < 0) {
00107         jack_error("Cannot open freewheel driver");
00108         goto fail_close4;
00109     }
00110 
00111     if (fAudioDriver->Attach() < 0) {
00112         jack_error("Cannot attach audio driver");
00113         goto fail_close5;
00114     }
00115 
00116     fFreewheelDriver->SetMaster(false);
00117     fAudioDriver->SetMaster(true);
00118     fAudioDriver->AddSlave(fFreewheelDriver);
00119     InitTime();
00120     SetClockSource(fEngineControl->fClockSource);
00121     return 0;
00122 
00123 fail_close5:
00124     fFreewheelDriver->Close();
00125 
00126 fail_close4:
00127     fEngine->Close();
00128 
00129 fail_close3:
00130     fRequestChannel.Close();
00131 
00132 fail_close2:
00133     fAudioDriver->Close();
00134 
00135 fail_close1:
00136     JackMessageBuffer::Destroy();
00137     return -1;
00138 }
00139 
00140 int JackServer::Close()
00141 {
00142     jack_log("JackServer::Close");
00143     fRequestChannel.Close();
00144     fAudioDriver->Detach();
00145     fAudioDriver->Close();
00146     fFreewheelDriver->Close();
00147     fEngine->Close();
00148     // TODO: move that in reworked JackServerGlobals::Destroy()
00149     JackMessageBuffer::Destroy();
00150     EndTime();
00151     return 0;
00152 }
00153 
00154 int JackServer::Start()
00155 {
00156     jack_log("JackServer::Start");
00157     if (fAudioDriver->Start() < 0) {
00158         return -1;
00159     }
00160     return fRequestChannel.Start();
00161 }
00162 
00163 int JackServer::Stop()
00164 {
00165     jack_log("JackServer::Stop");
00166     int res = -1;
00167     
00168     if (fFreewheel) {
00169         if (fThreadedFreewheelDriver) {
00170             res = fThreadedFreewheelDriver->Stop();
00171         }
00172     } else {
00173         if (fAudioDriver) {
00174             res = fAudioDriver->Stop();
00175         }
00176     }
00177     
00178     fEngine->NotifyQuit();
00179     fRequestChannel.Stop();
00180     fEngine->NotifyFailure(JackFailure | JackServerError, JACK_SERVER_FAILURE);
00181     
00182     return res;
00183 }
00184 
00185 bool JackServer::IsRunning()
00186 {
00187     jack_log("JackServer::IsRunning");
00188     assert(fAudioDriver);
00189     return fAudioDriver->IsRunning();
00190 }
00191 
00192 //------------------
00193 // Internal clients 
00194 //------------------
00195 
00196 int JackServer::InternalClientLoad1(const char* client_name, const char* so_name, const char* objet_data, int options, int* int_ref, int uuid, int* status)
00197 {
00198     JackLoadableInternalClient* client = new JackLoadableInternalClient1(JackServerGlobals::fInstance, GetSynchroTable(), objet_data);
00199     assert(client);
00200     return InternalClientLoadAux(client, so_name, client_name, options, int_ref, uuid, status);
00201  }
00202 
00203 int JackServer::InternalClientLoad2(const char* client_name, const char* so_name, const JSList * parameters, int options, int* int_ref, int uuid, int* status)
00204 {
00205     JackLoadableInternalClient* client = new JackLoadableInternalClient2(JackServerGlobals::fInstance, GetSynchroTable(), parameters);
00206     assert(client);
00207     return InternalClientLoadAux(client, so_name, client_name, options, int_ref, uuid, status);
00208 }
00209 
00210 int JackServer::InternalClientLoadAux(JackLoadableInternalClient* client, const char* so_name, const char* client_name, int options, int* int_ref, int uuid, int* status)
00211 {
00212     // Clear status
00213     *status = 0;
00214 
00215     // Client object is internally kept in JackEngine
00216     if ((client->Init(so_name) < 0) || (client->Open(JackTools::DefaultServerName(), client_name,  uuid, (jack_options_t)options, (jack_status_t*)status) < 0)) {
00217         delete client;
00218         int my_status1 = *status | JackFailure;
00219         *status = (jack_status_t)my_status1;
00220         *int_ref = 0;
00221         return -1;
00222     } else {
00223         *int_ref = client->GetClientControl()->fRefNum;
00224         return 0;
00225     }
00226  }
00227 
00228 //---------------------------
00229 // From request thread : API 
00230 //---------------------------
00231 
00232 int JackServer::SetBufferSize(jack_nframes_t buffer_size)
00233 {
00234     jack_log("JackServer::SetBufferSize nframes = %ld", buffer_size);
00235     jack_nframes_t current_buffer_size = fEngineControl->fBufferSize;
00236 
00237     if (current_buffer_size == buffer_size) {
00238         jack_log("SetBufferSize: requirement for new buffer size equals current value");
00239         return 0;
00240     }
00241 
00242     if (fAudioDriver->IsFixedBufferSize()) {
00243         jack_log("SetBufferSize: driver only supports a fixed buffer size");
00244         return -1;
00245     }
00246 
00247     if (fAudioDriver->Stop() != 0) {
00248         jack_error("Cannot stop audio driver");
00249         return -1;
00250     }
00251 
00252     if (fAudioDriver->SetBufferSize(buffer_size) == 0) {
00253         fEngine->NotifyBufferSize(buffer_size);
00254         return fAudioDriver->Start();
00255     } else { // Failure: try to restore current value
00256         jack_error("Cannot SetBufferSize for audio driver, restore current value %ld", current_buffer_size);
00257         fAudioDriver->SetBufferSize(current_buffer_size);
00258         fAudioDriver->Start();
00259         // SetBufferSize actually failed, so return an error...
00260         return -1;
00261     }
00262 }
00263 
00264 /*
00265 Freewheel mode is implemented by switching from the (audio [slaves] + freewheel) driver to the freewheel driver only:
00266 
00267     - "global" connection state is saved
00268     - all audio driver and slaves ports are deconnected, thus there is no more dependancies with the audio driver and slaves
00269     - the freewheel driver will be synchronized with the end of graph execution : all clients are connected to the freewheel driver
00270     - the freewheel driver becomes the "master"
00271 
00272 Normal mode is restored with the connections state valid before freewheel mode was done. Thus one consider that
00273 no graph state change can be done during freewheel mode.
00274 */
00275 
00276 int JackServer::SetFreewheel(bool onoff)
00277 {
00278     jack_log("JackServer::SetFreewheel is = %ld want = %ld", fFreewheel, onoff);
00279 
00280     if (fFreewheel) {
00281         if (onoff) {
00282             return -1;
00283         } else {
00284             fFreewheel = false;
00285             fThreadedFreewheelDriver->Stop();
00286             fGraphManager->Restore(&fConnectionState);   // Restore connection state
00287             fEngine->NotifyFreewheel(onoff);
00288             fFreewheelDriver->SetMaster(false);
00289             fAudioDriver->SetMaster(true);
00290             return fAudioDriver->Start();
00291         }
00292     } else {
00293         if (onoff) {
00294             fFreewheel = true;
00295             fAudioDriver->Stop();
00296             fGraphManager->Save(&fConnectionState);     // Save connection state
00297             // Disconnect all slaves
00298             std::list<JackDriverInterface*> slave_list = fAudioDriver->GetSlaves();
00299             std::list<JackDriverInterface*>::const_iterator it;
00300             for (it = slave_list.begin(); it != slave_list.end(); it++) {
00301                 JackDriver* slave = dynamic_cast<JackDriver*>(*it);
00302                 assert(slave);
00303                 fGraphManager->DisconnectAllPorts(slave->GetClientControl()->fRefNum);
00304             }
00305             // Disconnect master
00306             fGraphManager->DisconnectAllPorts(fAudioDriver->GetClientControl()->fRefNum);
00307             fEngine->NotifyFreewheel(onoff);
00308             fAudioDriver->SetMaster(false);
00309             fFreewheelDriver->SetMaster(true);
00310             return fThreadedFreewheelDriver->Start();
00311         } else {
00312             return -1;
00313         }
00314     }
00315 }
00316 
00317 //---------------------------
00318 // Coming from the RT thread
00319 //---------------------------
00320 
00321 void JackServer::Notify(int refnum, int notify, int value)
00322 {
00323     switch (notify) {
00324 
00325         case kGraphOrderCallback:
00326             fEngine->NotifyGraphReorder();
00327             break;
00328 
00329         case kXRunCallback:
00330             fEngine->NotifyClientXRun(refnum);
00331             break;
00332     }
00333 }
00334 
00335 //--------------------
00336 // Backend management
00337 //--------------------
00338 
00339 JackDriverInfo* JackServer::AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params)
00340 {
00341     JackDriverInfo* info = new JackDriverInfo();
00342     JackDriverClientInterface* slave = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
00343     
00344     if (!slave) {
00345         goto error1;
00346     }
00347     if (slave->Attach() < 0) {
00348         goto error2;
00349     }
00350     
00351     slave->SetMaster(false);
00352     fAudioDriver->AddSlave(slave);
00353     return info;
00354 
00355 error2:
00356     slave->Close();
00357     
00358 error1:
00359     delete info;
00360     return NULL;
00361 }
00362 
00363 void JackServer::RemoveSlave(JackDriverInfo* info)
00364 {
00365     JackDriverClientInterface* slave = info->GetBackend();
00366     fAudioDriver->RemoveSlave(slave);
00367     slave->Detach();
00368     slave->Close();
00369 }
00370 
00371 int JackServer::SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_params)
00372 {
00373     std::list<JackDriverInterface*> slave_list;
00374     std::list<JackDriverInterface*>::const_iterator it;
00375     
00376     // Remove current master
00377     fAudioDriver->Stop();
00378     fAudioDriver->Detach();
00379     fAudioDriver->Close();
00380 
00381     // Open new master
00382     JackDriverInfo* info = new JackDriverInfo();
00383     JackDriverClientInterface* master = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
00384 
00385     if (!master) {
00386        goto error;
00387     }
00388 
00389     // Get slaves list
00390     slave_list = fAudioDriver->GetSlaves();
00391  
00392     // Move slaves in new master
00393     for (it = slave_list.begin(); it != slave_list.end(); it++) {
00394         JackDriverInterface* slave = *it;
00395         master->AddSlave(slave);
00396     }
00397 
00398     // Delete old master
00399     delete fDriverInfo;
00400 
00401     // Activate master
00402     fAudioDriver = master;
00403     fDriverInfo = info;
00404     
00405     if (fAudioDriver->Attach() < 0) {
00406         goto error;
00407     }
00408     
00409     // Notify clients of new values
00410     fEngine->NotifyBufferSize(fEngineControl->fBufferSize);
00411     fEngine->NotifySampleRate(fEngineControl->fSampleRate);
00412     
00413     // And finally start
00414     fAudioDriver->SetMaster(true);
00415     return fAudioDriver->Start();
00416 
00417 error:
00418     delete info;
00419     return -1;
00420 }
00421 
00422 //----------------------
00423 // Transport management
00424 //----------------------
00425 
00426 int JackServer::ReleaseTimebase(int refnum)
00427 {
00428     return fEngineControl->fTransport.ResetTimebase(refnum);
00429 }
00430 
00431 int JackServer::SetTimebaseCallback(int refnum, int conditional)
00432 {
00433     return fEngineControl->fTransport.SetTimebaseMaster(refnum, conditional);
00434 }
00435 
00436 JackLockedEngine* JackServer::GetEngine()
00437 {
00438     return fEngine;
00439 }
00440 
00441 JackSynchro* JackServer::GetSynchroTable()
00442 {
00443     return fSynchroTable;
00444 }
00445 
00446 JackEngineControl* JackServer::GetEngineControl()
00447 {
00448     return fEngineControl;
00449 }
00450 
00451 JackGraphManager* JackServer::GetGraphManager()
00452 {
00453     return fGraphManager;
00454 }
00455 
00456 } // end of namespace
00457