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 "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"
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
)
44 jack_info("JACK server starting in realtime mode with priority %ld", priority
);
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();
56 JackServerGlobals::fInstance
= this; // Unique instance
57 JackServerGlobals::fUserCount
= 1; // One user
58 JackGlobals::fVerbose
= verbose
;
61 JackServer::~JackServer()
63 JackGraphManager::Destroy(fGraphManager
);
66 delete fFreewheelDriver
;
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");
81 if (fEngine
->Open() < 0) {
82 jack_error("Cannot open engine");
86 if ((fAudioDriver
= fDriverInfo
->Open(driver_desc
, fEngine
, GetSynchroTable(), driver_params
)) == NULL
) {
87 jack_error("Cannot initialize driver");
91 if (fFreewheelDriver
->Open() < 0) { // before engine open
92 jack_error("Cannot open driver");
96 if (fAudioDriver
->Attach() < 0) {
97 jack_error("Cannot attach audio driver");
101 fFreewheelDriver
->SetMaster(false);
102 fAudioDriver
->SetMaster(true);
103 fAudioDriver
->AddSlave(fFreewheelDriver
); // After ???
105 SetClockSource(fEngineControl
->fClockSource
);
109 fFreewheelDriver
->Close();
112 fAudioDriver
->Close();
121 JackMessageBuffer::Destroy();
125 int JackServer::Close()
127 jack_log("JackServer::Close");
128 fEngine
->NotifyQuit();
130 fAudioDriver
->Detach();
131 fAudioDriver
->Close();
132 fFreewheelDriver
->Close();
134 // TODO: move that in reworked JackServerGlobals::Destroy()
135 JackMessageBuffer::Destroy();
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
);
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
);
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
)
157 if ((client
->Init(so_name
) < 0) || (client
->Open(JACK_DEFAULT_SERVER_NAME
, client_name
, (jack_options_t
)options
, (jack_status_t
*)status
) < 0)) {
159 int my_status1
= *status
| JackFailure
;
160 *status
= (jack_status_t
)my_status1
;
164 *int_ref
= client
->GetClientControl()->fRefNum
;
169 int JackServer::Start()
171 jack_log("JackServer::Start");
172 if (fAudioDriver
->Start() < 0) {
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");
194 if (fAudioDriver
->IsFixedBufferSize()) {
195 jack_log("SetBufferSize: driver only supports a fixed buffer size");
199 if (fAudioDriver
->Stop() != 0) {
200 jack_error("Cannot stop audio driver");
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...
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
);
239 fFreewheelDriver
->Stop();
240 fGraphManager
->Restore(&fConnectionState
); // Restore previous connection state
241 fEngine
->NotifyFreewheel(onoff
);
242 fFreewheelDriver
->SetMaster(false);
243 return fAudioDriver
->Start();
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();
260 // Coming from the RT thread
261 void JackServer::Notify(int refnum
, int notify
, int value
)
265 case kGraphOrderCallback
:
266 fEngine
->NotifyGraphReorder();
270 fEngine
->NotifyXRun(refnum
);
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
);
300 fAudioDriver
->AddSlave(slave
);
305 void JackServer::RemoveSlave(JackDriverInfo
* info
)
307 JackDriverClientInterface
* slave
= info
->GetBackend();
308 fAudioDriver
->RemoveSlave(slave
);
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();
321 JackDriverInfo
* info
= new JackDriverInfo();
322 JackDriverClientInterface
* master
= info
->Open(driver_desc
, fEngine
, GetSynchroTable(), driver_params
);
324 if (master
== NULL
|| info
== NULL
) {
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
);
345 fAudioDriver
= master
;
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()
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