Jack2  1.9.8
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 
37 namespace Jack
38 {
39 
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)
41 {
42  if (rt) {
43  jack_info("JACK server starting in realtime mode with priority %ld", priority);
44  } else {
45  jack_info("JACK server starting in non-realtime mode");
46  }
47 
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);
51 
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);
59 
60  fFreewheelDriver = freewheelDriver;
61  fDriverInfo = new JackDriverInfo();
62  fAudioDriver = NULL;
63  fFreewheel = false;
64  JackServerGlobals::fInstance = this; // Unique instance
65  JackServerGlobals::fUserCount = 1; // One user
66  JackGlobals::fVerbose = verbose;
67 }
68 
69 JackServer::~JackServer()
70 {
71  JackGraphManager::Destroy(fGraphManager);
72  delete fDriverInfo;
73  delete fThreadedFreewheelDriver;
74  delete fEngine;
75  delete fEngineControl;
76 }
77 
78 int JackServer::Open(jack_driver_desc_t* driver_desc, JSList* driver_params)
79 {
80  // TODO: move that in reworked JackServerGlobals::Init()
81  JackMessageBuffer::Create();
82 
83  if ((fAudioDriver = fDriverInfo->Open(driver_desc, fEngine, GetSynchroTable(), driver_params)) == NULL) {
84  jack_error("Cannot initialize driver");
85  goto fail_close1;
86  }
87 
88  if (fChannel.Open(fEngineControl->fServerName, this) < 0) {
89  jack_error("Server channel open error");
90  goto fail_close2;
91  }
92 
93  if (fEngine->Open() < 0) {
94  jack_error("Cannot open engine");
95  goto fail_close3;
96  }
97 
98  if (fFreewheelDriver->Open() < 0) {
99  jack_error("Cannot open freewheel driver");
100  goto fail_close4;
101  }
102 
103  if (fAudioDriver->Attach() < 0) {
104  jack_error("Cannot attach audio driver");
105  goto fail_close5;
106  }
107 
108  fFreewheelDriver->SetMaster(false);
109  fAudioDriver->SetMaster(true);
110  fAudioDriver->AddSlave(fFreewheelDriver);
111  InitTime();
112  SetClockSource(fEngineControl->fClockSource);
113  return 0;
114 
115 fail_close5:
116  fFreewheelDriver->Close();
117 
118 fail_close4:
119  fEngine->Close();
120 
121 fail_close3:
122  fChannel.Close();
123 
124 fail_close2:
125  fAudioDriver->Close();
126 
127 fail_close1:
128  JackMessageBuffer::Destroy();
129  return -1;
130 }
131 
132 int JackServer::Close()
133 {
134  jack_log("JackServer::Close");
135  fEngine->NotifyQuit();
136  fChannel.Close();
137  fAudioDriver->Detach();
138  fAudioDriver->Close();
139  fFreewheelDriver->Close();
140  fEngine->Close();
141  // TODO: move that in reworked JackServerGlobals::Destroy()
142  JackMessageBuffer::Destroy();
143  return 0;
144 }
145 
146 int JackServer::InternalClientLoad1(const char* client_name, const char* so_name, const char* objet_data, int options, int* int_ref, int uuid, int* status)
147 {
148  JackLoadableInternalClient* client = new JackLoadableInternalClient1(JackServerGlobals::fInstance, GetSynchroTable(), objet_data);
149  assert(client);
150  return InternalClientLoadAux(client, so_name, client_name, options, int_ref, uuid, status);
151  }
152 
153 int JackServer::InternalClientLoad2(const char* client_name, const char* so_name, const JSList * parameters, int options, int* int_ref, int uuid, int* status)
154 {
155  JackLoadableInternalClient* client = new JackLoadableInternalClient2(JackServerGlobals::fInstance, GetSynchroTable(), parameters);
156  assert(client);
157  return InternalClientLoadAux(client, so_name, client_name, options, int_ref, uuid, status);
158 }
159 
160 int JackServer::InternalClientLoadAux(JackLoadableInternalClient* client, const char* so_name, const char* client_name, int options, int* int_ref, int uuid, int* status)
161 {
162  // Clear status
163  *status = 0;
164 
165  // Client object is internally kept in JackEngine
166  if ((client->Init(so_name) < 0) || (client->Open(JACK_DEFAULT_SERVER_NAME, client_name, uuid, (jack_options_t)options, (jack_status_t*)status) < 0)) {
167  delete client;
168  int my_status1 = *status | JackFailure;
169  *status = (jack_status_t)my_status1;
170  *int_ref = 0;
171  return -1;
172  } else {
173  *int_ref = client->GetClientControl()->fRefNum;
174  return 0;
175  }
176  }
177 
178 int JackServer::Start()
179 {
180  jack_log("JackServer::Start");
181  if (fAudioDriver->Start() < 0) {
182  return -1;
183  }
184  return fChannel.Start();
185 }
186 
187 int JackServer::Stop()
188 {
189  jack_log("JackServer::Stop");
190  fChannel.Stop();
191 
192  if (fFreewheel) {
193  return fThreadedFreewheelDriver->Stop();
194  } else {
195  return fAudioDriver->Stop();
196  }
197 }
198 
199 bool JackServer::IsRunning()
200 {
201  jack_log("JackServer::IsRunning");
202  assert(fAudioDriver);
203  return fAudioDriver->IsRunning();
204 }
205 
206 int JackServer::SetBufferSize(jack_nframes_t buffer_size)
207 {
208  jack_log("JackServer::SetBufferSize nframes = %ld", buffer_size);
209  jack_nframes_t current_buffer_size = fEngineControl->fBufferSize;
210 
211  if (current_buffer_size == buffer_size) {
212  jack_log("SetBufferSize: requirement for new buffer size equals current value");
213  return 0;
214  }
215 
216  if (fAudioDriver->IsFixedBufferSize()) {
217  jack_log("SetBufferSize: driver only supports a fixed buffer size");
218  return -1;
219  }
220 
221  if (fAudioDriver->Stop() != 0) {
222  jack_error("Cannot stop audio driver");
223  return -1;
224  }
225 
226  if (fAudioDriver->SetBufferSize(buffer_size) == 0) {
227  fEngine->NotifyBufferSize(buffer_size);
228  return fAudioDriver->Start();
229  } else { // Failure: try to restore current value
230  jack_error("Cannot SetBufferSize for audio driver, restore current value %ld", current_buffer_size);
231  fAudioDriver->SetBufferSize(current_buffer_size);
232  fAudioDriver->Start();
233  // SetBufferSize actually failed, so return an error...
234  return -1;
235  }
236 }
237 
238 /*
239 Freewheel mode is implemented by switching from the (audio + freewheel) driver to the freewheel driver only:
240 
241  - "global" connection state is saved
242  - all audio driver ports are deconnected, thus there is no more dependancies with the audio driver
243  - the freewheel driver will be synchronized with the end of graph execution : all clients are connected to the freewheel driver
244  - the freewheel driver becomes the "master"
245 
246 Normal mode is restored with the connections state valid before freewheel mode was done. Thus one consider that
247 no graph state change can be done during freewheel mode.
248 */
249 
250 int JackServer::SetFreewheel(bool onoff)
251 {
252  jack_log("JackServer::SetFreewheel is = %ld want = %ld", fFreewheel, onoff);
253 
254  if (fFreewheel) {
255  if (onoff) {
256  return -1;
257  } else {
258  fFreewheel = false;
259  fThreadedFreewheelDriver->Stop();
260  fGraphManager->Restore(&fConnectionState); // Restore previous connection state
261  fEngine->NotifyFreewheel(onoff);
262  fFreewheelDriver->SetMaster(false);
263  fAudioDriver->SetMaster(true);
264  return fAudioDriver->Start();
265  }
266  } else {
267  if (onoff) {
268  fFreewheel = true;
269  fAudioDriver->Stop();
270  fGraphManager->Save(&fConnectionState); // Save connection state
271  fGraphManager->DisconnectAllPorts(fAudioDriver->GetClientControl()->fRefNum);
272  fEngine->NotifyFreewheel(onoff);
273  fAudioDriver->SetMaster(false);
274  fFreewheelDriver->SetMaster(true);
275  return fThreadedFreewheelDriver->Start();
276  } else {
277  return -1;
278  }
279  }
280 }
281 
282 // Coming from the RT thread
283 void JackServer::Notify(int refnum, int notify, int value)
284 {
285  switch (notify) {
286 
287  case kGraphOrderCallback:
288  fEngine->NotifyGraphReorder();
289  break;
290 
291  case kXRunCallback:
292  fEngine->NotifyXRun(refnum);
293  break;
294  }
295 }
296 
297 void JackServer::ClientKill(int refnum)
298 {
299  jack_log("JackServer::ClientKill ref = %ld", refnum);
300  if (fEngine->ClientDeactivate(refnum) < 0) {
301  jack_error("JackServer::ClientKill ref = %ld cannot be removed from the graph !!", refnum);
302  }
303  if (fEngine->ClientExternalClose(refnum) < 0) {
304  jack_error("JackServer::ClientKill ref = %ld cannot be closed", refnum);
305  }
306 }
307 
308 //----------------------
309 // Backend management
310 //----------------------
311 
312 JackDriverInfo* JackServer::AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params)
313 {
314  JackDriverInfo* info = new JackDriverInfo();
315  JackDriverClientInterface* slave = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
316  if (slave == NULL) {
317  delete info;
318  return NULL;
319  }
320  slave->Attach();
321  slave->SetMaster(false);
322  fAudioDriver->AddSlave(slave);
323  return info;
324 }
325 
326 void JackServer::RemoveSlave(JackDriverInfo* info)
327 {
328  JackDriverClientInterface* slave = info->GetBackend();
329  fAudioDriver->RemoveSlave(slave);
330  slave->Detach();
331  slave->Close();
332 }
333 
334 int JackServer::SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_params)
335 {
337  fAudioDriver->Stop();
338  fAudioDriver->Detach();
339  fAudioDriver->Close();
340 
341  // Open new master
342  JackDriverInfo* info = new JackDriverInfo();
343  JackDriverClientInterface* master = info->Open(driver_desc, fEngine, GetSynchroTable(), driver_params);
344 
345  if (master == NULL) {
346  delete info;
347  return -1;
348  }
349 
350  // Get slaves list
351  std::list<JackDriverInterface*> slave_list = fAudioDriver->GetSlaves();
352  std::list<JackDriverInterface*>::const_iterator it;
353 
354  // Move slaves in new master
355  for (it = slave_list.begin(); it != slave_list.end(); it++) {
356  JackDriverInterface* slave = *it;
357  master->AddSlave(slave);
358  }
359 
360  // Delete old master
361  delete fDriverInfo;
362 
363  // Activate master
364  fAudioDriver = master;
365  fDriverInfo = info;
366  fAudioDriver->Attach();
367  fAudioDriver->SetMaster(true);
368  return fAudioDriver->Start();
369 }
370 
371 //----------------------
372 // Transport management
373 //----------------------
374 
375 int JackServer::ReleaseTimebase(int refnum)
376 {
377  return fEngineControl->fTransport.ResetTimebase(refnum);
378 }
379 
380 int JackServer::SetTimebaseCallback(int refnum, int conditional)
381 {
382  return fEngineControl->fTransport.SetTimebaseMaster(refnum, conditional);
383 }
384 
385 JackLockedEngine* JackServer::GetEngine()
386 {
387  return fEngine;
388 }
389 
390 JackSynchro* JackServer::GetSynchroTable()
391 {
392  return fSynchroTable;
393 }
394 
395 JackEngineControl* JackServer::GetEngineControl()
396 {
397  return fEngineControl;
398 }
399 
400 JackGraphManager* JackServer::GetGraphManager()
401 {
402  return fGraphManager;
403 }
404 
405 
406 } // end of namespace
407