Jack2 1.9.7
|
00001 /* 00002 Copyright (C) 2001 Paul Davis 00003 Copyright (C) 2004-2008 Grame 00004 00005 This program is free software; you can redistribute it and/or modify 00006 it under the terms of the GNU General Public License as published by 00007 the Free Software Foundation; either version 2 of the License, or 00008 (at your option) any later version. 00009 00010 This program is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with this program; if not, write to the Free Software 00017 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00018 00019 */ 00020 00021 #include <iostream> 00022 #include <assert.h> 00023 #include <cassert> 00024 #include <csignal> 00025 #include <sys/types.h> 00026 #include <getopt.h> 00027 #include <cstring> 00028 #include <cstdio> 00029 #include <list> 00030 00031 #include "types.h" 00032 #include "jack.h" 00033 #include "JackConstants.h" 00034 #include "JackDriverLoader.h" 00035 00036 #if defined(JACK_DBUS) && defined(__linux__) 00037 #include <dbus/dbus.h> 00038 #include "audio_reserve.h" 00039 #endif 00040 00041 /* 00042 This is a simple port of the old jackdmp.cpp file to use the new Jack 2.0 control API. Available options for the server 00043 are "hard-coded" in the source. A much better approach would be to use the control API to: 00044 - dynamically retrieve available server parameters and then prepare to parse them 00045 - get available drivers and their possible parameters, then prepare to parse them. 00046 */ 00047 00048 #ifdef __APPLE__ 00049 #include <CoreFoundation/CFNotificationCenter.h> 00050 #include <CoreFoundation/CoreFoundation.h> 00051 00052 static void notify_server_start(const char* server_name) 00053 { 00054 // Send notification to be used in the JackRouter plugin 00055 CFStringRef ref = CFStringCreateWithCString(NULL, server_name, kCFStringEncodingMacRoman); 00056 CFNotificationCenterPostNotificationWithOptions(CFNotificationCenterGetDistributedCenter(), 00057 CFSTR("com.grame.jackserver.start"), 00058 ref, 00059 NULL, 00060 kCFNotificationDeliverImmediately | kCFNotificationPostToAllSessions); 00061 CFRelease(ref); 00062 } 00063 00064 static void notify_server_stop(const char* server_name) 00065 { 00066 // Send notification to be used in the JackRouter plugin 00067 CFStringRef ref1 = CFStringCreateWithCString(NULL, server_name, kCFStringEncodingMacRoman); 00068 CFNotificationCenterPostNotificationWithOptions(CFNotificationCenterGetDistributedCenter(), 00069 CFSTR("com.grame.jackserver.stop"), 00070 ref1, 00071 NULL, 00072 kCFNotificationDeliverImmediately | kCFNotificationPostToAllSessions); 00073 CFRelease(ref1); 00074 } 00075 00076 #else 00077 00078 static void notify_server_start(const char* server_name) 00079 {} 00080 static void notify_server_stop(const char* server_name) 00081 {} 00082 00083 #endif 00084 00085 static void copyright(FILE* file) 00086 { 00087 fprintf(file, "jackdmp " VERSION "\n" 00088 "Copyright 2001-2005 Paul Davis and others.\n" 00089 "Copyright 2004-2011 Grame.\n" 00090 "jackdmp comes with ABSOLUTELY NO WARRANTY\n" 00091 "This is free software, and you are welcome to redistribute it\n" 00092 "under certain conditions; see the file COPYING for details\n"); 00093 } 00094 00095 static void usage(FILE* file) 00096 { 00097 fprintf(file, "\n" 00098 "usage: jackdmp [ --no-realtime OR -r ]\n" 00099 " [ --realtime OR -R [ --realtime-priority OR -P priority ] ]\n" 00100 " (the two previous arguments are mutually exclusive. The default is --realtime)\n" 00101 " [ --name OR -n server-name ]\n" 00102 " [ --timeout OR -t client-timeout-in-msecs ]\n" 00103 " [ --loopback OR -L loopback-port-number ]\n" 00104 " [ --port-max OR -p maximum-number-of-ports]\n" 00105 " [ --slave-backend OR -X slave-backend-name ]\n" 00106 " [ --internal-client OR -I internal-client-name ]\n" 00107 " [ --verbose OR -v ]\n" 00108 #ifdef __linux__ 00109 " [ --clocksource OR -c [ c(ycle) | h(pet) | s(ystem) ]\n" 00110 #endif 00111 " [ --replace-registry ]\n" 00112 " [ --silent OR -s ]\n" 00113 " [ --sync OR -S ]\n" 00114 " [ --temporary OR -T ]\n" 00115 " [ --version OR -V ]\n" 00116 " -d master-backend-name [ ... master-backend args ... ]\n" 00117 #ifdef __APPLE__ 00118 " Available master backends may include: coreaudio, dummy or net.\n\n" 00119 #endif 00120 #ifdef WIN32 00121 " Available master backends may include: portaudio, dummy or net.\n\n" 00122 #endif 00123 #ifdef __linux__ 00124 " Available master backends may include: alsa, dummy, freebob, firewire or net\n\n" 00125 #endif 00126 #if defined(__sun__) || defined(sun) 00127 " Available master backends may include: boomer, oss, dummy or net.\n\n" 00128 #endif 00129 " jackdmp -d master-backend-name --help\n" 00130 " to display options for each master backend\n\n"); 00131 } 00132 00133 // To put in the control.h interface?? 00134 static jackctl_driver_t * 00135 jackctl_server_get_driver( 00136 jackctl_server_t *server, 00137 const char *driver_name) 00138 { 00139 const JSList * node_ptr; 00140 00141 node_ptr = jackctl_server_get_drivers_list(server); 00142 00143 while (node_ptr) 00144 { 00145 if (strcmp(jackctl_driver_get_name((jackctl_driver_t *)node_ptr->data), driver_name) == 0) 00146 { 00147 return (jackctl_driver_t *)node_ptr->data; 00148 } 00149 00150 node_ptr = jack_slist_next(node_ptr); 00151 } 00152 00153 return NULL; 00154 } 00155 00156 static jackctl_internal_t * jackctl_server_get_internal(jackctl_server_t *server, const char *internal_name) 00157 { 00158 const JSList * node_ptr = jackctl_server_get_internals_list(server); 00159 00160 while (node_ptr) { 00161 if (strcmp(jackctl_internal_get_name((jackctl_internal_t *)node_ptr->data), internal_name) == 0) { 00162 return (jackctl_internal_t *)node_ptr->data; 00163 } 00164 node_ptr = jack_slist_next(node_ptr); 00165 } 00166 00167 return NULL; 00168 } 00169 00170 static jackctl_parameter_t * 00171 jackctl_get_parameter( 00172 const JSList * parameters_list, 00173 const char * parameter_name) 00174 { 00175 while (parameters_list) 00176 { 00177 if (strcmp(jackctl_parameter_get_name((jackctl_parameter_t *)parameters_list->data), parameter_name) == 0) 00178 { 00179 return (jackctl_parameter_t *)parameters_list->data; 00180 } 00181 00182 parameters_list = jack_slist_next(parameters_list); 00183 } 00184 00185 return NULL; 00186 } 00187 00188 int main(int argc, char* argv[]) 00189 { 00190 jackctl_server_t * server_ctl; 00191 const JSList * server_parameters; 00192 const char* server_name = "default"; 00193 jackctl_driver_t * master_driver_ctl; 00194 jackctl_driver_t * loopback_driver_ctl; 00195 int replace_registry = 0; 00196 00197 const char *options = "-d:X:I:P:uvshVrRL:STFl:t:mn:p:" 00198 #ifdef __linux__ 00199 "c:" 00200 #endif 00201 ; 00202 00203 struct option long_options[] = { 00204 #ifdef __linux__ 00205 { "clock-source", 1, 0, 'c' }, 00206 #endif 00207 { "loopback-driver", 1, 0, 'L' }, 00208 { "audio-driver", 1, 0, 'd' }, 00209 { "midi-driver", 1, 0, 'X' }, 00210 { "internal-client", 1, 0, 'I' }, 00211 { "verbose", 0, 0, 'v' }, 00212 { "help", 0, 0, 'h' }, 00213 { "port-max", 1, 0, 'p' }, 00214 { "no-mlock", 0, 0, 'm' }, 00215 { "name", 1, 0, 'n' }, 00216 { "unlock", 0, 0, 'u' }, 00217 { "realtime", 0, 0, 'R' }, 00218 { "no-realtime", 0, 0, 'r' }, 00219 { "replace-registry", 0, &replace_registry, 0 }, 00220 { "loopback", 0, 0, 'L' }, 00221 { "realtime-priority", 1, 0, 'P' }, 00222 { "timeout", 1, 0, 't' }, 00223 { "temporary", 0, 0, 'T' }, 00224 { "version", 0, 0, 'V' }, 00225 { "silent", 0, 0, 's' }, 00226 { "sync", 0, 0, 'S' }, 00227 { 0, 0, 0, 0 } 00228 }; 00229 00230 int i,opt = 0; 00231 int option_index = 0; 00232 char* master_driver_name = NULL; 00233 char** master_driver_args = NULL; 00234 int master_driver_nargs = 1; 00235 int do_mlock = 1; 00236 int do_unlock = 0; 00237 int loopback = 0; 00238 bool show_version = false; 00239 sigset_t signals; 00240 jackctl_parameter_t* param; 00241 union jackctl_parameter_value value; 00242 00243 std::list<char*> internals_list; 00244 std::list<char*> slaves_list; 00245 std::list<char*>::iterator it; 00246 00247 // Assume that we fail. 00248 int return_value = -1; 00249 bool notify_sent = false; 00250 00251 copyright(stdout); 00252 #if defined(JACK_DBUS) && defined(__linux__) 00253 server_ctl = jackctl_server_create(audio_acquire, audio_release); 00254 #else 00255 server_ctl = jackctl_server_create(NULL, NULL); 00256 #endif 00257 if (server_ctl == NULL) { 00258 fprintf(stderr, "Failed to create server object\n"); 00259 return -1; 00260 } 00261 00262 server_parameters = jackctl_server_get_parameters(server_ctl); 00263 00264 // Default setting 00265 param = jackctl_get_parameter(server_parameters, "realtime"); 00266 if (param != NULL) { 00267 value.b = true; 00268 jackctl_parameter_set_value(param, &value); 00269 } 00270 00271 opterr = 0; 00272 while (!master_driver_name && 00273 (opt = getopt_long(argc, argv, options, 00274 long_options, &option_index)) != EOF) { 00275 switch (opt) { 00276 00277 #ifdef __linux__ 00278 case 'c': 00279 param = jackctl_get_parameter(server_parameters, "clock-source"); 00280 if (param != NULL) { 00281 if (tolower (optarg[0]) == 'h') { 00282 value.ui = JACK_TIMER_HPET; 00283 jackctl_parameter_set_value(param, &value); 00284 } else if (tolower (optarg[0]) == 'c') { 00285 value.ui = JACK_TIMER_CYCLE_COUNTER; 00286 jackctl_parameter_set_value(param, &value); 00287 } else if (tolower (optarg[0]) == 's') { 00288 value.ui = JACK_TIMER_SYSTEM_CLOCK; 00289 jackctl_parameter_set_value(param, &value); 00290 } else { 00291 usage(stdout); 00292 goto destroy_server; 00293 } 00294 } 00295 break; 00296 #endif 00297 00298 case 'd': 00299 master_driver_name = optarg; 00300 break; 00301 00302 case 'L': 00303 loopback = atoi(optarg); 00304 break; 00305 00306 case 'X': 00307 slaves_list.push_back(optarg); 00308 break; 00309 00310 case 'I': 00311 internals_list.push_back(optarg); 00312 break; 00313 00314 case 'p': 00315 param = jackctl_get_parameter(server_parameters, "port-max"); 00316 if (param != NULL) { 00317 value.ui = atoi(optarg); 00318 jackctl_parameter_set_value(param, &value); 00319 } 00320 break; 00321 00322 case 'm': 00323 do_mlock = 0; 00324 break; 00325 00326 case 'u': 00327 do_unlock = 1; 00328 break; 00329 00330 case 'v': 00331 param = jackctl_get_parameter(server_parameters, "verbose"); 00332 if (param != NULL) { 00333 value.b = true; 00334 jackctl_parameter_set_value(param, &value); 00335 } 00336 break; 00337 00338 case 's': 00339 jack_set_error_function(silent_jack_error_callback); 00340 break; 00341 00342 case 'S': 00343 param = jackctl_get_parameter(server_parameters, "sync"); 00344 if (param != NULL) { 00345 value.b = true; 00346 jackctl_parameter_set_value(param, &value); 00347 } 00348 break; 00349 00350 case 'n': 00351 server_name = optarg; 00352 param = jackctl_get_parameter(server_parameters, "name"); 00353 if (param != NULL) { 00354 strncpy(value.str, optarg, JACK_PARAM_STRING_MAX); 00355 jackctl_parameter_set_value(param, &value); 00356 } 00357 break; 00358 00359 case 'P': 00360 param = jackctl_get_parameter(server_parameters, "realtime-priority"); 00361 if (param != NULL) { 00362 value.i = atoi(optarg); 00363 jackctl_parameter_set_value(param, &value); 00364 } 00365 break; 00366 00367 case 'r': 00368 param = jackctl_get_parameter(server_parameters, "realtime"); 00369 if (param != NULL) { 00370 value.b = false; 00371 jackctl_parameter_set_value(param, &value); 00372 } 00373 break; 00374 00375 case 'R': 00376 param = jackctl_get_parameter(server_parameters, "realtime"); 00377 if (param != NULL) { 00378 value.b = true; 00379 jackctl_parameter_set_value(param, &value); 00380 } 00381 break; 00382 00383 case 'T': 00384 param = jackctl_get_parameter(server_parameters, "temporary"); 00385 if (param != NULL) { 00386 value.b = true; 00387 jackctl_parameter_set_value(param, &value); 00388 } 00389 break; 00390 00391 case 't': 00392 param = jackctl_get_parameter(server_parameters, "client-timeout"); 00393 if (param != NULL) { 00394 value.i = atoi(optarg); 00395 jackctl_parameter_set_value(param, &value); 00396 } 00397 break; 00398 00399 case 'V': 00400 show_version = true; 00401 break; 00402 00403 default: 00404 fprintf(stderr, "unknown option character %c\n", optopt); 00405 /*fallthru*/ 00406 00407 case 'h': 00408 usage(stdout); 00409 goto destroy_server; 00410 } 00411 } 00412 00413 // Long option with no letter so treated separately 00414 param = jackctl_get_parameter(server_parameters, "replace-registry"); 00415 if (param != NULL) { 00416 value.b = replace_registry; 00417 jackctl_parameter_set_value(param, &value); 00418 } 00419 00420 if (show_version) { 00421 printf( "jackdmp version " VERSION 00422 " tmpdir " jack_server_dir 00423 " protocol %d" 00424 "\n", JACK_PROTOCOL_VERSION); 00425 return -1; 00426 } 00427 00428 if (!master_driver_name) { 00429 usage(stderr); 00430 goto destroy_server; 00431 } 00432 00433 // Master driver 00434 master_driver_ctl = jackctl_server_get_driver(server_ctl, master_driver_name); 00435 if (master_driver_ctl == NULL) { 00436 fprintf(stderr, "Unknown driver \"%s\"\n", master_driver_name); 00437 goto destroy_server; 00438 } 00439 00440 if (optind < argc) { 00441 master_driver_nargs = 1 + argc - optind; 00442 } else { 00443 master_driver_nargs = 1; 00444 } 00445 00446 if (master_driver_nargs == 0) { 00447 fprintf(stderr, "No driver specified ... hmm. JACK won't do" 00448 " anything when run like this.\n"); 00449 goto destroy_server; 00450 } 00451 00452 master_driver_args = (char **) malloc(sizeof(char *) * master_driver_nargs); 00453 master_driver_args[0] = master_driver_name; 00454 00455 for (i = 1; i < master_driver_nargs; i++) { 00456 master_driver_args[i] = argv[optind++]; 00457 } 00458 00459 if (jackctl_parse_driver_params(master_driver_ctl, master_driver_nargs, master_driver_args)) { 00460 goto destroy_server; 00461 } 00462 00463 // Setup signals 00464 signals = jackctl_setup_signals(0); 00465 00466 // Open server 00467 if (! jackctl_server_open(server_ctl, master_driver_ctl)) { 00468 fprintf(stderr, "Failed to open server\n"); 00469 goto destroy_server; 00470 } 00471 00472 // Slave drivers 00473 for (it = slaves_list.begin(); it != slaves_list.end(); it++) { 00474 jackctl_driver_t * slave_driver_ctl = jackctl_server_get_driver(server_ctl, *it); 00475 if (slave_driver_ctl == NULL) { 00476 fprintf(stderr, "Unknown driver \"%s\"\n", *it); 00477 goto close_server; 00478 } 00479 jackctl_server_add_slave(server_ctl, slave_driver_ctl); 00480 } 00481 00482 // Loopback driver 00483 if (loopback > 0) { 00484 loopback_driver_ctl = jackctl_server_get_driver(server_ctl, "loopback"); 00485 00486 // XX: What if this fails? 00487 if (loopback_driver_ctl != NULL) { 00488 const JSList * loopback_parameters = jackctl_driver_get_parameters(loopback_driver_ctl); 00489 param = jackctl_get_parameter(loopback_parameters, "channels"); 00490 if (param != NULL) { 00491 value.ui = loopback; 00492 jackctl_parameter_set_value(param, &value); 00493 } 00494 jackctl_server_add_slave(server_ctl, loopback_driver_ctl); 00495 } 00496 00497 } 00498 00499 // Start the server 00500 if (!jackctl_server_start(server_ctl)) { 00501 fprintf(stderr, "Failed to start server\n"); 00502 goto close_server; 00503 } 00504 00505 // Internal clients 00506 for (it = internals_list.begin(); it != internals_list.end(); it++) { 00507 jackctl_internal_t * internal_driver_ctl = jackctl_server_get_internal(server_ctl, *it); 00508 if (internal_driver_ctl == NULL) { 00509 fprintf(stderr, "Unknown internal \"%s\"\n", *it); 00510 goto stop_server; 00511 } 00512 jackctl_server_load_internal(server_ctl, internal_driver_ctl); 00513 } 00514 00515 notify_server_start(server_name); 00516 notify_sent = true; 00517 return_value = 0; 00518 00519 // Waits for signal 00520 jackctl_wait_signals(signals); 00521 00522 stop_server: 00523 if (! jackctl_server_stop(server_ctl)) { 00524 fprintf(stderr, "Cannot stop server...\n"); 00525 } 00526 if (notify_sent) { 00527 notify_server_stop(server_name); 00528 } 00529 close_server: 00530 jackctl_server_close(server_ctl); 00531 destroy_server: 00532 jackctl_server_destroy(server_ctl); 00533 return return_value; 00534 }