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"
36 #include "JackInternalSessionLoader.h"
38 const char * jack_get_self_connect_mode_description(char mode
);
46 JackServer::JackServer(bool sync
, bool temporary
, int timeout
, bool rt
, int priority
, int port_max
, bool verbose
, jack_timer_type_t clock
, char self_connect_mode
, const char* server_name
)
49 jack_info("JACK server starting in realtime mode with priority %ld", priority
);
51 jack_info("JACK server starting in non-realtime mode");
54 jack_info("self-connect-mode is \"%s\"", jack_get_self_connect_mode_description(self_connect_mode
));
56 fGraphManager
= JackGraphManager::Allocate(port_max
);
57 fEngineControl
= new JackEngineControl(sync
, temporary
, timeout
, rt
, priority
, verbose
, clock
, server_name
);
58 fEngine
= new JackLockedEngine(fGraphManager
, GetSynchroTable(), fEngineControl
, self_connect_mode
);
60 // A distinction is made between the threaded freewheel driver and the
61 // regular freewheel driver because the freewheel driver needs to run in
62 // threaded mode when freewheel mode is active and needs to run as a slave
63 // when freewheel mode isn't active.
64 JackFreewheelDriver
* freewheelDriver
= new JackFreewheelDriver(fEngine
, GetSynchroTable());
65 fThreadedFreewheelDriver
= new JackThreadedDriver(freewheelDriver
);
67 fFreewheelDriver
= freewheelDriver
;
68 fDriverInfo
= new JackDriverInfo();
71 JackServerGlobals::fInstance
= this; // Unique instance
72 JackServerGlobals::fUserCount
= 1; // One user
73 JackGlobals::fVerbose
= verbose
;
76 JackServer::~JackServer()
78 JackGraphManager::Destroy(fGraphManager
);
80 delete fThreadedFreewheelDriver
;
82 delete fEngineControl
;
85 int JackServer::Open(jack_driver_desc_t
* driver_desc
, JSList
* driver_params
)
87 // TODO: move that in reworked JackServerGlobals::Init()
88 if (!JackMessageBuffer::Create()) {
89 jack_error("Cannot create message buffer");
92 if ((fAudioDriver
= fDriverInfo
->Open(driver_desc
, fEngine
, GetSynchroTable(), driver_params
)) == NULL
) {
93 jack_error("Cannot initialize driver");
97 if (fRequestChannel
.Open(fEngineControl
->fServerName
, this) < 0) {
98 jack_error("Server channel open error");
102 if (fEngine
->Open() < 0) {
103 jack_error("Cannot open engine");
107 if (fFreewheelDriver
->Open() < 0) {
108 jack_error("Cannot open freewheel driver");
112 if (fAudioDriver
->Attach() < 0) {
113 jack_error("Cannot attach audio driver");
117 fFreewheelDriver
->SetMaster(false);
118 fAudioDriver
->SetMaster(true);
119 fAudioDriver
->AddSlave(fFreewheelDriver
);
121 SetClockSource(fEngineControl
->fClockSource
);
125 fFreewheelDriver
->Close();
131 fRequestChannel
.Close();
134 fAudioDriver
->Close();
137 JackMessageBuffer::Destroy();
141 int JackServer::Close()
143 jack_log("JackServer::Close");
144 fRequestChannel
.Close();
145 fAudioDriver
->Detach();
146 fAudioDriver
->Close();
147 fFreewheelDriver
->Close();
149 // TODO: move that in reworked JackServerGlobals::Destroy()
150 JackMessageBuffer::Destroy();
155 int JackServer::Start()
157 jack_log("JackServer::Start");
158 if (fAudioDriver
->Start() < 0) {
161 return fRequestChannel
.Start();
164 int JackServer::Stop()
166 jack_log("JackServer::Stop");
170 if (fThreadedFreewheelDriver
) {
171 res
= fThreadedFreewheelDriver
->Stop();
175 res
= fAudioDriver
->Stop();
179 fEngine
->NotifyQuit();
180 fRequestChannel
.Stop();
181 fEngine
->NotifyFailure(JackFailure
| JackServerError
, JACK_SERVER_FAILURE
);
186 bool JackServer::IsRunning()
188 jack_log("JackServer::IsRunning");
189 assert(fAudioDriver
);
190 return fAudioDriver
->IsRunning();
197 int JackServer::InternalClientLoad1(const char* client_name
, const char* so_name
, const char* objet_data
, int options
, int* int_ref
, int uuid
, int* status
)
199 JackLoadableInternalClient
* client
= new JackLoadableInternalClient1(JackServerGlobals::fInstance
, GetSynchroTable(), objet_data
);
201 return InternalClientLoadAux(client
, so_name
, client_name
, options
, int_ref
, uuid
, status
);
204 int JackServer::InternalClientLoad2(const char* client_name
, const char* so_name
, const JSList
* parameters
, int options
, int* int_ref
, int uuid
, int* status
)
206 JackLoadableInternalClient
* client
= new JackLoadableInternalClient2(JackServerGlobals::fInstance
, GetSynchroTable(), parameters
);
208 return InternalClientLoadAux(client
, so_name
, client_name
, options
, int_ref
, uuid
, status
);
211 int JackServer::InternalClientLoadAux(JackLoadableInternalClient
* client
, const char* so_name
, const char* client_name
, int options
, int* int_ref
, int uuid
, int* status
)
216 // Client object is internally kept in JackEngine
217 if ((client
->Init(so_name
) < 0) || (client
->Open(JackTools::DefaultServerName(), client_name
, uuid
, (jack_options_t
)options
, (jack_status_t
*)status
) < 0)) {
219 int my_status1
= *status
| JackFailure
;
220 *status
= (jack_status_t
)my_status1
;
224 *int_ref
= client
->GetClientControl()->fRefNum
;
229 //-----------------------
230 // Internal session file
231 //-----------------------
233 int JackServer::LoadInternalSessionFile(const char* file
)
235 JackInternalSessionLoader
loader(this);
236 return loader
.Load(file
);
239 //---------------------------
240 // From request thread : API
241 //---------------------------
243 int JackServer::SetBufferSize(jack_nframes_t buffer_size
)
245 jack_log("JackServer::SetBufferSize nframes = %ld", buffer_size
);
246 jack_nframes_t current_buffer_size
= fEngineControl
->fBufferSize
;
248 if (current_buffer_size
== buffer_size
) {
249 jack_log("SetBufferSize: requirement for new buffer size equals current value");
253 if (fAudioDriver
->IsFixedBufferSize()) {
254 jack_log("SetBufferSize: driver only supports a fixed buffer size");
258 if (fAudioDriver
->Stop() != 0) {
259 jack_error("Cannot stop audio driver");
263 if (fAudioDriver
->SetBufferSize(buffer_size
) == 0) {
264 fEngine
->NotifyBufferSize(buffer_size
);
265 return fAudioDriver
->Start();
266 } else { // Failure: try to restore current value
267 jack_error("Cannot SetBufferSize for audio driver, restore current value %ld", current_buffer_size
);
268 fAudioDriver
->SetBufferSize(current_buffer_size
);
269 fAudioDriver
->Start();
270 // SetBufferSize actually failed, so return an error...
276 Freewheel mode is implemented by switching from the (audio [slaves] + freewheel) driver to the freewheel driver only:
278 - "global" connection state is saved
279 - all audio driver and slaves ports are deconnected, thus there is no more dependancies with the audio driver and slaves
280 - the freewheel driver will be synchronized with the end of graph execution : all clients are connected to the freewheel driver
281 - the freewheel driver becomes the "master"
283 Normal mode is restored with the connections state valid before freewheel mode was done. Thus one consider that
284 no graph state change can be done during freewheel mode.
287 int JackServer::SetFreewheel(bool onoff
)
289 jack_log("JackServer::SetFreewheel is = %ld want = %ld", fFreewheel
, onoff
);
296 fThreadedFreewheelDriver
->Stop();
297 fGraphManager
->Restore(&fConnectionState
); // Restore connection state
298 fEngine
->NotifyFreewheel(onoff
);
299 fFreewheelDriver
->SetMaster(false);
300 fAudioDriver
->SetMaster(true);
301 return fAudioDriver
->Start();
306 fAudioDriver
->Stop();
307 fGraphManager
->Save(&fConnectionState
); // Save connection state
308 // Disconnect all slaves
309 std::list
<JackDriverInterface
*> slave_list
= fAudioDriver
->GetSlaves();
310 std::list
<JackDriverInterface
*>::const_iterator it
;
311 for (it
= slave_list
.begin(); it
!= slave_list
.end(); it
++) {
312 JackDriver
* slave
= dynamic_cast<JackDriver
*>(*it
);
314 fGraphManager
->DisconnectAllPorts(slave
->GetClientControl()->fRefNum
);
317 fGraphManager
->DisconnectAllPorts(fAudioDriver
->GetClientControl()->fRefNum
);
318 fEngine
->NotifyFreewheel(onoff
);
319 fAudioDriver
->SetMaster(false);
320 fFreewheelDriver
->SetMaster(true);
321 return fThreadedFreewheelDriver
->Start();
328 //---------------------------
329 // Coming from the RT thread
330 //---------------------------
332 void JackServer::Notify(int refnum
, int notify
, int value
)
336 case kGraphOrderCallback
:
337 fEngine
->NotifyGraphReorder();
341 fEngine
->NotifyClientXRun(refnum
);
346 //--------------------
347 // Backend management
348 //--------------------
350 JackDriverInfo
* JackServer::AddSlave(jack_driver_desc_t
* driver_desc
, JSList
* driver_params
)
352 JackDriverInfo
* info
= new JackDriverInfo();
353 JackDriverClientInterface
* slave
= info
->Open(driver_desc
, fEngine
, GetSynchroTable(), driver_params
);
358 if (slave
->Attach() < 0) {
362 slave
->SetMaster(false);
363 fAudioDriver
->AddSlave(slave
);
374 void JackServer::RemoveSlave(JackDriverInfo
* info
)
376 JackDriverClientInterface
* slave
= info
->GetBackend();
377 fAudioDriver
->RemoveSlave(slave
);
382 int JackServer::SwitchMaster(jack_driver_desc_t
* driver_desc
, JSList
* driver_params
)
384 std::list
<JackDriverInterface
*> slave_list
;
385 std::list
<JackDriverInterface
*>::const_iterator it
;
387 // Remove current master
388 fAudioDriver
->Stop();
389 fAudioDriver
->Detach();
390 fAudioDriver
->Close();
393 JackDriverInfo
* info
= new JackDriverInfo();
394 JackDriverClientInterface
* master
= info
->Open(driver_desc
, fEngine
, GetSynchroTable(), driver_params
);
401 slave_list
= fAudioDriver
->GetSlaves();
403 // Move slaves in new master
404 for (it
= slave_list
.begin(); it
!= slave_list
.end(); it
++) {
405 JackDriverInterface
* slave
= *it
;
406 master
->AddSlave(slave
);
413 fAudioDriver
= master
;
416 if (fAudioDriver
->Attach() < 0) {
420 // Notify clients of new values
421 fEngine
->NotifyBufferSize(fEngineControl
->fBufferSize
);
422 fEngine
->NotifySampleRate(fEngineControl
->fSampleRate
);
425 fAudioDriver
->SetMaster(true);
426 return fAudioDriver
->Start();
433 //----------------------
434 // Transport management
435 //----------------------
437 int JackServer::ReleaseTimebase(int refnum
)
439 return fEngineControl
->fTransport
.ResetTimebase(refnum
);
442 int JackServer::SetTimebaseCallback(int refnum
, int conditional
)
444 return fEngineControl
->fTransport
.SetTimebaseMaster(refnum
, conditional
);
447 JackLockedEngine
* JackServer::GetEngine()
452 JackSynchro
* JackServer::GetSynchroTable()
454 return fSynchroTable
;
457 JackEngineControl
* JackServer::GetEngineControl()
459 return fEngineControl
;
462 JackGraphManager
* JackServer::GetGraphManager()
464 return fGraphManager
;
467 } // end of namespace