Jack2  1.9.10
JackServerGlobals.cpp
1 /*
2 Copyright (C) 2005 Grame
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18 */
19 
20 #include "JackServerGlobals.h"
21 #include "JackLockedEngine.h"
22 #include "JackTools.h"
23 #include "shm.h"
24 #include <getopt.h>
25 #include <errno.h>
26 #include <sys/utsname.h>
27 
28 static char* server_name = NULL;
29 
30 namespace Jack
31 {
32 
33 JackServer* JackServerGlobals::fInstance;
34 unsigned int JackServerGlobals::fUserCount;
35 std::map<std::string, JackDriverInfo*> JackServerGlobals::fSlavesList;
36 std::map<std::string, int> JackServerGlobals::fInternalsList;
37 
38 bool (* JackServerGlobals::on_device_acquire)(const char * device_name) = NULL;
39 void (* JackServerGlobals::on_device_release)(const char * device_name) = NULL;
40 
41 int JackServerGlobals::Start(const char* server_name,
42  jack_driver_desc_t* driver_desc,
43  JSList* driver_params,
44  int sync,
45  int temporary,
46  int time_out_ms,
47  int rt,
48  int priority,
49  int port_max,
50  int verbose,
51  jack_timer_type_t clock,
52  char self_connect_mode)
53 {
54  jack_log("Jackdmp: sync = %ld timeout = %ld rt = %ld priority = %ld verbose = %ld ", sync, time_out_ms, rt, priority, verbose);
55  new JackServer(sync, temporary, time_out_ms, rt, priority, port_max, verbose, clock, self_connect_mode, server_name); // Will setup fInstance and fUserCount globals
56  int res = fInstance->Open(driver_desc, driver_params);
57  return (res < 0) ? res : fInstance->Start();
58 }
59 
60 void JackServerGlobals::Stop()
61 {
62  jack_log("Jackdmp: server close");
63  fInstance->Stop();
64  fInstance->Close();
65 }
66 
67 void JackServerGlobals::Delete()
68 {
69  jack_log("Jackdmp: delete server");
70 
71  // Slave drivers
72  std::map<std::string, JackDriverInfo*>::iterator it1;
73  for (it1 = fSlavesList.begin(); it1 != fSlavesList.end(); it1++) {
74  JackDriverInfo* info = (*it1).second;
75  if (info) {
76  fInstance->RemoveSlave((info));
77  delete (info);
78  }
79  }
80  fSlavesList.clear();
81 
82  // Internal clients
83  std::map<std::string, int> ::iterator it2;
84  for (it2 = fInternalsList.begin(); it2 != fInternalsList.end(); it2++) {
85  int status;
86  int refnum = (*it2).second;
87  if (refnum > 0) {
88  // Client object is internally kept in JackEngine, and will be deallocated in InternalClientUnload
89  fInstance->GetEngine()->InternalClientUnload(refnum, &status);
90  }
91  }
92  fInternalsList.clear();
93 
94  delete fInstance;
95  fInstance = NULL;
96 }
97 
98 bool JackServerGlobals::Init()
99 {
100  struct utsname utsname;
101  int success;
102  success = uname( &utsname );
103 
104  int realtime = 0;
105  int client_timeout = 0; /* msecs; if zero, use period size. */
106  int realtime_priority;
107  if( success == 0 && strstr( utsname.version, "PREEMPT RT" ) )
108  realtime_priority = 60;
109  else
110  realtime_priority = 20;
111 
112  int verbose_aux = 0;
113  unsigned int port_max = 128;
114  int temporary = 0;
115 
116  int opt = 0;
117  int option_index = 0;
118  char *master_driver_name = NULL;
119  char **master_driver_args = NULL;
120  JSList* master_driver_params = NULL;
121  jack_driver_desc_t* driver_desc;
122  jack_timer_type_t clock_source = JACK_TIMER_SYSTEM_CLOCK;
123  int driver_nargs = 1;
124  JSList* drivers = NULL;
125  int loopback = 0;
126  int sync = 0;
127  int rc, i;
128  int res;
129  int replace_registry = 0;
130 
131  FILE* fp = 0;
132  char filename[255];
133  char buffer[255];
134  int argc = 0;
135  char* argv[32];
136 
137  // First user starts the server
138  if (fUserCount++ == 0) {
139 
140  jack_log("JackServerGlobals Init");
141 
142  const char *options = "-d:X:I:P:uvshVrRL:STFl:t:mn:p:"
143  #ifdef __linux__
144  "c:"
145  #endif
146  ;
147 
148  struct option long_options[] = {
149  #ifdef __linux__
150  { "clock-source", 1, 0, 'c' },
151  #endif
152  { "loopback-driver", 1, 0, 'L' },
153  { "audio-driver", 1, 0, 'd' },
154  { "midi-driver", 1, 0, 'X' },
155  { "internal-client", 1, 0, 'I' },
156  { "verbose", 0, 0, 'v' },
157  { "help", 0, 0, 'h' },
158  { "port-max", 1, 0, 'p' },
159  { "no-mlock", 0, 0, 'm' },
160  { "name", 1, 0, 'n' },
161  { "unlock", 0, 0, 'u' },
162  { "realtime", 0, 0, 'R' },
163  { "no-realtime", 0, 0, 'r' },
164  { "replace-registry", 0, &replace_registry, 0 },
165  { "loopback", 0, 0, 'L' },
166  { "realtime-priority", 1, 0, 'P' },
167  { "timeout", 1, 0, 't' },
168  { "temporary", 0, 0, 'T' },
169  { "version", 0, 0, 'V' },
170  { "silent", 0, 0, 's' },
171  { "sync", 0, 0, 'S' },
172  { 0, 0, 0, 0 }
173  };
174 
175  snprintf(filename, 255, "%s/.jackdrc", getenv("HOME"));
176  fp = fopen(filename, "r");
177 
178  if (!fp) {
179  fp = fopen("/etc/jackdrc", "r");
180  }
181  // if still not found, check old config name for backwards compatability
182  if (!fp) {
183  fp = fopen("/etc/jackd.conf", "r");
184  }
185 
186  argc = 0;
187  if (fp) {
188  res = fscanf(fp, "%s", buffer);
189  while (res != 0 && res != EOF) {
190  argv[argc] = (char*)malloc(64);
191  strcpy(argv[argc], buffer);
192  res = fscanf(fp, "%s", buffer);
193  argc++;
194  }
195  fclose(fp);
196  }
197 
198  /*
199  For testing
200  int argc = 15;
201  char* argv[] = {"jackdmp", "-R", "-v", "-d", "coreaudio", "-p", "512", "-d", "~:Aggregate:0", "-r", "48000", "-i", "2", "-o", "2" };
202  */
203 
204  opterr = 0;
205  optind = 1; // Important : to reset argv parsing
206 
207  while (!master_driver_name &&
208  (opt = getopt_long(argc, argv, options, long_options, &option_index)) != EOF) {
209 
210  switch (opt) {
211 
212  case 'c':
213  if (tolower (optarg[0]) == 'h') {
214  clock_source = JACK_TIMER_HPET;
215  } else if (tolower (optarg[0]) == 'c') {
216  /* For backwards compatibility with scripts, allow
217  * the user to request the cycle clock on the
218  * command line, but use the system clock instead
219  */
220  clock_source = JACK_TIMER_SYSTEM_CLOCK;
221  } else if (tolower (optarg[0]) == 's') {
222  clock_source = JACK_TIMER_SYSTEM_CLOCK;
223  } else {
224  jack_error("unknown option character %c", optopt);
225  }
226  break;
227 
228  case 'd':
229  master_driver_name = optarg;
230  break;
231 
232  case 'L':
233  loopback = atoi(optarg);
234  break;
235 
236  case 'X':
237  fSlavesList[optarg] = NULL;
238  break;
239 
240  case 'I':
241  fInternalsList[optarg] = -1;
242  break;
243 
244  case 'p':
245  port_max = (unsigned int)atol(optarg);
246  break;
247 
248  case 'm':
249  break;
250 
251  case 'u':
252  break;
253 
254  case 'v':
255  verbose_aux = 1;
256  break;
257 
258  case 'S':
259  sync = 1;
260  break;
261 
262  case 'n':
263  server_name = optarg;
264  break;
265 
266  case 'P':
267  realtime_priority = atoi(optarg);
268  break;
269 
270  case 'r':
271  realtime = 0;
272  break;
273 
274  case 'R':
275  realtime = 1;
276  break;
277 
278  case 'T':
279  temporary = 1;
280  break;
281 
282  case 't':
283  client_timeout = atoi(optarg);
284  break;
285 
286  default:
287  jack_error("unknown option character %c", optopt);
288  break;
289  }
290  }
291 
292  drivers = jack_drivers_load(drivers);
293  if (!drivers) {
294  jack_error("jackdmp: no drivers found; exiting");
295  goto error;
296  }
297 
298  driver_desc = jack_find_driver_descriptor(drivers, master_driver_name);
299  if (!driver_desc) {
300  jack_error("jackdmp: unknown master driver '%s'", master_driver_name);
301  goto error;
302  }
303 
304  if (optind < argc) {
305  driver_nargs = 1 + argc - optind;
306  } else {
307  driver_nargs = 1;
308  }
309 
310  if (driver_nargs == 0) {
311  jack_error("No driver specified ... hmm. JACK won't do"
312  " anything when run like this.");
313  goto error;
314  }
315 
316  master_driver_args = (char**)malloc(sizeof(char*) * driver_nargs);
317  master_driver_args[0] = master_driver_name;
318 
319  for (i = 1; i < driver_nargs; i++) {
320  master_driver_args[i] = argv[optind++];
321  }
322 
323  if (jack_parse_driver_params(driver_desc, driver_nargs, master_driver_args, &master_driver_params)) {
324  goto error;
325  }
326 
327 #ifndef WIN32
328  if (server_name == NULL) {
329  server_name = (char*)JackTools::DefaultServerName();
330  }
331 #endif
332 
333  rc = jack_register_server(server_name, false);
334  switch (rc) {
335  case EEXIST:
336  jack_error("`%s' server already active", server_name);
337  goto error;
338  case ENOSPC:
339  jack_error("too many servers already active");
340  goto error;
341  case ENOMEM:
342  jack_error("no access to shm registry");
343  goto error;
344  default:
345  jack_info("server `%s' registered", server_name);
346  }
347 
348  /* clean up shared memory and files from any previous instance of this server name */
349  jack_cleanup_shm();
350  JackTools::CleanupFiles(server_name);
351 
352  if (!realtime && client_timeout == 0) {
353  client_timeout = 500; /* 0.5 sec; usable when non realtime. */
354  }
355 
356  for (i = 0; i < argc; i++) {
357  free(argv[i]);
358  }
359 
360  int res = Start(server_name, driver_desc, master_driver_params, sync, temporary, client_timeout, realtime, realtime_priority, port_max, verbose_aux, clock_source, JACK_DEFAULT_SELF_CONNECT_MODE);
361  if (res < 0) {
362  jack_error("Cannot start server... exit");
363  Delete();
364  jack_cleanup_shm();
365  JackTools::CleanupFiles(server_name);
366  jack_unregister_server(server_name);
367  goto error;
368  }
369 
370  // Slave drivers
371  std::map<std::string, JackDriverInfo*>::iterator it1;
372  for (it1 = fSlavesList.begin(); it1 != fSlavesList.end(); it1++) {
373  const char* name = ((*it1).first).c_str();
374  driver_desc = jack_find_driver_descriptor(drivers, name);
375  if (!driver_desc) {
376  jack_error("jackdmp: unknown slave driver '%s'", name);
377  } else {
378  (*it1).second = fInstance->AddSlave(driver_desc, NULL);
379  }
380  }
381 
382  // Loopback driver
383  if (loopback > 0) {
384  driver_desc = jack_find_driver_descriptor(drivers, "loopback");
385  if (!driver_desc) {
386  jack_error("jackdmp: unknown driver '%s'", "loopback");
387  } else {
388  fSlavesList["loopback"] = fInstance->AddSlave(driver_desc, NULL);
389  }
390  }
391 
392  // Internal clients
393  std::map<std::string, int>::iterator it2;
394  for (it2 = fInternalsList.begin(); it2 != fInternalsList.end(); it2++) {
395  int status, refnum;
396  const char* name = ((*it2).first).c_str();
397  fInstance->InternalClientLoad2(name, name, NULL, JackNullOption, &refnum, -1, &status);
398  (*it2).second = refnum;
399  }
400  }
401 
402  if (master_driver_params) {
403  jack_free_driver_params(master_driver_params);
404  }
405  return true;
406 
407 error:
408  jack_log("JackServerGlobals Init error");
409  if (master_driver_params) {
410  jack_free_driver_params(master_driver_params);
411  }
412  Destroy();
413  return false;
414 }
415 
416 void JackServerGlobals::Destroy()
417 {
418  if (--fUserCount == 0) {
419  jack_log("JackServerGlobals Destroy");
420  Stop();
421  Delete();
422  jack_cleanup_shm();
423  JackTools::CleanupFiles(server_name);
424  jack_unregister_server(server_name);
425  }
426 }
427 
428 } // end of namespace
429 
430 
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
SERVER_EXPORT void jack_info(const char *fmt,...)
Definition: JackError.cpp:100
Definition: getopt.h:84
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108