Jackdmp.cpp

00001 /*
00002 Copyright (C) 2001 Paul Davis 
00003 Copyright (C) 2004-2008 Grame
00004 
00005 This program is free software; you can redistribute it and/or modify
00006 it under the terms of the GNU General Public License as published by
00007 the Free Software Foundation; either version 2 of the License, or
00008 (at your option) any later version.
00009 
00010 This program is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 GNU General Public License for more details.
00014 
00015 You should have received a copy of the GNU General Public License
00016 along with this program; if not, write to the Free Software
00017 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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; /* msecs; if zero, use period size. */
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              // "               [ --no-mlock OR -m ]\n"
00079              // "               [ --unlock OR -u ]\n"
00080              "               [ --timeout OR -t client-timeout-in-msecs ]\n"
00081              "               [ --loopback OR -L loopback-port-number ]\n"
00082              // "               [ --port-max OR -p maximum-number-of-ports]\n"
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     /* this is used by the child (active) process, but it never
00099        gets called unless we are already shutting down after
00100        another signal.
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     //sigprocmask(SIG_BLOCK, &set, 0);
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                 /*fallthru*/
00252             case 'h':
00253                 usage(stdout);
00254                 return -1;
00255         }
00256     }
00257 
00258     /*
00259     if (show_version) {
00260         printf ( "jackd version " VERSION 
00261                         " tmpdir " DEFAULT_TMP_DIR 
00262                         " protocol " PROTOCOL_VERSION
00263                         "\n");
00264         return -1;
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     /* clean up shared memory and files from any previous
00331      * instance of this server name */
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     // all child threads will inherit this mask unless they
00347     // explicitly reset it
00348 
00349     FilterSIGPIPE();
00350     pthread_sigmask(SIG_BLOCK, &signals, 0);
00351 
00352     if (!realtime && client_timeout == 0)
00353         client_timeout = 500; /* 0.5 sec; usable when non realtime. */
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     // Send notification to be used in the JackRouter plugin
00365     CFNotificationCenterPostNotificationWithOptions(CFNotificationCenterGetDistributedCenter(),
00366                                                                                                         CFSTR("com.grame.jackserver.start"),
00367                                                                                                         ref,
00368                                                                                                         NULL,
00369                                                                                                         kCFNotificationDeliverImmediately | kCFNotificationPostToAllSessions);
00370         CFRelease(ref);
00371 #endif
00372         
00373     // install a do-nothing handler because otherwise pthreads
00374     // behaviour is undefined when we enter sigwait.
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                 //jack_dump_configuration(engine, 1);
00397                 break;
00398             case SIGUSR2:
00399                 // driver exit
00400                 waiting = FALSE;
00401                 break;
00402             default:
00403                 waiting = FALSE;
00404                 break;
00405         }
00406     }
00407 
00408     if (sig != SIGSEGV) {
00409         // unblock signals so we can see them during shutdown.
00410         // this will help prod developers not to lose sight of
00411         // bugs that cause segfaults etc. during shutdown.
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     // Send notification to be used in the JackRouter plugin
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 }

Generated on Thu Feb 14 11:16:01 2008 for Jackdmp by  doxygen 1.5.1