Jack2 1.9.6
|
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 00030 #include "types.h" 00031 #include "jack.h" 00032 #include "JackConstants.h" 00033 #include "JackDriverLoader.h" 00034 00035 #if defined(JACK_DBUS) && defined(__linux__) 00036 #include <dbus/dbus.h> 00037 #include "audio_reserve.h" 00038 #endif 00039 00040 /* 00041 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 00042 are "hard-coded" in the source. A much better approach would be to use the control API to: 00043 - dynamically retrieve available server parameters and then prepare to parse them 00044 - get available drivers and their possible parameters, then prepare to parse them. 00045 */ 00046 00047 #ifdef __APPLE__ 00048 #include <CoreFoundation/CFNotificationCenter.h> 00049 #include <CoreFoundation/CoreFoundation.h> 00050 00051 static void notify_server_start(const char* server_name) 00052 { 00053 // Send notification to be used in the JackRouter plugin 00054 CFStringRef ref = CFStringCreateWithCString(NULL, server_name, kCFStringEncodingMacRoman); 00055 CFNotificationCenterPostNotificationWithOptions(CFNotificationCenterGetDistributedCenter(), 00056 CFSTR("com.grame.jackserver.start"), 00057 ref, 00058 NULL, 00059 kCFNotificationDeliverImmediately | kCFNotificationPostToAllSessions); 00060 CFRelease(ref); 00061 } 00062 00063 static void notify_server_stop(const char* server_name) 00064 { 00065 // Send notification to be used in the JackRouter plugin 00066 CFStringRef ref1 = CFStringCreateWithCString(NULL, server_name, kCFStringEncodingMacRoman); 00067 CFNotificationCenterPostNotificationWithOptions(CFNotificationCenterGetDistributedCenter(), 00068 CFSTR("com.grame.jackserver.stop"), 00069 ref1, 00070 NULL, 00071 kCFNotificationDeliverImmediately | kCFNotificationPostToAllSessions); 00072 CFRelease(ref1); 00073 } 00074 00075 #else 00076 00077 static void notify_server_start(const char* server_name) 00078 {} 00079 static void notify_server_stop(const char* server_name) 00080 {} 00081 00082 #endif 00083 00084 static void copyright(FILE* file) 00085 { 00086 fprintf(file, "jackdmp " VERSION "\n" 00087 "Copyright 2001-2005 Paul Davis and others.\n" 00088 "Copyright 2004-2010 Grame.\n" 00089 "jackdmp comes with ABSOLUTELY NO WARRANTY\n" 00090 "This is free software, and you are welcome to redistribute it\n" 00091 "under certain conditions; see the file COPYING for details\n"); 00092 } 00093 00094 static void usage(FILE* file) 00095 { 00096 fprintf(file, "\n" 00097 "usage: jackdmp [ --no-realtime OR -r ]\n" 00098 " [ --realtime OR -R [ --realtime-priority OR -P priority ] ]\n" 00099 " (the two previous arguments are mutually exclusive. The default is --realtime)\n" 00100 " [ --name OR -n server-name ]\n" 00101 " [ --timeout OR -t client-timeout-in-msecs ]\n" 00102 " [ --loopback OR -L loopback-port-number ]\n" 00103 " [ --port-max OR -p maximum-number-of-ports]\n" 00104 " [ --midi OR -X midi-driver ]\n" 00105 " [ --verbose OR -v ]\n" 00106 #ifdef __linux__ 00107 " [ --clocksource OR -c [ c(ycle) | h(pet) | s(ystem) ]\n" 00108 #endif 00109 " [ --replace-registry ]\n" 00110 " [ --silent OR -s ]\n" 00111 " [ --sync OR -S ]\n" 00112 " [ --temporary OR -T ]\n" 00113 " [ --version OR -V ]\n" 00114 " -d backend [ ... backend args ... ]\n" 00115 #ifdef __APPLE__ 00116 " Available backends may include: coreaudio, dummy or net.\n\n" 00117 #endif 00118 #ifdef WIN32 00119 " Available backends may include: portaudio, dummy or net.\n\n" 00120 #endif 00121 #ifdef __linux__ 00122 " Available backends may include: alsa, dummy, freebob, firewire or net\n\n" 00123 #endif 00124 #if defined(__sun__) || defined(sun) 00125 " Available backends may include: boomer, oss, dummy or net.\n\n" 00126 #endif 00127 " jackdmp -d backend --help\n" 00128 " to display options for each backend\n\n"); 00129 } 00130 00131 // To put in the control.h interface?? 00132 static jackctl_driver_t * 00133 jackctl_server_get_driver( 00134 jackctl_server_t *server, 00135 const char *driver_name) 00136 { 00137 const JSList * node_ptr; 00138 00139 node_ptr = jackctl_server_get_drivers_list(server); 00140 00141 while (node_ptr) 00142 { 00143 if (strcmp(jackctl_driver_get_name((jackctl_driver_t *)node_ptr->data), driver_name) == 0) 00144 { 00145 return (jackctl_driver_t *)node_ptr->data; 00146 } 00147 00148 node_ptr = jack_slist_next(node_ptr); 00149 } 00150 00151 return NULL; 00152 } 00153 00154 static jackctl_parameter_t * 00155 jackctl_get_parameter( 00156 const JSList * parameters_list, 00157 const char * parameter_name) 00158 { 00159 while (parameters_list) 00160 { 00161 if (strcmp(jackctl_parameter_get_name((jackctl_parameter_t *)parameters_list->data), parameter_name) == 0) 00162 { 00163 return (jackctl_parameter_t *)parameters_list->data; 00164 } 00165 00166 parameters_list = jack_slist_next(parameters_list); 00167 } 00168 00169 return NULL; 00170 } 00171 00172 int main(int argc, char* argv[]) 00173 { 00174 jackctl_server_t * server_ctl; 00175 const JSList * server_parameters; 00176 const char* server_name = "default"; 00177 jackctl_driver_t * audio_driver_ctl; 00178 jackctl_driver_t * midi_driver_ctl; 00179 jackctl_driver_t * loopback_driver_ctl; 00180 int replace_registry = 0; 00181 00182 const char *options = "-d:X:P:uvshVrRL:STFl:t:mn:p:" 00183 #ifdef __linux__ 00184 "c:" 00185 #endif 00186 ; 00187 00188 struct option long_options[] = { 00189 #ifdef __linux__ 00190 { "clock-source", 1, 0, 'c' }, 00191 #endif 00192 { "loopback-driver", 1, 0, 'L' }, 00193 { "audio-driver", 1, 0, 'd' }, 00194 { "midi-driver", 1, 0, 'X' }, 00195 { "verbose", 0, 0, 'v' }, 00196 { "help", 0, 0, 'h' }, 00197 { "port-max", 1, 0, 'p' }, 00198 { "no-mlock", 0, 0, 'm' }, 00199 { "name", 0, 0, 'n' }, 00200 { "unlock", 0, 0, 'u' }, 00201 { "realtime", 0, 0, 'R' }, 00202 { "no-realtime", 0, 0, 'r' }, 00203 { "replace-registry", 0, &replace_registry, 0 }, 00204 { "loopback", 0, 0, 'L' }, 00205 { "realtime-priority", 1, 0, 'P' }, 00206 { "timeout", 1, 0, 't' }, 00207 { "temporary", 0, 0, 'T' }, 00208 { "version", 0, 0, 'V' }, 00209 { "silent", 0, 0, 's' }, 00210 { "sync", 0, 0, 'S' }, 00211 { 0, 0, 0, 0 } 00212 }; 00213 00214 int i,opt = 0; 00215 int option_index = 0; 00216 bool seen_audio_driver = false; 00217 bool seen_midi_driver = false; 00218 char *audio_driver_name = NULL; 00219 char **audio_driver_args = NULL; 00220 int audio_driver_nargs = 1; 00221 char *midi_driver_name = NULL; 00222 char **midi_driver_args = NULL; 00223 int midi_driver_nargs = 1; 00224 int do_mlock = 1; 00225 int do_unlock = 0; 00226 int loopback = 0; 00227 bool show_version = false; 00228 sigset_t signals; 00229 jackctl_parameter_t* param; 00230 union jackctl_parameter_value value; 00231 00232 copyright(stdout); 00233 #if defined(JACK_DBUS) && defined(__linux__) 00234 server_ctl = jackctl_server_create(audio_acquire, audio_release); 00235 #else 00236 server_ctl = jackctl_server_create(NULL, NULL); 00237 #endif 00238 if (server_ctl == NULL) { 00239 fprintf(stderr, "Failed to create server object\n"); 00240 return -1; 00241 } 00242 00243 server_parameters = jackctl_server_get_parameters(server_ctl); 00244 00245 // Default setting 00246 param = jackctl_get_parameter(server_parameters, "realtime"); 00247 if (param != NULL) { 00248 value.b = true; 00249 jackctl_parameter_set_value(param, &value); 00250 } 00251 00252 opterr = 0; 00253 while (!seen_audio_driver && 00254 (opt = getopt_long(argc, argv, options, 00255 long_options, &option_index)) != EOF) { 00256 switch (opt) { 00257 00258 #ifdef __linux__ 00259 case 'c': 00260 param = jackctl_get_parameter(server_parameters, "clock-source"); 00261 if (param != NULL) { 00262 if (tolower (optarg[0]) == 'h') { 00263 value.ui = JACK_TIMER_HPET; 00264 jackctl_parameter_set_value(param, &value); 00265 } else if (tolower (optarg[0]) == 'c') { 00266 value.ui = JACK_TIMER_CYCLE_COUNTER; 00267 jackctl_parameter_set_value(param, &value); 00268 } else if (tolower (optarg[0]) == 's') { 00269 value.ui = JACK_TIMER_SYSTEM_CLOCK; 00270 jackctl_parameter_set_value(param, &value); 00271 } else { 00272 usage(stdout); 00273 goto fail_free1; 00274 } 00275 } 00276 break; 00277 #endif 00278 00279 case 'd': 00280 seen_audio_driver = true; 00281 audio_driver_name = optarg; 00282 break; 00283 00284 case 'L': 00285 loopback = atoi(optarg); 00286 break; 00287 00288 case 'X': 00289 seen_midi_driver = true; 00290 midi_driver_name = optarg; 00291 break; 00292 00293 case 'p': 00294 param = jackctl_get_parameter(server_parameters, "port-max"); 00295 if (param != NULL) { 00296 value.ui = atoi(optarg); 00297 jackctl_parameter_set_value(param, &value); 00298 } 00299 break; 00300 00301 case 'm': 00302 do_mlock = 0; 00303 break; 00304 00305 case 'u': 00306 do_unlock = 1; 00307 break; 00308 00309 case 'v': 00310 param = jackctl_get_parameter(server_parameters, "verbose"); 00311 if (param != NULL) { 00312 value.b = true; 00313 jackctl_parameter_set_value(param, &value); 00314 } 00315 break; 00316 00317 case 's': 00318 jack_set_error_function(silent_jack_error_callback); 00319 break; 00320 00321 case 'S': 00322 param = jackctl_get_parameter(server_parameters, "sync"); 00323 if (param != NULL) { 00324 value.b = true; 00325 jackctl_parameter_set_value(param, &value); 00326 } 00327 break; 00328 00329 case 'n': 00330 server_name = optarg; 00331 param = jackctl_get_parameter(server_parameters, "name"); 00332 if (param != NULL) { 00333 strncpy(value.str, optarg, JACK_PARAM_STRING_MAX); 00334 jackctl_parameter_set_value(param, &value); 00335 } 00336 break; 00337 00338 case 'P': 00339 param = jackctl_get_parameter(server_parameters, "realtime-priority"); 00340 if (param != NULL) { 00341 value.i = atoi(optarg); 00342 jackctl_parameter_set_value(param, &value); 00343 } 00344 break; 00345 00346 case 'r': 00347 param = jackctl_get_parameter(server_parameters, "realtime"); 00348 if (param != NULL) { 00349 value.b = false; 00350 jackctl_parameter_set_value(param, &value); 00351 } 00352 break; 00353 00354 case 'R': 00355 param = jackctl_get_parameter(server_parameters, "realtime"); 00356 if (param != NULL) { 00357 value.b = true; 00358 jackctl_parameter_set_value(param, &value); 00359 } 00360 break; 00361 00362 case 'T': 00363 param = jackctl_get_parameter(server_parameters, "temporary"); 00364 if (param != NULL) { 00365 value.b = true; 00366 jackctl_parameter_set_value(param, &value); 00367 } 00368 break; 00369 00370 case 't': 00371 param = jackctl_get_parameter(server_parameters, "client-timeout"); 00372 if (param != NULL) { 00373 value.i = atoi(optarg); 00374 jackctl_parameter_set_value(param, &value); 00375 } 00376 break; 00377 00378 case 'V': 00379 show_version = true; 00380 break; 00381 00382 default: 00383 fprintf(stderr, "unknown option character %c\n", optopt); 00384 /*fallthru*/ 00385 00386 case 'h': 00387 usage(stdout); 00388 goto fail_free1; 00389 } 00390 } 00391 00392 // Long option with no letter so treated separately 00393 param = jackctl_get_parameter(server_parameters, "replace-registry"); 00394 if (param != NULL) { 00395 value.b = replace_registry; 00396 jackctl_parameter_set_value(param, &value); 00397 } 00398 00399 if (show_version) { 00400 printf( "jackdmp version " VERSION 00401 " tmpdir " jack_server_dir 00402 " protocol %d" 00403 "\n", JACK_PROTOCOL_VERSION); 00404 return -1; 00405 } 00406 00407 if (!seen_audio_driver) { 00408 usage(stderr); 00409 goto fail_free1; 00410 } 00411 00412 // Audio driver 00413 audio_driver_ctl = jackctl_server_get_driver(server_ctl, audio_driver_name); 00414 if (audio_driver_ctl == NULL) { 00415 fprintf(stderr, "Unknown driver \"%s\"\n", audio_driver_name); 00416 goto fail_free1; 00417 } 00418 00419 if (optind < argc) { 00420 audio_driver_nargs = 1 + argc - optind; 00421 } else { 00422 audio_driver_nargs = 1; 00423 } 00424 00425 if (audio_driver_nargs == 0) { 00426 fprintf(stderr, "No driver specified ... hmm. JACK won't do" 00427 " anything when run like this.\n"); 00428 goto fail_free1; 00429 } 00430 00431 audio_driver_args = (char **) malloc(sizeof(char *) * audio_driver_nargs); 00432 audio_driver_args[0] = audio_driver_name; 00433 00434 for (i = 1; i < audio_driver_nargs; i++) { 00435 audio_driver_args[i] = argv[optind++]; 00436 } 00437 00438 if (jackctl_parse_driver_params(audio_driver_ctl, audio_driver_nargs, audio_driver_args)) { 00439 goto fail_free1; 00440 } 00441 00442 // Start server 00443 if (!jackctl_server_start(server_ctl, audio_driver_ctl)) { 00444 fprintf(stderr, "Failed to start server\n"); 00445 goto fail_free1; 00446 } 00447 00448 // MIDI driver 00449 if (seen_midi_driver) { 00450 00451 midi_driver_ctl = jackctl_server_get_driver(server_ctl, midi_driver_name); 00452 if (midi_driver_ctl == NULL) { 00453 fprintf(stderr, "Unknown driver \"%s\"\n", midi_driver_name); 00454 goto fail_free2; 00455 } 00456 00457 jackctl_server_add_slave(server_ctl, midi_driver_ctl); 00458 } 00459 00460 // Loopback driver 00461 if (loopback > 0) { 00462 loopback_driver_ctl = jackctl_server_get_driver(server_ctl, "loopback"); 00463 if (loopback_driver_ctl != NULL) { 00464 const JSList * loopback_parameters = jackctl_driver_get_parameters(loopback_driver_ctl); 00465 param = jackctl_get_parameter(loopback_parameters, "channels"); 00466 if (param != NULL) { 00467 value.ui = loopback; 00468 jackctl_parameter_set_value(param, &value); 00469 } 00470 jackctl_server_add_slave(server_ctl, loopback_driver_ctl); 00471 } 00472 } 00473 00474 notify_server_start(server_name); 00475 00476 // Waits for signal 00477 signals = jackctl_setup_signals(0); 00478 jackctl_wait_signals(signals); 00479 00480 if (!jackctl_server_stop(server_ctl)) 00481 fprintf(stderr, "Cannot stop server...\n"); 00482 00483 jackctl_server_destroy(server_ctl); 00484 notify_server_stop(server_name); 00485 return 0; 00486 00487 fail_free1: 00488 jackctl_server_destroy(server_ctl); 00489 return -1; 00490 00491 fail_free2: 00492 jackctl_server_stop(server_ctl); 00493 jackctl_server_destroy(server_ctl); 00494 notify_server_stop(server_name); 00495 return -1; 00496 }