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