Jack2
1.9.7
|
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 int JackServerGlobals::fRTNotificationSocket; 00036 std::map<std::string, JackDriverInfo*> JackServerGlobals::fSlavesList; 00037 std::map<std::string, int> JackServerGlobals::fInternalsList; 00038 00039 bool (* JackServerGlobals::on_device_acquire)(const char * device_name) = NULL; 00040 void (* JackServerGlobals::on_device_release)(const char * device_name) = NULL; 00041 00042 int JackServerGlobals::Start(const char* server_name, 00043 jack_driver_desc_t* driver_desc, 00044 JSList* driver_params, 00045 int sync, 00046 int temporary, 00047 int time_out_ms, 00048 int rt, 00049 int priority, 00050 int port_max, 00051 int verbose, 00052 jack_timer_type_t clock) 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, 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 desallocated 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 int do_mlock = 1; 00113 unsigned int port_max = 128; 00114 int do_unlock = 0; 00115 int temporary = 0; 00116 00117 int opt = 0; 00118 int option_index = 0; 00119 char *master_driver_name = NULL; 00120 char **master_driver_args = NULL; 00121 JSList* master_driver_params = NULL; 00122 jack_driver_desc_t* driver_desc; 00123 jack_timer_type_t clock_source = JACK_TIMER_SYSTEM_CLOCK; 00124 int driver_nargs = 1; 00125 JSList* drivers = NULL; 00126 int loopback = 0; 00127 int sync = 0; 00128 int rc, i; 00129 int ret; 00130 int replace_registry = 0; 00131 00132 FILE* fp = 0; 00133 char filename[255]; 00134 char buffer[255]; 00135 int argc = 0; 00136 char* argv[32]; 00137 00138 // First user starts the server 00139 if (fUserCount++ == 0) { 00140 00141 jack_log("JackServerGlobals Init"); 00142 00143 const char *options = "-d:X:I:P:uvshVrRL:STFl:t:mn:p:" 00144 #ifdef __linux__ 00145 "c:" 00146 #endif 00147 ; 00148 00149 struct option long_options[] = { 00150 #ifdef __linux__ 00151 { "clock-source", 1, 0, 'c' }, 00152 #endif 00153 { "loopback-driver", 1, 0, 'L' }, 00154 { "audio-driver", 1, 0, 'd' }, 00155 { "midi-driver", 1, 0, 'X' }, 00156 { "internal-client", 1, 0, 'I' }, 00157 { "verbose", 0, 0, 'v' }, 00158 { "help", 0, 0, 'h' }, 00159 { "port-max", 1, 0, 'p' }, 00160 { "no-mlock", 0, 0, 'm' }, 00161 { "name", 1, 0, 'n' }, 00162 { "unlock", 0, 0, 'u' }, 00163 { "realtime", 0, 0, 'R' }, 00164 { "no-realtime", 0, 0, 'r' }, 00165 { "replace-registry", 0, &replace_registry, 0 }, 00166 { "loopback", 0, 0, 'L' }, 00167 { "realtime-priority", 1, 0, 'P' }, 00168 { "timeout", 1, 0, 't' }, 00169 { "temporary", 0, 0, 'T' }, 00170 { "version", 0, 0, 'V' }, 00171 { "silent", 0, 0, 's' }, 00172 { "sync", 0, 0, 'S' }, 00173 { 0, 0, 0, 0 } 00174 }; 00175 00176 snprintf(filename, 255, "%s/.jackdrc", getenv("HOME")); 00177 fp = fopen(filename, "r"); 00178 00179 if (!fp) { 00180 fp = fopen("/etc/jackdrc", "r"); 00181 } 00182 // if still not found, check old config name for backwards compatability 00183 if (!fp) { 00184 fp = fopen("/etc/jackd.conf", "r"); 00185 } 00186 00187 argc = 0; 00188 if (fp) { 00189 ret = fscanf(fp, "%s", buffer); 00190 while (ret != 0 && ret != EOF) { 00191 argv[argc] = (char*)malloc(64); 00192 strcpy(argv[argc], buffer); 00193 ret = fscanf(fp, "%s", buffer); 00194 argc++; 00195 } 00196 fclose(fp); 00197 } 00198 00199 /* 00200 For testing 00201 int argc = 15; 00202 char* argv[] = {"jackdmp", "-R", "-v", "-d", "coreaudio", "-p", "512", "-d", "~:Aggregate:0", "-r", "48000", "-i", "2", "-o", "2" }; 00203 */ 00204 00205 opterr = 0; 00206 optind = 1; // Important : to reset argv parsing 00207 00208 while (!master_driver_name && 00209 (opt = getopt_long(argc, argv, options, long_options, &option_index)) != EOF) { 00210 00211 switch (opt) { 00212 00213 case 'c': 00214 if (tolower (optarg[0]) == 'h') { 00215 clock_source = JACK_TIMER_HPET; 00216 } else if (tolower (optarg[0]) == 'c') { 00217 clock_source = JACK_TIMER_CYCLE_COUNTER; 00218 } else if (tolower (optarg[0]) == 's') { 00219 clock_source = JACK_TIMER_SYSTEM_CLOCK; 00220 } else { 00221 jack_error("unknown option character %c", optopt); 00222 } 00223 break; 00224 00225 case 'd': 00226 master_driver_name = optarg; 00227 break; 00228 00229 case 'L': 00230 loopback = atoi(optarg); 00231 break; 00232 00233 case 'X': 00234 fSlavesList[optarg] = NULL; 00235 break; 00236 00237 case 'I': 00238 fInternalsList[optarg] = -1; 00239 break; 00240 00241 case 'p': 00242 port_max = (unsigned int)atol(optarg); 00243 break; 00244 00245 case 'm': 00246 do_mlock = 0; 00247 break; 00248 00249 case 'u': 00250 do_unlock = 1; 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 #endif 00330 00331 rc = jack_register_server(server_name, false); 00332 switch (rc) { 00333 case EEXIST: 00334 jack_error("`%s' server already active", server_name); 00335 goto error; 00336 case ENOSPC: 00337 jack_error("too many servers already active"); 00338 goto error; 00339 case ENOMEM: 00340 jack_error("no access to shm registry"); 00341 goto error; 00342 default: 00343 jack_info("server `%s' registered", server_name); 00344 } 00345 00346 /* clean up shared memory and files from any previous instance of this server name */ 00347 jack_cleanup_shm(); 00348 JackTools::CleanupFiles(server_name); 00349 00350 if (!realtime && client_timeout == 0) 00351 client_timeout = 500; /* 0.5 sec; usable when non realtime. */ 00352 00353 for (i = 0; i < argc; i++) { 00354 free(argv[i]); 00355 } 00356 00357 int res = Start(server_name, driver_desc, master_driver_params, sync, temporary, client_timeout, realtime, realtime_priority, port_max, verbose_aux, clock_source); 00358 if (res < 0) { 00359 jack_error("Cannot start server... exit"); 00360 Delete(); 00361 jack_cleanup_shm(); 00362 JackTools::CleanupFiles(server_name); 00363 jack_unregister_server(server_name); 00364 goto error; 00365 } 00366 00367 // Slave drivers 00368 std::map<std::string, JackDriverInfo*>::iterator it1; 00369 for (it1 = fSlavesList.begin(); it1 != fSlavesList.end(); it1++) { 00370 const char* name = ((*it1).first).c_str(); 00371 driver_desc = jack_find_driver_descriptor(drivers, name); 00372 if (!driver_desc) { 00373 jack_error("jackdmp: unknown slave driver '%s'", name); 00374 } else { 00375 (*it1).second = fInstance->AddSlave(driver_desc, NULL); 00376 } 00377 } 00378 00379 // Loopback driver 00380 if (loopback > 0) { 00381 driver_desc = jack_find_driver_descriptor(drivers, "loopback"); 00382 if (!driver_desc) { 00383 jack_error("jackdmp: unknown driver '%s'", "loopback"); 00384 } else { 00385 fSlavesList["loopback"] = fInstance->AddSlave(driver_desc, NULL); 00386 } 00387 } 00388 00389 // Internal clients 00390 std::map<std::string, int>::iterator it2; 00391 for (it2 = fInternalsList.begin(); it2 != fInternalsList.end(); it2++) { 00392 int status, refnum; 00393 const char* name = ((*it2).first).c_str(); 00394 fInstance->InternalClientLoad2(name, name, NULL, JackNullOption, &refnum, -1, &status); 00395 (*it2).second = refnum; 00396 } 00397 } 00398 00399 if (master_driver_params) 00400 jack_free_driver_params(master_driver_params); 00401 return true; 00402 00403 error: 00404 jack_log("JackServerGlobals Init error"); 00405 if (master_driver_params) 00406 jack_free_driver_params(master_driver_params); 00407 Destroy(); 00408 return false; 00409 } 00410 00411 void JackServerGlobals::Destroy() 00412 { 00413 if (--fUserCount == 0) { 00414 jack_log("JackServerGlobals Destroy"); 00415 Stop(); 00416 Delete(); 00417 jack_cleanup_shm(); 00418 JackTools::CleanupFiles(server_name); 00419 jack_unregister_server(server_name); 00420 } 00421 } 00422 00423 } // end of namespace 00424 00425