00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <iostream>
00022 #include <assert.h>
00023 #include <signal.h>
00024 #include <pwd.h>
00025 #include <sys/types.h>
00026 #include <dirent.h>
00027 #include <getopt.h>
00028
00029 #include "JackServer.h"
00030 #include "JackConstants.h"
00031 #include "driver_interface.h"
00032 #include "driver_parse.h"
00033 #include "JackDriverLoader.h"
00034 #include "jslist.h"
00035 #include "JackError.h"
00036 #include "shm.h"
00037 #include "jack.h"
00038
00039 using namespace Jack;
00040
00041 static JackServer* fServer;
00042 static char* server_name = NULL;
00043 static int realtime_priority = 10;
00044 static int do_mlock = 1;
00045 static unsigned int port_max = 128;
00046 static int realtime = 0;
00047 static int loopback = 0;
00048 static int temporary = 0;
00049 static int client_timeout = 0;
00050 static int do_unlock = 0;
00051 static JSList* drivers = NULL;
00052
00053 static sigset_t signals;
00054
00055 #define DEFAULT_TMP_DIR "/tmp"
00056 char* jack_tmpdir = DEFAULT_TMP_DIR;
00057
00058 static void silent_jack_error_callback (const char *desc)
00059 {}
00060
00061 static void copyright(FILE* file)
00062 {
00063 fprintf (file, "jackdmp " VERSION "\n"
00064 "Copyright 2001-2005 Paul Davis and others.\n"
00065 "Copyright 2004-2006 Grame.\n"
00066 "jackdmp comes with ABSOLUTELY NO WARRANTY\n"
00067 "This is free software, and you are welcome to redistribute it\n"
00068 "under certain conditions; see the file COPYING for details\n");
00069 }
00070
00071 static void usage (FILE* file)
00072 {
00073 copyright (file);
00074 fprintf (file, "\n"
00075 "usage: jackdmp [ --realtime OR -R [ --realtime-priority OR -P priority ] ]\n"
00076 " [ --name OR -n server-name ]\n"
00077
00078
00079 " [ --timeout OR -t client-timeout-in-msecs ]\n"
00080 " [ --loopback OR -L loopback-port-number ]\n"
00081
00082 " [ --verbose OR -v ]\n"
00083 " [ --silent OR -s ]\n"
00084 " [ --sync OR -S ]\n"
00085 " [ --version OR -V ]\n"
00086 " -d driver [ ... driver args ... ]\n"
00087 " where driver can be `alsa', `coreaudio', 'portaudio' or `dummy'\n"
00088 " jackdmp -d driver --help\n"
00089 " to display options for each driver\n\n");
00090 }
00091
00092
00093 static void DoNothingHandler(int sig)
00094 {
00095
00096
00097
00098
00099 char buf[64];
00100 snprintf(buf, sizeof(buf), "received signal %d during shutdown (ignored)\n", sig);
00101 write(1, buf, strlen(buf));
00102 }
00103
00104 static int JackStart(jack_driver_desc_t* driver_desc, JSList* driver_params, int sync, int time_out_ms, int rt, int priority, int loopback, int verbose)
00105 {
00106 JackLog("Jackdmp: sync = %ld timeout = %ld rt = %ld priority = %ld verbose = %ld \n", sync, time_out_ms, rt, priority, verbose);
00107 fServer = new JackServer(sync, time_out_ms, rt, priority, loopback, verbose);
00108 int res = fServer->Open(driver_desc, driver_params);
00109 return (res < 0) ? res : fServer->Start();
00110 }
00111
00112 static int JackStop()
00113 {
00114 fServer->Stop();
00115 fServer->Close();
00116 JackLog("Jackdmp: server close\n");
00117 delete fServer;
00118 JackLog("Jackdmp: delete server\n");
00119 return 0;
00120 }
00121
00122 static int JackDelete()
00123 {
00124 delete fServer;
00125 JackLog("Jackdmp: delete server\n");
00126 return 0;
00127 }
00128
00129 static void FilterSIGPIPE()
00130 {
00131 sigset_t set;
00132 sigemptyset(&set);
00133 sigaddset(&set, SIGPIPE);
00134
00135 pthread_sigmask(SIG_BLOCK, &set, 0);
00136 }
00137
00138 static char* jack_default_server_name(void)
00139 {
00140 char *server_name;
00141 if ((server_name = getenv("JACK_DEFAULT_SERVER")) == NULL)
00142 server_name = "default";
00143 return server_name;
00144 }
00145
00146
00147 static char* jack_user_dir(void)
00148 {
00149 static char user_dir[PATH_MAX] = "";
00150
00151
00152 if (user_dir[0] == '\0') {
00153 snprintf (user_dir, sizeof (user_dir), "%s/jack-%d",
00154 jack_tmpdir, getuid ());
00155 }
00156
00157 return user_dir;
00158 }
00159
00160
00161
00162 static char* get_jack_server_dir(const char* toto)
00163 {
00164 static char server_dir[PATH_MAX] = "";
00165
00166
00167 if (server_dir[0] == '\0') {
00168 snprintf (server_dir, sizeof (server_dir), "%s/%s",
00169 jack_user_dir (), server_name);
00170 }
00171
00172 return server_dir;
00173 }
00174
00175 static void
00176 jack_cleanup_files (const char *server_name)
00177 {
00178 DIR *dir;
00179 struct dirent *dirent;
00180 char *dir_name = get_jack_server_dir (server_name);
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199 if ((dir = opendir (dir_name)) == NULL) {
00200 return ;
00201 }
00202
00203
00204 while ((dirent = readdir (dir)) != NULL) {
00205
00206 char fullpath[PATH_MAX];
00207
00208 if ((strcmp (dirent->d_name, ".") == 0)
00209 || (strcmp (dirent->d_name, "..") == 0)) {
00210 continue;
00211 }
00212
00213 snprintf (fullpath, sizeof (fullpath), "%s/%s",
00214 dir_name, dirent->d_name);
00215
00216 if (unlink (fullpath)) {
00217 jack_error ("cannot unlink `%s' (%s)", fullpath,
00218 strerror (errno));
00219 }
00220 }
00221
00222 closedir (dir);
00223
00224
00225 if (rmdir (dir_name)) {
00226 jack_error ("cannot remove `%s' (%s)", dir_name,
00227 strerror (errno));
00228 }
00229
00230
00231 if (rmdir (jack_user_dir ())) {
00232 if (errno != ENOTEMPTY) {
00233 jack_error ("cannot remove `%s' (%s)",
00234 jack_user_dir (), strerror (errno));
00235 }
00236 }
00237 }
00238
00239 #ifdef FORK_SERVER
00240
00241 int main(int argc, char* argv[])
00242 {
00243 int sig;
00244 sigset_t allsignals;
00245 struct sigaction action;
00246 int waiting;
00247
00248 jack_driver_desc_t* driver_desc;
00249 const char *options = "-ad:P:uvshVRL:STFl:t:mn:p:";
00250 struct option long_options[] = {
00251 { "driver", 1, 0, 'd'
00252 },
00253 { "verbose", 0, 0, 'v' },
00254 { "help", 0, 0, 'h' },
00255 { "port-max", 1, 0, 'p' },
00256 { "no-mlock", 0, 0, 'm' },
00257 { "name", 0, 0, 'n' },
00258 { "unlock", 0, 0, 'u' },
00259 { "realtime", 0, 0, 'R' },
00260 { "loopback", 0, 0, 'L' },
00261 { "realtime-priority", 1, 0, 'P' },
00262 { "timeout", 1, 0, 't' },
00263 { "temporary", 0, 0, 'T' },
00264 { "version", 0, 0, 'V' },
00265 { "silent", 0, 0, 's' },
00266 { "sync", 0, 0, 'S' },
00267 { 0, 0, 0, 0 }
00268 };
00269 int opt = 0;
00270 int option_index = 0;
00271 int seen_driver = 0;
00272 char *driver_name = NULL;
00273 char **driver_args = NULL;
00274 JSList* driver_params;
00275 int driver_nargs = 1;
00276 int show_version = 0;
00277 int sync = 0;
00278 int rc, i;
00279
00280 opterr = 0;
00281 while (!seen_driver &&
00282 (opt = getopt_long(argc, argv, options,
00283 long_options, &option_index)) != EOF) {
00284 switch (opt) {
00285
00286 case 'd':
00287 seen_driver = 1;
00288 driver_name = optarg;
00289 break;
00290
00291 case 'v':
00292 jack_verbose = 1;
00293 break;
00294
00295 case 's':
00296 jack_set_error_function(silent_jack_error_callback);
00297 break;
00298
00299 case 'S':
00300 sync = 1;
00301 break;
00302
00303 case 'n':
00304 server_name = optarg;
00305 break;
00306
00307 case 'm':
00308 do_mlock = 0;
00309 break;
00310
00311 case 'p':
00312 port_max = (unsigned int)atol(optarg);
00313 break;
00314
00315 case 'P':
00316 realtime_priority = atoi(optarg);
00317 break;
00318
00319 case 'R':
00320 realtime = 1;
00321 break;
00322
00323 case 'L':
00324 loopback = atoi(optarg);
00325 break;
00326
00327 case 'T':
00328 temporary = 1;
00329 break;
00330
00331 case 't':
00332 client_timeout = atoi(optarg);
00333 break;
00334
00335 case 'u':
00336 do_unlock = 1;
00337 break;
00338
00339 case 'V':
00340 show_version = 1;
00341 break;
00342
00343 default:
00344 fprintf(stderr, "unknown option character %c\n",
00345 optopt);
00346
00347 case 'h':
00348 usage(stdout);
00349 return -1;
00350 }
00351 }
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363 if (!seen_driver) {
00364 usage (stderr);
00365 exit (1);
00366 }
00367
00368 drivers = jack_drivers_load (drivers);
00369 if (!drivers) {
00370 fprintf (stderr, "jackdmp: no drivers found; exiting\n");
00371 exit (1);
00372 }
00373
00374 driver_desc = jack_find_driver_descriptor (drivers, driver_name);
00375 if (!driver_desc) {
00376 fprintf (stderr, "jackdmp: unknown driver '%s'\n", driver_name);
00377 exit (1);
00378 }
00379
00380 if (optind < argc) {
00381 driver_nargs = 1 + argc - optind;
00382 } else {
00383 driver_nargs = 1;
00384 }
00385
00386 if (driver_nargs == 0) {
00387 fprintf (stderr, "No driver specified ... hmm. JACK won't do"
00388 " anything when run like this.\n");
00389 return -1;
00390 }
00391
00392 driver_args = (char **) malloc (sizeof (char *) * driver_nargs);
00393 driver_args[0] = driver_name;
00394
00395 for (i = 1; i < driver_nargs; i++) {
00396 driver_args[i] = argv[optind++];
00397 }
00398
00399 if (jack_parse_driver_params (driver_desc, driver_nargs,
00400 driver_args, &driver_params)) {
00401 exit (0);
00402 }
00403
00404 if (server_name == NULL)
00405 server_name = jack_default_server_name ();
00406
00407 copyright (stdout);
00408
00409 rc = jack_register_server (server_name);
00410 switch (rc) {
00411 case EEXIST:
00412 fprintf (stderr, "`%s' server already active\n", server_name);
00413 exit (1);
00414 case ENOSPC:
00415 fprintf (stderr, "too many servers already active\n");
00416 exit (2);
00417 case ENOMEM:
00418 fprintf (stderr, "no access to shm registry\n");
00419 exit (3);
00420 default:
00421 if (jack_verbose)
00422 fprintf (stderr, "server `%s' registered\n",
00423 server_name);
00424 }
00425
00426
00427
00428 jack_cleanup_shm();
00429 jack_cleanup_files(server_name);
00430
00431 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
00432
00433 sigemptyset(&signals);
00434 sigaddset(&signals, SIGHUP);
00435 sigaddset(&signals, SIGINT);
00436 sigaddset(&signals, SIGQUIT);
00437 sigaddset(&signals, SIGPIPE);
00438 sigaddset(&signals, SIGTERM);
00439 sigaddset(&signals, SIGUSR1);
00440 sigaddset(&signals, SIGUSR2);
00441
00442
00443
00444
00445 FilterSIGPIPE();
00446 pthread_sigmask(SIG_BLOCK, &signals, 0);
00447
00448 if (!realtime && client_timeout == 0)
00449 client_timeout = 500;
00450
00451 int res = JackStart(driver_desc, driver_params, sync, client_timeout, realtime, realtime_priority, loopback, jack_verbose);
00452 if (res < 0) {
00453 jack_error("Cannot start server... exit");
00454 JackDelete();
00455 return 0;
00456 }
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475 sigfillset(&allsignals);
00476 action.sa_handler = DoNothingHandler;
00477 action.sa_mask = allsignals;
00478 action.sa_flags = SA_RESTART | SA_RESETHAND;
00479
00480 for (i = 1; i < NSIG; i++) {
00481 if (sigismember(&signals, i)) {
00482 sigaction(i, &action, 0);
00483 }
00484 }
00485
00486 waiting = TRUE;
00487
00488 while (waiting) {
00489 sigwait(&signals, &sig);
00490
00491 fprintf(stderr, "jack main caught signal %d\n", sig);
00492
00493 switch (sig) {
00494 case SIGUSR1:
00495
00496 break;
00497 case SIGUSR2:
00498
00499 waiting = FALSE;
00500 break;
00501 default:
00502 waiting = FALSE;
00503 break;
00504 }
00505 }
00506
00507 if (sig != SIGSEGV) {
00508
00509
00510
00511 sigprocmask(SIG_UNBLOCK, &signals, 0);
00512 }
00513
00514 JackStop();
00515
00516 jack_cleanup_shm();
00517 jack_cleanup_files(server_name);
00518 jack_unregister_server(server_name);
00519
00520 return 1;
00521 }
00522
00523 #else
00524
00525 int main(int argc, char* argv[])
00526 {
00527 char c;
00528 long sample_sate = lopt(argv, "-r", 44100);
00529 long buffer_size = lopt(argv, "-p", 512);
00530 long chan_in = lopt(argv, "-i", 2);
00531 long chan_out = lopt(argv, "-o", 2);
00532 long audiodevice = lopt(argv, "-I", -1);
00533 long sync = lopt(argv, "-s", 0);
00534 long timeout = lopt(argv, "-t", 100 * 1000);
00535 const char* name = flag(argv, "-n", "Built-in Audio");
00536 long rt = lopt(argv, "-R", 0);
00537 verbose = lopt(argv, "-v", 0);
00538
00539 copyright(stdout);
00540 usage(stdout);
00541
00542 FilterSIGPIPE();
00543
00544 printf("jackdmp: sample_sate = %ld buffer_size = %ld chan_in = %ld chan_out = %ld name = %s sync-mode = %ld\n",
00545 sample_sate, buffer_size, chan_in, chan_out, name, sync);
00546 assert(buffer_size <= BUFFER_SIZE_MAX);
00547
00548 int res = JackStart(sample_sate, buffer_size, chan_in, chan_out, name, audiodevice, sync, timeout, rt);
00549 if (res < 0) {
00550 jack_error("Cannot start server... exit\n");
00551 JackDelete();
00552 return 0;
00553 }
00554
00555 while (((c = getchar()) != 'q')) {
00556
00557 switch (c) {
00558
00559 case 's':
00560 fServer->PrintState();
00561 break;
00562 }
00563 }
00564
00565 JackStop();
00566 return 0;
00567 }
00568
00569 #endif