Merge branch 'master' into no-self-connect
[jack2.git] / common / JackServer.cpp
bloba35fa9396eeb20e3860ae40f9eac076841b19401
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 "JackDummyDriver.h"
26 #include "JackThreadedDriver.h"
27 #include "JackGlobals.h"
28 #include "JackLockedEngine.h"
29 #include "JackAudioDriver.h"
30 #include "JackChannel.h"
31 #include "JackClientControl.h"
32 #include "JackEngineControl.h"
33 #include "JackGraphManager.h"
34 #include "JackInternalClient.h"
35 #include "JackError.h"
36 #include "JackMessageBuffer.h"
38 namespace Jack
41 JackServer::JackServer(bool sync, bool temporary, int timeout, bool rt, int priority, int port_max, bool verbose, jack_timer_type_t clock, JackSelfConnectMode self_connect_mode, const char* server_name)
43 if (rt) {
44 jack_info("JACK server starting in realtime mode with priority %ld", priority);
45 } else {
46 jack_info("JACK server starting in non-realtime mode");
49 fGraphManager = JackGraphManager::Allocate(port_max);
50 fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, clock, server_name);
51 fEngine = new JackLockedEngine(fGraphManager, GetSynchroTable(), fEngineControl, self_connect_mode);
53 // A distinction is made between the threaded freewheel driver and the
54 // regular freewheel driver because the freewheel driver needs to run in
55 // threaded mode when freewheel mode is active and needs to run as a slave
56 // when freewheel mode isn't active.
57 JackFreewheelDriver *freewheelDriver =
58 new JackFreewheelDriver(fEngine, GetSynchroTable());
59 fThreadedFreewheelDriver = new JackThreadedDriver(freewheelDriver);
61 fFreewheelDriver = freewheelDriver;
62 fDriverInfo = new JackDriverInfo();
63 fAudioDriver = NULL;
64 fFreewheel = false;
65 JackServerGlobals::fInstance = this; // Unique instance
66 JackServerGlobals::fUserCount = 1; // One user
67 JackGlobals::fVerbose = verbose;
70 JackServer::~JackServer()
72 JackGraphManager::Destroy(fGraphManager);
73 delete fDriverInfo;
74 delete fThreadedFreewheelDriver;
75 delete fEngine;
76 delete fEngineControl;
79 int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params)
81 // TODO: move that in reworked JackServerGlobals::Init()
82 JackMessageBuffer::Create();
84 if ((fAudioDriver = fDriverInfo->Open(driver_desc, fEngine, GetSynchroTable(), driver_params)) == NULL) {
85 jack_error("Cannot initialize driver");
86 goto fail_close1;
89 if (fChannel.Open(fEngineControl->fServerName, this) < 0) {
90 jack_error("Server channel open error");
91 goto fail_close2;
94 if (fEngine->Open() < 0) {
95 jack_error("Cannot open engine");
96 goto fail_close3;
99 if (fFreewheelDriver->Open() < 0) {
100 jack_error("Cannot open freewheel driver");
101 goto fail_close4;
104 if (fAudioDriver->Attach() < 0) {
105 jack_error("Cannot attach audio driver");
106 goto fail_close5;
109 fFreewheelDriver->SetMaster(false);
110 fAudioDriver->SetMaster(true);
111 fAudioDriver->AddSlave(fFreewheelDriver);
112 InitTime();
113 SetClockSource(fEngineControl->fClockSource);
114 return 0;
116 fail_close5:
117 fFreewheelDriver->Close();
119 fail_close4:
120 fEngine->Close();
122 fail_close3:
123 fChannel.Close();
125 fail_close2:
126 fAudioDriver->Close();
128 fail_close1:
129 JackMessageBuffer::Destroy();
130 return -1;
133 int JackServer::Close()
135 jack_log("JackServer::Close");
136 fEngine->NotifyQuit();
137 fChannel.Close();
138 fAudioDriver->Detach();
139 fAudioDriver->Close();
140 fFreewheelDriver->Close();
141 fEngine->Close();
142 // TODO: move that in reworked JackServerGlobals::Destroy()
143 JackMessageBuffer::Destroy();
144 return 0;
147 int JackServer::InternalClientLoad1(const char* client_name, const char* so_name, const char* objet_data, int options, int* int_ref, int uuid, int* status)
149 JackLoadableInternalClient* client = new JackLoadableInternalClient1(JackServerGlobals::fInstance, GetSynchroTable(), objet_data);
150 assert(client);
151 return InternalClientLoadAux(client, so_name, client_name, options, int_ref, uuid, status);
154 int JackServer::InternalClientLoad2(const char* client_name, const char* so_name, const JSList * parameters, int options, int* int_ref, int uuid, int* status)
156 JackLoadableInternalClient* client = new JackLoadableInternalClient2(JackServerGlobals::fInstance, GetSynchroTable(), parameters);
157 assert(client);
158 return InternalClientLoadAux(client, so_name, client_name, options, int_ref, uuid, status);
161 int JackServer::InternalClientLoadAux(JackLoadableInternalClient* client, const char* so_name, const char* client_name, int options, int* int_ref, int uuid, int* status)
163 // Clear status
164 *status = 0;
166 // Client object is internally kept in JackEngine
167 if ((client->Init(so_name) < 0) || (client->Open(JACK_DEFAULT_SERVER_NAME, client_name, uuid, (jack_options_t)options, (jack_status_t*)status) < 0)) {
168 delete client;
169 int my_status1 = *status | JackFailure;
170 *status = (jack_status_t)my_status1;
171 *int_ref = 0;
172 return -1;
173 } else {
174 *int_ref = client->GetClientControl()->fRefNum;
175 return 0;
179 int JackServer::Start()
181 jack_log("JackServer::Start");
182 if (fAudioDriver->Start() < 0) {
183 return -1;
185 return fChannel.Start();
188 int JackServer::Stop()
190 jack_log("JackServer::Stop");
191 if (fFreewheel) {
192 return fThreadedFreewheelDriver->Stop();
193 } else {
194 return fAudioDriver->Stop();
198 bool JackServer::IsRunning()
200 jack_log("JackServer::IsRunning");
201 assert(fAudioDriver);
202 return fAudioDriver->IsRunning();
205 int JackServer::SetBufferSize(jack_nframes_t buffer_size)
207 jack_log("JackServer::SetBufferSize nframes = %ld", buffer_size);
208 jack_nframes_t current_buffer_size = fEngineControl->fBufferSize;
210 if (current_buffer_size == buffer_size) {
211 jack_log("SetBufferSize: requirement for new buffer size equals current value");
212 return 0;
215 if (fAudioDriver->IsFixedBufferSize()) {
216 jack_log("SetBufferSize: driver only supports a fixed buffer size");
217 return -1;
220 if (fAudioDriver->Stop() != 0) {
221 jack_error("Cannot stop audio driver");
222 return -1;
225 if (fAudioDriver->SetBufferSize(buffer_size) == 0) {
226 fFreewheelDriver->SetBufferSize(buffer_size);
227 fEngine->NotifyBufferSize(buffer_size);
228 return fAudioDriver->Start();
229 } else { // Failure: try to restore current value
230 jack_error("Cannot SetBufferSize for audio driver, restore current value %ld", current_buffer_size);
231 fAudioDriver->SetBufferSize(current_buffer_size);
232 fFreewheelDriver->SetBufferSize(current_buffer_size);
233 fAudioDriver->Start();
234 // SetBufferSize actually failed, so return an error...
235 return -1;
240 Freewheel mode is implemented by switching from the (audio + freewheel) driver to the freewheel driver only:
242 - "global" connection state is saved
243 - all audio driver ports are deconnected, thus there is no more dependancies with the audio driver
244 - the freewheel driver will be synchronized with the end of graph execution : all clients are connected to the freewheel driver
245 - the freewheel driver becomes the "master"
247 Normal mode is restored with the connections state valid before freewheel mode was done. Thus one consider that
248 no graph state change can be done during freewheel mode.
251 int JackServer::SetFreewheel(bool onoff)
253 jack_log("JackServer::SetFreewheel is = %ld want = %ld", fFreewheel, onoff);
255 if (fFreewheel) {
256 if (onoff) {
257 return -1;
258 } else {
259 fFreewheel = false;
260 fThreadedFreewheelDriver->Stop();
261 fGraphManager->Restore(&fConnectionState); // Restore previous connection state
262 fEngine->NotifyFreewheel(onoff);
263 fFreewheelDriver->SetMaster(false);
264 fAudioDriver->SetMaster(true);
265 return fAudioDriver->Start();
267 } else {
268 if (onoff) {
269 fFreewheel = true;
270 fAudioDriver->Stop();
271 fGraphManager->Save(&fConnectionState); // Save connection state
272 fGraphManager->DisconnectAllPorts(fAudioDriver->GetClientControl()->fRefNum);
273 fEngine->NotifyFreewheel(onoff);
274 fAudioDriver->SetMaster(false);
275 fFreewheelDriver->SetMaster(true);
276 return fThreadedFreewheelDriver->Start();
277 } else {
278 return -1;
283 // Coming from the RT thread
284 void JackServer::Notify(int refnum, int notify, int value)
286 switch (notify) {
288 case kGraphOrderCallback:
289 fEngine->NotifyGraphReorder();
290 break;
292 case kXRunCallback:
293 fEngine->NotifyXRun(refnum);
294 break;
298 void JackServer::ClientKill(int refnum)
300 jack_log("JackServer::ClientKill ref = %ld", refnum);
301 if (fEngine->ClientDeactivate(refnum) < 0) {
302 jack_error("JackServer::ClientKill ref = %ld cannot be removed from the graph !!", refnum);
304 if (fEngine->ClientExternalClose(refnum) < 0) {
305 jack_error("JackServer::ClientKill ref = %ld cannot be closed", refnum);
309 //----------------------
310 // Backend management
311 //----------------------
313 JackDriverInfo* JackServer::AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params)
315 JackDriverInfo* info = new JackDriverInfo();
316 JackDriverClientInterface* slave = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
317 if (slave == NULL) {
318 delete info;
319 return NULL;
321 slave->Attach();
322 slave->SetMaster(false);
323 fAudioDriver->AddSlave(slave);
324 return info;
327 void JackServer::RemoveSlave(JackDriverInfo* info)
329 JackDriverClientInterface* slave = info->GetBackend();
330 fAudioDriver->RemoveSlave(slave);
331 slave->Detach();
332 slave->Close();
335 int JackServer::SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_params)
337 /// Remove current master
338 fAudioDriver->Stop();
339 fAudioDriver->Detach();
340 fAudioDriver->Close();
342 // Open new master
343 JackDriverInfo* info = new JackDriverInfo();
344 JackDriverClientInterface* master = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
346 if (master == NULL) {
347 delete info;
348 return -1;
351 // Get slaves list
352 std::list<JackDriverInterface*> slave_list = fAudioDriver->GetSlaves();
353 std::list<JackDriverInterface*>::const_iterator it;
355 // Move slaves in new master
356 for (it = slave_list.begin(); it != slave_list.end(); it++) {
357 JackDriverInterface* slave = *it;
358 master->AddSlave(slave);
361 // Delete old master
362 delete fDriverInfo;
364 // Activate master
365 fAudioDriver = master;
366 fDriverInfo = info;
367 fAudioDriver->Attach();
368 fAudioDriver->SetMaster(true);
369 return fAudioDriver->Start();
372 //----------------------
373 // Transport management
374 //----------------------
376 int JackServer::ReleaseTimebase(int refnum)
378 return fEngineControl->fTransport.ResetTimebase(refnum);
381 int JackServer::SetTimebaseCallback(int refnum, int conditional)
383 return fEngineControl->fTransport.SetTimebaseMaster(refnum, conditional);
386 JackLockedEngine* JackServer::GetEngine()
388 return fEngine;
391 JackSynchro* JackServer::GetSynchroTable()
393 return fSynchroTable;
396 JackEngineControl* JackServer::GetEngineControl()
398 return fEngineControl;
401 JackGraphManager* JackServer::GetGraphManager()
403 return fGraphManager;
407 } // end of namespace