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"
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"
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
)
43 jack_info("JACK server starting in realtime mode with priority %ld", priority
);
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();
64 JackServerGlobals::fInstance
= this; // Unique instance
65 JackServerGlobals::fUserCount
= 1; // One user
66 JackGlobals::fVerbose
= verbose
;
69 JackServer::~JackServer()
71 JackGraphManager::Destroy(fGraphManager
);
73 delete fThreadedFreewheelDriver
;
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");
90 if (fChannel
.Open(fEngineControl
->fServerName
, this) < 0) {
91 jack_error("Server channel open error");
95 if (fEngine
->Open() < 0) {
96 jack_error("Cannot open engine");
100 if (fFreewheelDriver
->Open() < 0) {
101 jack_error("Cannot open freewheel driver");
105 if (fAudioDriver
->Attach() < 0) {
106 jack_error("Cannot attach audio driver");
110 fFreewheelDriver
->SetMaster(false);
111 fAudioDriver
->SetMaster(true);
112 fAudioDriver
->AddSlave(fFreewheelDriver
);
114 SetClockSource(fEngineControl
->fClockSource
);
118 fFreewheelDriver
->Close();
127 fAudioDriver
->Close();
130 JackMessageBuffer::Destroy();
134 int JackServer::Close()
136 jack_log("JackServer::Close");
137 fEngine
->NotifyQuit();
139 fAudioDriver
->Detach();
140 fAudioDriver
->Close();
141 fFreewheelDriver
->Close();
143 // TODO: move that in reworked JackServerGlobals::Destroy()
144 JackMessageBuffer::Destroy();
149 int JackServer::InternalClientLoad1(const char* client_name
, const char* so_name
, const char* objet_data
, int options
, int* int_ref
, int uuid
, int* status
)
151 JackLoadableInternalClient
* client
= new JackLoadableInternalClient1(JackServerGlobals::fInstance
, GetSynchroTable(), objet_data
);
153 return InternalClientLoadAux(client
, so_name
, client_name
, options
, int_ref
, uuid
, status
);
156 int JackServer::InternalClientLoad2(const char* client_name
, const char* so_name
, const JSList
* parameters
, int options
, int* int_ref
, int uuid
, int* status
)
158 JackLoadableInternalClient
* client
= new JackLoadableInternalClient2(JackServerGlobals::fInstance
, GetSynchroTable(), parameters
);
160 return InternalClientLoadAux(client
, so_name
, client_name
, options
, int_ref
, uuid
, status
);
163 int JackServer::InternalClientLoadAux(JackLoadableInternalClient
* client
, const char* so_name
, const char* client_name
, int options
, int* int_ref
, int uuid
, int* status
)
168 // Client object is internally kept in JackEngine
169 if ((client
->Init(so_name
) < 0) || (client
->Open(JACK_DEFAULT_SERVER_NAME
, client_name
, uuid
, (jack_options_t
)options
, (jack_status_t
*)status
) < 0)) {
171 int my_status1
= *status
| JackFailure
;
172 *status
= (jack_status_t
)my_status1
;
176 *int_ref
= client
->GetClientControl()->fRefNum
;
181 int JackServer::Start()
183 jack_log("JackServer::Start");
184 if (fAudioDriver
->Start() < 0) {
187 return fChannel
.Start();
190 int JackServer::Stop()
192 jack_log("JackServer::Stop");
198 return fThreadedFreewheelDriver
->Stop();
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");
221 if (fAudioDriver
->IsFixedBufferSize()) {
222 jack_log("SetBufferSize: driver only supports a fixed buffer size");
226 if (fAudioDriver
->Stop() != 0) {
227 jack_error("Cannot stop audio driver");
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...
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
);
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();
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();
287 // Coming from the RT thread
288 void JackServer::Notify(int refnum
, int notify
, int value
)
292 case kGraphOrderCallback
:
293 fEngine
->NotifyGraphReorder();
297 fEngine
->NotifyXRun(refnum
);
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
);
326 slave
->SetMaster(false);
327 fAudioDriver
->AddSlave(slave
);
331 void JackServer::RemoveSlave(JackDriverInfo
* info
)
333 JackDriverClientInterface
* slave
= info
->GetBackend();
334 fAudioDriver
->RemoveSlave(slave
);
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();
347 JackDriverInfo
* info
= new JackDriverInfo();
348 JackDriverClientInterface
* master
= info
->Open(driver_desc
, fEngine
, GetSynchroTable(), driver_params
);
350 if (master
== NULL
) {
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
);
369 fAudioDriver
= master
;
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()
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