README updated.
[jack2.git] / common / JackServer.cpp
blobe267650002e686a40f8a64b55b68af5912cedb1c
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, 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);
52 fFreewheelDriver = new JackThreadedDriver(new JackFreewheelDriver(fEngine, GetSynchroTable()));
53 fDriverInfo = new JackDriverInfo();
54 fAudioDriver = NULL;
55 fFreewheel = false;
56 JackServerGlobals::fInstance = this; // Unique instance
57 JackServerGlobals::fUserCount = 1; // One user
58 JackGlobals::fVerbose = verbose;
61 JackServer::~JackServer()
63 JackGraphManager::Destroy(fGraphManager);
64 delete fAudioDriver;
65 delete fDriverInfo;
66 delete fFreewheelDriver;
67 delete fEngine;
68 delete fEngineControl;
71 int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params)
73 // TODO: move that in reworked JackServerGlobals::Init()
74 JackMessageBuffer::Create();
76 if (fChannel.Open(fEngineControl->fServerName, this) < 0) {
77 jack_error("Server channel open error");
78 goto fail_close1;
81 if (fEngine->Open() < 0) {
82 jack_error("Cannot open engine");
83 goto fail_close2;
86 if ((fAudioDriver = fDriverInfo->Open(driver_desc, fEngine, GetSynchroTable(), driver_params)) == NULL) {
87 jack_error("Cannot initialize driver");
88 goto fail_close3;
91 if (fFreewheelDriver->Open() < 0) { // before engine open
92 jack_error("Cannot open driver");
93 goto fail_close4;
96 if (fAudioDriver->Attach() < 0) {
97 jack_error("Cannot attach audio driver");
98 goto fail_close5;
101 fFreewheelDriver->SetMaster(false);
102 fAudioDriver->SetMaster(true);
103 fAudioDriver->AddSlave(fFreewheelDriver); // After ???
104 InitTime();
105 SetClockSource(fEngineControl->fClockSource);
106 return 0;
108 fail_close5:
109 fFreewheelDriver->Close();
111 fail_close4:
112 fAudioDriver->Close();
114 fail_close3:
115 fEngine->Close();
117 fail_close2:
118 fChannel.Close();
120 fail_close1:
121 JackMessageBuffer::Destroy();
122 return -1;
125 int JackServer::Close()
127 jack_log("JackServer::Close");
128 fEngine->NotifyQuit();
129 fChannel.Close();
130 fAudioDriver->Detach();
131 fAudioDriver->Close();
132 fFreewheelDriver->Close();
133 fEngine->Close();
134 // TODO: move that in reworked JackServerGlobals::Destroy()
135 JackMessageBuffer::Destroy();
136 return 0;
139 int JackServer::InternalClientLoad(const char* client_name, const char* so_name, const char* objet_data, int options, int* int_ref, int* status)
141 JackLoadableInternalClient* client = new JackLoadableInternalClient1(JackServerGlobals::fInstance, GetSynchroTable(), objet_data);
142 assert(client);
143 return InternalClientLoadAux(client, so_name, client_name, options, int_ref, status);
146 int JackServer::InternalClientLoad(const char* client_name, const char* so_name, const JSList * parameters, int options, int* int_ref, int* status)
148 JackLoadableInternalClient* client = new JackLoadableInternalClient2(JackServerGlobals::fInstance, GetSynchroTable(), parameters);
149 assert(client);
150 return InternalClientLoadAux(client, so_name, client_name, options, int_ref, status);
153 int JackServer::InternalClientLoadAux(JackLoadableInternalClient* client, const char* so_name, const char* client_name, int options, int* int_ref, int* status)
155 // Clear status
156 *status = 0;
157 if ((client->Init(so_name) < 0) || (client->Open(JACK_DEFAULT_SERVER_NAME, client_name, (jack_options_t)options, (jack_status_t*)status) < 0)) {
158 delete client;
159 int my_status1 = *status | JackFailure;
160 *status = (jack_status_t)my_status1;
161 *int_ref = 0;
162 return -1;
163 } else {
164 *int_ref = client->GetClientControl()->fRefNum;
165 return 0;
169 int JackServer::Start()
171 jack_log("JackServer::Start");
172 if (fAudioDriver->Start() < 0) {
173 return -1;
175 return fChannel.Start();
178 int JackServer::Stop()
180 jack_log("JackServer::Stop");
181 return fAudioDriver->Stop();
184 int JackServer::SetBufferSize(jack_nframes_t buffer_size)
186 jack_log("JackServer::SetBufferSize nframes = %ld", buffer_size);
187 jack_nframes_t current_buffer_size = fEngineControl->fBufferSize;
189 if (current_buffer_size == buffer_size) {
190 jack_log("SetBufferSize: requirement for new buffer size equals current value");
191 return 0;
194 if (fAudioDriver->IsFixedBufferSize()) {
195 jack_log("SetBufferSize: driver only supports a fixed buffer size");
196 return -1;
199 if (fAudioDriver->Stop() != 0) {
200 jack_error("Cannot stop audio driver");
201 return -1;
204 if (fAudioDriver->SetBufferSize(buffer_size) == 0) {
205 fFreewheelDriver->SetBufferSize(buffer_size);
206 fEngine->NotifyBufferSize(buffer_size);
207 return fAudioDriver->Start();
208 } else { // Failure: try to restore current value
209 jack_error("Cannot SetBufferSize for audio driver, restore current value %ld", current_buffer_size);
210 fAudioDriver->SetBufferSize(current_buffer_size);
211 fFreewheelDriver->SetBufferSize(current_buffer_size);
212 fAudioDriver->Start();
213 // SetBufferSize actually failed, so return an error...
214 return -1;
219 Freewheel mode is implemented by switching from the (audio + freewheel) driver to the freewheel driver only:
221 - "global" connection state is saved
222 - all audio driver ports are deconnected, thus there is no more dependancies with the audio driver
223 - the freewheel driver will be synchronized with the end of graph execution : all clients are connected to the freewheel driver
224 - the freewheel driver becomes the "master"
226 Normal mode is restored with the connections state valid before freewheel mode was done. Thus one consider that
227 no graph state change can be done during freewheel mode.
230 int JackServer::SetFreewheel(bool onoff)
232 jack_log("JackServer::SetFreewheel is = %ld want = %ld", fFreewheel, onoff);
234 if (fFreewheel) {
235 if (onoff) {
236 return -1;
237 } else {
238 fFreewheel = false;
239 fFreewheelDriver->Stop();
240 fGraphManager->Restore(&fConnectionState); // Restore previous connection state
241 fEngine->NotifyFreewheel(onoff);
242 fFreewheelDriver->SetMaster(false);
243 return fAudioDriver->Start();
245 } else {
246 if (onoff) {
247 fFreewheel = true;
248 fAudioDriver->Stop();
249 fGraphManager->Save(&fConnectionState); // Save connection state
250 fGraphManager->DisconnectAllPorts(fAudioDriver->GetClientControl()->fRefNum);
251 fEngine->NotifyFreewheel(onoff);
252 fFreewheelDriver->SetMaster(true);
253 return fFreewheelDriver->Start();
254 } else {
255 return -1;
260 // Coming from the RT thread
261 void JackServer::Notify(int refnum, int notify, int value)
263 switch (notify) {
265 case kGraphOrderCallback:
266 fEngine->NotifyGraphReorder();
267 break;
269 case kXRunCallback:
270 fEngine->NotifyXRun(refnum);
271 break;
276 void JackServer::ClientKill(int refnum)
278 jack_log("JackServer::ClientKill ref = %ld", refnum);
279 if (fEngine->ClientDeactivate(refnum) < 0) {
280 jack_error("JackServer::ClientKill ref = %ld cannot be removed from the graph !!", refnum);
282 if (fEngine->ClientExternalClose(refnum) < 0) {
283 jack_error("JackServer::ClientKill ref = %ld cannot be closed", refnum);
287 //----------------------
288 // Backend management
289 //----------------------
291 JackDriverInfo* JackServer::AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params)
293 JackDriverInfo* info = new JackDriverInfo();
294 JackDriverClientInterface* slave = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
295 if (slave == NULL) {
296 delete info;
297 return NULL;
298 } else {
299 slave->Attach();
300 fAudioDriver->AddSlave(slave);
301 return info;
305 void JackServer::RemoveSlave(JackDriverInfo* info)
307 JackDriverClientInterface* slave = info->GetBackend();
308 fAudioDriver->RemoveSlave(slave);
309 slave->Detach();
310 slave->Close();
313 int JackServer::SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_params)
315 /// Remove current master
316 fAudioDriver->Stop();
317 fAudioDriver->Detach();
318 fAudioDriver->Close();
320 // Open new master
321 JackDriverInfo* info = new JackDriverInfo();
322 JackDriverClientInterface* master = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
324 if (master == NULL || info == NULL) {
325 delete info;
326 delete master;
327 return -1;
328 } else {
330 // Get slaves list
331 std::list<JackDriverInterface*> slave_list = fAudioDriver->GetSlaves();
332 std::list<JackDriverInterface*>::const_iterator it;
334 // Move slaves in new master
335 for (it = slave_list.begin(); it != slave_list.end(); it++) {
336 JackDriverInterface* slave = *it;
337 master->AddSlave(slave);
340 // Delete old master
341 delete fAudioDriver;
342 delete fDriverInfo;
344 // Activate master
345 fAudioDriver = master;
346 fDriverInfo = info;
347 fAudioDriver->Attach();
348 fAudioDriver->SetMaster(true);
349 return fAudioDriver->Start();
353 //----------------------
354 // Transport management
355 //----------------------
357 int JackServer::ReleaseTimebase(int refnum)
359 return fEngineControl->fTransport.ResetTimebase(refnum);
362 int JackServer::SetTimebaseCallback(int refnum, int conditional)
364 return fEngineControl->fTransport.SetTimebaseMaster(refnum, conditional);
367 JackLockedEngine* JackServer::GetEngine()
369 return fEngine;
372 JackSynchro* JackServer::GetSynchroTable()
374 return fSynchroTable;
377 JackEngineControl* JackServer::GetEngineControl()
379 return fEngineControl;
382 JackGraphManager* JackServer::GetGraphManager()
384 return fGraphManager;
388 } // end of namespace