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