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 "JackTools.h"
00037 #include "shm.h"
00038 #include "jack.h"
00039
00040 #ifdef __APPLE_
00041 #include <CoreFoundation/CFNotificationCenter.h>
00042 #endif
00043
00044 using namespace Jack;
00045
00046 static JackServer* fServer;
00047 static char* server_name = NULL;
00048 static int realtime_priority = 10;
00049 static int do_mlock = 1;
00050 static unsigned int port_max = 128;
00051 static int realtime = 0;
00052 static int loopback = 0;
00053 static int temporary = 0;
00054 static int client_timeout = 0;
00055 static int do_unlock = 0;
00056 static JSList* drivers = NULL;
00057 static sigset_t signals;
00058
00059 static void silent_jack_error_callback(const char *desc)
00060 {}
00061
00062 static void copyright(FILE* file)
00063 {
00064 fprintf(file, "jackdmp " VERSION "\n"
00065 "Copyright 2001-2005 Paul Davis and others.\n"
00066 "Copyright 2004-2008 Grame.\n"
00067 "jackdmp comes with ABSOLUTELY NO WARRANTY\n"
00068 "This is free software, and you are welcome to redistribute it\n"
00069 "under certain conditions; see the file COPYING for details\n");
00070 }
00071
00072 static void usage(FILE* file)
00073 {
00074 copyright(file);
00075 fprintf(file, "\n"
00076 "usage: jackdmp [ --realtime OR -R [ --realtime-priority OR -P priority ] ]\n"
00077 " [ --name OR -n server-name ]\n"
00078
00079
00080 " [ --timeout OR -t client-timeout-in-msecs ]\n"
00081 " [ --loopback OR -L loopback-port-number ]\n"
00082
00083 " [ --verbose OR -v ]\n"
00084 " [ --replace-registry OR -r ]\n"
00085 " [ --silent OR -s ]\n"
00086 " [ --sync OR -S ]\n"
00087 " [ --temporary OR -T ]\n"
00088 " [ --version OR -V ]\n"
00089 " -d driver [ ... driver args ... ]\n"
00090 " where driver can be `alsa', `coreaudio', 'portaudio' or `dummy'\n"
00091 " jackdmp -d driver --help\n"
00092 " to display options for each driver\n\n");
00093 }
00094
00095
00096 static void DoNothingHandler(int sig)
00097 {
00098
00099
00100
00101
00102 char buf[64];
00103 snprintf(buf, sizeof(buf), "received signal %d during shutdown(ignored)\n", sig);
00104 write(1, buf, strlen(buf));
00105 }
00106
00107 static int JackStart(const char* server_name, jack_driver_desc_t* driver_desc, JSList* driver_params, int sync, int temporary, int time_out_ms, int rt, int priority, int loopback, int verbose)
00108 {
00109 JackLog("Jackdmp: sync = %ld timeout = %ld rt = %ld priority = %ld verbose = %ld \n", sync, time_out_ms, rt, priority, verbose);
00110 fServer = new JackServer(sync, temporary, time_out_ms, rt, priority, loopback, verbose, server_name);
00111 int res = fServer->Open(driver_desc, driver_params);
00112 return (res < 0) ? res : fServer->Start();
00113 }
00114
00115 static int JackStop()
00116 {
00117 fServer->Stop();
00118 fServer->Close();
00119 JackLog("Jackdmp: server close\n");
00120 delete fServer;
00121 JackLog("Jackdmp: delete server\n");
00122 return 0;
00123 }
00124
00125 static int JackDelete()
00126 {
00127 delete fServer;
00128 JackLog("Jackdmp: delete server\n");
00129 return 0;
00130 }
00131
00132 static void FilterSIGPIPE()
00133 {
00134 sigset_t set;
00135 sigemptyset(&set);
00136 sigaddset(&set, SIGPIPE);
00137
00138 pthread_sigmask(SIG_BLOCK, &set, 0);
00139 }
00140
00141 int main(int argc, char* argv[])
00142 {
00143 int sig;
00144 sigset_t allsignals;
00145 struct sigaction action;
00146 int waiting;
00147
00148 jack_driver_desc_t* driver_desc;
00149 const char *options = "-ad:P:uvrshVRL:STFl:t:mn:p:";
00150 struct option long_options[] = {
00151 { "driver", 1, 0, 'd' },
00152 { "verbose", 0, 0, 'v' },
00153 { "help", 0, 0, 'h' },
00154 { "port-max", 1, 0, 'p' },
00155 { "no-mlock", 0, 0, 'm' },
00156 { "name", 0, 0, 'n' },
00157 { "unlock", 0, 0, 'u' },
00158 { "realtime", 0, 0, 'R' },
00159 { "replace-registry", 0, 0, 'r' },
00160 { "loopback", 0, 0, 'L' },
00161 { "realtime-priority", 1, 0, 'P' },
00162 { "timeout", 1, 0, 't' },
00163 { "temporary", 0, 0, 'T' },
00164 { "version", 0, 0, 'V' },
00165 { "silent", 0, 0, 's' },
00166 { "sync", 0, 0, 'S' },
00167 { 0, 0, 0, 0 }
00168 };
00169 int opt = 0;
00170 int option_index = 0;
00171 int seen_driver = 0;
00172 char *driver_name = NULL;
00173 char **driver_args = NULL;
00174 JSList* driver_params;
00175 int driver_nargs = 1;
00176 int show_version = 0;
00177 int replace_registry = 0;
00178 int sync = 0;
00179 int rc, i;
00180
00181 opterr = 0;
00182 while (!seen_driver &&
00183 (opt = getopt_long(argc, argv, options,
00184 long_options, &option_index)) != EOF) {
00185 switch (opt) {
00186
00187 case 'd':
00188 seen_driver = 1;
00189 driver_name = optarg;
00190 break;
00191
00192 case 'v':
00193 jack_verbose = 1;
00194 break;
00195
00196 case 's':
00197 jack_set_error_function(silent_jack_error_callback);
00198 break;
00199
00200 case 'S':
00201 sync = 1;
00202 break;
00203
00204 case 'n':
00205 server_name = optarg;
00206 break;
00207
00208 case 'm':
00209 do_mlock = 0;
00210 break;
00211
00212 case 'p':
00213 port_max = (unsigned int)atol(optarg);
00214 break;
00215
00216 case 'P':
00217 realtime_priority = atoi(optarg);
00218 break;
00219
00220 case 'r':
00221 replace_registry = 1;
00222 break;
00223
00224 case 'R':
00225 realtime = 1;
00226 break;
00227
00228 case 'L':
00229 loopback = atoi(optarg);
00230 break;
00231
00232 case 'T':
00233 temporary = 1;
00234 break;
00235
00236 case 't':
00237 client_timeout = atoi(optarg);
00238 break;
00239
00240 case 'u':
00241 do_unlock = 1;
00242 break;
00243
00244 case 'V':
00245 show_version = 1;
00246 break;
00247
00248 default:
00249 fprintf(stderr, "unknown option character %c\n",
00250 optopt);
00251
00252 case 'h':
00253 usage(stdout);
00254 return -1;
00255 }
00256 }
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268 if (!seen_driver) {
00269 usage(stderr);
00270 exit(1);
00271 }
00272
00273 drivers = jack_drivers_load(drivers);
00274 if (!drivers) {
00275 fprintf(stderr, "jackdmp: no drivers found; exiting\n");
00276 exit(1);
00277 }
00278
00279 driver_desc = jack_find_driver_descriptor(drivers, driver_name);
00280 if (!driver_desc) {
00281 fprintf(stderr, "jackdmp: unknown driver '%s'\n", driver_name);
00282 exit(1);
00283 }
00284
00285 if (optind < argc) {
00286 driver_nargs = 1 + argc - optind;
00287 } else {
00288 driver_nargs = 1;
00289 }
00290
00291 if (driver_nargs == 0) {
00292 fprintf(stderr, "No driver specified ... hmm. JACK won't do"
00293 " anything when run like this.\n");
00294 return -1;
00295 }
00296
00297 driver_args = (char **) malloc(sizeof(char *) * driver_nargs);
00298 driver_args[0] = driver_name;
00299
00300 for (i = 1; i < driver_nargs; i++) {
00301 driver_args[i] = argv[optind++];
00302 }
00303
00304 if (jack_parse_driver_params(driver_desc, driver_nargs,
00305 driver_args, &driver_params)) {
00306 exit(0);
00307 }
00308
00309 if (server_name == NULL)
00310 server_name = (char*)JackTools::DefaultServerName();
00311
00312 copyright(stdout);
00313
00314 rc = jack_register_server(server_name, replace_registry);
00315 switch (rc) {
00316 case EEXIST:
00317 fprintf(stderr, "`%s' server already active\n", server_name);
00318 exit(1);
00319 case ENOSPC:
00320 fprintf(stderr, "too many servers already active\n");
00321 exit(2);
00322 case ENOMEM:
00323 fprintf(stderr, "no access to shm registry\n");
00324 exit(3);
00325 default:
00326 if (jack_verbose)
00327 fprintf(stderr, "server `%s' registered\n", server_name);
00328 }
00329
00330
00331
00332 jack_cleanup_shm();
00333 JackTools::CleanupFiles(server_name);
00334
00335 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
00336
00337 sigemptyset(&signals);
00338 sigaddset(&signals, SIGHUP);
00339 sigaddset(&signals, SIGINT);
00340 sigaddset(&signals, SIGQUIT);
00341 sigaddset(&signals, SIGPIPE);
00342 sigaddset(&signals, SIGTERM);
00343 sigaddset(&signals, SIGUSR1);
00344 sigaddset(&signals, SIGUSR2);
00345
00346
00347
00348
00349 FilterSIGPIPE();
00350 pthread_sigmask(SIG_BLOCK, &signals, 0);
00351
00352 if (!realtime && client_timeout == 0)
00353 client_timeout = 500;
00354
00355 int res = JackStart(server_name, driver_desc, driver_params, sync, temporary, client_timeout, realtime, realtime_priority, loopback, jack_verbose);
00356 if (res < 0) {
00357 jack_error("Cannot start server... exit");
00358 JackDelete();
00359 return 0;
00360 }
00361
00362 #ifdef __APPLE__
00363 CFStringRef ref = CFStringCreateWithCString(NULL, server_name, kCFStringEncodingMacRoman);
00364
00365 CFNotificationCenterPostNotificationWithOptions(CFNotificationCenterGetDistributedCenter(),
00366 CFSTR("com.grame.jackserver.start"),
00367 ref,
00368 NULL,
00369 kCFNotificationDeliverImmediately | kCFNotificationPostToAllSessions);
00370 CFRelease(ref);
00371 #endif
00372
00373
00374
00375
00376 sigfillset(&allsignals);
00377 action.sa_handler = DoNothingHandler;
00378 action.sa_mask = allsignals;
00379 action.sa_flags = SA_RESTART | SA_RESETHAND;
00380
00381 for (i = 1; i < NSIG; i++) {
00382 if (sigismember(&signals, i)) {
00383 sigaction(i, &action, 0);
00384 }
00385 }
00386
00387 waiting = TRUE;
00388
00389 while (waiting) {
00390 sigwait(&signals, &sig);
00391
00392 fprintf(stderr, "jack main caught signal %d\n", sig);
00393
00394 switch (sig) {
00395 case SIGUSR1:
00396
00397 break;
00398 case SIGUSR2:
00399
00400 waiting = FALSE;
00401 break;
00402 default:
00403 waiting = FALSE;
00404 break;
00405 }
00406 }
00407
00408 if (sig != SIGSEGV) {
00409
00410
00411
00412 sigprocmask(SIG_UNBLOCK, &signals, 0);
00413 }
00414
00415 JackStop();
00416
00417 jack_cleanup_shm();
00418 JackTools::CleanupFiles(server_name);
00419 jack_unregister_server(server_name);
00420
00421 #ifdef __APPLE__
00422 CFStringRef ref1 = CFStringCreateWithCString(NULL, server_name, kCFStringEncodingMacRoman);
00423
00424 CFNotificationCenterPostNotificationWithOptions(CFNotificationCenterGetDistributedCenter(),
00425 CFSTR("com.grame.jackserver.stop"),
00426 ref1,
00427 NULL,
00428 kCFNotificationDeliverImmediately | kCFNotificationPostToAllSessions);
00429 CFRelease(ref1);
00430 #endif
00431
00432 return 1;
00433 }