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_log
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108
JackDriverInfo
Definition: JackDriverInfo.h:30
jack_error
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
jack_driver_desc_t
Definition: driver_interface.h:132
_JSList
Definition: linux/alsa/jslist.h:35
jack_info
SERVER_EXPORT void jack_info(const char *fmt,...)
Definition: JackError.cpp:100