Merge pull request #23 from jackaudio/device_reservation_fixes
[jack2.git] / common / JackServer.cpp
blobb7e7639a2c690d6f63a87897d7e2090b960cdcca
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"
37 namespace Jack
40 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)
42 if (rt) {
43 jack_info("JACK server starting in realtime mode with priority %ld", priority);
44 } else {
45 jack_info("JACK server starting in non-realtime mode");
48 fGraphManager = JackGraphManager::Allocate(port_max);
49 fEngineControl = new JackEngineControl(sync, temporary, timeout, rt, priority, verbose, clock, server_name);
50 fEngine = new JackLockedEngine(fGraphManager, GetSynchroTable(), fEngineControl);
52 // A distinction is made between the threaded freewheel driver and the
53 // regular freewheel driver because the freewheel driver needs to run in
54 // threaded mode when freewheel mode is active and needs to run as a slave
55 // when freewheel mode isn't active.
56 JackFreewheelDriver *freewheelDriver =
57 new JackFreewheelDriver(fEngine, GetSynchroTable());
58 fThreadedFreewheelDriver = new JackThreadedDriver(freewheelDriver);
60 fFreewheelDriver = freewheelDriver;
61 fDriverInfo = new JackDriverInfo();
62 fAudioDriver = NULL;
63 fFreewheel = false;
64 JackServerGlobals::fInstance = this; // Unique instance
65 JackServerGlobals::fUserCount = 1; // One user
66 JackGlobals::fVerbose = verbose;
69 JackServer::~JackServer()
71 JackGraphManager::Destroy(fGraphManager);
72 delete fDriverInfo;
73 delete fThreadedFreewheelDriver;
74 delete fEngine;
75 delete fEngineControl;
78 int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params)
80 // TODO: move that in reworked JackServerGlobals::Init()
81 if (!JackMessageBuffer::Create()) {
82 jack_error("Cannot create message buffer");
85 if ((fAudioDriver = fDriverInfo->Open(driver_desc, fEngine, GetSynchroTable(), driver_params)) == NULL) {
86 jack_error("Cannot initialize driver");
87 goto fail_close1;
90 if (fChannel.Open(fEngineControl->fServerName, this) < 0) {
91 jack_error("Server channel open error");
92 goto fail_close2;
95 if (fEngine->Open() < 0) {
96 jack_error("Cannot open engine");
97 goto fail_close3;
100 if (fFreewheelDriver->Open() < 0) {
101 jack_error("Cannot open freewheel driver");
102 goto fail_close4;
105 if (fAudioDriver->Attach() < 0) {
106 jack_error("Cannot attach audio driver");
107 goto fail_close5;
110 fFreewheelDriver->SetMaster(false);
111 fAudioDriver->SetMaster(true);
112 fAudioDriver->AddSlave(fFreewheelDriver);
113 InitTime();
114 SetClockSource(fEngineControl->fClockSource);
115 return 0;
117 fail_close5:
118 fFreewheelDriver->Close();
120 fail_close4:
121 fEngine->Close();
123 fail_close3:
124 fChannel.Close();
126 fail_close2:
127 fAudioDriver->Close();
129 fail_close1:
130 JackMessageBuffer::Destroy();
131 return -1;
134 int JackServer::Close()
136 jack_log("JackServer::Close");
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 EndTime();
145 return 0;
148 int JackServer::InternalClientLoad1(const char* client_name, const char* so_name, const char* objet_data, int options, int* int_ref, int uuid, int* status)
150 JackLoadableInternalClient* client = new JackLoadableInternalClient1(JackServerGlobals::fInstance, GetSynchroTable(), objet_data);
151 assert(client);
152 return InternalClientLoadAux(client, so_name, client_name, options, int_ref, uuid, status);
155 int JackServer::InternalClientLoad2(const char* client_name, const char* so_name, const JSList * parameters, int options, int* int_ref, int uuid, int* status)
157 JackLoadableInternalClient* client = new JackLoadableInternalClient2(JackServerGlobals::fInstance, GetSynchroTable(), parameters);
158 assert(client);
159 return InternalClientLoadAux(client, so_name, client_name, options, int_ref, uuid, status);
162 int JackServer::InternalClientLoadAux(JackLoadableInternalClient* client, const char* so_name, const char* client_name, int options, int* int_ref, int uuid, int* status)
164 // Clear status
165 *status = 0;
167 // Client object is internally kept in JackEngine
168 if ((client->Init(so_name) < 0) || (client->Open(JACK_DEFAULT_SERVER_NAME, client_name, uuid, (jack_options_t)options, (jack_status_t*)status) < 0)) {
169 delete client;
170 int my_status1 = *status | JackFailure;
171 *status = (jack_status_t)my_status1;
172 *int_ref = 0;
173 return -1;
174 } else {
175 *int_ref = client->GetClientControl()->fRefNum;
176 return 0;
180 int JackServer::Start()
182 jack_log("JackServer::Start");
183 if (fAudioDriver->Start() < 0) {
184 return -1;
186 return fChannel.Start();
189 int JackServer::Stop()
191 jack_log("JackServer::Stop");
192 fEngine->NotifyQuit();
193 fChannel.Stop();
195 fEngine->ShutDown();
197 if (fFreewheel) {
198 return fThreadedFreewheelDriver->Stop();
199 } else {
200 return fAudioDriver->Stop();
204 bool JackServer::IsRunning()
206 jack_log("JackServer::IsRunning");
207 assert(fAudioDriver);
208 return fAudioDriver->IsRunning();
211 int JackServer::SetBufferSize(jack_nframes_t buffer_size)
213 jack_log("JackServer::SetBufferSize nframes = %ld", buffer_size);
214 jack_nframes_t current_buffer_size = fEngineControl->fBufferSize;
216 if (current_buffer_size == buffer_size) {
217 jack_log("SetBufferSize: requirement for new buffer size equals current value");
218 return 0;
221 if (fAudioDriver->IsFixedBufferSize()) {
222 jack_log("SetBufferSize: driver only supports a fixed buffer size");
223 return -1;
226 if (fAudioDriver->Stop() != 0) {
227 jack_error("Cannot stop audio driver");
228 return -1;
231 if (fAudioDriver->SetBufferSize(buffer_size) == 0) {
232 fEngine->NotifyBufferSize(buffer_size);
233 return fAudioDriver->Start();
234 } else { // Failure: try to restore current value
235 jack_error("Cannot SetBufferSize for audio driver, restore current value %ld", current_buffer_size);
236 fAudioDriver->SetBufferSize(current_buffer_size);
237 fAudioDriver->Start();
238 // SetBufferSize actually failed, so return an error...
239 return -1;
244 Freewheel mode is implemented by switching from the (audio + freewheel) driver to the freewheel driver only:
246 - "global" connection state is saved
247 - all audio driver ports are deconnected, thus there is no more dependancies with the audio driver
248 - the freewheel driver will be synchronized with the end of graph execution : all clients are connected to the freewheel driver
249 - the freewheel driver becomes the "master"
251 Normal mode is restored with the connections state valid before freewheel mode was done. Thus one consider that
252 no graph state change can be done during freewheel mode.
255 int JackServer::SetFreewheel(bool onoff)
257 jack_log("JackServer::SetFreewheel is = %ld want = %ld", fFreewheel, onoff);
259 if (fFreewheel) {
260 if (onoff) {
261 return -1;
262 } else {
263 fFreewheel = false;
264 fThreadedFreewheelDriver->Stop();
265 fGraphManager->Restore(&fConnectionState); // Restore previous connection state
266 fEngine->NotifyFreewheel(onoff);
267 fFreewheelDriver->SetMaster(false);
268 fAudioDriver->SetMaster(true);
269 return fAudioDriver->Start();
271 } else {
272 if (onoff) {
273 fFreewheel = true;
274 fAudioDriver->Stop();
275 fGraphManager->Save(&fConnectionState); // Save connection state
276 fGraphManager->DisconnectAllPorts(fAudioDriver->GetClientControl()->fRefNum);
277 fEngine->NotifyFreewheel(onoff);
278 fAudioDriver->SetMaster(false);
279 fFreewheelDriver->SetMaster(true);
280 return fThreadedFreewheelDriver->Start();
281 } else {
282 return -1;
287 // Coming from the RT thread
288 void JackServer::Notify(int refnum, int notify, int value)
290 switch (notify) {
292 case kGraphOrderCallback:
293 fEngine->NotifyGraphReorder();
294 break;
296 case kXRunCallback:
297 fEngine->NotifyXRun(refnum);
298 break;
302 void JackServer::ClientKill(int refnum)
304 jack_log("JackServer::ClientKill ref = %ld", refnum);
305 if (fEngine->ClientDeactivate(refnum) < 0) {
306 jack_error("JackServer::ClientKill ref = %ld cannot be removed from the graph !!", refnum);
308 if (fEngine->ClientExternalClose(refnum) < 0) {
309 jack_error("JackServer::ClientKill ref = %ld cannot be closed", refnum);
313 //----------------------
314 // Backend management
315 //----------------------
317 JackDriverInfo* JackServer::AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params)
319 JackDriverInfo* info = new JackDriverInfo();
320 JackDriverClientInterface* slave = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
321 if (slave == NULL) {
322 delete info;
323 return NULL;
325 slave->Attach();
326 slave->SetMaster(false);
327 fAudioDriver->AddSlave(slave);
328 return info;
331 void JackServer::RemoveSlave(JackDriverInfo* info)
333 JackDriverClientInterface* slave = info->GetBackend();
334 fAudioDriver->RemoveSlave(slave);
335 slave->Detach();
336 slave->Close();
339 int JackServer::SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_params)
341 /// Remove current master
342 fAudioDriver->Stop();
343 fAudioDriver->Detach();
344 fAudioDriver->Close();
346 // Open new master
347 JackDriverInfo* info = new JackDriverInfo();
348 JackDriverClientInterface* master = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
350 if (master == NULL) {
351 delete info;
352 return -1;
355 // Get slaves list
356 std::list<JackDriverInterface*> slave_list = fAudioDriver->GetSlaves();
357 std::list<JackDriverInterface*>::const_iterator it;
359 // Move slaves in new master
360 for (it = slave_list.begin(); it != slave_list.end(); it++) {
361 JackDriverInterface* slave = *it;
362 master->AddSlave(slave);
365 // Delete old master
366 delete fDriverInfo;
368 // Activate master
369 fAudioDriver = master;
370 fDriverInfo = info;
371 fAudioDriver->Attach();
372 fAudioDriver->SetMaster(true);
373 return fAudioDriver->Start();
376 //----------------------
377 // Transport management
378 //----------------------
380 int JackServer::ReleaseTimebase(int refnum)
382 return fEngineControl->fTransport.ResetTimebase(refnum);
385 int JackServer::SetTimebaseCallback(int refnum, int conditional)
387 return fEngineControl->fTransport.SetTimebaseMaster(refnum, conditional);
390 JackLockedEngine* JackServer::GetEngine()
392 return fEngine;
395 JackSynchro* JackServer::GetSynchroTable()
397 return fSynchroTable;
400 JackEngineControl* JackServer::GetEngineControl()
402 return fEngineControl;
405 JackGraphManager* JackServer::GetGraphManager()
407 return fGraphManager;
411 } // end of namespace