JackServerGlobals.cpp

00001 /*
00002 Copyright (C) 2005 Grame  
00003 
00004 This program is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 of the License, or
00007   (at your option) any later version.
00008 
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details.
00013 
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017 
00018 */
00019 
00020 #ifdef WIN32 
00021 #pragma warning (disable : 4786)
00022 #endif
00023 
00024 #include "JackServerGlobals.h"
00025 #include "JackError.h"
00026 #include "shm.h"
00027 #include <getopt.h>
00028 
00029 #ifndef WIN32
00030         #include <dirent.h>
00031 #endif
00032 
00033 #define DEFAULT_TMP_DIR "/tmp"
00034 char* jack_tmpdir = DEFAULT_TMP_DIR;
00035 static char* server_name = "default";
00036 static int realtime = 0;
00037 static int client_timeout = 0; /* msecs; if zero, use period size. */
00038 static int realtime_priority = 10;
00039 static int verbose_aux = 0;
00040 static int do_mlock = 1;
00041 static unsigned int port_max = 128;
00042 static int loopback = 0;
00043 static int do_unlock = 0;
00044 static int temporary = 0;
00045 
00046 namespace Jack
00047 {
00048 
00049 JackServerGlobals* JackServerGlobals::fGlobals = NULL;
00050 long JackServerGlobals::fClientCount = 0;
00051 JackServer* JackServerGlobals::fServer = NULL;
00052 
00053 #ifndef WIN32
00054 
00055 static char* jack_default_server_name(void)
00056 {
00057     char *server_name;
00058     if ((server_name = getenv("JACK_DEFAULT_SERVER")) == NULL)
00059         server_name = "default";
00060     return server_name;
00061 }
00062 
00063 /* returns the name of the per-user subdirectory of jack_tmpdir */
00064 static char* jack_user_dir(void)
00065 {
00066     static char user_dir[PATH_MAX] = "";
00067 
00068     /* format the path name on the first call */
00069     if (user_dir[0] == '\0') {
00070         snprintf (user_dir, sizeof (user_dir), "%s/jack-%d",
00071                   jack_tmpdir, getuid ());
00072     }
00073 
00074     return user_dir;
00075 }
00076 
00077 /* returns the name of the per-server subdirectory of jack_user_dir() */
00078 
00079 static char* get_jack_server_dir(const char* toto)
00080 {
00081     static char server_dir[PATH_MAX] = "";
00082 
00083     // format the path name on the first call
00084     if (server_dir[0] == '\0') {
00085         snprintf (server_dir, sizeof (server_dir), "%s/%s",
00086                   jack_user_dir (), server_name);
00087     }
00088 
00089     return server_dir;
00090 }
00091 
00092 static void
00093 jack_cleanup_files (const char *server_name)
00094 {
00095     DIR *dir;
00096     struct dirent *dirent;
00097     char *dir_name = get_jack_server_dir (server_name);
00098 
00099     /* On termination, we remove all files that jackd creates so
00100      * subsequent attempts to start jackd will not believe that an
00101      * instance is already running.  If the server crashes or is
00102      * terminated with SIGKILL, this is not possible.  So, cleanup
00103      * is also attempted when jackd starts.
00104      *
00105      * There are several tricky issues.  First, the previous JACK
00106      * server may have run for a different user ID, so its files
00107      * may be inaccessible.  This is handled by using a separate
00108      * JACK_TMP_DIR subdirectory for each user.  Second, there may
00109      * be other servers running with different names.  Each gets
00110      * its own subdirectory within the per-user directory.  The
00111      * current process has already registered as `server_name', so
00112      * we know there is no other server actively using that name.
00113      */
00114 
00115     /* nothing to do if the server directory does not exist */
00116     if ((dir = opendir (dir_name)) == NULL) {
00117         return ;
00118     }
00119 
00120     /* unlink all the files in this directory, they are mine */
00121     while ((dirent = readdir (dir)) != NULL) {
00122 
00123         char fullpath[PATH_MAX];
00124 
00125         if ((strcmp (dirent->d_name, ".") == 0)
00126                 || (strcmp (dirent->d_name, "..") == 0)) {
00127             continue;
00128         }
00129 
00130         snprintf (fullpath, sizeof (fullpath), "%s/%s",
00131                   dir_name, dirent->d_name);
00132 
00133         if (unlink (fullpath)) {
00134             jack_error ("cannot unlink `%s' (%s)", fullpath,
00135                         strerror (errno));
00136         }
00137     }
00138 
00139     closedir (dir);
00140 
00141     /* now, delete the per-server subdirectory, itself */
00142     if (rmdir (dir_name)) {
00143         jack_error ("cannot remove `%s' (%s)", dir_name,
00144                     strerror (errno));
00145     }
00146 
00147     /* finally, delete the per-user subdirectory, if empty */
00148     if (rmdir (jack_user_dir ())) {
00149         if (errno != ENOTEMPTY) {
00150             jack_error ("cannot remove `%s' (%s)",
00151                         jack_user_dir (), strerror (errno));
00152         }
00153     }
00154 }
00155 
00156 #endif
00157 
00158 int JackServerGlobals::JackStart(jack_driver_desc_t* driver_desc, JSList* driver_params, int sync, int time_out_ms, int rt, int priority, int loopback, int verbose)
00159 {
00160     JackLog("Jackdmp: sync = %ld timeout = %ld rt = %ld priority = %ld verbose = %ld \n", sync, time_out_ms, rt, priority, verbose);
00161     fServer = new JackServer(sync, time_out_ms, rt, priority, loopback, verbose);
00162     int res = fServer->Open(driver_desc, driver_params);
00163     return (res < 0) ? res : fServer->Start();
00164 }
00165 
00166 int JackServerGlobals::JackStop()
00167 {
00168     fServer->Stop();
00169     fServer->Close();
00170     JackLog("Jackdmp: server close\n");
00171     delete fServer;
00172     JackLog("Jackdmp: delete server\n");
00173     return 0;
00174 }
00175 
00176 int JackServerGlobals::JackDelete()
00177 {
00178     delete fServer;
00179     JackLog("Jackdmp: delete server\n");
00180     return 0;
00181 }
00182 
00183 // Temporary : to test
00184 
00185 JackServerGlobals::JackServerGlobals()
00186 {
00187     jack_driver_desc_t* driver_desc;
00188     const char *options = "-ad:P:uvshVRL:STFl:t:mn:p:";
00189     struct option long_options[] = {
00190                                        { "driver", 1, 0, 'd'
00191                                        },
00192                                        { "verbose", 0, 0, 'v' },
00193                                        { "help", 0, 0, 'h' },
00194                                        { "port-max", 1, 0, 'p' },
00195                                        { "no-mlock", 0, 0, 'm' },
00196                                        { "name", 0, 0, 'n' },
00197                                        { "unlock", 0, 0, 'u' },
00198                                        { "realtime", 0, 0, 'R' },
00199                                        { "loopback", 0, 0, 'L' },
00200                                        { "realtime-priority", 1, 0, 'P' },
00201                                        { "timeout", 1, 0, 't' },
00202                                        { "temporary", 0, 0, 'T' },
00203                                        { "version", 0, 0, 'V' },
00204                                        { "silent", 0, 0, 's' },
00205                                        { "sync", 0, 0, 'S' },
00206                                        { 0, 0, 0, 0 }
00207                                    };
00208     int opt = 0;
00209     int option_index = 0;
00210     int seen_driver = 0;
00211     char *driver_name = NULL;
00212     char **driver_args = NULL;
00213     JSList* driver_params;
00214     int driver_nargs = 1;
00215     JSList* drivers = NULL;
00216     char* server_name = NULL;
00217     int show_version = 0;
00218     int sync = 0;
00219     int rc, i;
00220 
00221     int argc = 8;
00222     //char* argv[] = {"jackdmp", "-R", "-v", "-d", "coreaudio", "-p", "512"};
00223     char* argv[] = {"jackdmp", "-R", "-S", "-v", "-d", "portaudio", "-p", "512"};
00224 
00225     for (i = 0; i < argc; i++) {
00226         printf("arg %i %s\n", i, argv[i]);
00227     }
00228 
00229     opterr = 0;
00230     while (!seen_driver &&
00231             (opt = getopt_long(argc, argv, options,
00232                                long_options, &option_index)) != EOF) {
00233         switch (opt) {
00234 
00235             case 'd':
00236                 seen_driver = 1;
00237                 driver_name = optarg;
00238                 break;
00239 
00240             case 'v':
00241                 verbose_aux = 1;
00242                 break;
00243 
00244             case 's':
00245                 // jack_set_error_function(silent_jack_error_callback);
00246                 break;
00247 
00248             case 'S':
00249                 sync = 1;
00250                 break;
00251 
00252             case 'n':
00253                 server_name = optarg;
00254                 break;
00255 
00256             case 'm':
00257                 do_mlock = 0;
00258                 break;
00259 
00260             case 'p':
00261                 port_max = (unsigned int)atol(optarg);
00262                 break;
00263 
00264             case 'P':
00265                 realtime_priority = atoi(optarg);
00266                 break;
00267 
00268             case 'R':
00269                 realtime = 1;
00270                 break;
00271 
00272             case 'L':
00273                 loopback = atoi(optarg);
00274                 break;
00275 
00276             case 'T':
00277                 temporary = 1;
00278                 break;
00279 
00280             case 't':
00281                 client_timeout = atoi(optarg);
00282                 break;
00283 
00284             case 'u':
00285                 do_unlock = 1;
00286                 break;
00287 
00288             case 'V':
00289                 show_version = 1;
00290                 break;
00291 
00292             default:
00293                 fprintf(stderr, "unknown option character %c\n",
00294                         optopt);
00295                 /*fallthru*/
00296             case 'h':
00297                 //usage(stdout);
00298                 return ;
00299         }
00300     }
00301 
00302     drivers = jack_drivers_load (drivers);
00303     if (!drivers) {
00304         fprintf (stderr, "jackdmp: no drivers found; exiting\n");
00305         exit (1);
00306     }
00307 
00308     driver_desc = jack_find_driver_descriptor (drivers, driver_name);
00309     if (!driver_desc) {
00310         fprintf (stderr, "jackdmp: unknown driver '%s'\n", driver_name);
00311         exit (1);
00312     }
00313 
00314     if (optind < argc) {
00315         driver_nargs = 1 + argc - optind;
00316     } else {
00317         driver_nargs = 1;
00318     }
00319 
00320     if (driver_nargs == 0) {
00321         fprintf (stderr, "No driver specified ... hmm. JACK won't do"
00322                  " anything when run like this.\n");
00323         return ;
00324     }
00325 
00326     driver_args = (char **) malloc (sizeof (char *) * driver_nargs);
00327     driver_args[0] = driver_name;
00328 
00329     for (i = 1; i < driver_nargs; i++) {
00330         driver_args[i] = argv[optind++];
00331     }
00332 
00333     if (jack_parse_driver_params (driver_desc, driver_nargs,
00334                                   driver_args, &driver_params)) {
00335         return ;
00336     }
00337 
00338 #ifndef WIN32
00339     if (server_name == NULL)
00340         server_name = jack_default_server_name ();
00341 #endif
00342 
00343     rc = jack_register_server (server_name);
00344 
00345     /* clean up shared memory and files from any previous
00346     * instance of this server name */
00347     jack_cleanup_shm();
00348 #ifndef WIN32
00349     jack_cleanup_files(server_name);
00350 #endif
00351 
00352     if (!realtime && client_timeout == 0)
00353         client_timeout = 500; /* 0.5 sec; usable when non realtime. */
00354 
00355     int res = JackStart(driver_desc, driver_params, sync, client_timeout, realtime, realtime_priority, loopback, verbose_aux);
00356     if (res < 0) {
00357         jack_error("Cannot start server... exit");
00358         JackDelete();
00359         return ;
00360     }
00361 }
00362 
00363 JackServerGlobals::~JackServerGlobals()
00364 {
00365     JackLog("~JackServerGlobals\n");
00366     JackStop();
00367     jack_cleanup_shm();
00368 #ifndef WIN32
00369     jack_cleanup_files(server_name);
00370 #endif
00371     jack_unregister_server(server_name);
00372 }
00373 
00374 void JackServerGlobals::Init()
00375 {
00376     if (fClientCount++ == 0 && !fGlobals) {
00377         JackLog("JackServerGlobals Init %x\n", fGlobals);
00378         fGlobals = new JackServerGlobals();
00379     }
00380 }
00381 
00382 void JackServerGlobals::Destroy()
00383 {
00384     if (--fClientCount == 0 && fGlobals) {
00385         JackLog("JackServerGlobals Destroy %x\n", fGlobals);
00386         delete fGlobals;
00387         fGlobals = NULL;
00388     }
00389 }
00390 
00391 } // end of namespace
00392 
00393 

Generated on Wed Jan 10 11:42:46 2007 for Jackdmp by  doxygen 1.4.5