Jack2  1.9.10
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 "JackLockedEngine.h"
00022 #include "JackTools.h"
00023 #include "shm.h"
00024 #include <getopt.h>
00025 #include <errno.h>
00026 #include <sys/utsname.h>
00027 
00028 static char* server_name = NULL;
00029 
00030 namespace Jack
00031 {
00032 
00033 JackServer* JackServerGlobals::fInstance;
00034 unsigned int JackServerGlobals::fUserCount;
00035 std::map<std::string, JackDriverInfo*> JackServerGlobals::fSlavesList;
00036 std::map<std::string, int> JackServerGlobals::fInternalsList;
00037 
00038 bool (* JackServerGlobals::on_device_acquire)(const char * device_name) = NULL;
00039 void (* JackServerGlobals::on_device_release)(const char * device_name) = NULL;
00040 
00041 int JackServerGlobals::Start(const char* server_name,
00042                              jack_driver_desc_t* driver_desc,
00043                              JSList* driver_params,
00044                              int sync,
00045                              int temporary,
00046                              int time_out_ms,
00047                              int rt,
00048                              int priority,
00049                              int port_max,
00050                              int verbose,
00051                              jack_timer_type_t clock,
00052                              char self_connect_mode)
00053 {
00054     jack_log("Jackdmp: sync = %ld timeout = %ld rt = %ld priority = %ld verbose = %ld ", sync, time_out_ms, rt, priority, verbose);
00055     new JackServer(sync, temporary, time_out_ms, rt, priority, port_max, verbose, clock, self_connect_mode, server_name);  // Will setup fInstance and fUserCount globals
00056     int res = fInstance->Open(driver_desc, driver_params);
00057     return (res < 0) ? res : fInstance->Start();
00058 }
00059 
00060 void JackServerGlobals::Stop()
00061 {
00062     jack_log("Jackdmp: server close");
00063     fInstance->Stop();
00064     fInstance->Close();
00065 }
00066 
00067 void JackServerGlobals::Delete()
00068 {
00069     jack_log("Jackdmp: delete server");
00070 
00071     // Slave drivers
00072     std::map<std::string, JackDriverInfo*>::iterator it1;
00073     for (it1 = fSlavesList.begin(); it1 != fSlavesList.end(); it1++) {
00074         JackDriverInfo* info = (*it1).second;
00075         if (info) {
00076             fInstance->RemoveSlave((info));
00077             delete (info);
00078         }
00079     }
00080     fSlavesList.clear();
00081 
00082     // Internal clients
00083     std::map<std::string, int> ::iterator it2;
00084     for (it2 = fInternalsList.begin(); it2 != fInternalsList.end(); it2++) {
00085         int status;
00086         int refnum = (*it2).second;
00087         if (refnum > 0) {
00088             // Client object is internally kept in JackEngine, and will be deallocated in InternalClientUnload
00089             fInstance->GetEngine()->InternalClientUnload(refnum, &status);
00090         }
00091     }
00092     fInternalsList.clear();
00093 
00094     delete fInstance;
00095     fInstance = NULL;
00096 }
00097 
00098 bool JackServerGlobals::Init()
00099 {
00100     struct utsname utsname;
00101     int success;
00102     success = uname( &utsname );
00103     
00104     int realtime = 0;
00105     int client_timeout = 0; /* msecs; if zero, use period size. */
00106     int realtime_priority;
00107     if( success == 0 && strstr( utsname.version, "ccrma" ) )
00108       realtime_priority = 60;
00109     else
00110       realtime_priority = 20;
00111     int verbose_aux = 0;
00112     unsigned int port_max = 128;
00113     int temporary = 0;
00114 
00115     int opt = 0;
00116     int option_index = 0;
00117     char *master_driver_name = NULL;
00118     char **master_driver_args = NULL;
00119     JSList* master_driver_params = NULL;
00120     jack_driver_desc_t* driver_desc;
00121     jack_timer_type_t clock_source = JACK_TIMER_SYSTEM_CLOCK;
00122     int driver_nargs = 1;
00123     JSList* drivers = NULL;
00124     int loopback = 0;
00125     int sync = 0;
00126     int rc, i;
00127     int res;
00128     int replace_registry = 0;
00129 
00130     FILE* fp = 0;
00131     char filename[255];
00132     char buffer[255];
00133     int argc = 0;
00134     char* argv[32];
00135 
00136     // First user starts the server
00137     if (fUserCount++ == 0) {
00138 
00139         jack_log("JackServerGlobals Init");
00140 
00141         const char *options = "-d:X:I:P:uvshVrRL:STFl:t:mn:p:"
00142     #ifdef __linux__
00143             "c:"
00144     #endif
00145         ;
00146 
00147     struct option long_options[] = {
00148     #ifdef __linux__
00149                                        { "clock-source", 1, 0, 'c' },
00150     #endif
00151                                        { "loopback-driver", 1, 0, 'L' },
00152                                        { "audio-driver", 1, 0, 'd' },
00153                                        { "midi-driver", 1, 0, 'X' },
00154                                        { "internal-client", 1, 0, 'I' },
00155                                        { "verbose", 0, 0, 'v' },
00156                                        { "help", 0, 0, 'h' },
00157                                        { "port-max", 1, 0, 'p' },
00158                                        { "no-mlock", 0, 0, 'm' },
00159                                        { "name", 1, 0, 'n' },
00160                                        { "unlock", 0, 0, 'u' },
00161                                        { "realtime", 0, 0, 'R' },
00162                                        { "no-realtime", 0, 0, 'r' },
00163                                        { "replace-registry", 0, &replace_registry, 0 },
00164                                        { "loopback", 0, 0, 'L' },
00165                                        { "realtime-priority", 1, 0, 'P' },
00166                                        { "timeout", 1, 0, 't' },
00167                                        { "temporary", 0, 0, 'T' },
00168                                        { "version", 0, 0, 'V' },
00169                                        { "silent", 0, 0, 's' },
00170                                        { "sync", 0, 0, 'S' },
00171                                        { 0, 0, 0, 0 }
00172                                    };
00173 
00174         snprintf(filename, 255, "%s/.jackdrc", getenv("HOME"));
00175         fp = fopen(filename, "r");
00176 
00177         if (!fp) {
00178             fp = fopen("/etc/jackdrc", "r");
00179         }
00180         // if still not found, check old config name for backwards compatability
00181         if (!fp) {
00182             fp = fopen("/etc/jackd.conf", "r");
00183         }
00184 
00185         argc = 0;
00186         if (fp) {
00187             res = fscanf(fp, "%s", buffer);
00188             while (res != 0 && res != EOF) {
00189                 argv[argc] = (char*)malloc(64);
00190                 strcpy(argv[argc], buffer);
00191                 res = fscanf(fp, "%s", buffer);
00192                 argc++;
00193             }
00194             fclose(fp);
00195         }
00196 
00197         /*
00198         For testing
00199         int argc = 15;
00200         char* argv[] = {"jackdmp", "-R", "-v", "-d", "coreaudio", "-p", "512", "-d", "~:Aggregate:0", "-r", "48000", "-i", "2", "-o", "2" };
00201         */
00202 
00203         opterr = 0;
00204         optind = 1; // Important : to reset argv parsing
00205 
00206         while (!master_driver_name &&
00207                 (opt = getopt_long(argc, argv, options, long_options, &option_index)) != EOF) {
00208 
00209             switch (opt) {
00210 
00211                 case 'c':
00212                     if (tolower (optarg[0]) == 'h') {
00213                         clock_source = JACK_TIMER_HPET;
00214                     } else if (tolower (optarg[0]) == 'c') {
00215                         /* For backwards compatibility with scripts, allow
00216                          * the user to request the cycle clock on the
00217                          * command line, but use the system clock instead
00218                          */
00219                         clock_source = JACK_TIMER_SYSTEM_CLOCK;
00220                     } else if (tolower (optarg[0]) == 's') {
00221                         clock_source = JACK_TIMER_SYSTEM_CLOCK;
00222                     } else {
00223                         jack_error("unknown option character %c", optopt);
00224                     }
00225                     break;
00226 
00227                 case 'd':
00228                     master_driver_name = optarg;
00229                     break;
00230 
00231                 case 'L':
00232                     loopback = atoi(optarg);
00233                     break;
00234 
00235                  case 'X':
00236                     fSlavesList[optarg] = NULL;
00237                     break;
00238 
00239                 case 'I':
00240                     fInternalsList[optarg] = -1;
00241                     break;
00242 
00243                 case 'p':
00244                     port_max = (unsigned int)atol(optarg);
00245                     break;
00246 
00247                 case 'm':
00248                     break;
00249 
00250                 case 'u':
00251                     break;
00252 
00253                 case 'v':
00254                     verbose_aux = 1;
00255                     break;
00256 
00257                 case 'S':
00258                     sync = 1;
00259                     break;
00260 
00261                 case 'n':
00262                     server_name = optarg;
00263                     break;
00264 
00265                 case 'P':
00266                     realtime_priority = atoi(optarg);
00267                     break;
00268 
00269                 case 'r':
00270                     realtime = 0;
00271                     break;
00272 
00273                 case 'R':
00274                     realtime = 1;
00275                     break;
00276 
00277                 case 'T':
00278                     temporary = 1;
00279                     break;
00280 
00281                 case 't':
00282                     client_timeout = atoi(optarg);
00283                     break;
00284 
00285                 default:
00286                     jack_error("unknown option character %c", optopt);
00287                     break;
00288             }
00289         }
00290 
00291         drivers = jack_drivers_load(drivers);
00292         if (!drivers) {
00293             jack_error("jackdmp: no drivers found; exiting");
00294             goto error;
00295         }
00296 
00297         driver_desc = jack_find_driver_descriptor(drivers, master_driver_name);
00298         if (!driver_desc) {
00299             jack_error("jackdmp: unknown master driver '%s'", master_driver_name);
00300             goto error;
00301         }
00302 
00303         if (optind < argc) {
00304             driver_nargs = 1 + argc - optind;
00305         } else {
00306             driver_nargs = 1;
00307         }
00308 
00309         if (driver_nargs == 0) {
00310             jack_error("No driver specified ... hmm. JACK won't do"
00311                        " anything when run like this.");
00312             goto error;
00313         }
00314 
00315         master_driver_args = (char**)malloc(sizeof(char*) * driver_nargs);
00316         master_driver_args[0] = master_driver_name;
00317 
00318         for (i = 1; i < driver_nargs; i++) {
00319             master_driver_args[i] = argv[optind++];
00320         }
00321 
00322         if (jack_parse_driver_params(driver_desc, driver_nargs, master_driver_args, &master_driver_params)) {
00323             goto error;
00324         }
00325 
00326 #ifndef WIN32
00327         if (server_name == NULL) {
00328             server_name = (char*)JackTools::DefaultServerName();
00329         }
00330 #endif
00331 
00332         rc = jack_register_server(server_name, false);
00333         switch (rc) {
00334             case EEXIST:
00335                 jack_error("`%s' server already active", server_name);
00336                 goto error;
00337             case ENOSPC:
00338                 jack_error("too many servers already active");
00339                 goto error;
00340             case ENOMEM:
00341                 jack_error("no access to shm registry");
00342                 goto error;
00343             default:
00344                 jack_info("server `%s' registered", server_name);
00345         }
00346 
00347         /* clean up shared memory and files from any previous instance of this server name */
00348         jack_cleanup_shm();
00349         JackTools::CleanupFiles(server_name);
00350 
00351         if (!realtime && client_timeout == 0) {
00352             client_timeout = 500; /* 0.5 sec; usable when non realtime. */
00353         }
00354 
00355         for (i = 0; i < argc; i++) {
00356             free(argv[i]);
00357         }
00358 
00359         int res = Start(server_name, driver_desc, master_driver_params, sync, temporary, client_timeout, realtime, realtime_priority, port_max, verbose_aux, clock_source, JACK_DEFAULT_SELF_CONNECT_MODE);
00360         if (res < 0) {
00361             jack_error("Cannot start server... exit");
00362             Delete();
00363             jack_cleanup_shm();
00364             JackTools::CleanupFiles(server_name);
00365             jack_unregister_server(server_name);
00366             goto error;
00367         }
00368 
00369         // Slave drivers
00370         std::map<std::string, JackDriverInfo*>::iterator it1;
00371         for (it1 = fSlavesList.begin(); it1 != fSlavesList.end(); it1++) {
00372             const char* name = ((*it1).first).c_str();
00373             driver_desc = jack_find_driver_descriptor(drivers, name);
00374             if (!driver_desc) {
00375                 jack_error("jackdmp: unknown slave driver '%s'", name);
00376             } else {
00377                 (*it1).second = fInstance->AddSlave(driver_desc, NULL);
00378             }
00379         }
00380 
00381         // Loopback driver
00382         if (loopback > 0) {
00383             driver_desc = jack_find_driver_descriptor(drivers, "loopback");
00384             if (!driver_desc) {
00385                 jack_error("jackdmp: unknown driver '%s'", "loopback");
00386             } else {
00387                 fSlavesList["loopback"] = fInstance->AddSlave(driver_desc, NULL);
00388             }
00389         }
00390 
00391         // Internal clients
00392         std::map<std::string, int>::iterator it2;
00393         for (it2 = fInternalsList.begin(); it2 != fInternalsList.end(); it2++) {
00394             int status, refnum;
00395             const char* name = ((*it2).first).c_str();
00396             fInstance->InternalClientLoad2(name, name, NULL, JackNullOption, &refnum, -1, &status);
00397             (*it2).second = refnum;
00398         }
00399     }
00400 
00401     if (master_driver_params) {
00402         jack_free_driver_params(master_driver_params);
00403     }
00404     return true;
00405 
00406 error:
00407     jack_log("JackServerGlobals Init error");
00408     if (master_driver_params) {
00409         jack_free_driver_params(master_driver_params);
00410     }
00411     Destroy();
00412     return false;
00413 }
00414 
00415 void JackServerGlobals::Destroy()
00416 {
00417     if (--fUserCount == 0) {
00418         jack_log("JackServerGlobals Destroy");
00419         Stop();
00420         Delete();
00421         jack_cleanup_shm();
00422         JackTools::CleanupFiles(server_name);
00423         jack_unregister_server(server_name);
00424     }
00425 }
00426 
00427 } // end of namespace
00428 
00429