Merge branch 'master' into develop
[jack2.git] / common / JackServer.cpp
blob5cee13fbde37640ecc78cf68ee3e1b0963d0b132
1 /*
2 Copyright (C) 2001 Paul Davis
3 Copyright (C) 2004-2008 Grame
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "JackSystemDeps.h"
22 #include "JackServerGlobals.h"
23 #include "JackTime.h"
24 #include "JackFreewheelDriver.h"
25 #include "JackThreadedDriver.h"
26 #include "JackGlobals.h"
27 #include "JackLockedEngine.h"
28 #include "JackAudioDriver.h"
29 #include "JackChannel.h"
30 #include "JackClientControl.h"
31 #include "JackEngineControl.h"
32 #include "JackGraphManager.h"
33 #include "JackInternalClient.h"
34 #include "JackError.h"
35 #include "JackMessageBuffer.h"
36 #include "JackInternalSessionLoader.h"
38 const char * jack_get_self_connect_mode_description(char mode);
40 namespace Jack
43 //----------------
44 // Server control
45 //----------------
46 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)
48 if (rt) {
49 jack_info("JACK server starting in realtime mode with priority %ld", priority);
50 } else {
51 jack_info("JACK server starting in non-realtime mode");
54 jack_info("self-connect-mode is \"%s\"", jack_get_self_connect_mode_description(self_connect_mode));
56 fGraphManager = JackGraphManager::Allocate(port_max);
57 fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, clock, server_name);
58 fEngine = new JackLockedEngine(fGraphManager, GetSynchroTable(), fEngineControl, self_connect_mode);
60 // A distinction is made between the threaded freewheel driver and the
61 // regular freewheel driver because the freewheel driver needs to run in
62 // threaded mode when freewheel mode is active and needs to run as a slave
63 // when freewheel mode isn't active.
64 JackFreewheelDriver* freewheelDriver = new JackFreewheelDriver(fEngine, GetSynchroTable());
65 fThreadedFreewheelDriver = new JackThreadedDriver(freewheelDriver);
67 fFreewheelDriver = freewheelDriver;
68 fDriverInfo = new JackDriverInfo();
69 fAudioDriver = NULL;
70 fFreewheel = false;
71 JackServerGlobals::fInstance = this; // Unique instance
72 JackServerGlobals::fUserCount = 1; // One user
73 JackGlobals::fVerbose = verbose;
76 JackServer::~JackServer()
78 JackGraphManager::Destroy(fGraphManager);
79 delete fDriverInfo;
80 delete fThreadedFreewheelDriver;
81 delete fEngine;
82 delete fEngineControl;
85 int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params)
87 // TODO: move that in reworked JackServerGlobals::Init()
88 if (!JackMessageBuffer::Create()) {
89 jack_error("Cannot create message buffer");
92 if ((fAudioDriver = fDriverInfo->Open(driver_desc, fEngine, GetSynchroTable(), driver_params)) == NULL) {
93 jack_error("Cannot initialize driver");
94 goto fail_close1;
97 if (fRequestChannel.Open(fEngineControl->fServerName, this) < 0) {
98 jack_error("Server channel open error");
99 goto fail_close2;
102 if (fEngine->Open() < 0) {
103 jack_error("Cannot open engine");
104 goto fail_close3;
107 if (fFreewheelDriver->Open() < 0) {
108 jack_error("Cannot open freewheel driver");
109 goto fail_close4;
112 if (fAudioDriver->Attach() < 0) {
113 jack_error("Cannot attach audio driver");
114 goto fail_close5;
117 fFreewheelDriver->SetMaster(false);
118 fAudioDriver->SetMaster(true);
119 fAudioDriver->AddSlave(fFreewheelDriver);
120 InitTime();
121 SetClockSource(fEngineControl->fClockSource);
122 return 0;
124 fail_close5:
125 fFreewheelDriver->Close();
127 fail_close4:
128 fEngine->Close();
130 fail_close3:
131 fRequestChannel.Close();
133 fail_close2:
134 fAudioDriver->Close();
136 fail_close1:
137 JackMessageBuffer::Destroy();
138 return -1;
141 int JackServer::Close()
143 jack_log("JackServer::Close");
144 fRequestChannel.Close();
145 fAudioDriver->Detach();
146 fAudioDriver->Close();
147 fFreewheelDriver->Close();
148 fEngine->Close();
149 // TODO: move that in reworked JackServerGlobals::Destroy()
150 JackMessageBuffer::Destroy();
151 EndTime();
152 return 0;
155 int JackServer::Start()
157 jack_log("JackServer::Start");
158 if (fAudioDriver->Start() < 0) {
159 return -1;
161 return fRequestChannel.Start();
164 int JackServer::Stop()
166 jack_log("JackServer::Stop");
167 int res = -1;
169 if (fFreewheel) {
170 if (fThreadedFreewheelDriver) {
171 res = fThreadedFreewheelDriver->Stop();
173 } else {
174 if (fAudioDriver) {
175 res = fAudioDriver->Stop();
179 fEngine->NotifyQuit();
180 fRequestChannel.Stop();
181 fEngine->NotifyFailure(JackFailure | JackServerError, JACK_SERVER_FAILURE);
183 return res;
186 bool JackServer::IsRunning()
188 jack_log("JackServer::IsRunning");
189 assert(fAudioDriver);
190 return fAudioDriver->IsRunning();
193 //------------------
194 // Internal clients
195 //------------------
197 int JackServer::InternalClientLoad1(const char* client_name, const char* so_name, const char* objet_data, int options, int* int_ref, jack_uuid_t uuid, int* status)
199 JackLoadableInternalClient* client = new JackLoadableInternalClient1(JackServerGlobals::fInstance, GetSynchroTable(), objet_data);
200 assert(client);
201 return InternalClientLoadAux(client, so_name, client_name, options, int_ref, uuid, status);
204 int JackServer::InternalClientLoad2(const char* client_name, const char* so_name, const JSList * parameters, int options, int* int_ref, jack_uuid_t uuid, int* status)
206 JackLoadableInternalClient* client = new JackLoadableInternalClient2(JackServerGlobals::fInstance, GetSynchroTable(), parameters);
207 assert(client);
208 return InternalClientLoadAux(client, so_name, client_name, options, int_ref, uuid, status);
211 int JackServer::InternalClientLoadAux(JackLoadableInternalClient* client, const char* so_name, const char* client_name, int options, int* int_ref, jack_uuid_t uuid, int* status)
213 // Clear status
214 *status = 0;
216 // Client object is internally kept in JackEngine
217 if ((client->Init(so_name) < 0) || (client->Open(JackTools::DefaultServerName(), client_name, uuid, (jack_options_t)options, (jack_status_t*)status) < 0)) {
218 delete client;
219 int my_status1 = *status | JackFailure;
220 *status = (jack_status_t)my_status1;
221 *int_ref = 0;
222 return -1;
223 } else {
224 *int_ref = client->GetClientControl()->fRefNum;
225 return 0;
229 //-----------------------
230 // Internal session file
231 //-----------------------
233 int JackServer::LoadInternalSessionFile(const char* file)
235 JackInternalSessionLoader loader(this);
236 return loader.Load(file);
239 //---------------------------
240 // From request thread : API
241 //---------------------------
243 int JackServer::SetBufferSize(jack_nframes_t buffer_size)
245 jack_log("JackServer::SetBufferSize nframes = %ld", buffer_size);
246 jack_nframes_t current_buffer_size = fEngineControl->fBufferSize;
248 if (current_buffer_size == buffer_size) {
249 jack_log("SetBufferSize: requirement for new buffer size equals current value");
250 return 0;
253 if (fAudioDriver->IsFixedBufferSize()) {
254 jack_log("SetBufferSize: driver only supports a fixed buffer size");
255 return -1;
258 if (fAudioDriver->Stop() != 0) {
259 jack_error("Cannot stop audio driver");
260 return -1;
263 if (fAudioDriver->SetBufferSize(buffer_size) == 0) {
264 fEngine->NotifyBufferSize(buffer_size);
265 return fAudioDriver->Start();
266 } else { // Failure: try to restore current value
267 jack_error("Cannot SetBufferSize for audio driver, restore current value %ld", current_buffer_size);
268 fAudioDriver->SetBufferSize(current_buffer_size);
269 fAudioDriver->Start();
270 // SetBufferSize actually failed, so return an error...
271 return -1;
276 Freewheel mode is implemented by switching from the (audio [slaves] + freewheel) driver to the freewheel driver only:
278 - "global" connection state is saved
279 - all audio driver and slaves ports are deconnected, thus there is no more dependencies with the audio driver and slaves
280 - the freewheel driver will be synchronized with the end of graph execution : all clients are connected to the freewheel driver
281 - the freewheel driver becomes the "master"
283 Normal mode is restored with the connections state valid before freewheel mode was done. Thus one consider that
284 no graph state change can be done during freewheel mode.
287 int JackServer::SetFreewheel(bool onoff)
289 jack_log("JackServer::SetFreewheel is = %ld want = %ld", fFreewheel, onoff);
291 if (fFreewheel) {
292 if (onoff) {
293 return -1;
294 } else {
295 fFreewheel = false;
296 fThreadedFreewheelDriver->Stop();
297 fGraphManager->Restore(&fConnectionState); // Restore connection state
298 fEngine->NotifyFreewheel(onoff);
299 fFreewheelDriver->SetMaster(false);
300 fAudioDriver->SetMaster(true);
301 return fAudioDriver->Start();
303 } else {
304 if (onoff) {
305 fFreewheel = true;
306 fAudioDriver->Stop();
307 fGraphManager->Save(&fConnectionState); // Save connection state
308 // Disconnect all slaves
309 std::list<JackDriverInterface*> slave_list = fAudioDriver->GetSlaves();
310 std::list<JackDriverInterface*>::const_iterator it;
311 for (it = slave_list.begin(); it != slave_list.end(); it++) {
312 JackDriver* slave = dynamic_cast<JackDriver*>(*it);
313 assert(slave);
314 fGraphManager->DisconnectAllPorts(slave->GetClientControl()->fRefNum);
316 // Disconnect master
317 fGraphManager->DisconnectAllPorts(fAudioDriver->GetClientControl()->fRefNum);
318 fEngine->NotifyFreewheel(onoff);
319 fAudioDriver->SetMaster(false);
320 fFreewheelDriver->SetMaster(true);
321 return fThreadedFreewheelDriver->Start();
322 } else {
323 return -1;
328 //---------------------------
329 // Coming from the RT thread
330 //---------------------------
332 void JackServer::Notify(int refnum, int notify, int value)
334 switch (notify) {
336 case kGraphOrderCallback:
337 fEngine->NotifyGraphReorder();
338 break;
340 case kXRunCallback:
341 fEngine->NotifyClientXRun(refnum);
342 break;
346 //--------------------
347 // Backend management
348 //--------------------
350 JackDriverInfo* JackServer::AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params)
352 JackDriverInfo* info = new JackDriverInfo();
353 JackDriverClientInterface* slave = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
355 if (!slave) {
356 goto error1;
358 if (slave->Attach() < 0) {
359 goto error2;
362 slave->SetMaster(false);
363 fAudioDriver->AddSlave(slave);
364 return info;
366 error2:
367 slave->Close();
369 error1:
370 delete info;
371 return NULL;
374 void JackServer::RemoveSlave(JackDriverInfo* info)
376 JackDriverClientInterface* slave = info->GetBackend();
377 fAudioDriver->RemoveSlave(slave);
378 slave->Detach();
379 slave->Close();
382 int JackServer::SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_params)
384 std::list<JackDriverInterface*> slave_list;
385 std::list<JackDriverInterface*>::const_iterator it;
387 // Remove current master
388 fAudioDriver->Stop();
389 fAudioDriver->Detach();
390 fAudioDriver->Close();
392 // Open new master
393 JackDriverInfo* info = new JackDriverInfo();
394 JackDriverClientInterface* master = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
396 if (!master) {
397 goto error;
400 // Get slaves list
401 slave_list = fAudioDriver->GetSlaves();
403 // Move slaves in new master
404 for (it = slave_list.begin(); it != slave_list.end(); it++) {
405 JackDriverInterface* slave = *it;
406 master->AddSlave(slave);
409 // Delete old master
410 delete fDriverInfo;
412 // Activate master
413 fAudioDriver = master;
414 fDriverInfo = info;
416 if (fAudioDriver->Attach() < 0) {
417 goto error;
420 // Notify clients of new values
421 fEngine->NotifyBufferSize(fEngineControl->fBufferSize);
422 fEngine->NotifySampleRate(fEngineControl->fSampleRate);
424 // And finally start
425 fAudioDriver->SetMaster(true);
426 return fAudioDriver->Start();
428 error:
429 delete info;
430 return -1;
433 //----------------------
434 // Transport management
435 //----------------------
437 int JackServer::ReleaseTimebase(int refnum)
439 return fEngineControl->fTransport.ResetTimebase(refnum);
442 int JackServer::SetTimebaseCallback(int refnum, int conditional)
444 return fEngineControl->fTransport.SetTimebaseMaster(refnum, conditional);
447 JackLockedEngine* JackServer::GetEngine()
449 return fEngine;
452 JackSynchro* JackServer::GetSynchroTable()
454 return fSynchroTable;
457 JackEngineControl* JackServer::GetEngineControl()
459 return fEngineControl;
462 JackGraphManager* JackServer::GetGraphManager()
464 return fGraphManager;
467 } // end of namespace