Jack2  1.9.12
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, "ccrma" ) )
108  realtime_priority = 60;
109  else
110  realtime_priority = 20;
111  int verbose_aux = 0;
112  unsigned int port_max = 128;
113  int temporary = 0;
114 
115  int opt = 0;
116  int option_index = 0;
117  char *master_driver_name = NULL;
118  char **master_driver_args = NULL;
119  JSList* master_driver_params = NULL;
120  jack_driver_desc_t* driver_desc;
121  jack_timer_type_t clock_source = JACK_TIMER_SYSTEM_CLOCK;
122  int driver_nargs = 1;
123  JSList* drivers = NULL;
124  int loopback = 0;
125  int sync = 0;
126  int rc, i;
127  int res;
128  int replace_registry = 0;
129 
130  FILE* fp = 0;
131  char filename[255];
132  char buffer[255];
133  int argc = 0;
134  char* argv[32];
135 
136  // First user starts the server
137  if (fUserCount++ == 0) {
138 
139  jack_log("JackServerGlobals Init");
140 
141  const char *options = "-d:X:I:P:uvshVrRL:STFl:t:mn:p:"
142  #ifdef __linux__
143  "c:"
144  #endif
145  ;
146 
147  struct option long_options[] = {
148  #ifdef __linux__
149  { "clock-source", 1, 0, 'c' },
150  #endif
151  { "loopback-driver", 1, 0, 'L' },
152  { "audio-driver", 1, 0, 'd' },
153  { "midi-driver", 1, 0, 'X' },
154  { "internal-client", 1, 0, 'I' },
155  { "verbose", 0, 0, 'v' },
156  { "help", 0, 0, 'h' },
157  { "port-max", 1, 0, 'p' },
158  { "no-mlock", 0, 0, 'm' },
159  { "name", 1, 0, 'n' },
160  { "unlock", 0, 0, 'u' },
161  { "realtime", 0, 0, 'R' },
162  { "no-realtime", 0, 0, 'r' },
163  { "replace-registry", 0, &replace_registry, 0 },
164  { "loopback", 0, 0, 'L' },
165  { "realtime-priority", 1, 0, 'P' },
166  { "timeout", 1, 0, 't' },
167  { "temporary", 0, 0, 'T' },
168  { "version", 0, 0, 'V' },
169  { "silent", 0, 0, 's' },
170  { "sync", 0, 0, 'S' },
171  { 0, 0, 0, 0 }
172  };
173 
174  snprintf(filename, 255, "%s/.jackdrc", getenv("HOME"));
175  fp = fopen(filename, "r");
176 
177  if (!fp) {
178  fp = fopen("/etc/jackdrc", "r");
179  }
180  // if still not found, check old config name for backwards compatability
181  if (!fp) {
182  fp = fopen("/etc/jackd.conf", "r");
183  }
184 
185  argc = 0;
186  if (fp) {
187  res = fscanf(fp, "%s", buffer);
188  while (res != 0 && res != EOF) {
189  argv[argc] = (char*)malloc(64);
190  strcpy(argv[argc], buffer);
191  res = fscanf(fp, "%s", buffer);
192  argc++;
193  }
194  fclose(fp);
195  }
196 
197  /*
198  For testing
199  int argc = 15;
200  char* argv[] = {"jackdmp", "-R", "-v", "-d", "coreaudio", "-p", "512", "-d", "~:Aggregate:0", "-r", "48000", "-i", "2", "-o", "2" };
201  */
202 
203  opterr = 0;
204  optind = 1; // Important : to reset argv parsing
205 
206  while (!master_driver_name &&
207  (opt = getopt_long(argc, argv, options, long_options, &option_index)) != EOF) {
208 
209  switch (opt) {
210 
211  case 'c':
212  if (tolower (optarg[0]) == 'h') {
213  clock_source = JACK_TIMER_HPET;
214  } else if (tolower (optarg[0]) == 'c') {
215  /* For backwards compatibility with scripts, allow
216  * the user to request the cycle clock on the
217  * command line, but use the system clock instead
218  */
219  clock_source = JACK_TIMER_SYSTEM_CLOCK;
220  } else if (tolower (optarg[0]) == 's') {
221  clock_source = JACK_TIMER_SYSTEM_CLOCK;
222  } else {
223  jack_error("unknown option character %c", optopt);
224  }
225  break;
226 
227  case 'd':
228  master_driver_name = optarg;
229  break;
230 
231  case 'L':
232  loopback = atoi(optarg);
233  break;
234 
235  case 'X':
236  fSlavesList[optarg] = NULL;
237  break;
238 
239  case 'I':
240  fInternalsList[optarg] = -1;
241  break;
242 
243  case 'p':
244  port_max = (unsigned int)atol(optarg);
245  break;
246 
247  case 'm':
248  break;
249 
250  case 'u':
251  break;
252 
253  case 'v':
254  verbose_aux = 1;
255  break;
256 
257  case 'S':
258  sync = 1;
259  break;
260 
261  case 'n':
262  server_name = optarg;
263  break;
264 
265  case 'P':
266  realtime_priority = atoi(optarg);
267  break;
268 
269  case 'r':
270  realtime = 0;
271  break;
272 
273  case 'R':
274  realtime = 1;
275  break;
276 
277  case 'T':
278  temporary = 1;
279  break;
280 
281  case 't':
282  client_timeout = atoi(optarg);
283  break;
284 
285  default:
286  jack_error("unknown option character %c", optopt);
287  break;
288  }
289  }
290 
291  drivers = jack_drivers_load(drivers);
292  if (!drivers) {
293  jack_error("jackdmp: no drivers found; exiting");
294  goto error;
295  }
296 
297  driver_desc = jack_find_driver_descriptor(drivers, master_driver_name);
298  if (!driver_desc) {
299  jack_error("jackdmp: unknown master driver '%s'", master_driver_name);
300  goto error;
301  }
302 
303  if (optind < argc) {
304  driver_nargs = 1 + argc - optind;
305  } else {
306  driver_nargs = 1;
307  }
308 
309  if (driver_nargs == 0) {
310  jack_error("No driver specified ... hmm. JACK won't do"
311  " anything when run like this.");
312  goto error;
313  }
314 
315  master_driver_args = (char**)malloc(sizeof(char*) * driver_nargs);
316  master_driver_args[0] = master_driver_name;
317 
318  for (i = 1; i < driver_nargs; i++) {
319  master_driver_args[i] = argv[optind++];
320  }
321 
322  if (jack_parse_driver_params(driver_desc, driver_nargs, master_driver_args, &master_driver_params)) {
323  goto error;
324  }
325 
326 #ifndef WIN32
327  if (server_name == NULL) {
328  server_name = (char*)JackTools::DefaultServerName();
329  }
330 #endif
331 
332  rc = jack_register_server(server_name, false);
333  switch (rc) {
334  case EEXIST:
335  jack_error("`%s' server already active", server_name);
336  goto error;
337  case ENOSPC:
338  jack_error("too many servers already active");
339  goto error;
340  case ENOMEM:
341  jack_error("no access to shm registry");
342  goto error;
343  default:
344  jack_info("server `%s' registered", server_name);
345  }
346 
347  /* clean up shared memory and files from any previous instance of this server name */
348  jack_cleanup_shm();
349  JackTools::CleanupFiles(server_name);
350 
351  if (!realtime && client_timeout == 0) {
352  client_timeout = 500; /* 0.5 sec; usable when non realtime. */
353  }
354 
355  for (i = 0; i < argc; i++) {
356  free(argv[i]);
357  }
358 
359  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);
360  if (res < 0) {
361  jack_error("Cannot start server... exit");
362  Delete();
363  jack_cleanup_shm();
364  JackTools::CleanupFiles(server_name);
365  jack_unregister_server(server_name);
366  goto error;
367  }
368 
369  // Slave drivers
370  std::map<std::string, JackDriverInfo*>::iterator it1;
371  for (it1 = fSlavesList.begin(); it1 != fSlavesList.end(); it1++) {
372  const char* name = ((*it1).first).c_str();
373  driver_desc = jack_find_driver_descriptor(drivers, name);
374  if (!driver_desc) {
375  jack_error("jackdmp: unknown slave driver '%s'", name);
376  } else {
377  (*it1).second = fInstance->AddSlave(driver_desc, NULL);
378  }
379  }
380 
381  // Loopback driver
382  if (loopback > 0) {
383  driver_desc = jack_find_driver_descriptor(drivers, "loopback");
384  if (!driver_desc) {
385  jack_error("jackdmp: unknown driver '%s'", "loopback");
386  } else {
387  fSlavesList["loopback"] = fInstance->AddSlave(driver_desc, NULL);
388  }
389  }
390 
391  // Internal clients
392  std::map<std::string, int>::iterator it2;
393  for (it2 = fInternalsList.begin(); it2 != fInternalsList.end(); it2++) {
394  int status, refnum;
395  const char* name = ((*it2).first).c_str();
396  fInstance->InternalClientLoad2(name, name, NULL, JackNullOption, &refnum, -1, &status);
397  (*it2).second = refnum;
398  }
399  }
400 
401  if (master_driver_params) {
402  jack_free_driver_params(master_driver_params);
403  }
404  return true;
405 
406 error:
407  jack_log("JackServerGlobals Init error");
408  if (master_driver_params) {
409  jack_free_driver_params(master_driver_params);
410  }
411  Destroy();
412  return false;
413 }
414 
415 void JackServerGlobals::Destroy()
416 {
417  if (--fUserCount == 0) {
418  jack_log("JackServerGlobals Destroy");
419  Stop();
420  Delete();
421  jack_cleanup_shm();
422  JackTools::CleanupFiles(server_name);
423  jack_unregister_server(server_name);
424  }
425 }
426 
427 } // end of namespace
428 
429 
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