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 #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