Jack2 1.9.6

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 #include "JackServerGlobals.h"
00021 #include "JackTools.h"
00022 #include "shm.h"
00023 #include <getopt.h>
00024 #include <errno.h>
00025 
00026 static char* server_name = NULL;
00027 
00028 namespace Jack
00029 {
00030 
00031 JackServer* JackServerGlobals::fInstance; 
00032 unsigned int JackServerGlobals::fUserCount;
00033 bool (* JackServerGlobals::on_device_acquire)(const char * device_name) = NULL;
00034 void (* JackServerGlobals::on_device_release)(const char * device_name) = NULL;
00035 
00036 int JackServerGlobals::Start(const char* server_name,
00037                              jack_driver_desc_t* driver_desc,
00038                              JSList* driver_params,
00039                              int sync,
00040                              int temporary,
00041                              int time_out_ms,
00042                              int rt,
00043                              int priority,
00044                              int port_max,
00045                              int verbose,
00046                             jack_timer_type_t clock)
00047 {
00048     jack_log("Jackdmp: sync = %ld timeout = %ld rt = %ld priority = %ld verbose = %ld ", sync, time_out_ms, rt, priority, verbose);
00049     new JackServer(sync, temporary, time_out_ms, rt, priority, port_max, verbose, clock, server_name);  // Will setup fInstance and fUserCount globals
00050     int res = fInstance->Open(driver_desc, driver_params);
00051     return (res < 0) ? res : fInstance->Start();
00052 }
00053 
00054 void JackServerGlobals::Stop()
00055 {
00056     jack_log("Jackdmp: server close");
00057     fInstance->Stop();
00058     fInstance->Close();
00059 }
00060 
00061 void JackServerGlobals::Delete()
00062 {
00063     jack_log("Jackdmp: delete server");
00064     delete fInstance;
00065     fInstance = NULL;
00066 }
00067 
00068 bool JackServerGlobals::Init()
00069 {
00070     int realtime = 0;
00071     int client_timeout = 0; /* msecs; if zero, use period size. */
00072     int realtime_priority = 10;
00073     int verbose_aux = 0;
00074     int do_mlock = 1;
00075     unsigned int port_max = 128;
00076     int do_unlock = 0;
00077     int temporary = 0;
00078 
00079     int opt = 0;
00080     int option_index = 0;
00081     int seen_driver = 0;
00082     char *driver_name = NULL;
00083     char **driver_args = NULL;
00084     JSList* driver_params = NULL;
00085     int driver_nargs = 1;
00086     JSList* drivers = NULL;
00087     int show_version = 0;
00088     int sync = 0;
00089     int rc, i;
00090     int ret;
00091 
00092     FILE* fp = 0;
00093     char filename[255];
00094     char buffer[255];
00095     int argc = 0;
00096     char* argv[32];
00097     jack_timer_type_t clock_source = JACK_TIMER_SYSTEM_CLOCK;
00098     
00099     // First user starts the server
00100     if (fUserCount++ == 0) {
00101 
00102         jack_log("JackServerGlobals Init");
00103 
00104         jack_driver_desc_t* driver_desc;
00105         const char *options = "-ad:P:uvshVRL:STFl:t:mn:p:c:";
00106         static struct option long_options[] = {
00107                                                   { "clock-source", 1, 0, 'c' },
00108                                                   { "driver", 1, 0, 'd' },
00109                                                   { "verbose", 0, 0, 'v' },
00110                                                   { "help", 0, 0, 'h' },
00111                                                   { "port-max", 1, 0, 'p' },
00112                                                   { "no-mlock", 0, 0, 'm' },
00113                                                   { "name", 0, 0, 'n' },
00114                                                   { "unlock", 0, 0, 'u' },
00115                                                   { "realtime", 0, 0, 'R' },
00116                                                   { "realtime-priority", 1, 0, 'P' },
00117                                                   { "timeout", 1, 0, 't' },
00118                                                   { "temporary", 0, 0, 'T' },
00119                                                   { "version", 0, 0, 'V' },
00120                                                   { "silent", 0, 0, 's' },
00121                                                   { "sync", 0, 0, 'S' },
00122                                                   { 0, 0, 0, 0 }
00123                                               };
00124 
00125         snprintf(filename, 255, "%s/.jackdrc", getenv("HOME"));
00126         fp = fopen(filename, "r");
00127 
00128         if (!fp) {
00129             fp = fopen("/etc/jackdrc", "r");
00130         }
00131         // if still not found, check old config name for backwards compatability
00132         if (!fp) {
00133             fp = fopen("/etc/jackd.conf", "r");
00134         }
00135 
00136         argc = 0;
00137         if (fp) {
00138             ret = fscanf(fp, "%s", buffer);
00139             while (ret != 0 && ret != EOF) {
00140                 argv[argc] = (char*)malloc(64);
00141                 strcpy(argv[argc], buffer);
00142                 ret = fscanf(fp, "%s", buffer);
00143                 argc++;
00144             }
00145             fclose(fp);
00146         }
00147 
00148         /*
00149         For testing
00150         int argc = 15;
00151         char* argv[] = {"jackdmp", "-R", "-v", "-d", "coreaudio", "-p", "512", "-d", "~:Aggregate:0", "-r", "48000", "-i", "2", "-o", "2" };
00152         */
00153 
00154         opterr = 0;
00155         optind = 1; // Important : to reset argv parsing
00156 
00157         while (!seen_driver &&
00158                 (opt = getopt_long(argc, argv, options, long_options, &option_index)) != EOF) {
00159 
00160             switch (opt) {
00161             
00162                 case 'c':
00163                     if (tolower (optarg[0]) == 'h') {
00164                         clock_source = JACK_TIMER_HPET;
00165                     } else if (tolower (optarg[0]) == 'c') {
00166                         clock_source = JACK_TIMER_CYCLE_COUNTER;
00167                     } else if (tolower (optarg[0]) == 's') {
00168                         clock_source = JACK_TIMER_SYSTEM_CLOCK;
00169                     } else {
00170                         jack_error("unknown option character %c", optopt);
00171                     }                
00172                     break;
00173 
00174                 case 'd':
00175                     seen_driver = 1;
00176                     driver_name = optarg;
00177                     break;
00178 
00179                 case 'v':
00180                     verbose_aux = 1;
00181                     break;
00182 
00183                 case 'S':
00184                     sync = 1;
00185                     break;
00186 
00187                 case 'n':
00188                     server_name = optarg;
00189                     break;
00190 
00191                 case 'm':
00192                     do_mlock = 0;
00193                     break;
00194 
00195                 case 'p':
00196                     port_max = (unsigned int)atol(optarg);
00197                     break;
00198 
00199                 case 'P':
00200                     realtime_priority = atoi(optarg);
00201                     break;
00202 
00203                 case 'R':
00204                     realtime = 1;
00205                     break;
00206 
00207                 case 'T':
00208                     temporary = 1;
00209                     break;
00210 
00211                 case 't':
00212                     client_timeout = atoi(optarg);
00213                     break;
00214 
00215                 case 'u':
00216                     do_unlock = 1;
00217                     break;
00218 
00219                 case 'V':
00220                     show_version = 1;
00221                     break;
00222 
00223                 default:
00224                     jack_error("unknown option character %c", optopt);
00225                     break;
00226             }
00227         }
00228 
00229         drivers = jack_drivers_load(drivers);
00230         if (!drivers) {
00231             jack_error("jackdmp: no drivers found; exiting");
00232             goto error;
00233         }
00234 
00235         driver_desc = jack_find_driver_descriptor(drivers, driver_name);
00236         if (!driver_desc) {
00237             jack_error("jackdmp: unknown driver '%s'", driver_name);
00238             goto error;
00239         }
00240 
00241         if (optind < argc) {
00242             driver_nargs = 1 + argc - optind;
00243         } else {
00244             driver_nargs = 1;
00245         }
00246 
00247         if (driver_nargs == 0) {
00248             jack_error("No driver specified ... hmm. JACK won't do"
00249                        " anything when run like this.");
00250             goto error;
00251         }
00252 
00253         driver_args = (char**)malloc(sizeof(char*) * driver_nargs);
00254         driver_args[0] = driver_name;
00255 
00256         for (i = 1; i < driver_nargs; i++) {
00257             driver_args[i] = argv[optind++];
00258         }
00259 
00260         if (jack_parse_driver_params(driver_desc, driver_nargs, driver_args, &driver_params)) {
00261             goto error;
00262         }
00263 
00264 #ifndef WIN32
00265         if (server_name == NULL)
00266             server_name = (char*)JackTools::DefaultServerName();
00267 #endif
00268 
00269         rc = jack_register_server(server_name, false);
00270         switch (rc) {
00271             case EEXIST:
00272                 jack_error("`%s' server already active", server_name);
00273                 goto error;
00274             case ENOSPC:
00275                 jack_error("too many servers already active");
00276                 goto error;
00277             case ENOMEM:
00278                 jack_error("no access to shm registry");
00279                 goto error;
00280             default:
00281                 jack_info("server `%s' registered", server_name);
00282         }
00283 
00284         /* clean up shared memory and files from any previous instance of this server name */
00285         jack_cleanup_shm();
00286         JackTools::CleanupFiles(server_name);
00287 
00288         if (!realtime && client_timeout == 0)
00289             client_timeout = 500; /* 0.5 sec; usable when non realtime. */
00290 
00291         for (i = 0; i < argc; i++) {
00292             free(argv[i]);
00293         }
00294 
00295         int res = Start(server_name, driver_desc, driver_params, sync, temporary, client_timeout, realtime, realtime_priority, port_max, verbose_aux, clock_source);
00296         if (res < 0) {
00297             jack_error("Cannot start server... exit");
00298             Delete();
00299             jack_cleanup_shm();
00300             JackTools::CleanupFiles(server_name);
00301             jack_unregister_server(server_name);
00302             goto error;
00303         }
00304     }
00305 
00306     if (driver_params)
00307         jack_free_driver_params(driver_params);
00308     return true;
00309 
00310 error:
00311     if (driver_params)
00312         jack_free_driver_params(driver_params);
00313     fUserCount--;
00314     return false;
00315 }
00316 
00317 void JackServerGlobals::Destroy()
00318 {
00319     if (--fUserCount == 0) {
00320         jack_log("JackServerGlobals Destroy");
00321         Stop();
00322         Delete();
00323         jack_cleanup_shm();
00324         JackTools::CleanupFiles(server_name);
00325         jack_unregister_server(server_name);
00326     }
00327 }
00328 
00329 } // end of namespace
00330 
00331