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