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