Jack2 1.9.12

JackServer.cpp
1 /*
2 Copyright (C) 2001 Paul Davis
3 Copyright (C) 2004-2008 Grame
4
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.
9
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.
14
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.
18
19 */
20
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"
36 #include "JackInternalSessionLoader.h"
37
38 const char * jack_get_self_connect_mode_description(char mode);
39
40 namespace Jack
41 {
42
43 //----------------
44 // Server control
45 //----------------
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)
47 {
48 if (rt) {
49 jack_info("JACK server starting in realtime mode with priority %ld", priority);
50 } else {
51 jack_info("JACK server starting in non-realtime mode");
52 }
53
54 jack_info("self-connect-mode is \"%s\"", jack_get_self_connect_mode_description(self_connect_mode));
55
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);
59
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);
66
67 fFreewheelDriver = freewheelDriver;
68 fDriverInfo = new JackDriverInfo();
69 fAudioDriver = NULL;
70 fFreewheel = false;
71 JackServerGlobals::fInstance = this; // Unique instance
72 JackServerGlobals::fUserCount = 1; // One user
73 JackGlobals::fVerbose = verbose;
74 }
75
76 JackServer::~JackServer()
77 {
78 JackGraphManager::Destroy(fGraphManager);
79 delete fDriverInfo;
80 delete fThreadedFreewheelDriver;
81 delete fEngine;
82 delete fEngineControl;
83 }
84
85 int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params)
86 {
87 // TODO: move that in reworked JackServerGlobals::Init()
88 if (!JackMessageBuffer::Create()) {
89 jack_error("Cannot create message buffer");
90 }
91
92 if ((fAudioDriver = fDriverInfo->Open(driver_desc, fEngine, GetSynchroTable(), driver_params)) == NULL) {
93 jack_error("Cannot initialize driver");
94 goto fail_close1;
95 }
96
97 if (fRequestChannel.Open(fEngineControl->fServerName, this) < 0) {
98 jack_error("Server channel open error");
99 goto fail_close2;
100 }
101
102 if (fEngine->Open() < 0) {
103 jack_error("Cannot open engine");
104 goto fail_close3;
105 }
106
107 if (fFreewheelDriver->Open() < 0) {
108 jack_error("Cannot open freewheel driver");
109 goto fail_close4;
110 }
111
112 if (fAudioDriver->Attach() < 0) {
113 jack_error("Cannot attach audio driver");
114 goto fail_close5;
115 }
116
117 fFreewheelDriver->SetMaster(false);
118 fAudioDriver->SetMaster(true);
119 fAudioDriver->AddSlave(fFreewheelDriver);
120 InitTime();
121 SetClockSource(fEngineControl->fClockSource);
122 return 0;
123
124 fail_close5:
125 fFreewheelDriver->Close();
126
127 fail_close4:
128 fEngine->Close();
129
130 fail_close3:
131 fRequestChannel.Close();
132
133 fail_close2:
134 fAudioDriver->Close();
135
136 fail_close1:
137 JackMessageBuffer::Destroy();
138 return -1;
139 }
140
141 int JackServer::Close()
142 {
143 jack_log("JackServer::Close");
144 fRequestChannel.Close();
145 fAudioDriver->Detach();
146 fAudioDriver->Close();
147 fFreewheelDriver->Close();
148 fEngine->Close();
149 // TODO: move that in reworked JackServerGlobals::Destroy()
150 JackMessageBuffer::Destroy();
151 EndTime();
152 return 0;
153 }
154
155 int JackServer::Start()
156 {
157 jack_log("JackServer::Start");
158 if (fAudioDriver->Start() < 0) {
159 return -1;
160 }
161 return fRequestChannel.Start();
162 }
163
164 int JackServer::Stop()
165 {
166 jack_log("JackServer::Stop");
167 int res = -1;
168
169 if (fFreewheel) {
170 if (fThreadedFreewheelDriver) {
171 res = fThreadedFreewheelDriver->Stop();
172 }
173 } else {
174 if (fAudioDriver) {
175 res = fAudioDriver->Stop();
176 }
177 }
178
179 fEngine->NotifyQuit();
180 fRequestChannel.Stop();
181 fEngine->NotifyFailure(JackFailure | JackServerError, JACK_SERVER_FAILURE);
182
183 return res;
184 }
185
186 bool JackServer::IsRunning()
187 {
188 jack_log("JackServer::IsRunning");
189 assert(fAudioDriver);
190 return fAudioDriver->IsRunning();
191 }
192
193 //------------------
194 // Internal clients
195 //------------------
196
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)
198 {
199 JackLoadableInternalClient* client = new JackLoadableInternalClient1(JackServerGlobals::fInstance, GetSynchroTable(), objet_data);
200 assert(client);
201 return InternalClientLoadAux(client, so_name, client_name, options, int_ref, uuid, status);
202 }
203
204 int JackServer::InternalClientLoad2(const char* client_name, const char* so_name, const JSList * parameters, int options, int* int_ref, int uuid, int* status)
205 {
206 JackLoadableInternalClient* client = new JackLoadableInternalClient2(JackServerGlobals::fInstance, GetSynchroTable(), parameters);
207 assert(client);
208 return InternalClientLoadAux(client, so_name, client_name, options, int_ref, uuid, status);
209 }
210
211 int JackServer::InternalClientLoadAux(JackLoadableInternalClient* client, const char* so_name, const char* client_name, int options, int* int_ref, int uuid, int* status)
212 {
213 // Clear status
214 *status = 0;
215
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)) {
218 delete client;
219 int my_status1 = *status | JackFailure;
220 *status = (jack_status_t)my_status1;
221 *int_ref = 0;
222 return -1;
223 } else {
224 *int_ref = client->GetClientControl()->fRefNum;
225 return 0;
226 }
227 }
228
229 //-----------------------
230 // Internal session file
231 //-----------------------
232
233 int JackServer::LoadInternalSessionFile(const char* file)
234 {
235 JackInternalSessionLoader loader(this);
236 return loader.Load(file);
237 }
238
239 //---------------------------
240 // From request thread : API
241 //---------------------------
242
243 int JackServer::SetBufferSize(jack_nframes_t buffer_size)
244 {
245 jack_log("JackServer::SetBufferSize nframes = %ld", buffer_size);
246 jack_nframes_t current_buffer_size = fEngineControl->fBufferSize;
247
248 if (current_buffer_size == buffer_size) {
249 jack_log("SetBufferSize: requirement for new buffer size equals current value");
250 return 0;
251 }
252
253 if (fAudioDriver->IsFixedBufferSize()) {
254 jack_log("SetBufferSize: driver only supports a fixed buffer size");
255 return -1;
256 }
257
258 if (fAudioDriver->Stop() != 0) {
259 jack_error("Cannot stop audio driver");
260 return -1;
261 }
262
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...
271 return -1;
272 }
273 }
274
275 /*
276 Freewheel mode is implemented by switching from the (audio [slaves] + freewheel) driver to the freewheel driver only:
277
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"
282
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.
285 */
286
287 int JackServer::SetFreewheel(bool onoff)
288 {
289 jack_log("JackServer::SetFreewheel is = %ld want = %ld", fFreewheel, onoff);
290
291 if (fFreewheel) {
292 if (onoff) {
293 return -1;
294 } else {
295 fFreewheel = false;
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();
302 }
303 } else {
304 if (onoff) {
305 fFreewheel = true;
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);
313 assert(slave);
314 fGraphManager->DisconnectAllPorts(slave->GetClientControl()->fRefNum);
315 }
316 // Disconnect master
317 fGraphManager->DisconnectAllPorts(fAudioDriver->GetClientControl()->fRefNum);
318 fEngine->NotifyFreewheel(onoff);
319 fAudioDriver->SetMaster(false);
320 fFreewheelDriver->SetMaster(true);
321 return fThreadedFreewheelDriver->Start();
322 } else {
323 return -1;
324 }
325 }
326 }
327
328 //---------------------------
329 // Coming from the RT thread
330 //---------------------------
331
332 void JackServer::Notify(int refnum, int notify, int value)
333 {
334 switch (notify) {
335
336 case kGraphOrderCallback:
337 fEngine->NotifyGraphReorder();
338 break;
339
340 case kXRunCallback:
341 fEngine->NotifyClientXRun(refnum);
342 break;
343 }
344 }
345
346 //--------------------
347 // Backend management
348 //--------------------
349
350 JackDriverInfo* JackServer::AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params)
351 {
352 JackDriverInfo* info = new JackDriverInfo();
353 JackDriverClientInterface* slave = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
354
355 if (!slave) {
356 goto error1;
357 }
358 if (slave->Attach() < 0) {
359 goto error2;
360 }
361
362 slave->SetMaster(false);
363 fAudioDriver->AddSlave(slave);
364 return info;
365
366 error2:
367 slave->Close();
368
369 error1:
370 delete info;
371 return NULL;
372 }
373
374 void JackServer::RemoveSlave(JackDriverInfo* info)
375 {
376 JackDriverClientInterface* slave = info->GetBackend();
377 fAudioDriver->RemoveSlave(slave);
378 slave->Detach();
379 slave->Close();
380 }
381
382 int JackServer::SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_params)
383 {
384 std::list<JackDriverInterface*> slave_list;
385 std::list<JackDriverInterface*>::const_iterator it;
386
387 // Remove current master
388 fAudioDriver->Stop();
389 fAudioDriver->Detach();
390 fAudioDriver->Close();
391
392 // Open new master
393 JackDriverInfo* info = new JackDriverInfo();
394 JackDriverClientInterface* master = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
395
396 if (!master) {
397 goto error;
398 }
399
400 // Get slaves list
401 slave_list = fAudioDriver->GetSlaves();
402
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);
407 }
408
409 // Delete old master
410 delete fDriverInfo;
411
412 // Activate master
413 fAudioDriver = master;
414 fDriverInfo = info;
415
416 if (fAudioDriver->Attach() < 0) {
417 goto error;
418 }
419
420 // Notify clients of new values
421 fEngine->NotifyBufferSize(fEngineControl->fBufferSize);
422 fEngine->NotifySampleRate(fEngineControl->fSampleRate);
423
424 // And finally start
425 fAudioDriver->SetMaster(true);
426 return fAudioDriver->Start();
427
428 error:
429 delete info;
430 return -1;
431 }
432
433 //----------------------
434 // Transport management
435 //----------------------
436
437 int JackServer::ReleaseTimebase(int refnum)
438 {
439 return fEngineControl->fTransport.ResetTimebase(refnum);
440 }
441
442 int JackServer::SetTimebaseCallback(int refnum, int conditional)
443 {
444 return fEngineControl->fTransport.SetTimebaseMaster(refnum, conditional);
445 }
446
447 JackLockedEngine* JackServer::GetEngine()
448 {
449 return fEngine;
450 }
451
452 JackSynchro* JackServer::GetSynchroTable()
453 {
454 return fSynchroTable;
455 }
456
457 JackEngineControl* JackServer::GetEngineControl()
458 {
459 return fEngineControl;
460 }
461
462 JackGraphManager* JackServer::GetGraphManager()
463 {
464 return fGraphManager;
465 }
466
467 } // end of namespace
468
jack_error
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
jack_info
SERVER_EXPORT void jack_info(const char *fmt,...)
Definition: JackError.cpp:100
JackDriverInfo
Definition: JackDriverInfo.h:30
_JSList
Definition: linux/alsa/jslist.h:35
jack_log
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108
jack_driver_desc_t
Definition: driver_interface.h:132